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