124084f9bSBrian Somers /* 224084f9bSBrian Somers * natd - Network Address Translation Daemon for FreeBSD. 324084f9bSBrian Somers * 424084f9bSBrian Somers * This software ois provided free of charge, with no 524084f9bSBrian Somers * warranty of any kind, either expressed or implied. 624084f9bSBrian Somers * Use at your own risk. 724084f9bSBrian Somers * 824084f9bSBrian Somers * You may copy, modify and distribute this software (natd.c) freely. 924084f9bSBrian Somers * 1024084f9bSBrian Somers * Ari Suutari (ari@kn6-045.ktvlpr.inet.fi, ari@ps.carel.fi) 1124084f9bSBrian Somers * 1224084f9bSBrian Somers */ 1324084f9bSBrian Somers 1424084f9bSBrian Somers #include <stdlib.h> 1524084f9bSBrian Somers #include <stdio.h> 1624084f9bSBrian Somers #include <unistd.h> 1724084f9bSBrian Somers #include <string.h> 1824084f9bSBrian Somers #include <ctype.h> 1924084f9bSBrian Somers 2024084f9bSBrian Somers #include <sys/types.h> 2124084f9bSBrian Somers #include <sys/socket.h> 2224084f9bSBrian Somers #include <sys/time.h> 2324084f9bSBrian Somers #include <errno.h> 2424084f9bSBrian Somers #include <signal.h> 2524084f9bSBrian Somers 2624084f9bSBrian Somers #include <netdb.h> 2724084f9bSBrian Somers 2824084f9bSBrian Somers #include <netinet/in.h> 2924084f9bSBrian Somers #include <netinet/in_systm.h> 3024084f9bSBrian Somers #include <netinet/ip.h> 3124084f9bSBrian Somers #include <machine/in_cksum.h> 3224084f9bSBrian Somers #include <netinet/tcp.h> 3324084f9bSBrian Somers #include <sys/ioctl.h> 3424084f9bSBrian Somers #include <net/if.h> 3524084f9bSBrian Somers #include <net/route.h> 3624084f9bSBrian Somers #include <arpa/inet.h> 3724084f9bSBrian Somers 3824084f9bSBrian Somers #include <syslog.h> 3924084f9bSBrian Somers #include <alias.h> 4024084f9bSBrian Somers 4124084f9bSBrian Somers #include "natd.h" 4224084f9bSBrian Somers 4324084f9bSBrian Somers /* 4424084f9bSBrian Somers * Default values for input and output 4524084f9bSBrian Somers * divert socket ports. 4624084f9bSBrian Somers */ 4724084f9bSBrian Somers 4824084f9bSBrian Somers #define DEFAULT_SERVICE "natd" 4924084f9bSBrian Somers 5024084f9bSBrian Somers /* 5124084f9bSBrian Somers * Function prototypes. 5224084f9bSBrian Somers */ 5324084f9bSBrian Somers 5424084f9bSBrian Somers static void DoAliasing (int fd); 5524084f9bSBrian Somers static void DaemonMode (); 5624084f9bSBrian Somers static void HandleRoutingInfo (int fd); 5724084f9bSBrian Somers static void Usage (); 5824084f9bSBrian Somers static void PrintPacket (struct ip*); 5924084f9bSBrian Somers static void SetAliasAddressFromIfName (char* ifName); 6024084f9bSBrian Somers static void InitiateShutdown (); 6124084f9bSBrian Somers static void Shutdown (); 6224084f9bSBrian Somers static void RefreshAddr (); 6324084f9bSBrian Somers static void ParseOption (char* option, char* parms, int cmdLine); 6424084f9bSBrian Somers static void ReadConfigFile (char* fileName); 6524084f9bSBrian Somers static void SetupPermanentLink (char* parms); 6624084f9bSBrian Somers static void SetupPortRedirect (char* parms); 6724084f9bSBrian Somers static void SetupAddressRedirect (char* parms); 6824084f9bSBrian Somers static void StrToAddr (char* str, struct in_addr* addr); 6924084f9bSBrian Somers static int StrToPort (char* str, char* proto); 7024084f9bSBrian Somers static int StrToProto (char* str); 7124084f9bSBrian Somers static int StrToAddrAndPort (char* str, struct in_addr* addr, char* proto); 7224084f9bSBrian Somers static void ParseArgs (int argc, char** argv); 7324084f9bSBrian Somers 7424084f9bSBrian Somers /* 7524084f9bSBrian Somers * Globals. 7624084f9bSBrian Somers */ 7724084f9bSBrian Somers 7824084f9bSBrian Somers static int verbose; 7924084f9bSBrian Somers static int background; 8024084f9bSBrian Somers static int running; 8124084f9bSBrian Somers static int assignAliasAddr; 8224084f9bSBrian Somers static char* ifName; 8324084f9bSBrian Somers static int ifIndex; 8424084f9bSBrian Somers static int inPort; 8524084f9bSBrian Somers static int outPort; 8624084f9bSBrian Somers static int inOutPort; 8724084f9bSBrian Somers static struct in_addr aliasAddr; 8824084f9bSBrian Somers static int dynamicMode; 8924084f9bSBrian Somers static int ifMTU; 9024084f9bSBrian Somers static int aliasOverhead; 9124084f9bSBrian Somers static int icmpSock; 9224084f9bSBrian Somers 9324084f9bSBrian Somers int main (int argc, char** argv) 9424084f9bSBrian Somers { 9524084f9bSBrian Somers int divertIn; 9624084f9bSBrian Somers int divertOut; 9724084f9bSBrian Somers int divertInOut; 9824084f9bSBrian Somers int routeSock; 9924084f9bSBrian Somers struct sockaddr_in addr; 10024084f9bSBrian Somers fd_set readMask; 10124084f9bSBrian Somers int fdMax; 10224084f9bSBrian Somers /* 10324084f9bSBrian Somers * Initialize packet aliasing software. 10424084f9bSBrian Somers * Done already here to be able to alter option bits 10524084f9bSBrian Somers * during command line and configuration file processing. 10624084f9bSBrian Somers */ 10724084f9bSBrian Somers InitPacketAlias (); 10824084f9bSBrian Somers /* 10924084f9bSBrian Somers * Parse options. 11024084f9bSBrian Somers */ 11124084f9bSBrian Somers inPort = 0; 11224084f9bSBrian Somers outPort = 0; 11324084f9bSBrian Somers verbose = 0; 11424084f9bSBrian Somers inOutPort = 0; 11524084f9bSBrian Somers ifName = NULL; 11624084f9bSBrian Somers ifMTU = -1; 11724084f9bSBrian Somers background = 0; 11824084f9bSBrian Somers running = 1; 11924084f9bSBrian Somers assignAliasAddr = 0; 12024084f9bSBrian Somers aliasAddr.s_addr = INADDR_NONE; 12124084f9bSBrian Somers aliasOverhead = 12; 12224084f9bSBrian Somers dynamicMode = 0; 12324084f9bSBrian Somers 12424084f9bSBrian Somers ParseArgs (argc, argv); 12524084f9bSBrian Somers /* 12624084f9bSBrian Somers * Check that valid aliasing address has been given. 12724084f9bSBrian Somers */ 12824084f9bSBrian Somers if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL) { 12924084f9bSBrian Somers 13024084f9bSBrian Somers fprintf (stderr, "Aliasing address not given.\n"); 13124084f9bSBrian Somers exit (1); 13224084f9bSBrian Somers } 13324084f9bSBrian Somers 13424084f9bSBrian Somers if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL) { 13524084f9bSBrian Somers 13624084f9bSBrian Somers fprintf (stderr, "Both alias address and interface name " 13724084f9bSBrian Somers "are not allowed.\n"); 13824084f9bSBrian Somers exit (1); 13924084f9bSBrian Somers } 14024084f9bSBrian Somers /* 14124084f9bSBrian Somers * Check that valid port number is known. 14224084f9bSBrian Somers */ 14324084f9bSBrian Somers if (inPort != 0 || outPort != 0) 14424084f9bSBrian Somers if (inPort == 0 || outPort == 0) { 14524084f9bSBrian Somers 14624084f9bSBrian Somers fprintf (stderr, "Both input and output ports" 14724084f9bSBrian Somers " are required.\n"); 14824084f9bSBrian Somers exit (1); 14924084f9bSBrian Somers } 15024084f9bSBrian Somers 15124084f9bSBrian Somers if (inPort == 0 && outPort == 0 && inOutPort == 0) 15224084f9bSBrian Somers ParseOption ("port", DEFAULT_SERVICE, 0); 15324084f9bSBrian Somers 15424084f9bSBrian Somers /* 15524084f9bSBrian Somers * Create divert sockets. Use only one socket if -p was specified 15624084f9bSBrian Somers * on command line. Otherwise, create separate sockets for 15724084f9bSBrian Somers * outgoing and incoming connnections. 15824084f9bSBrian Somers */ 15924084f9bSBrian Somers if (inOutPort) { 16024084f9bSBrian Somers 16124084f9bSBrian Somers divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 16224084f9bSBrian Somers if (divertInOut == -1) 16324084f9bSBrian Somers Quit ("Unable to create divert socket."); 16424084f9bSBrian Somers 16524084f9bSBrian Somers divertIn = -1; 16624084f9bSBrian Somers divertOut = -1; 16724084f9bSBrian Somers /* 16824084f9bSBrian Somers * Bind socket. 16924084f9bSBrian Somers */ 17024084f9bSBrian Somers 17124084f9bSBrian Somers addr.sin_family = AF_INET; 17224084f9bSBrian Somers addr.sin_addr.s_addr = INADDR_ANY; 17324084f9bSBrian Somers addr.sin_port = inOutPort; 17424084f9bSBrian Somers 17524084f9bSBrian Somers if (bind (divertInOut, 17624084f9bSBrian Somers (struct sockaddr*) &addr, 17724084f9bSBrian Somers sizeof addr) == -1) 17824084f9bSBrian Somers Quit ("Unable to bind divert socket."); 17924084f9bSBrian Somers } 18024084f9bSBrian Somers else { 18124084f9bSBrian Somers 18224084f9bSBrian Somers divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 18324084f9bSBrian Somers if (divertIn == -1) 18424084f9bSBrian Somers Quit ("Unable to create incoming divert socket."); 18524084f9bSBrian Somers 18624084f9bSBrian Somers divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 18724084f9bSBrian Somers if (divertOut == -1) 18824084f9bSBrian Somers Quit ("Unable to create outgoing divert socket."); 18924084f9bSBrian Somers 19024084f9bSBrian Somers divertInOut = -1; 19124084f9bSBrian Somers 19224084f9bSBrian Somers /* 19324084f9bSBrian Somers * Bind divert sockets. 19424084f9bSBrian Somers */ 19524084f9bSBrian Somers 19624084f9bSBrian Somers addr.sin_family = AF_INET; 19724084f9bSBrian Somers addr.sin_addr.s_addr = INADDR_ANY; 19824084f9bSBrian Somers addr.sin_port = inPort; 19924084f9bSBrian Somers 20024084f9bSBrian Somers if (bind (divertIn, 20124084f9bSBrian Somers (struct sockaddr*) &addr, 20224084f9bSBrian Somers sizeof addr) == -1) 20324084f9bSBrian Somers Quit ("Unable to bind incoming divert socket."); 20424084f9bSBrian Somers 20524084f9bSBrian Somers addr.sin_family = AF_INET; 20624084f9bSBrian Somers addr.sin_addr.s_addr = INADDR_ANY; 20724084f9bSBrian Somers addr.sin_port = outPort; 20824084f9bSBrian Somers 20924084f9bSBrian Somers if (bind (divertOut, 21024084f9bSBrian Somers (struct sockaddr*) &addr, 21124084f9bSBrian Somers sizeof addr) == -1) 21224084f9bSBrian Somers Quit ("Unable to bind outgoing divert socket."); 21324084f9bSBrian Somers } 21424084f9bSBrian Somers /* 21524084f9bSBrian Somers * Create routing socket if interface name specified. 21624084f9bSBrian Somers */ 21724084f9bSBrian Somers if (ifName && dynamicMode) { 21824084f9bSBrian Somers 21924084f9bSBrian Somers routeSock = socket (PF_ROUTE, SOCK_RAW, 0); 22024084f9bSBrian Somers if (routeSock == -1) 22124084f9bSBrian Somers Quit ("Unable to create routing info socket."); 22224084f9bSBrian Somers } 22324084f9bSBrian Somers else 22424084f9bSBrian Somers routeSock = -1; 22524084f9bSBrian Somers /* 22624084f9bSBrian Somers * Create socket for sending ICMP messages. 22724084f9bSBrian Somers */ 22824084f9bSBrian Somers icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); 22924084f9bSBrian Somers if (icmpSock == -1) 23024084f9bSBrian Somers Quit ("Unable to create ICMP socket."); 23124084f9bSBrian Somers /* 23224084f9bSBrian Somers * Become a daemon unless verbose mode was requested. 23324084f9bSBrian Somers */ 23424084f9bSBrian Somers if (!verbose) 23524084f9bSBrian Somers DaemonMode (); 23624084f9bSBrian Somers /* 23724084f9bSBrian Somers * Catch signals to manage shutdown and 23824084f9bSBrian Somers * refresh of interface address. 23924084f9bSBrian Somers */ 24024084f9bSBrian Somers signal (SIGTERM, InitiateShutdown); 24124084f9bSBrian Somers signal (SIGHUP, RefreshAddr); 24224084f9bSBrian Somers /* 24324084f9bSBrian Somers * Set alias address if it has been given. 24424084f9bSBrian Somers */ 24524084f9bSBrian Somers if (aliasAddr.s_addr != INADDR_NONE) 24624084f9bSBrian Somers SetPacketAliasAddress (aliasAddr); 24724084f9bSBrian Somers 24824084f9bSBrian Somers if (divertInOut != -1 && !ifName) { 24924084f9bSBrian Somers 25024084f9bSBrian Somers /* 25124084f9bSBrian Somers * When using only one socket, just call 25224084f9bSBrian Somers * DoAliasing repeatedly to process packets. 25324084f9bSBrian Somers */ 25424084f9bSBrian Somers while (running) 25524084f9bSBrian Somers DoAliasing (divertInOut); 25624084f9bSBrian Somers } 25724084f9bSBrian Somers else { 25824084f9bSBrian Somers /* 25924084f9bSBrian Somers * We need largest descriptor number for select. 26024084f9bSBrian Somers */ 26124084f9bSBrian Somers 26224084f9bSBrian Somers fdMax = -1; 26324084f9bSBrian Somers 26424084f9bSBrian Somers if (divertIn > fdMax) 26524084f9bSBrian Somers fdMax = divertIn; 26624084f9bSBrian Somers 26724084f9bSBrian Somers if (divertOut > fdMax) 26824084f9bSBrian Somers fdMax = divertOut; 26924084f9bSBrian Somers 27024084f9bSBrian Somers if (divertInOut > fdMax) 27124084f9bSBrian Somers fdMax = divertInOut; 27224084f9bSBrian Somers 27324084f9bSBrian Somers if (routeSock > fdMax) 27424084f9bSBrian Somers fdMax = routeSock; 27524084f9bSBrian Somers 27624084f9bSBrian Somers while (running) { 27724084f9bSBrian Somers /* 27824084f9bSBrian Somers * Build read mask from socket descriptors to select. 27924084f9bSBrian Somers */ 28024084f9bSBrian Somers FD_ZERO (&readMask); 28124084f9bSBrian Somers 28224084f9bSBrian Somers if (divertIn != -1) 28324084f9bSBrian Somers FD_SET (divertIn, &readMask); 28424084f9bSBrian Somers 28524084f9bSBrian Somers if (divertOut != -1) 28624084f9bSBrian Somers FD_SET (divertOut, &readMask); 28724084f9bSBrian Somers 28824084f9bSBrian Somers if (divertInOut != -1) 28924084f9bSBrian Somers FD_SET (divertInOut, &readMask); 29024084f9bSBrian Somers 29124084f9bSBrian Somers if (routeSock != -1) 29224084f9bSBrian Somers FD_SET (routeSock, &readMask); 29324084f9bSBrian Somers 29424084f9bSBrian Somers if (select (fdMax + 1, 29524084f9bSBrian Somers &readMask, 29624084f9bSBrian Somers NULL, 29724084f9bSBrian Somers NULL, 29824084f9bSBrian Somers NULL) == -1) { 29924084f9bSBrian Somers 30024084f9bSBrian Somers if (errno == EINTR) 30124084f9bSBrian Somers continue; 30224084f9bSBrian Somers 30324084f9bSBrian Somers Quit ("Select failed."); 30424084f9bSBrian Somers } 30524084f9bSBrian Somers 30624084f9bSBrian Somers if (divertIn != -1) 30724084f9bSBrian Somers if (FD_ISSET (divertIn, &readMask)) 30824084f9bSBrian Somers DoAliasing (divertIn); 30924084f9bSBrian Somers 31024084f9bSBrian Somers if (divertOut != -1) 31124084f9bSBrian Somers if (FD_ISSET (divertOut, &readMask)) 31224084f9bSBrian Somers DoAliasing (divertOut); 31324084f9bSBrian Somers 31424084f9bSBrian Somers if (divertInOut != -1) 31524084f9bSBrian Somers if (FD_ISSET (divertInOut, &readMask)) 31624084f9bSBrian Somers DoAliasing (divertInOut); 31724084f9bSBrian Somers 31824084f9bSBrian Somers if (routeSock != -1) 31924084f9bSBrian Somers if (FD_ISSET (routeSock, &readMask)) 32024084f9bSBrian Somers HandleRoutingInfo (routeSock); 32124084f9bSBrian Somers } 32224084f9bSBrian Somers } 32324084f9bSBrian Somers 32424084f9bSBrian Somers if (background) 32524084f9bSBrian Somers unlink (PIDFILE); 32624084f9bSBrian Somers 32724084f9bSBrian Somers return 0; 32824084f9bSBrian Somers } 32924084f9bSBrian Somers 33024084f9bSBrian Somers static void DaemonMode () 33124084f9bSBrian Somers { 33224084f9bSBrian Somers FILE* pidFile; 33324084f9bSBrian Somers 33424084f9bSBrian Somers daemon (0, 0); 33524084f9bSBrian Somers background = 1; 33624084f9bSBrian Somers 33724084f9bSBrian Somers pidFile = fopen (PIDFILE, "w"); 33824084f9bSBrian Somers if (pidFile) { 33924084f9bSBrian Somers 34024084f9bSBrian Somers fprintf (pidFile, "%d\n", getpid ()); 34124084f9bSBrian Somers fclose (pidFile); 34224084f9bSBrian Somers } 34324084f9bSBrian Somers } 34424084f9bSBrian Somers 34524084f9bSBrian Somers static void ParseArgs (int argc, char** argv) 34624084f9bSBrian Somers { 34724084f9bSBrian Somers int arg; 34824084f9bSBrian Somers char* parm; 34924084f9bSBrian Somers char* opt; 35024084f9bSBrian Somers char parmBuf[256]; 35124084f9bSBrian Somers 35224084f9bSBrian Somers for (arg = 1; arg < argc; arg++) { 35324084f9bSBrian Somers 35424084f9bSBrian Somers opt = argv[arg]; 35524084f9bSBrian Somers if (*opt != '-') { 35624084f9bSBrian Somers 35724084f9bSBrian Somers fprintf (stderr, "Invalid option %s.\n", opt); 35824084f9bSBrian Somers Usage (); 35924084f9bSBrian Somers } 36024084f9bSBrian Somers 36124084f9bSBrian Somers parm = NULL; 36224084f9bSBrian Somers parmBuf[0] = '\0'; 36324084f9bSBrian Somers 36424084f9bSBrian Somers while (arg < argc - 1) { 36524084f9bSBrian Somers 36624084f9bSBrian Somers if (argv[arg + 1][0] == '-') 36724084f9bSBrian Somers break; 36824084f9bSBrian Somers 36924084f9bSBrian Somers if (parm) 37024084f9bSBrian Somers strcat (parmBuf, " "); 37124084f9bSBrian Somers 37224084f9bSBrian Somers ++arg; 37324084f9bSBrian Somers parm = parmBuf; 37424084f9bSBrian Somers strcat (parmBuf, argv[arg]); 37524084f9bSBrian Somers } 37624084f9bSBrian Somers 37724084f9bSBrian Somers ParseOption (opt + 1, parm, 1); 37824084f9bSBrian Somers } 37924084f9bSBrian Somers } 38024084f9bSBrian Somers 38124084f9bSBrian Somers static void DoAliasing (int fd) 38224084f9bSBrian Somers { 38324084f9bSBrian Somers int bytes; 38424084f9bSBrian Somers int origBytes; 38524084f9bSBrian Somers char buf[IP_MAXPACKET]; 38624084f9bSBrian Somers struct sockaddr_in addr; 38724084f9bSBrian Somers int wrote; 38824084f9bSBrian Somers int addrSize; 38924084f9bSBrian Somers struct ip* ip; 39024084f9bSBrian Somers char msgBuf[80]; 39124084f9bSBrian Somers 39224084f9bSBrian Somers if (assignAliasAddr) { 39324084f9bSBrian Somers 39424084f9bSBrian Somers SetAliasAddressFromIfName (ifName); 39524084f9bSBrian Somers assignAliasAddr = 0; 39624084f9bSBrian Somers } 39724084f9bSBrian Somers /* 39824084f9bSBrian Somers * Get packet from socket. 39924084f9bSBrian Somers */ 40024084f9bSBrian Somers addrSize = sizeof addr; 40124084f9bSBrian Somers origBytes = recvfrom (fd, 40224084f9bSBrian Somers buf, 40324084f9bSBrian Somers sizeof buf, 40424084f9bSBrian Somers 0, 40524084f9bSBrian Somers (struct sockaddr*) &addr, 40624084f9bSBrian Somers &addrSize); 40724084f9bSBrian Somers 40824084f9bSBrian Somers if (origBytes == -1) { 40924084f9bSBrian Somers 41024084f9bSBrian Somers if (errno != EINTR) 41124084f9bSBrian Somers Warn ("Read from divert socket failed."); 41224084f9bSBrian Somers 41324084f9bSBrian Somers return; 41424084f9bSBrian Somers } 41524084f9bSBrian Somers /* 41624084f9bSBrian Somers * This is a IP packet. 41724084f9bSBrian Somers */ 41824084f9bSBrian Somers ip = (struct ip*) buf; 41924084f9bSBrian Somers 42024084f9bSBrian Somers if (verbose) { 42124084f9bSBrian Somers 42224084f9bSBrian Somers /* 42324084f9bSBrian Somers * Print packet direction and protocol type. 42424084f9bSBrian Somers */ 42524084f9bSBrian Somers 42624084f9bSBrian Somers if (addr.sin_addr.s_addr == INADDR_ANY) 42724084f9bSBrian Somers printf ("Out "); 42824084f9bSBrian Somers else 42924084f9bSBrian Somers printf ("In "); 43024084f9bSBrian Somers 43124084f9bSBrian Somers switch (ip->ip_p) { 43224084f9bSBrian Somers case IPPROTO_TCP: 43324084f9bSBrian Somers printf ("[TCP] "); 43424084f9bSBrian Somers break; 43524084f9bSBrian Somers 43624084f9bSBrian Somers case IPPROTO_UDP: 43724084f9bSBrian Somers printf ("[UDP] "); 43824084f9bSBrian Somers break; 43924084f9bSBrian Somers 44024084f9bSBrian Somers case IPPROTO_ICMP: 44124084f9bSBrian Somers printf ("[ICMP] "); 44224084f9bSBrian Somers break; 44324084f9bSBrian Somers 44424084f9bSBrian Somers default: 44524084f9bSBrian Somers printf ("[?] "); 44624084f9bSBrian Somers break; 44724084f9bSBrian Somers } 44824084f9bSBrian Somers /* 44924084f9bSBrian Somers * Print addresses. 45024084f9bSBrian Somers */ 45124084f9bSBrian Somers PrintPacket (ip); 45224084f9bSBrian Somers } 45324084f9bSBrian Somers 45424084f9bSBrian Somers if (addr.sin_addr.s_addr == INADDR_ANY) { 45524084f9bSBrian Somers /* 45624084f9bSBrian Somers * Outgoing packets. Do aliasing. 45724084f9bSBrian Somers */ 45824084f9bSBrian Somers PacketAliasOut (buf, IP_MAXPACKET); 45924084f9bSBrian Somers } 46024084f9bSBrian Somers else { 46124084f9bSBrian Somers /* 46224084f9bSBrian Somers * Incoming packets may have ip checksum zeroed 46324084f9bSBrian Somers * when read from divert socket. Re-calculate it. 46424084f9bSBrian Somers */ 46524084f9bSBrian Somers if (ip->ip_sum == 0) 46624084f9bSBrian Somers ip->ip_sum = in_cksum_hdr (ip); 46724084f9bSBrian Somers /* 46824084f9bSBrian Somers * Do aliasing. 46924084f9bSBrian Somers */ 47024084f9bSBrian Somers PacketAliasIn (buf, IP_MAXPACKET); 47124084f9bSBrian Somers } 47224084f9bSBrian Somers /* 47324084f9bSBrian Somers * Length might have changed during aliasing. 47424084f9bSBrian Somers */ 47524084f9bSBrian Somers bytes = ntohs (ip->ip_len); 47624084f9bSBrian Somers /* 47724084f9bSBrian Somers * Update alias overhead size for outgoing packets. 47824084f9bSBrian Somers */ 47924084f9bSBrian Somers if (addr.sin_addr.s_addr == INADDR_ANY && 48024084f9bSBrian Somers bytes - origBytes > aliasOverhead) 48124084f9bSBrian Somers aliasOverhead = bytes - origBytes; 48224084f9bSBrian Somers 48324084f9bSBrian Somers if (verbose) { 48424084f9bSBrian Somers 48524084f9bSBrian Somers /* 48624084f9bSBrian Somers * Print addresses after aliasing. 48724084f9bSBrian Somers */ 48824084f9bSBrian Somers printf (" aliased to\n"); 48924084f9bSBrian Somers printf (" "); 49024084f9bSBrian Somers PrintPacket (ip); 49124084f9bSBrian Somers printf ("\n"); 49224084f9bSBrian Somers } 49324084f9bSBrian Somers /* 49424084f9bSBrian Somers * Put packet back for processing. 49524084f9bSBrian Somers */ 49624084f9bSBrian Somers wrote = sendto (fd, 49724084f9bSBrian Somers buf, 49824084f9bSBrian Somers bytes, 49924084f9bSBrian Somers 0, 50024084f9bSBrian Somers (struct sockaddr*) &addr, 50124084f9bSBrian Somers sizeof addr); 50224084f9bSBrian Somers 50324084f9bSBrian Somers if (wrote != bytes) { 50424084f9bSBrian Somers 50524084f9bSBrian Somers if (errno == EMSGSIZE) { 50624084f9bSBrian Somers 50724084f9bSBrian Somers if (addr.sin_addr.s_addr == INADDR_ANY && 50824084f9bSBrian Somers ifMTU != -1) 50924084f9bSBrian Somers SendNeedFragIcmp (icmpSock, 51024084f9bSBrian Somers (struct ip*) buf, 51124084f9bSBrian Somers ifMTU - aliasOverhead); 51224084f9bSBrian Somers } 51324084f9bSBrian Somers else { 51424084f9bSBrian Somers 51524084f9bSBrian Somers sprintf (msgBuf, "Failed to write packet back."); 51624084f9bSBrian Somers Warn (msgBuf); 51724084f9bSBrian Somers } 51824084f9bSBrian Somers } 51924084f9bSBrian Somers } 52024084f9bSBrian Somers 52124084f9bSBrian Somers static void HandleRoutingInfo (int fd) 52224084f9bSBrian Somers { 52324084f9bSBrian Somers int bytes; 52424084f9bSBrian Somers struct if_msghdr ifMsg; 52524084f9bSBrian Somers /* 52624084f9bSBrian Somers * Get packet from socket. 52724084f9bSBrian Somers */ 52824084f9bSBrian Somers bytes = read (fd, &ifMsg, sizeof ifMsg); 52924084f9bSBrian Somers if (bytes == -1) { 53024084f9bSBrian Somers 53124084f9bSBrian Somers Warn ("Read from routing socket failed."); 53224084f9bSBrian Somers return; 53324084f9bSBrian Somers } 53424084f9bSBrian Somers 53524084f9bSBrian Somers if (ifMsg.ifm_version != RTM_VERSION) { 53624084f9bSBrian Somers 53724084f9bSBrian Somers Warn ("Unexpected packet read from routing socket."); 53824084f9bSBrian Somers return; 53924084f9bSBrian Somers } 54024084f9bSBrian Somers 54124084f9bSBrian Somers if (verbose) 54224084f9bSBrian Somers printf ("Routing message %X received.\n", ifMsg.ifm_type); 54324084f9bSBrian Somers 54424084f9bSBrian Somers if (ifMsg.ifm_type != RTM_NEWADDR) 54524084f9bSBrian Somers return; 54624084f9bSBrian Somers 54724084f9bSBrian Somers if (verbose && ifMsg.ifm_index == ifIndex) 54824084f9bSBrian Somers printf ("Interface address has changed.\n"); 54924084f9bSBrian Somers 55024084f9bSBrian Somers if (ifMsg.ifm_index == ifIndex) 55124084f9bSBrian Somers assignAliasAddr = 1; 55224084f9bSBrian Somers } 55324084f9bSBrian Somers 55424084f9bSBrian Somers static void PrintPacket (struct ip* ip) 55524084f9bSBrian Somers { 55624084f9bSBrian Somers struct tcphdr* tcphdr; 55724084f9bSBrian Somers 55824084f9bSBrian Somers if (ip->ip_p == IPPROTO_TCP) 55924084f9bSBrian Somers tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2)); 56024084f9bSBrian Somers else 56124084f9bSBrian Somers tcphdr = NULL; 56224084f9bSBrian Somers 56324084f9bSBrian Somers printf ("%s", inet_ntoa (ip->ip_src)); 56424084f9bSBrian Somers if (tcphdr) 56524084f9bSBrian Somers printf (":%d", ntohs (tcphdr->th_sport)); 56624084f9bSBrian Somers 56724084f9bSBrian Somers printf (" -> "); 56824084f9bSBrian Somers printf ("%s", inet_ntoa (ip->ip_dst)); 56924084f9bSBrian Somers if (tcphdr) 57024084f9bSBrian Somers printf (":%d", ntohs (tcphdr->th_dport)); 57124084f9bSBrian Somers } 57224084f9bSBrian Somers 57324084f9bSBrian Somers static void SetAliasAddressFromIfName (char* ifName) 57424084f9bSBrian Somers { 57524084f9bSBrian Somers struct ifconf cf; 57624084f9bSBrian Somers struct ifreq buf[32]; 57724084f9bSBrian Somers char msg[80]; 57824084f9bSBrian Somers struct ifreq* ifPtr; 57924084f9bSBrian Somers int extra; 58024084f9bSBrian Somers int helperSock; 58124084f9bSBrian Somers int bytes; 58224084f9bSBrian Somers struct sockaddr_in* addr; 58324084f9bSBrian Somers int found; 58424084f9bSBrian Somers struct ifreq req; 58524084f9bSBrian Somers char last[10]; 58624084f9bSBrian Somers /* 58724084f9bSBrian Somers * Create a dummy socket to access interface information. 58824084f9bSBrian Somers */ 58924084f9bSBrian Somers helperSock = socket (AF_INET, SOCK_DGRAM, 0); 59024084f9bSBrian Somers if (helperSock == -1) { 59124084f9bSBrian Somers 59224084f9bSBrian Somers Quit ("Failed to create helper socket."); 59324084f9bSBrian Somers exit (1); 59424084f9bSBrian Somers } 59524084f9bSBrian Somers 59624084f9bSBrian Somers cf.ifc_len = sizeof (buf); 59724084f9bSBrian Somers cf.ifc_req = buf; 59824084f9bSBrian Somers /* 59924084f9bSBrian Somers * Get interface data. 60024084f9bSBrian Somers */ 60124084f9bSBrian Somers if (ioctl (helperSock, SIOCGIFCONF, &cf) == -1) { 60224084f9bSBrian Somers 60324084f9bSBrian Somers Quit ("Ioctl SIOCGIFCONF failed."); 60424084f9bSBrian Somers exit (1); 60524084f9bSBrian Somers } 60624084f9bSBrian Somers 60724084f9bSBrian Somers ifIndex = 0; 60824084f9bSBrian Somers ifPtr = buf; 60924084f9bSBrian Somers bytes = cf.ifc_len; 61024084f9bSBrian Somers found = 0; 61124084f9bSBrian Somers last[0] = '\0'; 61224084f9bSBrian Somers /* 61324084f9bSBrian Somers * Loop through interfaces until one with 61424084f9bSBrian Somers * given name is found. This is done to 61524084f9bSBrian Somers * find correct interface index for routing 61624084f9bSBrian Somers * message processing. 61724084f9bSBrian Somers */ 61824084f9bSBrian Somers while (bytes) { 61924084f9bSBrian Somers 62024084f9bSBrian Somers if (ifPtr->ifr_addr.sa_family == AF_INET && 62124084f9bSBrian Somers !strcmp (ifPtr->ifr_name, ifName)) { 62224084f9bSBrian Somers 62324084f9bSBrian Somers found = 1; 62424084f9bSBrian Somers break; 62524084f9bSBrian Somers } 62624084f9bSBrian Somers 62724084f9bSBrian Somers if (strcmp (last, ifPtr->ifr_name)) { 62824084f9bSBrian Somers 62924084f9bSBrian Somers strcpy (last, ifPtr->ifr_name); 63024084f9bSBrian Somers ++ifIndex; 63124084f9bSBrian Somers } 63224084f9bSBrian Somers 63324084f9bSBrian Somers extra = ifPtr->ifr_addr.sa_len - sizeof (struct sockaddr); 63424084f9bSBrian Somers 63524084f9bSBrian Somers ifPtr++; 63624084f9bSBrian Somers ifPtr = (struct ifreq*) ((char*) ifPtr + extra); 63724084f9bSBrian Somers bytes -= sizeof (struct ifreq) + extra; 63824084f9bSBrian Somers } 63924084f9bSBrian Somers 64024084f9bSBrian Somers if (!found) { 64124084f9bSBrian Somers 64224084f9bSBrian Somers close (helperSock); 64324084f9bSBrian Somers sprintf (msg, "Unknown interface name %s.\n", ifName); 64424084f9bSBrian Somers Quit (msg); 64524084f9bSBrian Somers } 64624084f9bSBrian Somers /* 64724084f9bSBrian Somers * Get MTU size. 64824084f9bSBrian Somers */ 64924084f9bSBrian Somers strcpy (req.ifr_name, ifName); 65024084f9bSBrian Somers 65124084f9bSBrian Somers if (ioctl (helperSock, SIOCGIFMTU, &req) == -1) 65224084f9bSBrian Somers Quit ("Cannot get interface mtu size."); 65324084f9bSBrian Somers 65424084f9bSBrian Somers ifMTU = req.ifr_mtu; 65524084f9bSBrian Somers /* 65624084f9bSBrian Somers * Get interface address. 65724084f9bSBrian Somers */ 65824084f9bSBrian Somers if (ioctl (helperSock, SIOCGIFADDR, &req) == -1) 65924084f9bSBrian Somers Quit ("Cannot get interface address."); 66024084f9bSBrian Somers 66124084f9bSBrian Somers addr = (struct sockaddr_in*) &req.ifr_addr; 66224084f9bSBrian Somers SetPacketAliasAddress (addr->sin_addr); 66324084f9bSBrian Somers syslog (LOG_INFO, "Aliasing to %s, mtu %d bytes", 66424084f9bSBrian Somers inet_ntoa (addr->sin_addr), 66524084f9bSBrian Somers ifMTU); 66624084f9bSBrian Somers 66724084f9bSBrian Somers close (helperSock); 66824084f9bSBrian Somers } 66924084f9bSBrian Somers 67024084f9bSBrian Somers void Quit (char* msg) 67124084f9bSBrian Somers { 67224084f9bSBrian Somers Warn (msg); 67324084f9bSBrian Somers exit (1); 67424084f9bSBrian Somers } 67524084f9bSBrian Somers 67624084f9bSBrian Somers void Warn (char* msg) 67724084f9bSBrian Somers { 67824084f9bSBrian Somers if (background) 67924084f9bSBrian Somers syslog (LOG_ALERT, "%s (%m)", msg); 68024084f9bSBrian Somers else 68124084f9bSBrian Somers perror (msg); 68224084f9bSBrian Somers } 68324084f9bSBrian Somers 68424084f9bSBrian Somers static void RefreshAddr () 68524084f9bSBrian Somers { 68624084f9bSBrian Somers signal (SIGHUP, RefreshAddr); 68724084f9bSBrian Somers if (ifName) 68824084f9bSBrian Somers assignAliasAddr = 1; 68924084f9bSBrian Somers } 69024084f9bSBrian Somers 69124084f9bSBrian Somers static void InitiateShutdown () 69224084f9bSBrian Somers { 69324084f9bSBrian Somers /* 69424084f9bSBrian Somers * Start timer to allow kernel gracefully 69524084f9bSBrian Somers * shutdown existing connections when system 69624084f9bSBrian Somers * is shut down. 69724084f9bSBrian Somers */ 69824084f9bSBrian Somers signal (SIGALRM, Shutdown); 69924084f9bSBrian Somers alarm (10); 70024084f9bSBrian Somers } 70124084f9bSBrian Somers 70224084f9bSBrian Somers static void Shutdown () 70324084f9bSBrian Somers { 70424084f9bSBrian Somers running = 0; 70524084f9bSBrian Somers } 70624084f9bSBrian Somers 70724084f9bSBrian Somers /* 70824084f9bSBrian Somers * Different options recognized by this program. 70924084f9bSBrian Somers */ 71024084f9bSBrian Somers 71124084f9bSBrian Somers enum Option { 71224084f9bSBrian Somers 71324084f9bSBrian Somers PacketAliasOption, 71424084f9bSBrian Somers Verbose, 71524084f9bSBrian Somers InPort, 71624084f9bSBrian Somers OutPort, 71724084f9bSBrian Somers Port, 71824084f9bSBrian Somers AliasAddress, 71924084f9bSBrian Somers InterfaceName, 72024084f9bSBrian Somers PermanentLink, 72124084f9bSBrian Somers RedirectPort, 72224084f9bSBrian Somers RedirectAddress, 72324084f9bSBrian Somers ConfigFile, 72424084f9bSBrian Somers DynamicMode 72524084f9bSBrian Somers }; 72624084f9bSBrian Somers 72724084f9bSBrian Somers enum Param { 72824084f9bSBrian Somers 72924084f9bSBrian Somers YesNo, 73024084f9bSBrian Somers Numeric, 73124084f9bSBrian Somers String, 73224084f9bSBrian Somers None, 73324084f9bSBrian Somers Address, 73424084f9bSBrian Somers Service 73524084f9bSBrian Somers }; 73624084f9bSBrian Somers 73724084f9bSBrian Somers /* 73824084f9bSBrian Somers * Option information structure (used by ParseOption). 73924084f9bSBrian Somers */ 74024084f9bSBrian Somers 74124084f9bSBrian Somers struct OptionInfo { 74224084f9bSBrian Somers 74324084f9bSBrian Somers enum Option type; 74424084f9bSBrian Somers int packetAliasOpt; 74524084f9bSBrian Somers enum Param parm; 74624084f9bSBrian Somers char* parmDescription; 74724084f9bSBrian Somers char* description; 74824084f9bSBrian Somers char* name; 74924084f9bSBrian Somers char* shortName; 75024084f9bSBrian Somers }; 75124084f9bSBrian Somers 75224084f9bSBrian Somers /* 75324084f9bSBrian Somers * Table of known options. 75424084f9bSBrian Somers */ 75524084f9bSBrian Somers 75624084f9bSBrian Somers static struct OptionInfo optionTable[] = { 75724084f9bSBrian Somers 75824084f9bSBrian Somers { PacketAliasOption, 75924084f9bSBrian Somers PKT_ALIAS_UNREGISTERED_ONLY, 76024084f9bSBrian Somers YesNo, 76124084f9bSBrian Somers "[yes|no]", 76224084f9bSBrian Somers "alias only unregistered addresses", 76324084f9bSBrian Somers "unregistered_only", 76424084f9bSBrian Somers "u" }, 76524084f9bSBrian Somers 76624084f9bSBrian Somers { PacketAliasOption, 76724084f9bSBrian Somers PKT_ALIAS_LOG, 76824084f9bSBrian Somers YesNo, 76924084f9bSBrian Somers "[yes|no]", 77024084f9bSBrian Somers "enable logging", 77124084f9bSBrian Somers "log", 77224084f9bSBrian Somers "l" }, 77324084f9bSBrian Somers 77424084f9bSBrian Somers { PacketAliasOption, 77524084f9bSBrian Somers PKT_ALIAS_DENY_INCOMING, 77624084f9bSBrian Somers YesNo, 77724084f9bSBrian Somers "[yes|no]", 77824084f9bSBrian Somers "allow incoming connections", 77924084f9bSBrian Somers "deny_incoming", 78024084f9bSBrian Somers "d" }, 78124084f9bSBrian Somers 78224084f9bSBrian Somers { PacketAliasOption, 78324084f9bSBrian Somers PKT_ALIAS_USE_SOCKETS, 78424084f9bSBrian Somers YesNo, 78524084f9bSBrian Somers "[yes|no]", 78624084f9bSBrian Somers "use sockets to inhibit port conflict", 78724084f9bSBrian Somers "use_sockets", 78824084f9bSBrian Somers "s" }, 78924084f9bSBrian Somers 79024084f9bSBrian Somers { PacketAliasOption, 79124084f9bSBrian Somers PKT_ALIAS_SAME_PORTS, 79224084f9bSBrian Somers YesNo, 79324084f9bSBrian Somers "[yes|no]", 79424084f9bSBrian Somers "try to keep original port numbers for connections", 79524084f9bSBrian Somers "same_ports", 79624084f9bSBrian Somers "m" }, 79724084f9bSBrian Somers 79824084f9bSBrian Somers { Verbose, 79924084f9bSBrian Somers 0, 80024084f9bSBrian Somers YesNo, 80124084f9bSBrian Somers "[yes|no]", 80224084f9bSBrian Somers "verbose mode, dump packet information", 80324084f9bSBrian Somers "verbose", 80424084f9bSBrian Somers "v" }, 80524084f9bSBrian Somers 80624084f9bSBrian Somers { DynamicMode, 80724084f9bSBrian Somers 0, 80824084f9bSBrian Somers YesNo, 80924084f9bSBrian Somers "[yes|no]", 81024084f9bSBrian Somers "dynamic mode, automatically detect interface address changes", 81124084f9bSBrian Somers "dynamic", 81224084f9bSBrian Somers NULL }, 81324084f9bSBrian Somers 81424084f9bSBrian Somers { InPort, 81524084f9bSBrian Somers 0, 81624084f9bSBrian Somers Service, 81724084f9bSBrian Somers "number|service_name", 81824084f9bSBrian Somers "set port for incoming packets", 81924084f9bSBrian Somers "in_port", 82024084f9bSBrian Somers "i" }, 82124084f9bSBrian Somers 82224084f9bSBrian Somers { OutPort, 82324084f9bSBrian Somers 0, 82424084f9bSBrian Somers Service, 82524084f9bSBrian Somers "number|service_name", 82624084f9bSBrian Somers "set port for outgoing packets", 82724084f9bSBrian Somers "out_port", 82824084f9bSBrian Somers "o" }, 82924084f9bSBrian Somers 83024084f9bSBrian Somers { Port, 83124084f9bSBrian Somers 0, 83224084f9bSBrian Somers Service, 83324084f9bSBrian Somers "number|service_name", 83424084f9bSBrian Somers "set port (defaults to natd/divert)", 83524084f9bSBrian Somers "port", 83624084f9bSBrian Somers "p" }, 83724084f9bSBrian Somers 83824084f9bSBrian Somers { AliasAddress, 83924084f9bSBrian Somers 0, 84024084f9bSBrian Somers Address, 84124084f9bSBrian Somers "x.x.x.x", 84224084f9bSBrian Somers "address to use for aliasing", 84324084f9bSBrian Somers "alias_address", 84424084f9bSBrian Somers "a" }, 84524084f9bSBrian Somers 84624084f9bSBrian Somers { InterfaceName, 84724084f9bSBrian Somers 0, 84824084f9bSBrian Somers String, 84924084f9bSBrian Somers "network_if_name", 85024084f9bSBrian Somers "take aliasing address from interface", 85124084f9bSBrian Somers "interface", 85224084f9bSBrian Somers "n" }, 85324084f9bSBrian Somers 85424084f9bSBrian Somers { PermanentLink, 85524084f9bSBrian Somers 0, 85624084f9bSBrian Somers String, 85724084f9bSBrian Somers "tcp|udp src:port dst:port alias", 85824084f9bSBrian Somers "define permanent link for incoming connection", 85924084f9bSBrian Somers "permanent_link", 86024084f9bSBrian Somers NULL }, 86124084f9bSBrian Somers 86224084f9bSBrian Somers { RedirectPort, 86324084f9bSBrian Somers 0, 86424084f9bSBrian Somers String, 86524084f9bSBrian Somers "tcp|udp local_addr:local_port [public_addr:]public_port" 86624084f9bSBrian Somers " [remote_addr[:remote_port]]", 86724084f9bSBrian Somers "redirect a port for incoming traffic", 86824084f9bSBrian Somers "redirect_port", 86924084f9bSBrian Somers NULL }, 87024084f9bSBrian Somers 87124084f9bSBrian Somers { RedirectAddress, 87224084f9bSBrian Somers 0, 87324084f9bSBrian Somers String, 87424084f9bSBrian Somers "local_addr public_addr", 87524084f9bSBrian Somers "define mapping between local and public addresses", 87624084f9bSBrian Somers "redirect_address", 87724084f9bSBrian Somers NULL }, 87824084f9bSBrian Somers 87924084f9bSBrian Somers { ConfigFile, 88024084f9bSBrian Somers 0, 88124084f9bSBrian Somers String, 88224084f9bSBrian Somers "file_name", 88324084f9bSBrian Somers "read options from configuration file", 88424084f9bSBrian Somers "config", 88524084f9bSBrian Somers "f" } 88624084f9bSBrian Somers }; 88724084f9bSBrian Somers 88824084f9bSBrian Somers static void ParseOption (char* option, char* parms, int cmdLine) 88924084f9bSBrian Somers { 89024084f9bSBrian Somers int i; 89124084f9bSBrian Somers struct OptionInfo* info; 89224084f9bSBrian Somers int yesNoValue; 89324084f9bSBrian Somers int aliasValue; 89424084f9bSBrian Somers int numValue; 89524084f9bSBrian Somers char* strValue; 89624084f9bSBrian Somers struct in_addr addrValue; 89724084f9bSBrian Somers int max; 89824084f9bSBrian Somers char* end; 89924084f9bSBrian Somers /* 90024084f9bSBrian Somers * Find option from table. 90124084f9bSBrian Somers */ 90224084f9bSBrian Somers max = sizeof (optionTable) / sizeof (struct OptionInfo); 90324084f9bSBrian Somers for (i = 0, info = optionTable; i < max; i++, info++) { 90424084f9bSBrian Somers 90524084f9bSBrian Somers if (!strcmp (info->name, option)) 90624084f9bSBrian Somers break; 90724084f9bSBrian Somers 90824084f9bSBrian Somers if (info->shortName) 90924084f9bSBrian Somers if (!strcmp (info->shortName, option)) 91024084f9bSBrian Somers break; 91124084f9bSBrian Somers } 91224084f9bSBrian Somers 91324084f9bSBrian Somers if (i >= max) { 91424084f9bSBrian Somers 91524084f9bSBrian Somers fprintf (stderr, "Unknown option %s.\n", option); 91624084f9bSBrian Somers Usage (); 91724084f9bSBrian Somers } 91824084f9bSBrian Somers 91924084f9bSBrian Somers yesNoValue = 0; 92024084f9bSBrian Somers numValue = 0; 92124084f9bSBrian Somers strValue = NULL; 92224084f9bSBrian Somers /* 92324084f9bSBrian Somers * Check parameters. 92424084f9bSBrian Somers */ 92524084f9bSBrian Somers switch (info->parm) { 92624084f9bSBrian Somers case YesNo: 92724084f9bSBrian Somers if (!parms) 92824084f9bSBrian Somers parms = "yes"; 92924084f9bSBrian Somers 93024084f9bSBrian Somers if (!strcmp (parms, "yes")) 93124084f9bSBrian Somers yesNoValue = 1; 93224084f9bSBrian Somers else 93324084f9bSBrian Somers if (!strcmp (parms, "no")) 93424084f9bSBrian Somers yesNoValue = 0; 93524084f9bSBrian Somers else { 93624084f9bSBrian Somers 93724084f9bSBrian Somers fprintf (stderr, "%s needs yes/no parameter.\n", 93824084f9bSBrian Somers option); 93924084f9bSBrian Somers exit (1); 94024084f9bSBrian Somers } 94124084f9bSBrian Somers break; 94224084f9bSBrian Somers 94324084f9bSBrian Somers case Service: 94424084f9bSBrian Somers if (!parms) { 94524084f9bSBrian Somers 94624084f9bSBrian Somers fprintf (stderr, "%s needs service name or " 94724084f9bSBrian Somers "port number parameter.\n", 94824084f9bSBrian Somers option); 94924084f9bSBrian Somers exit (1); 95024084f9bSBrian Somers } 95124084f9bSBrian Somers 95224084f9bSBrian Somers numValue = StrToPort (parms, "divert"); 95324084f9bSBrian Somers break; 95424084f9bSBrian Somers 95524084f9bSBrian Somers case Numeric: 95624084f9bSBrian Somers if (parms) 95724084f9bSBrian Somers numValue = strtol (parms, &end, 10); 95824084f9bSBrian Somers else 95924084f9bSBrian Somers end = parms; 96024084f9bSBrian Somers 96124084f9bSBrian Somers if (end == parms) { 96224084f9bSBrian Somers 96324084f9bSBrian Somers fprintf (stderr, "%s needs numeric parameter.\n", 96424084f9bSBrian Somers option); 96524084f9bSBrian Somers exit (1); 96624084f9bSBrian Somers } 96724084f9bSBrian Somers break; 96824084f9bSBrian Somers 96924084f9bSBrian Somers case String: 97024084f9bSBrian Somers strValue = parms; 97124084f9bSBrian Somers if (!strValue) { 97224084f9bSBrian Somers 97324084f9bSBrian Somers fprintf (stderr, "%s needs parameter.\n", 97424084f9bSBrian Somers option); 97524084f9bSBrian Somers exit (1); 97624084f9bSBrian Somers } 97724084f9bSBrian Somers break; 97824084f9bSBrian Somers 97924084f9bSBrian Somers case None: 98024084f9bSBrian Somers if (parms) { 98124084f9bSBrian Somers 98224084f9bSBrian Somers fprintf (stderr, "%s does not take parameters.\n", 98324084f9bSBrian Somers option); 98424084f9bSBrian Somers exit (1); 98524084f9bSBrian Somers } 98624084f9bSBrian Somers break; 98724084f9bSBrian Somers 98824084f9bSBrian Somers case Address: 98924084f9bSBrian Somers if (!parms) { 99024084f9bSBrian Somers 99124084f9bSBrian Somers fprintf (stderr, "%s needs address/host parameter.\n", 99224084f9bSBrian Somers option); 99324084f9bSBrian Somers exit (1); 99424084f9bSBrian Somers } 99524084f9bSBrian Somers 99624084f9bSBrian Somers StrToAddr (parms, &addrValue); 99724084f9bSBrian Somers break; 99824084f9bSBrian Somers } 99924084f9bSBrian Somers 100024084f9bSBrian Somers switch (info->type) { 100124084f9bSBrian Somers case PacketAliasOption: 100224084f9bSBrian Somers 100324084f9bSBrian Somers aliasValue = yesNoValue ? info->packetAliasOpt : 0; 100424084f9bSBrian Somers SetPacketAliasMode (aliasValue, info->packetAliasOpt); 100524084f9bSBrian Somers break; 100624084f9bSBrian Somers 100724084f9bSBrian Somers case Verbose: 100824084f9bSBrian Somers verbose = yesNoValue; 100924084f9bSBrian Somers break; 101024084f9bSBrian Somers 101124084f9bSBrian Somers case DynamicMode: 101224084f9bSBrian Somers dynamicMode = yesNoValue; 101324084f9bSBrian Somers break; 101424084f9bSBrian Somers 101524084f9bSBrian Somers case InPort: 101624084f9bSBrian Somers inPort = numValue; 101724084f9bSBrian Somers break; 101824084f9bSBrian Somers 101924084f9bSBrian Somers case OutPort: 102024084f9bSBrian Somers outPort = numValue; 102124084f9bSBrian Somers break; 102224084f9bSBrian Somers 102324084f9bSBrian Somers case Port: 102424084f9bSBrian Somers inOutPort = numValue; 102524084f9bSBrian Somers break; 102624084f9bSBrian Somers 102724084f9bSBrian Somers case AliasAddress: 102824084f9bSBrian Somers memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr)); 102924084f9bSBrian Somers break; 103024084f9bSBrian Somers 103124084f9bSBrian Somers case PermanentLink: 103224084f9bSBrian Somers SetupPermanentLink (strValue); 103324084f9bSBrian Somers break; 103424084f9bSBrian Somers 103524084f9bSBrian Somers case RedirectPort: 103624084f9bSBrian Somers SetupPortRedirect (strValue); 103724084f9bSBrian Somers break; 103824084f9bSBrian Somers 103924084f9bSBrian Somers case RedirectAddress: 104024084f9bSBrian Somers SetupAddressRedirect (strValue); 104124084f9bSBrian Somers break; 104224084f9bSBrian Somers 104324084f9bSBrian Somers case InterfaceName: 104424084f9bSBrian Somers if (ifName) 104524084f9bSBrian Somers free (ifName); 104624084f9bSBrian Somers 104724084f9bSBrian Somers ifName = strdup (strValue); 104824084f9bSBrian Somers assignAliasAddr = 1; 104924084f9bSBrian Somers break; 105024084f9bSBrian Somers 105124084f9bSBrian Somers case ConfigFile: 105224084f9bSBrian Somers ReadConfigFile (strValue); 105324084f9bSBrian Somers break; 105424084f9bSBrian Somers } 105524084f9bSBrian Somers } 105624084f9bSBrian Somers 105724084f9bSBrian Somers void ReadConfigFile (char* fileName) 105824084f9bSBrian Somers { 105924084f9bSBrian Somers FILE* file; 106024084f9bSBrian Somers char buf[128]; 106124084f9bSBrian Somers char* ptr; 106224084f9bSBrian Somers char* option; 106324084f9bSBrian Somers 106424084f9bSBrian Somers file = fopen (fileName, "r"); 106524084f9bSBrian Somers if (!file) { 106624084f9bSBrian Somers 106724084f9bSBrian Somers sprintf (buf, "Cannot open config file %s.\n", fileName); 106824084f9bSBrian Somers Quit (buf); 106924084f9bSBrian Somers } 107024084f9bSBrian Somers 107124084f9bSBrian Somers while (fgets (buf, sizeof (buf), file)) { 107224084f9bSBrian Somers 107324084f9bSBrian Somers ptr = strchr (buf, '\n'); 107424084f9bSBrian Somers if (!ptr) { 107524084f9bSBrian Somers 107624084f9bSBrian Somers fprintf (stderr, "config line too link: %s\n", buf); 107724084f9bSBrian Somers exit (1); 107824084f9bSBrian Somers } 107924084f9bSBrian Somers 108024084f9bSBrian Somers *ptr = '\0'; 108124084f9bSBrian Somers if (buf[0] == '#') 108224084f9bSBrian Somers continue; 108324084f9bSBrian Somers 108424084f9bSBrian Somers ptr = buf; 108524084f9bSBrian Somers /* 108624084f9bSBrian Somers * Skip white space at beginning of line. 108724084f9bSBrian Somers */ 108824084f9bSBrian Somers while (*ptr && isspace (*ptr)) 108924084f9bSBrian Somers ++ptr; 109024084f9bSBrian Somers 109124084f9bSBrian Somers if (*ptr == '\0') 109224084f9bSBrian Somers continue; 109324084f9bSBrian Somers /* 109424084f9bSBrian Somers * Extract option name. 109524084f9bSBrian Somers */ 109624084f9bSBrian Somers option = ptr; 109724084f9bSBrian Somers while (*ptr && !isspace (*ptr)) 109824084f9bSBrian Somers ++ptr; 109924084f9bSBrian Somers 110024084f9bSBrian Somers if (*ptr != '\0') { 110124084f9bSBrian Somers 110224084f9bSBrian Somers *ptr = '\0'; 110324084f9bSBrian Somers ++ptr; 110424084f9bSBrian Somers } 110524084f9bSBrian Somers /* 110624084f9bSBrian Somers * Skip white space between name and parms. 110724084f9bSBrian Somers */ 110824084f9bSBrian Somers while (*ptr && isspace (*ptr)) 110924084f9bSBrian Somers ++ptr; 111024084f9bSBrian Somers 111124084f9bSBrian Somers ParseOption (option, *ptr ? ptr : NULL, 0); 111224084f9bSBrian Somers } 111324084f9bSBrian Somers 111424084f9bSBrian Somers fclose (file); 111524084f9bSBrian Somers } 111624084f9bSBrian Somers 111724084f9bSBrian Somers static void Usage () 111824084f9bSBrian Somers { 111924084f9bSBrian Somers int i; 112024084f9bSBrian Somers int max; 112124084f9bSBrian Somers struct OptionInfo* info; 112224084f9bSBrian Somers 112324084f9bSBrian Somers fprintf (stderr, "Recognized options:\n\n"); 112424084f9bSBrian Somers 112524084f9bSBrian Somers max = sizeof (optionTable) / sizeof (struct OptionInfo); 112624084f9bSBrian Somers for (i = 0, info = optionTable; i < max; i++, info++) { 112724084f9bSBrian Somers 112824084f9bSBrian Somers fprintf (stderr, "-%-20s %s\n", info->name, 112924084f9bSBrian Somers info->parmDescription); 113024084f9bSBrian Somers 113124084f9bSBrian Somers if (info->shortName) 113224084f9bSBrian Somers fprintf (stderr, "-%-20s %s\n", info->shortName, 113324084f9bSBrian Somers info->parmDescription); 113424084f9bSBrian Somers 113524084f9bSBrian Somers fprintf (stderr, " %s\n\n", info->description); 113624084f9bSBrian Somers } 113724084f9bSBrian Somers 113824084f9bSBrian Somers exit (1); 113924084f9bSBrian Somers } 114024084f9bSBrian Somers 114124084f9bSBrian Somers void SetupPermanentLink (char* parms) 114224084f9bSBrian Somers { 114324084f9bSBrian Somers char buf[128]; 114424084f9bSBrian Somers char* ptr; 114524084f9bSBrian Somers struct in_addr srcAddr; 114624084f9bSBrian Somers struct in_addr dstAddr; 114724084f9bSBrian Somers int srcPort; 114824084f9bSBrian Somers int dstPort; 114924084f9bSBrian Somers int aliasPort; 115024084f9bSBrian Somers int proto; 115124084f9bSBrian Somers char* protoName; 115224084f9bSBrian Somers 115324084f9bSBrian Somers strcpy (buf, parms); 115424084f9bSBrian Somers /* 115524084f9bSBrian Somers * Extract protocol. 115624084f9bSBrian Somers */ 115724084f9bSBrian Somers protoName = strtok (buf, " \t"); 115824084f9bSBrian Somers if (!protoName) { 115924084f9bSBrian Somers 116024084f9bSBrian Somers fprintf (stderr, "permanent_link: missing protocol.\n"); 116124084f9bSBrian Somers exit (1); 116224084f9bSBrian Somers } 116324084f9bSBrian Somers 116424084f9bSBrian Somers proto = StrToProto (protoName); 116524084f9bSBrian Somers /* 116624084f9bSBrian Somers * Extract source address. 116724084f9bSBrian Somers */ 116824084f9bSBrian Somers ptr = strtok (NULL, " \t"); 116924084f9bSBrian Somers if (!ptr) { 117024084f9bSBrian Somers 117124084f9bSBrian Somers fprintf (stderr, "permanent_link: missing src address.\n"); 117224084f9bSBrian Somers exit (1); 117324084f9bSBrian Somers } 117424084f9bSBrian Somers 117524084f9bSBrian Somers srcPort = StrToAddrAndPort (ptr, &srcAddr, protoName); 117624084f9bSBrian Somers /* 117724084f9bSBrian Somers * Extract destination address. 117824084f9bSBrian Somers */ 117924084f9bSBrian Somers ptr = strtok (NULL, " \t"); 118024084f9bSBrian Somers if (!ptr) { 118124084f9bSBrian Somers 118224084f9bSBrian Somers fprintf (stderr, "permanent_link: missing dst address.\n"); 118324084f9bSBrian Somers exit (1); 118424084f9bSBrian Somers } 118524084f9bSBrian Somers 118624084f9bSBrian Somers dstPort = StrToAddrAndPort (ptr, &dstAddr, protoName); 118724084f9bSBrian Somers /* 118824084f9bSBrian Somers * Export alias port. 118924084f9bSBrian Somers */ 119024084f9bSBrian Somers ptr = strtok (NULL, " \t"); 119124084f9bSBrian Somers if (!ptr) { 119224084f9bSBrian Somers 119324084f9bSBrian Somers fprintf (stderr, "permanent_link: missing alias port.\n"); 119424084f9bSBrian Somers exit (1); 119524084f9bSBrian Somers } 119624084f9bSBrian Somers 119724084f9bSBrian Somers aliasPort = StrToPort (ptr, protoName); 119824084f9bSBrian Somers 119924084f9bSBrian Somers PacketAliasPermanentLink (srcAddr, 120024084f9bSBrian Somers srcPort, 120124084f9bSBrian Somers dstAddr, 120224084f9bSBrian Somers dstPort, 120324084f9bSBrian Somers aliasPort, 120424084f9bSBrian Somers proto); 120524084f9bSBrian Somers } 120624084f9bSBrian Somers 120724084f9bSBrian Somers void SetupPortRedirect (char* parms) 120824084f9bSBrian Somers { 120924084f9bSBrian Somers char buf[128]; 121024084f9bSBrian Somers char* ptr; 121124084f9bSBrian Somers struct in_addr localAddr; 121224084f9bSBrian Somers struct in_addr publicAddr; 121324084f9bSBrian Somers struct in_addr remoteAddr; 121424084f9bSBrian Somers int localPort; 121524084f9bSBrian Somers int publicPort; 121624084f9bSBrian Somers int remotePort; 121724084f9bSBrian Somers int proto; 121824084f9bSBrian Somers char* protoName; 121924084f9bSBrian Somers char* separator; 122024084f9bSBrian Somers 122124084f9bSBrian Somers strcpy (buf, parms); 122224084f9bSBrian Somers /* 122324084f9bSBrian Somers * Extract protocol. 122424084f9bSBrian Somers */ 122524084f9bSBrian Somers protoName = strtok (buf, " \t"); 122624084f9bSBrian Somers if (!protoName) { 122724084f9bSBrian Somers 122824084f9bSBrian Somers fprintf (stderr, "redirect_port: missing protocol.\n"); 122924084f9bSBrian Somers exit (1); 123024084f9bSBrian Somers } 123124084f9bSBrian Somers 123224084f9bSBrian Somers proto = StrToProto (protoName); 123324084f9bSBrian Somers /* 123424084f9bSBrian Somers * Extract local address. 123524084f9bSBrian Somers */ 123624084f9bSBrian Somers ptr = strtok (NULL, " \t"); 123724084f9bSBrian Somers if (!ptr) { 123824084f9bSBrian Somers 123924084f9bSBrian Somers fprintf (stderr, "redirect_port: missing local address.\n"); 124024084f9bSBrian Somers exit (1); 124124084f9bSBrian Somers } 124224084f9bSBrian Somers 124324084f9bSBrian Somers localPort = StrToAddrAndPort (ptr, &localAddr, protoName); 124424084f9bSBrian Somers /* 124524084f9bSBrian Somers * Extract public port and optinally address. 124624084f9bSBrian Somers */ 124724084f9bSBrian Somers ptr = strtok (NULL, " \t"); 124824084f9bSBrian Somers if (!ptr) { 124924084f9bSBrian Somers 125024084f9bSBrian Somers fprintf (stderr, "redirect_port: missing public port.\n"); 125124084f9bSBrian Somers exit (1); 125224084f9bSBrian Somers } 125324084f9bSBrian Somers 125424084f9bSBrian Somers separator = strchr (ptr, ':'); 125524084f9bSBrian Somers if (separator) 125624084f9bSBrian Somers publicPort = StrToAddrAndPort (ptr, &publicAddr, protoName); 125724084f9bSBrian Somers else { 125824084f9bSBrian Somers 125924084f9bSBrian Somers publicAddr.s_addr = INADDR_ANY; 126024084f9bSBrian Somers publicPort = StrToPort (ptr, protoName); 126124084f9bSBrian Somers } 126224084f9bSBrian Somers 126324084f9bSBrian Somers /* 126424084f9bSBrian Somers * Extract remote address and optionally port. 126524084f9bSBrian Somers */ 126624084f9bSBrian Somers ptr = strtok (NULL, " \t"); 126724084f9bSBrian Somers if (ptr) { 126824084f9bSBrian Somers 126924084f9bSBrian Somers 127024084f9bSBrian Somers separator = strchr (ptr, ':'); 127124084f9bSBrian Somers if (separator) 127224084f9bSBrian Somers remotePort = StrToAddrAndPort (ptr, 127324084f9bSBrian Somers &remoteAddr, 127424084f9bSBrian Somers protoName); 127524084f9bSBrian Somers else { 127624084f9bSBrian Somers 127724084f9bSBrian Somers remotePort = 0; 127824084f9bSBrian Somers StrToAddr (ptr, &remoteAddr); 127924084f9bSBrian Somers } 128024084f9bSBrian Somers } 128124084f9bSBrian Somers else { 128224084f9bSBrian Somers 128324084f9bSBrian Somers remotePort = 0; 128424084f9bSBrian Somers remoteAddr.s_addr = INADDR_ANY; 128524084f9bSBrian Somers } 128624084f9bSBrian Somers 128724084f9bSBrian Somers PacketAliasRedirectPort (localAddr, 128824084f9bSBrian Somers localPort, 128924084f9bSBrian Somers remoteAddr, 129024084f9bSBrian Somers remotePort, 129124084f9bSBrian Somers publicAddr, 129224084f9bSBrian Somers publicPort, 129324084f9bSBrian Somers proto); 129424084f9bSBrian Somers } 129524084f9bSBrian Somers 129624084f9bSBrian Somers void SetupAddressRedirect (char* parms) 129724084f9bSBrian Somers { 129824084f9bSBrian Somers char buf[128]; 129924084f9bSBrian Somers char* ptr; 130024084f9bSBrian Somers struct in_addr localAddr; 130124084f9bSBrian Somers struct in_addr publicAddr; 130224084f9bSBrian Somers 130324084f9bSBrian Somers strcpy (buf, parms); 130424084f9bSBrian Somers /* 130524084f9bSBrian Somers * Extract local address. 130624084f9bSBrian Somers */ 130724084f9bSBrian Somers ptr = strtok (buf, " \t"); 130824084f9bSBrian Somers if (!ptr) { 130924084f9bSBrian Somers 131024084f9bSBrian Somers fprintf (stderr, "redirect_address: missing local address.\n"); 131124084f9bSBrian Somers exit (1); 131224084f9bSBrian Somers } 131324084f9bSBrian Somers 131424084f9bSBrian Somers StrToAddr (ptr, &localAddr); 131524084f9bSBrian Somers /* 131624084f9bSBrian Somers * Extract public address. 131724084f9bSBrian Somers */ 131824084f9bSBrian Somers ptr = strtok (NULL, " \t"); 131924084f9bSBrian Somers if (!ptr) { 132024084f9bSBrian Somers 132124084f9bSBrian Somers fprintf (stderr, "redirect_address: missing public address.\n"); 132224084f9bSBrian Somers exit (1); 132324084f9bSBrian Somers } 132424084f9bSBrian Somers 132524084f9bSBrian Somers StrToAddr (ptr, &publicAddr); 132624084f9bSBrian Somers PacketAliasRedirectAddr (localAddr, publicAddr); 132724084f9bSBrian Somers } 132824084f9bSBrian Somers 132924084f9bSBrian Somers void StrToAddr (char* str, struct in_addr* addr) 133024084f9bSBrian Somers { 133124084f9bSBrian Somers struct hostent* hp; 133224084f9bSBrian Somers 133324084f9bSBrian Somers if (inet_aton (str, addr)) 133424084f9bSBrian Somers return; 133524084f9bSBrian Somers 133624084f9bSBrian Somers hp = gethostbyname (str); 133724084f9bSBrian Somers if (!hp) { 133824084f9bSBrian Somers 133924084f9bSBrian Somers fprintf (stderr, "Unknown host %s.\n", str); 134024084f9bSBrian Somers exit (1); 134124084f9bSBrian Somers } 134224084f9bSBrian Somers 134324084f9bSBrian Somers memcpy (addr, hp->h_addr, sizeof (struct in_addr)); 134424084f9bSBrian Somers } 134524084f9bSBrian Somers 134624084f9bSBrian Somers int StrToPort (char* str, char* proto) 134724084f9bSBrian Somers { 134824084f9bSBrian Somers int port; 134924084f9bSBrian Somers struct servent* sp; 135024084f9bSBrian Somers char* end; 135124084f9bSBrian Somers 135224084f9bSBrian Somers port = strtol (str, &end, 10); 135324084f9bSBrian Somers if (end != str) 135424084f9bSBrian Somers return htons (port); 135524084f9bSBrian Somers 135624084f9bSBrian Somers sp = getservbyname (str, proto); 135724084f9bSBrian Somers if (!sp) { 135824084f9bSBrian Somers 135924084f9bSBrian Somers fprintf (stderr, "Unknown service %s/%s.\n", 136024084f9bSBrian Somers str, proto); 136124084f9bSBrian Somers exit (1); 136224084f9bSBrian Somers } 136324084f9bSBrian Somers 136424084f9bSBrian Somers return sp->s_port; 136524084f9bSBrian Somers } 136624084f9bSBrian Somers 136724084f9bSBrian Somers int StrToProto (char* str) 136824084f9bSBrian Somers { 136924084f9bSBrian Somers if (!strcmp (str, "tcp")) 137024084f9bSBrian Somers return IPPROTO_TCP; 137124084f9bSBrian Somers 137224084f9bSBrian Somers if (!strcmp (str, "udp")) 137324084f9bSBrian Somers return IPPROTO_UDP; 137424084f9bSBrian Somers 137524084f9bSBrian Somers fprintf (stderr, "Unknown protocol %s. Expected tcp or udp.\n", str); 137624084f9bSBrian Somers exit (1); 137724084f9bSBrian Somers } 137824084f9bSBrian Somers 137924084f9bSBrian Somers int StrToAddrAndPort (char* str, struct in_addr* addr, char* proto) 138024084f9bSBrian Somers { 138124084f9bSBrian Somers char* ptr; 138224084f9bSBrian Somers 138324084f9bSBrian Somers ptr = strchr (str, ':'); 138424084f9bSBrian Somers if (!ptr) { 138524084f9bSBrian Somers 138624084f9bSBrian Somers fprintf (stderr, "%s is missing port number.\n", str); 138724084f9bSBrian Somers exit (1); 138824084f9bSBrian Somers } 138924084f9bSBrian Somers 139024084f9bSBrian Somers *ptr = '\0'; 139124084f9bSBrian Somers ++ptr; 139224084f9bSBrian Somers 139324084f9bSBrian Somers StrToAddr (str, addr); 139424084f9bSBrian Somers return StrToPort (ptr, proto); 139524084f9bSBrian Somers } 139624084f9bSBrian Somers 1397