124084f9bSBrian Somers /* 224084f9bSBrian Somers * natd - Network Address Translation Daemon for FreeBSD. 324084f9bSBrian Somers * 4f13f9fadSAlexander Langer * This software is 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 * 12f3d64024SBrian Somers * $Id: natd.c,v 1.13 1999/03/24 20:30:48 brian Exp $ 1324084f9bSBrian Somers */ 1424084f9bSBrian Somers 1559a7c613SBrian Somers #define SYSLOG_NAMES 1659a7c613SBrian Somers 1724084f9bSBrian Somers #include <sys/types.h> 1824084f9bSBrian Somers #include <sys/socket.h> 1924084f9bSBrian Somers #include <sys/time.h> 2024084f9bSBrian Somers 2124084f9bSBrian Somers #include <netinet/in.h> 2224084f9bSBrian Somers #include <netinet/in_systm.h> 2324084f9bSBrian Somers #include <netinet/ip.h> 2424084f9bSBrian Somers #include <machine/in_cksum.h> 2524084f9bSBrian Somers #include <netinet/tcp.h> 2659a7c613SBrian Somers #include <netinet/udp.h> 2759a7c613SBrian Somers #include <netinet/ip_icmp.h> 2824084f9bSBrian Somers #include <sys/ioctl.h> 2924084f9bSBrian Somers #include <net/if.h> 3024084f9bSBrian Somers #include <net/route.h> 3124084f9bSBrian Somers #include <arpa/inet.h> 3224084f9bSBrian Somers 3324084f9bSBrian Somers #include <alias.h> 340fc81af1SPhilippe Charnier #include <ctype.h> 350fc81af1SPhilippe Charnier #include <err.h> 360fc81af1SPhilippe Charnier #include <errno.h> 370fc81af1SPhilippe Charnier #include <netdb.h> 380fc81af1SPhilippe Charnier #include <signal.h> 390fc81af1SPhilippe Charnier #include <stdio.h> 400fc81af1SPhilippe Charnier #include <stdlib.h> 410fc81af1SPhilippe Charnier #include <string.h> 420fc81af1SPhilippe Charnier #include <syslog.h> 430fc81af1SPhilippe Charnier #include <unistd.h> 4467a886fbSBrian Somers 4524084f9bSBrian Somers #include "natd.h" 4624084f9bSBrian Somers 4724084f9bSBrian Somers /* 4824084f9bSBrian Somers * Default values for input and output 4924084f9bSBrian Somers * divert socket ports. 5024084f9bSBrian Somers */ 5124084f9bSBrian Somers 5224084f9bSBrian Somers #define DEFAULT_SERVICE "natd" 5324084f9bSBrian Somers 5424084f9bSBrian Somers /* 555d8ee958SBrian Somers * Definition of a port range, and macros to deal with values. 565d8ee958SBrian Somers * FORMAT: HI 16-bits == first port in range, 0 == all ports. 575d8ee958SBrian Somers * LO 16-bits == number of ports in range 585d8ee958SBrian Somers * NOTES: - Port values are not stored in network byte order. 595d8ee958SBrian Somers */ 605d8ee958SBrian Somers 615d8ee958SBrian Somers typedef u_long port_range; 625d8ee958SBrian Somers 635d8ee958SBrian Somers #define GETLOPORT(x) ((x) >> 0x10) 645d8ee958SBrian Somers #define GETNUMPORTS(x) ((x) & 0x0000ffff) 655d8ee958SBrian Somers #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x))) 665d8ee958SBrian Somers 675d8ee958SBrian Somers /* Set y to be the low-port value in port_range variable x. */ 685d8ee958SBrian Somers #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10)) 695d8ee958SBrian Somers 705d8ee958SBrian Somers /* Set y to be the number of ports in port_range variable x. */ 715d8ee958SBrian Somers #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y)) 725d8ee958SBrian Somers 735d8ee958SBrian Somers /* 7424084f9bSBrian Somers * Function prototypes. 7524084f9bSBrian Somers */ 7624084f9bSBrian Somers 7759a7c613SBrian Somers static void DoAliasing (int fd, int direction); 78902cb50aSBrian Somers static void DaemonMode (void); 7924084f9bSBrian Somers static void HandleRoutingInfo (int fd); 80902cb50aSBrian Somers static void Usage (void); 8159a7c613SBrian Somers static char* FormatPacket (struct ip*); 8224084f9bSBrian Somers static void PrintPacket (struct ip*); 83902cb50aSBrian Somers static void SyslogPacket (struct ip*, int priority, const char *label); 8424084f9bSBrian Somers static void SetAliasAddressFromIfName (char* ifName); 85902cb50aSBrian Somers static void InitiateShutdown (int); 86902cb50aSBrian Somers static void Shutdown (int); 87902cb50aSBrian Somers static void RefreshAddr (int); 88902cb50aSBrian Somers static void ParseOption (const char* option, const char* parms, int cmdLine); 89902cb50aSBrian Somers static void ReadConfigFile (const char* fileName); 90902cb50aSBrian Somers static void SetupPortRedirect (const char* parms); 91902cb50aSBrian Somers static void SetupAddressRedirect (const char* parms); 92902cb50aSBrian Somers static void SetupPptpAlias (const char* parms); 93902cb50aSBrian Somers static void StrToAddr (const char* str, struct in_addr* addr); 94902cb50aSBrian Somers static u_short StrToPort (const char* str, const char* proto); 95902cb50aSBrian Somers static int StrToPortRange (const char* str, const char* proto, port_range *portRange); 96902cb50aSBrian Somers static int StrToProto (const char* str); 97902cb50aSBrian Somers static int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange); 9824084f9bSBrian Somers static void ParseArgs (int argc, char** argv); 99fb994b07SBrian Somers static void FlushPacketBuffer (int fd); 10024084f9bSBrian Somers 10124084f9bSBrian Somers /* 10224084f9bSBrian Somers * Globals. 10324084f9bSBrian Somers */ 10424084f9bSBrian Somers 10524084f9bSBrian Somers static int verbose; 10624084f9bSBrian Somers static int background; 10724084f9bSBrian Somers static int running; 10824084f9bSBrian Somers static int assignAliasAddr; 10924084f9bSBrian Somers static char* ifName; 11024084f9bSBrian Somers static int ifIndex; 11167a886fbSBrian Somers static u_short inPort; 11267a886fbSBrian Somers static u_short outPort; 11367a886fbSBrian Somers static u_short inOutPort; 11424084f9bSBrian Somers static struct in_addr aliasAddr; 11524084f9bSBrian Somers static int dynamicMode; 11624084f9bSBrian Somers static int ifMTU; 11724084f9bSBrian Somers static int aliasOverhead; 11824084f9bSBrian Somers static int icmpSock; 119fb994b07SBrian Somers static char packetBuf[IP_MAXPACKET]; 120fb994b07SBrian Somers static int packetLen; 121fb994b07SBrian Somers static struct sockaddr_in packetAddr; 122fb994b07SBrian Somers static int packetSock; 12359a7c613SBrian Somers static int packetDirection; 124f9b06d5cSBrian Somers static int dropIgnoredIncoming; 12559a7c613SBrian Somers static int logDropped; 12659a7c613SBrian Somers static int logFacility; 12724084f9bSBrian Somers 12824084f9bSBrian Somers int main (int argc, char** argv) 12924084f9bSBrian Somers { 13024084f9bSBrian Somers int divertIn; 13124084f9bSBrian Somers int divertOut; 13224084f9bSBrian Somers int divertInOut; 13324084f9bSBrian Somers int routeSock; 13424084f9bSBrian Somers struct sockaddr_in addr; 13524084f9bSBrian Somers fd_set readMask; 136fb994b07SBrian Somers fd_set writeMask; 13724084f9bSBrian Somers int fdMax; 13824084f9bSBrian Somers /* 13924084f9bSBrian Somers * Initialize packet aliasing software. 14024084f9bSBrian Somers * Done already here to be able to alter option bits 14124084f9bSBrian Somers * during command line and configuration file processing. 14224084f9bSBrian Somers */ 143fb994b07SBrian Somers PacketAliasInit (); 14424084f9bSBrian Somers /* 14524084f9bSBrian Somers * Parse options. 14624084f9bSBrian Somers */ 14724084f9bSBrian Somers inPort = 0; 14824084f9bSBrian Somers outPort = 0; 14924084f9bSBrian Somers verbose = 0; 15024084f9bSBrian Somers inOutPort = 0; 15124084f9bSBrian Somers ifName = NULL; 15224084f9bSBrian Somers ifMTU = -1; 15324084f9bSBrian Somers background = 0; 15424084f9bSBrian Somers running = 1; 15524084f9bSBrian Somers assignAliasAddr = 0; 15624084f9bSBrian Somers aliasAddr.s_addr = INADDR_NONE; 15724084f9bSBrian Somers aliasOverhead = 12; 15824084f9bSBrian Somers dynamicMode = 0; 15959a7c613SBrian Somers logDropped = 0; 16059a7c613SBrian Somers logFacility = LOG_DAEMON; 161fb994b07SBrian Somers /* 162fb994b07SBrian Somers * Mark packet buffer empty. 163fb994b07SBrian Somers */ 164fb994b07SBrian Somers packetSock = -1; 16559a7c613SBrian Somers packetDirection = DONT_KNOW; 16624084f9bSBrian Somers 16724084f9bSBrian Somers ParseArgs (argc, argv); 16824084f9bSBrian Somers /* 16959a7c613SBrian Somers * Open syslog channel. 17059a7c613SBrian Somers */ 17159a7c613SBrian Somers openlog ("natd", LOG_CONS | LOG_PID, logFacility); 17259a7c613SBrian Somers /* 17324084f9bSBrian Somers * Check that valid aliasing address has been given. 17424084f9bSBrian Somers */ 1750fc81af1SPhilippe Charnier if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL) 1760fc81af1SPhilippe Charnier errx (1, "aliasing address not given"); 17724084f9bSBrian Somers 1780fc81af1SPhilippe Charnier if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL) 17967a886fbSBrian Somers errx (1, "both alias address and interface " 18067a886fbSBrian Somers "name are not allowed"); 18124084f9bSBrian Somers /* 18224084f9bSBrian Somers * Check that valid port number is known. 18324084f9bSBrian Somers */ 18424084f9bSBrian Somers if (inPort != 0 || outPort != 0) 1850fc81af1SPhilippe Charnier if (inPort == 0 || outPort == 0) 1860fc81af1SPhilippe Charnier errx (1, "both input and output ports are required"); 18724084f9bSBrian Somers 18824084f9bSBrian Somers if (inPort == 0 && outPort == 0 && inOutPort == 0) 18924084f9bSBrian Somers ParseOption ("port", DEFAULT_SERVICE, 0); 19024084f9bSBrian Somers 19124084f9bSBrian Somers /* 192f9b06d5cSBrian Somers * Check if ignored packets should be dropped. 193f9b06d5cSBrian Somers */ 194f9b06d5cSBrian Somers dropIgnoredIncoming = PacketAliasSetMode (0, 0); 195f9b06d5cSBrian Somers dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING; 196f9b06d5cSBrian Somers /* 19724084f9bSBrian Somers * Create divert sockets. Use only one socket if -p was specified 19824084f9bSBrian Somers * on command line. Otherwise, create separate sockets for 19924084f9bSBrian Somers * outgoing and incoming connnections. 20024084f9bSBrian Somers */ 20124084f9bSBrian Somers if (inOutPort) { 20224084f9bSBrian Somers 20324084f9bSBrian Somers divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 20424084f9bSBrian Somers if (divertInOut == -1) 20524084f9bSBrian Somers Quit ("Unable to create divert socket."); 20624084f9bSBrian Somers 20724084f9bSBrian Somers divertIn = -1; 20824084f9bSBrian Somers divertOut = -1; 20924084f9bSBrian Somers /* 21024084f9bSBrian Somers * Bind socket. 21124084f9bSBrian Somers */ 21224084f9bSBrian Somers 21324084f9bSBrian Somers addr.sin_family = AF_INET; 21424084f9bSBrian Somers addr.sin_addr.s_addr = INADDR_ANY; 21524084f9bSBrian Somers addr.sin_port = inOutPort; 21624084f9bSBrian Somers 21724084f9bSBrian Somers if (bind (divertInOut, 21824084f9bSBrian Somers (struct sockaddr*) &addr, 21924084f9bSBrian Somers sizeof addr) == -1) 22024084f9bSBrian Somers Quit ("Unable to bind divert socket."); 22124084f9bSBrian Somers } 22224084f9bSBrian Somers else { 22324084f9bSBrian Somers 22424084f9bSBrian Somers divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 22524084f9bSBrian Somers if (divertIn == -1) 22624084f9bSBrian Somers Quit ("Unable to create incoming divert socket."); 22724084f9bSBrian Somers 22824084f9bSBrian Somers divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 22924084f9bSBrian Somers if (divertOut == -1) 23024084f9bSBrian Somers Quit ("Unable to create outgoing divert socket."); 23124084f9bSBrian Somers 23224084f9bSBrian Somers divertInOut = -1; 23324084f9bSBrian Somers 23424084f9bSBrian Somers /* 23524084f9bSBrian Somers * Bind divert sockets. 23624084f9bSBrian Somers */ 23724084f9bSBrian Somers 23824084f9bSBrian Somers addr.sin_family = AF_INET; 23924084f9bSBrian Somers addr.sin_addr.s_addr = INADDR_ANY; 24024084f9bSBrian Somers addr.sin_port = inPort; 24124084f9bSBrian Somers 24224084f9bSBrian Somers if (bind (divertIn, 24324084f9bSBrian Somers (struct sockaddr*) &addr, 24424084f9bSBrian Somers sizeof addr) == -1) 24524084f9bSBrian Somers Quit ("Unable to bind incoming divert socket."); 24624084f9bSBrian Somers 24724084f9bSBrian Somers addr.sin_family = AF_INET; 24824084f9bSBrian Somers addr.sin_addr.s_addr = INADDR_ANY; 24924084f9bSBrian Somers addr.sin_port = outPort; 25024084f9bSBrian Somers 25124084f9bSBrian Somers if (bind (divertOut, 25224084f9bSBrian Somers (struct sockaddr*) &addr, 25324084f9bSBrian Somers sizeof addr) == -1) 25424084f9bSBrian Somers Quit ("Unable to bind outgoing divert socket."); 25524084f9bSBrian Somers } 25624084f9bSBrian Somers /* 25724084f9bSBrian Somers * Create routing socket if interface name specified. 25824084f9bSBrian Somers */ 25924084f9bSBrian Somers if (ifName && dynamicMode) { 26024084f9bSBrian Somers 26124084f9bSBrian Somers routeSock = socket (PF_ROUTE, SOCK_RAW, 0); 26224084f9bSBrian Somers if (routeSock == -1) 26324084f9bSBrian Somers Quit ("Unable to create routing info socket."); 26424084f9bSBrian Somers } 26524084f9bSBrian Somers else 26624084f9bSBrian Somers routeSock = -1; 26724084f9bSBrian Somers /* 26824084f9bSBrian Somers * Create socket for sending ICMP messages. 26924084f9bSBrian Somers */ 27024084f9bSBrian Somers icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); 27124084f9bSBrian Somers if (icmpSock == -1) 27224084f9bSBrian Somers Quit ("Unable to create ICMP socket."); 273f3d64024SBrian Somers 274f3d64024SBrian Somers /* 275f3d64024SBrian Somers * And disable reads for the socket, otherwise it slowly fills 276f3d64024SBrian Somers * up with received icmps which we do not use. 277f3d64024SBrian Somers */ 278f3d64024SBrian Somers shutdown(icmpSock, SHUT_RD); 279f3d64024SBrian Somers 28024084f9bSBrian Somers /* 28124084f9bSBrian Somers * Become a daemon unless verbose mode was requested. 28224084f9bSBrian Somers */ 28324084f9bSBrian Somers if (!verbose) 28424084f9bSBrian Somers DaemonMode (); 28524084f9bSBrian Somers /* 28624084f9bSBrian Somers * Catch signals to manage shutdown and 28724084f9bSBrian Somers * refresh of interface address. 28824084f9bSBrian Somers */ 28924084f9bSBrian Somers signal (SIGTERM, InitiateShutdown); 29024084f9bSBrian Somers signal (SIGHUP, RefreshAddr); 29124084f9bSBrian Somers /* 29224084f9bSBrian Somers * Set alias address if it has been given. 29324084f9bSBrian Somers */ 29424084f9bSBrian Somers if (aliasAddr.s_addr != INADDR_NONE) 295fb994b07SBrian Somers PacketAliasSetAddress (aliasAddr); 29624084f9bSBrian Somers /* 29724084f9bSBrian Somers * We need largest descriptor number for select. 29824084f9bSBrian Somers */ 29924084f9bSBrian Somers 30024084f9bSBrian Somers fdMax = -1; 30124084f9bSBrian Somers 30224084f9bSBrian Somers if (divertIn > fdMax) 30324084f9bSBrian Somers fdMax = divertIn; 30424084f9bSBrian Somers 30524084f9bSBrian Somers if (divertOut > fdMax) 30624084f9bSBrian Somers fdMax = divertOut; 30724084f9bSBrian Somers 30824084f9bSBrian Somers if (divertInOut > fdMax) 30924084f9bSBrian Somers fdMax = divertInOut; 31024084f9bSBrian Somers 31124084f9bSBrian Somers if (routeSock > fdMax) 31224084f9bSBrian Somers fdMax = routeSock; 31324084f9bSBrian Somers 31424084f9bSBrian Somers while (running) { 315fb994b07SBrian Somers 316fb994b07SBrian Somers if (divertInOut != -1 && !ifName && packetSock == -1) { 317fb994b07SBrian Somers /* 318fb994b07SBrian Somers * When using only one socket, just call 319fb994b07SBrian Somers * DoAliasing repeatedly to process packets. 320fb994b07SBrian Somers */ 32159a7c613SBrian Somers DoAliasing (divertInOut, DONT_KNOW); 322fb994b07SBrian Somers continue; 323fb994b07SBrian Somers } 32424084f9bSBrian Somers /* 32524084f9bSBrian Somers * Build read mask from socket descriptors to select. 32624084f9bSBrian Somers */ 32724084f9bSBrian Somers FD_ZERO (&readMask); 328fb994b07SBrian Somers FD_ZERO (&writeMask); 32924084f9bSBrian Somers 330fb994b07SBrian Somers /* 331fb994b07SBrian Somers * If there is unsent packet in buffer, use select 332fb994b07SBrian Somers * to check when socket comes writable again. 333fb994b07SBrian Somers */ 334fb994b07SBrian Somers if (packetSock != -1) { 335fb994b07SBrian Somers 336fb994b07SBrian Somers FD_SET (packetSock, &writeMask); 337fb994b07SBrian Somers } 338fb994b07SBrian Somers else { 339fb994b07SBrian Somers /* 340fb994b07SBrian Somers * No unsent packet exists - safe to check if 341fb994b07SBrian Somers * new ones are available. 342fb994b07SBrian Somers */ 34324084f9bSBrian Somers if (divertIn != -1) 34424084f9bSBrian Somers FD_SET (divertIn, &readMask); 34524084f9bSBrian Somers 34624084f9bSBrian Somers if (divertOut != -1) 34724084f9bSBrian Somers FD_SET (divertOut, &readMask); 34824084f9bSBrian Somers 34924084f9bSBrian Somers if (divertInOut != -1) 35024084f9bSBrian Somers FD_SET (divertInOut, &readMask); 351fb994b07SBrian Somers } 352fb994b07SBrian Somers /* 353fb994b07SBrian Somers * Routing info is processed always. 354fb994b07SBrian Somers */ 35524084f9bSBrian Somers if (routeSock != -1) 35624084f9bSBrian Somers FD_SET (routeSock, &readMask); 35724084f9bSBrian Somers 35824084f9bSBrian Somers if (select (fdMax + 1, 35924084f9bSBrian Somers &readMask, 360fb994b07SBrian Somers &writeMask, 36124084f9bSBrian Somers NULL, 36224084f9bSBrian Somers NULL) == -1) { 36324084f9bSBrian Somers 36424084f9bSBrian Somers if (errno == EINTR) 36524084f9bSBrian Somers continue; 36624084f9bSBrian Somers 36724084f9bSBrian Somers Quit ("Select failed."); 36824084f9bSBrian Somers } 36924084f9bSBrian Somers 370fb994b07SBrian Somers if (packetSock != -1) 371fb994b07SBrian Somers if (FD_ISSET (packetSock, &writeMask)) 372fb994b07SBrian Somers FlushPacketBuffer (packetSock); 373fb994b07SBrian Somers 37424084f9bSBrian Somers if (divertIn != -1) 37524084f9bSBrian Somers if (FD_ISSET (divertIn, &readMask)) 37659a7c613SBrian Somers DoAliasing (divertIn, INPUT); 37724084f9bSBrian Somers 37824084f9bSBrian Somers if (divertOut != -1) 37924084f9bSBrian Somers if (FD_ISSET (divertOut, &readMask)) 38059a7c613SBrian Somers DoAliasing (divertOut, OUTPUT); 38124084f9bSBrian Somers 38224084f9bSBrian Somers if (divertInOut != -1) 38324084f9bSBrian Somers if (FD_ISSET (divertInOut, &readMask)) 38459a7c613SBrian Somers DoAliasing (divertInOut, DONT_KNOW); 38524084f9bSBrian Somers 38624084f9bSBrian Somers if (routeSock != -1) 38724084f9bSBrian Somers if (FD_ISSET (routeSock, &readMask)) 38824084f9bSBrian Somers HandleRoutingInfo (routeSock); 38924084f9bSBrian Somers } 39024084f9bSBrian Somers 39124084f9bSBrian Somers if (background) 39224084f9bSBrian Somers unlink (PIDFILE); 39324084f9bSBrian Somers 39424084f9bSBrian Somers return 0; 39524084f9bSBrian Somers } 39624084f9bSBrian Somers 39724084f9bSBrian Somers static void DaemonMode () 39824084f9bSBrian Somers { 39924084f9bSBrian Somers FILE* pidFile; 40024084f9bSBrian Somers 40124084f9bSBrian Somers daemon (0, 0); 40224084f9bSBrian Somers background = 1; 40324084f9bSBrian Somers 40424084f9bSBrian Somers pidFile = fopen (PIDFILE, "w"); 40524084f9bSBrian Somers if (pidFile) { 40624084f9bSBrian Somers 40724084f9bSBrian Somers fprintf (pidFile, "%d\n", getpid ()); 40824084f9bSBrian Somers fclose (pidFile); 40924084f9bSBrian Somers } 41024084f9bSBrian Somers } 41124084f9bSBrian Somers 41224084f9bSBrian Somers static void ParseArgs (int argc, char** argv) 41324084f9bSBrian Somers { 41424084f9bSBrian Somers int arg; 41524084f9bSBrian Somers char* parm; 41624084f9bSBrian Somers char* opt; 41724084f9bSBrian Somers char parmBuf[256]; 41824084f9bSBrian Somers 41924084f9bSBrian Somers for (arg = 1; arg < argc; arg++) { 42024084f9bSBrian Somers 42124084f9bSBrian Somers opt = argv[arg]; 42224084f9bSBrian Somers if (*opt != '-') { 42324084f9bSBrian Somers 4240fc81af1SPhilippe Charnier warnx ("invalid option %s", opt); 42524084f9bSBrian Somers Usage (); 42624084f9bSBrian Somers } 42724084f9bSBrian Somers 42824084f9bSBrian Somers parm = NULL; 42924084f9bSBrian Somers parmBuf[0] = '\0'; 43024084f9bSBrian Somers 43124084f9bSBrian Somers while (arg < argc - 1) { 43224084f9bSBrian Somers 43324084f9bSBrian Somers if (argv[arg + 1][0] == '-') 43424084f9bSBrian Somers break; 43524084f9bSBrian Somers 43624084f9bSBrian Somers if (parm) 43724084f9bSBrian Somers strcat (parmBuf, " "); 43824084f9bSBrian Somers 43924084f9bSBrian Somers ++arg; 44024084f9bSBrian Somers parm = parmBuf; 44124084f9bSBrian Somers strcat (parmBuf, argv[arg]); 44224084f9bSBrian Somers } 44324084f9bSBrian Somers 44424084f9bSBrian Somers ParseOption (opt + 1, parm, 1); 44524084f9bSBrian Somers } 44624084f9bSBrian Somers } 44724084f9bSBrian Somers 44859a7c613SBrian Somers static void DoAliasing (int fd, int direction) 44924084f9bSBrian Somers { 45024084f9bSBrian Somers int bytes; 45124084f9bSBrian Somers int origBytes; 452f9b06d5cSBrian Somers int status; 45324084f9bSBrian Somers int addrSize; 45424084f9bSBrian Somers struct ip* ip; 45524084f9bSBrian Somers 45624084f9bSBrian Somers if (assignAliasAddr) { 45724084f9bSBrian Somers 45824084f9bSBrian Somers SetAliasAddressFromIfName (ifName); 45924084f9bSBrian Somers assignAliasAddr = 0; 46024084f9bSBrian Somers } 46124084f9bSBrian Somers /* 46224084f9bSBrian Somers * Get packet from socket. 46324084f9bSBrian Somers */ 464fb994b07SBrian Somers addrSize = sizeof packetAddr; 46524084f9bSBrian Somers origBytes = recvfrom (fd, 466fb994b07SBrian Somers packetBuf, 467fb994b07SBrian Somers sizeof packetBuf, 46824084f9bSBrian Somers 0, 469fb994b07SBrian Somers (struct sockaddr*) &packetAddr, 47024084f9bSBrian Somers &addrSize); 47124084f9bSBrian Somers 47224084f9bSBrian Somers if (origBytes == -1) { 47324084f9bSBrian Somers 47424084f9bSBrian Somers if (errno != EINTR) 4750fc81af1SPhilippe Charnier Warn ("read from divert socket failed"); 47624084f9bSBrian Somers 47724084f9bSBrian Somers return; 47824084f9bSBrian Somers } 47924084f9bSBrian Somers /* 48024084f9bSBrian Somers * This is a IP packet. 48124084f9bSBrian Somers */ 482fb994b07SBrian Somers ip = (struct ip*) packetBuf; 48359a7c613SBrian Somers if (direction == DONT_KNOW) 48459a7c613SBrian Somers if (packetAddr.sin_addr.s_addr == INADDR_ANY) 48559a7c613SBrian Somers direction = OUTPUT; 48659a7c613SBrian Somers else 48759a7c613SBrian Somers direction = INPUT; 48824084f9bSBrian Somers 48924084f9bSBrian Somers if (verbose) { 49024084f9bSBrian Somers 49124084f9bSBrian Somers /* 49224084f9bSBrian Somers * Print packet direction and protocol type. 49324084f9bSBrian Somers */ 49459a7c613SBrian Somers printf (direction == OUTPUT ? "Out " : "In "); 49524084f9bSBrian Somers 49624084f9bSBrian Somers switch (ip->ip_p) { 49724084f9bSBrian Somers case IPPROTO_TCP: 49824084f9bSBrian Somers printf ("[TCP] "); 49924084f9bSBrian Somers break; 50024084f9bSBrian Somers 50124084f9bSBrian Somers case IPPROTO_UDP: 50224084f9bSBrian Somers printf ("[UDP] "); 50324084f9bSBrian Somers break; 50424084f9bSBrian Somers 50524084f9bSBrian Somers case IPPROTO_ICMP: 50624084f9bSBrian Somers printf ("[ICMP] "); 50724084f9bSBrian Somers break; 50824084f9bSBrian Somers 50924084f9bSBrian Somers default: 51059a7c613SBrian Somers printf ("[%d] ", ip->ip_p); 51124084f9bSBrian Somers break; 51224084f9bSBrian Somers } 51324084f9bSBrian Somers /* 51424084f9bSBrian Somers * Print addresses. 51524084f9bSBrian Somers */ 51624084f9bSBrian Somers PrintPacket (ip); 51724084f9bSBrian Somers } 51824084f9bSBrian Somers 51959a7c613SBrian Somers if (direction == OUTPUT) { 52024084f9bSBrian Somers /* 52124084f9bSBrian Somers * Outgoing packets. Do aliasing. 52224084f9bSBrian Somers */ 523fb994b07SBrian Somers PacketAliasOut (packetBuf, IP_MAXPACKET); 52424084f9bSBrian Somers } 52524084f9bSBrian Somers else { 52659a7c613SBrian Somers 52724084f9bSBrian Somers /* 52824084f9bSBrian Somers * Do aliasing. 52924084f9bSBrian Somers */ 530f9b06d5cSBrian Somers status = PacketAliasIn (packetBuf, IP_MAXPACKET); 531f9b06d5cSBrian Somers if (status == PKT_ALIAS_IGNORED && 532f9b06d5cSBrian Somers dropIgnoredIncoming) { 533f9b06d5cSBrian Somers 53459a7c613SBrian Somers if (verbose) 535f9b06d5cSBrian Somers printf (" dropped.\n"); 53659a7c613SBrian Somers 53759a7c613SBrian Somers if (logDropped) 53859a7c613SBrian Somers SyslogPacket (ip, LOG_WARNING, "denied"); 53959a7c613SBrian Somers 540f9b06d5cSBrian Somers return; 541f9b06d5cSBrian Somers } 54224084f9bSBrian Somers } 54324084f9bSBrian Somers /* 54424084f9bSBrian Somers * Length might have changed during aliasing. 54524084f9bSBrian Somers */ 54624084f9bSBrian Somers bytes = ntohs (ip->ip_len); 54724084f9bSBrian Somers /* 54824084f9bSBrian Somers * Update alias overhead size for outgoing packets. 54924084f9bSBrian Somers */ 55059a7c613SBrian Somers if (direction == OUTPUT && 55124084f9bSBrian Somers bytes - origBytes > aliasOverhead) 55224084f9bSBrian Somers aliasOverhead = bytes - origBytes; 55324084f9bSBrian Somers 55424084f9bSBrian Somers if (verbose) { 55524084f9bSBrian Somers 55624084f9bSBrian Somers /* 55724084f9bSBrian Somers * Print addresses after aliasing. 55824084f9bSBrian Somers */ 55924084f9bSBrian Somers printf (" aliased to\n"); 56024084f9bSBrian Somers printf (" "); 56124084f9bSBrian Somers PrintPacket (ip); 56224084f9bSBrian Somers printf ("\n"); 56324084f9bSBrian Somers } 564fb994b07SBrian Somers 565fb994b07SBrian Somers packetLen = bytes; 566fb994b07SBrian Somers packetSock = fd; 56759a7c613SBrian Somers packetDirection = direction; 56859a7c613SBrian Somers 569fb994b07SBrian Somers FlushPacketBuffer (fd); 570fb994b07SBrian Somers } 571fb994b07SBrian Somers 572fb994b07SBrian Somers static void FlushPacketBuffer (int fd) 573fb994b07SBrian Somers { 574fb994b07SBrian Somers int wrote; 575fb994b07SBrian Somers char msgBuf[80]; 57624084f9bSBrian Somers /* 57724084f9bSBrian Somers * Put packet back for processing. 57824084f9bSBrian Somers */ 57924084f9bSBrian Somers wrote = sendto (fd, 580fb994b07SBrian Somers packetBuf, 581fb994b07SBrian Somers packetLen, 58224084f9bSBrian Somers 0, 583fb994b07SBrian Somers (struct sockaddr*) &packetAddr, 584fb994b07SBrian Somers sizeof packetAddr); 58524084f9bSBrian Somers 586fb994b07SBrian Somers if (wrote != packetLen) { 587fb994b07SBrian Somers /* 588fb994b07SBrian Somers * If buffer space is not available, 589fb994b07SBrian Somers * just return. Main loop will take care of 590fb994b07SBrian Somers * retrying send when space becomes available. 591fb994b07SBrian Somers */ 592fb994b07SBrian Somers if (errno == ENOBUFS) 593fb994b07SBrian Somers return; 59424084f9bSBrian Somers 59524084f9bSBrian Somers if (errno == EMSGSIZE) { 59624084f9bSBrian Somers 59759a7c613SBrian Somers if (packetDirection == OUTPUT && 59824084f9bSBrian Somers ifMTU != -1) 59924084f9bSBrian Somers SendNeedFragIcmp (icmpSock, 600fb994b07SBrian Somers (struct ip*) packetBuf, 60124084f9bSBrian Somers ifMTU - aliasOverhead); 60224084f9bSBrian Somers } 60324084f9bSBrian Somers else { 60424084f9bSBrian Somers 6050fc81af1SPhilippe Charnier sprintf (msgBuf, "failed to write packet back"); 60624084f9bSBrian Somers Warn (msgBuf); 60724084f9bSBrian Somers } 60824084f9bSBrian Somers } 609fb994b07SBrian Somers 610fb994b07SBrian Somers packetSock = -1; 61124084f9bSBrian Somers } 61224084f9bSBrian Somers 61324084f9bSBrian Somers static void HandleRoutingInfo (int fd) 61424084f9bSBrian Somers { 61524084f9bSBrian Somers int bytes; 61624084f9bSBrian Somers struct if_msghdr ifMsg; 61724084f9bSBrian Somers /* 61824084f9bSBrian Somers * Get packet from socket. 61924084f9bSBrian Somers */ 62024084f9bSBrian Somers bytes = read (fd, &ifMsg, sizeof ifMsg); 62124084f9bSBrian Somers if (bytes == -1) { 62224084f9bSBrian Somers 6230fc81af1SPhilippe Charnier Warn ("read from routing socket failed"); 62424084f9bSBrian Somers return; 62524084f9bSBrian Somers } 62624084f9bSBrian Somers 62724084f9bSBrian Somers if (ifMsg.ifm_version != RTM_VERSION) { 62824084f9bSBrian Somers 6290fc81af1SPhilippe Charnier Warn ("unexpected packet read from routing socket"); 63024084f9bSBrian Somers return; 63124084f9bSBrian Somers } 63224084f9bSBrian Somers 63324084f9bSBrian Somers if (verbose) 63424084f9bSBrian Somers printf ("Routing message %X received.\n", ifMsg.ifm_type); 63524084f9bSBrian Somers 63624084f9bSBrian Somers if (ifMsg.ifm_type != RTM_NEWADDR) 63724084f9bSBrian Somers return; 63824084f9bSBrian Somers 63924084f9bSBrian Somers if (verbose && ifMsg.ifm_index == ifIndex) 64024084f9bSBrian Somers printf ("Interface address has changed.\n"); 64124084f9bSBrian Somers 64224084f9bSBrian Somers if (ifMsg.ifm_index == ifIndex) 64324084f9bSBrian Somers assignAliasAddr = 1; 64424084f9bSBrian Somers } 64524084f9bSBrian Somers 64624084f9bSBrian Somers static void PrintPacket (struct ip* ip) 64724084f9bSBrian Somers { 64859a7c613SBrian Somers printf ("%s", FormatPacket (ip)); 64959a7c613SBrian Somers } 65059a7c613SBrian Somers 651902cb50aSBrian Somers static void SyslogPacket (struct ip* ip, int priority, const char *label) 65259a7c613SBrian Somers { 65359a7c613SBrian Somers syslog (priority, "%s %s", label, FormatPacket (ip)); 65459a7c613SBrian Somers } 65559a7c613SBrian Somers 65659a7c613SBrian Somers static char* FormatPacket (struct ip* ip) 65759a7c613SBrian Somers { 65859a7c613SBrian Somers static char buf[256]; 65924084f9bSBrian Somers struct tcphdr* tcphdr; 66059a7c613SBrian Somers struct udphdr* udphdr; 66159a7c613SBrian Somers struct icmp* icmphdr; 66259a7c613SBrian Somers char src[20]; 66359a7c613SBrian Somers char dst[20]; 66424084f9bSBrian Somers 66559a7c613SBrian Somers strcpy (src, inet_ntoa (ip->ip_src)); 66659a7c613SBrian Somers strcpy (dst, inet_ntoa (ip->ip_dst)); 66759a7c613SBrian Somers 66859a7c613SBrian Somers switch (ip->ip_p) { 66959a7c613SBrian Somers case IPPROTO_TCP: 67024084f9bSBrian Somers tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2)); 67159a7c613SBrian Somers sprintf (buf, "[TCP] %s:%d -> %s:%d", 67259a7c613SBrian Somers src, 67359a7c613SBrian Somers ntohs (tcphdr->th_sport), 67459a7c613SBrian Somers dst, 67559a7c613SBrian Somers ntohs (tcphdr->th_dport)); 67659a7c613SBrian Somers break; 67724084f9bSBrian Somers 67859a7c613SBrian Somers case IPPROTO_UDP: 67959a7c613SBrian Somers udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2)); 68059a7c613SBrian Somers sprintf (buf, "[UDP] %s:%d -> %s:%d", 68159a7c613SBrian Somers src, 68259a7c613SBrian Somers ntohs (udphdr->uh_sport), 68359a7c613SBrian Somers dst, 68459a7c613SBrian Somers ntohs (udphdr->uh_dport)); 68559a7c613SBrian Somers break; 68624084f9bSBrian Somers 68759a7c613SBrian Somers case IPPROTO_ICMP: 68859a7c613SBrian Somers icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2)); 689b71e869dSBrian Somers sprintf (buf, "[ICMP] %s -> %s %u(%u)", 69059a7c613SBrian Somers src, 69159a7c613SBrian Somers dst, 692b71e869dSBrian Somers icmphdr->icmp_type, 693b71e869dSBrian Somers icmphdr->icmp_code); 69459a7c613SBrian Somers break; 69559a7c613SBrian Somers 69659a7c613SBrian Somers default: 69759a7c613SBrian Somers sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst); 69859a7c613SBrian Somers break; 69959a7c613SBrian Somers } 70059a7c613SBrian Somers 70159a7c613SBrian Somers return buf; 70224084f9bSBrian Somers } 70324084f9bSBrian Somers 704902cb50aSBrian Somers static void SetAliasAddressFromIfName (char* ifn) 70524084f9bSBrian Somers { 70624084f9bSBrian Somers struct ifconf cf; 70724084f9bSBrian Somers struct ifreq buf[32]; 70824084f9bSBrian Somers char msg[80]; 70924084f9bSBrian Somers struct ifreq* ifPtr; 71024084f9bSBrian Somers int extra; 71124084f9bSBrian Somers int helperSock; 71224084f9bSBrian Somers int bytes; 71324084f9bSBrian Somers struct sockaddr_in* addr; 71424084f9bSBrian Somers int found; 71524084f9bSBrian Somers struct ifreq req; 71624084f9bSBrian Somers char last[10]; 71724084f9bSBrian Somers /* 71824084f9bSBrian Somers * Create a dummy socket to access interface information. 71924084f9bSBrian Somers */ 72024084f9bSBrian Somers helperSock = socket (AF_INET, SOCK_DGRAM, 0); 72124084f9bSBrian Somers if (helperSock == -1) { 72224084f9bSBrian Somers 72324084f9bSBrian Somers Quit ("Failed to create helper socket."); 72424084f9bSBrian Somers exit (1); 72524084f9bSBrian Somers } 72624084f9bSBrian Somers 72724084f9bSBrian Somers cf.ifc_len = sizeof (buf); 72824084f9bSBrian Somers cf.ifc_req = buf; 72924084f9bSBrian Somers /* 73024084f9bSBrian Somers * Get interface data. 73124084f9bSBrian Somers */ 73224084f9bSBrian Somers if (ioctl (helperSock, SIOCGIFCONF, &cf) == -1) { 73324084f9bSBrian Somers 73424084f9bSBrian Somers Quit ("Ioctl SIOCGIFCONF failed."); 73524084f9bSBrian Somers exit (1); 73624084f9bSBrian Somers } 73724084f9bSBrian Somers 73824084f9bSBrian Somers ifIndex = 0; 73924084f9bSBrian Somers ifPtr = buf; 74024084f9bSBrian Somers bytes = cf.ifc_len; 74124084f9bSBrian Somers found = 0; 74224084f9bSBrian Somers last[0] = '\0'; 74324084f9bSBrian Somers /* 74424084f9bSBrian Somers * Loop through interfaces until one with 74524084f9bSBrian Somers * given name is found. This is done to 74624084f9bSBrian Somers * find correct interface index for routing 74724084f9bSBrian Somers * message processing. 74824084f9bSBrian Somers */ 74924084f9bSBrian Somers while (bytes) { 75024084f9bSBrian Somers 75124084f9bSBrian Somers if (ifPtr->ifr_addr.sa_family == AF_INET && 752902cb50aSBrian Somers !strcmp (ifPtr->ifr_name, ifn)) { 75324084f9bSBrian Somers 75424084f9bSBrian Somers found = 1; 75524084f9bSBrian Somers break; 75624084f9bSBrian Somers } 75724084f9bSBrian Somers 75824084f9bSBrian Somers if (strcmp (last, ifPtr->ifr_name)) { 75924084f9bSBrian Somers 76024084f9bSBrian Somers strcpy (last, ifPtr->ifr_name); 76124084f9bSBrian Somers ++ifIndex; 76224084f9bSBrian Somers } 76324084f9bSBrian Somers 76424084f9bSBrian Somers extra = ifPtr->ifr_addr.sa_len - sizeof (struct sockaddr); 76524084f9bSBrian Somers 76624084f9bSBrian Somers ifPtr++; 76724084f9bSBrian Somers ifPtr = (struct ifreq*) ((char*) ifPtr + extra); 76824084f9bSBrian Somers bytes -= sizeof (struct ifreq) + extra; 76924084f9bSBrian Somers } 77024084f9bSBrian Somers 77124084f9bSBrian Somers if (!found) { 77224084f9bSBrian Somers 77324084f9bSBrian Somers close (helperSock); 774902cb50aSBrian Somers sprintf (msg, "Unknown interface name %s.\n", ifn); 77524084f9bSBrian Somers Quit (msg); 77624084f9bSBrian Somers } 77724084f9bSBrian Somers /* 77824084f9bSBrian Somers * Get MTU size. 77924084f9bSBrian Somers */ 780902cb50aSBrian Somers strcpy (req.ifr_name, ifn); 78124084f9bSBrian Somers 78224084f9bSBrian Somers if (ioctl (helperSock, SIOCGIFMTU, &req) == -1) 78324084f9bSBrian Somers Quit ("Cannot get interface mtu size."); 78424084f9bSBrian Somers 78524084f9bSBrian Somers ifMTU = req.ifr_mtu; 78624084f9bSBrian Somers /* 78724084f9bSBrian Somers * Get interface address. 78824084f9bSBrian Somers */ 78924084f9bSBrian Somers if (ioctl (helperSock, SIOCGIFADDR, &req) == -1) 79024084f9bSBrian Somers Quit ("Cannot get interface address."); 79124084f9bSBrian Somers 79224084f9bSBrian Somers addr = (struct sockaddr_in*) &req.ifr_addr; 793f627793dSJordan K. Hubbard PacketAliasSetAddress (addr->sin_addr); 79424084f9bSBrian Somers syslog (LOG_INFO, "Aliasing to %s, mtu %d bytes", 79524084f9bSBrian Somers inet_ntoa (addr->sin_addr), 79624084f9bSBrian Somers ifMTU); 79724084f9bSBrian Somers 79824084f9bSBrian Somers close (helperSock); 79924084f9bSBrian Somers } 80024084f9bSBrian Somers 801902cb50aSBrian Somers void Quit (const char* msg) 80224084f9bSBrian Somers { 80324084f9bSBrian Somers Warn (msg); 80424084f9bSBrian Somers exit (1); 80524084f9bSBrian Somers } 80624084f9bSBrian Somers 807902cb50aSBrian Somers void Warn (const char* msg) 80824084f9bSBrian Somers { 80924084f9bSBrian Somers if (background) 81024084f9bSBrian Somers syslog (LOG_ALERT, "%s (%m)", msg); 81124084f9bSBrian Somers else 8120fc81af1SPhilippe Charnier warn (msg); 81324084f9bSBrian Somers } 81424084f9bSBrian Somers 815902cb50aSBrian Somers static void RefreshAddr (int sig) 81624084f9bSBrian Somers { 81724084f9bSBrian Somers signal (SIGHUP, RefreshAddr); 81824084f9bSBrian Somers if (ifName) 81924084f9bSBrian Somers assignAliasAddr = 1; 82024084f9bSBrian Somers } 82124084f9bSBrian Somers 822902cb50aSBrian Somers static void InitiateShutdown (int sig) 82324084f9bSBrian Somers { 82424084f9bSBrian Somers /* 82524084f9bSBrian Somers * Start timer to allow kernel gracefully 82624084f9bSBrian Somers * shutdown existing connections when system 82724084f9bSBrian Somers * is shut down. 82824084f9bSBrian Somers */ 82924084f9bSBrian Somers signal (SIGALRM, Shutdown); 83024084f9bSBrian Somers alarm (10); 83124084f9bSBrian Somers } 83224084f9bSBrian Somers 833902cb50aSBrian Somers static void Shutdown (int sig) 83424084f9bSBrian Somers { 83524084f9bSBrian Somers running = 0; 83624084f9bSBrian Somers } 83724084f9bSBrian Somers 83824084f9bSBrian Somers /* 83924084f9bSBrian Somers * Different options recognized by this program. 84024084f9bSBrian Somers */ 84124084f9bSBrian Somers 84224084f9bSBrian Somers enum Option { 84324084f9bSBrian Somers 84424084f9bSBrian Somers PacketAliasOption, 84524084f9bSBrian Somers Verbose, 84624084f9bSBrian Somers InPort, 84724084f9bSBrian Somers OutPort, 84824084f9bSBrian Somers Port, 84924084f9bSBrian Somers AliasAddress, 85024084f9bSBrian Somers InterfaceName, 85124084f9bSBrian Somers RedirectPort, 85224084f9bSBrian Somers RedirectAddress, 85324084f9bSBrian Somers ConfigFile, 85459a7c613SBrian Somers DynamicMode, 85559a7c613SBrian Somers PptpAlias, 85659a7c613SBrian Somers ProxyRule, 85759a7c613SBrian Somers LogDenied, 85859a7c613SBrian Somers LogFacility 85924084f9bSBrian Somers }; 86024084f9bSBrian Somers 86124084f9bSBrian Somers enum Param { 86224084f9bSBrian Somers 86324084f9bSBrian Somers YesNo, 86424084f9bSBrian Somers Numeric, 86524084f9bSBrian Somers String, 86624084f9bSBrian Somers None, 86724084f9bSBrian Somers Address, 86824084f9bSBrian Somers Service 86924084f9bSBrian Somers }; 87024084f9bSBrian Somers 87124084f9bSBrian Somers /* 87224084f9bSBrian Somers * Option information structure (used by ParseOption). 87324084f9bSBrian Somers */ 87424084f9bSBrian Somers 87524084f9bSBrian Somers struct OptionInfo { 87624084f9bSBrian Somers 87724084f9bSBrian Somers enum Option type; 87824084f9bSBrian Somers int packetAliasOpt; 87924084f9bSBrian Somers enum Param parm; 880902cb50aSBrian Somers const char* parmDescription; 881902cb50aSBrian Somers const char* description; 882902cb50aSBrian Somers const char* name; 883902cb50aSBrian Somers const char* shortName; 88424084f9bSBrian Somers }; 88524084f9bSBrian Somers 88624084f9bSBrian Somers /* 88724084f9bSBrian Somers * Table of known options. 88824084f9bSBrian Somers */ 88924084f9bSBrian Somers 89024084f9bSBrian Somers static struct OptionInfo optionTable[] = { 89124084f9bSBrian Somers 89224084f9bSBrian Somers { PacketAliasOption, 89324084f9bSBrian Somers PKT_ALIAS_UNREGISTERED_ONLY, 89424084f9bSBrian Somers YesNo, 89524084f9bSBrian Somers "[yes|no]", 89624084f9bSBrian Somers "alias only unregistered addresses", 89724084f9bSBrian Somers "unregistered_only", 89824084f9bSBrian Somers "u" }, 89924084f9bSBrian Somers 90024084f9bSBrian Somers { PacketAliasOption, 90124084f9bSBrian Somers PKT_ALIAS_LOG, 90224084f9bSBrian Somers YesNo, 90324084f9bSBrian Somers "[yes|no]", 90424084f9bSBrian Somers "enable logging", 90524084f9bSBrian Somers "log", 90624084f9bSBrian Somers "l" }, 90724084f9bSBrian Somers 90824084f9bSBrian Somers { PacketAliasOption, 90959a7c613SBrian Somers PKT_ALIAS_PROXY_ONLY, 91059a7c613SBrian Somers YesNo, 91159a7c613SBrian Somers "[yes|no]", 91259a7c613SBrian Somers "proxy only", 91359a7c613SBrian Somers "proxy_only", 91459a7c613SBrian Somers NULL }, 91559a7c613SBrian Somers 91659a7c613SBrian Somers { PacketAliasOption, 91759a7c613SBrian Somers PKT_ALIAS_REVERSE, 91859a7c613SBrian Somers YesNo, 91959a7c613SBrian Somers "[yes|no]", 92059a7c613SBrian Somers "operate in reverse mode", 92159a7c613SBrian Somers "reverse", 92259a7c613SBrian Somers NULL }, 92359a7c613SBrian Somers 92459a7c613SBrian Somers { PacketAliasOption, 92524084f9bSBrian Somers PKT_ALIAS_DENY_INCOMING, 92624084f9bSBrian Somers YesNo, 92724084f9bSBrian Somers "[yes|no]", 92824084f9bSBrian Somers "allow incoming connections", 92924084f9bSBrian Somers "deny_incoming", 93024084f9bSBrian Somers "d" }, 93124084f9bSBrian Somers 93224084f9bSBrian Somers { PacketAliasOption, 93324084f9bSBrian Somers PKT_ALIAS_USE_SOCKETS, 93424084f9bSBrian Somers YesNo, 93524084f9bSBrian Somers "[yes|no]", 93624084f9bSBrian Somers "use sockets to inhibit port conflict", 93724084f9bSBrian Somers "use_sockets", 93824084f9bSBrian Somers "s" }, 93924084f9bSBrian Somers 94024084f9bSBrian Somers { PacketAliasOption, 94124084f9bSBrian Somers PKT_ALIAS_SAME_PORTS, 94224084f9bSBrian Somers YesNo, 94324084f9bSBrian Somers "[yes|no]", 94424084f9bSBrian Somers "try to keep original port numbers for connections", 94524084f9bSBrian Somers "same_ports", 94624084f9bSBrian Somers "m" }, 94724084f9bSBrian Somers 94824084f9bSBrian Somers { Verbose, 94924084f9bSBrian Somers 0, 95024084f9bSBrian Somers YesNo, 95124084f9bSBrian Somers "[yes|no]", 95224084f9bSBrian Somers "verbose mode, dump packet information", 95324084f9bSBrian Somers "verbose", 95424084f9bSBrian Somers "v" }, 95524084f9bSBrian Somers 95624084f9bSBrian Somers { DynamicMode, 95724084f9bSBrian Somers 0, 95824084f9bSBrian Somers YesNo, 95924084f9bSBrian Somers "[yes|no]", 96024084f9bSBrian Somers "dynamic mode, automatically detect interface address changes", 96124084f9bSBrian Somers "dynamic", 96224084f9bSBrian Somers NULL }, 96324084f9bSBrian Somers 96424084f9bSBrian Somers { InPort, 96524084f9bSBrian Somers 0, 96624084f9bSBrian Somers Service, 96724084f9bSBrian Somers "number|service_name", 96824084f9bSBrian Somers "set port for incoming packets", 96924084f9bSBrian Somers "in_port", 97024084f9bSBrian Somers "i" }, 97124084f9bSBrian Somers 97224084f9bSBrian Somers { OutPort, 97324084f9bSBrian Somers 0, 97424084f9bSBrian Somers Service, 97524084f9bSBrian Somers "number|service_name", 97624084f9bSBrian Somers "set port for outgoing packets", 97724084f9bSBrian Somers "out_port", 97824084f9bSBrian Somers "o" }, 97924084f9bSBrian Somers 98024084f9bSBrian Somers { Port, 98124084f9bSBrian Somers 0, 98224084f9bSBrian Somers Service, 98324084f9bSBrian Somers "number|service_name", 98424084f9bSBrian Somers "set port (defaults to natd/divert)", 98524084f9bSBrian Somers "port", 98624084f9bSBrian Somers "p" }, 98724084f9bSBrian Somers 98824084f9bSBrian Somers { AliasAddress, 98924084f9bSBrian Somers 0, 99024084f9bSBrian Somers Address, 99124084f9bSBrian Somers "x.x.x.x", 99224084f9bSBrian Somers "address to use for aliasing", 99324084f9bSBrian Somers "alias_address", 99424084f9bSBrian Somers "a" }, 99524084f9bSBrian Somers 99624084f9bSBrian Somers { InterfaceName, 99724084f9bSBrian Somers 0, 99824084f9bSBrian Somers String, 99924084f9bSBrian Somers "network_if_name", 100024084f9bSBrian Somers "take aliasing address from interface", 100124084f9bSBrian Somers "interface", 100224084f9bSBrian Somers "n" }, 100324084f9bSBrian Somers 100459a7c613SBrian Somers { ProxyRule, 100524084f9bSBrian Somers 0, 100624084f9bSBrian Somers String, 100759a7c613SBrian Somers "[type encode_ip_hdr|encode_tcp_stream] port xxxx server " 100859a7c613SBrian Somers "a.b.c.d:yyyy", 100959a7c613SBrian Somers "add transparent proxying / destination NAT", 101059a7c613SBrian Somers "proxy_rule", 101124084f9bSBrian Somers NULL }, 101224084f9bSBrian Somers 101324084f9bSBrian Somers { RedirectPort, 101424084f9bSBrian Somers 0, 101524084f9bSBrian Somers String, 10165d8ee958SBrian Somers "tcp|udp local_addr:local_port_range [public_addr:]public_port_range" 10175d8ee958SBrian Somers " [remote_addr[:remote_port_range]]", 10185d8ee958SBrian Somers "redirect a port (or ports) for incoming traffic", 101924084f9bSBrian Somers "redirect_port", 102024084f9bSBrian Somers NULL }, 102124084f9bSBrian Somers 102224084f9bSBrian Somers { RedirectAddress, 102324084f9bSBrian Somers 0, 102424084f9bSBrian Somers String, 102524084f9bSBrian Somers "local_addr public_addr", 102624084f9bSBrian Somers "define mapping between local and public addresses", 102724084f9bSBrian Somers "redirect_address", 102824084f9bSBrian Somers NULL }, 102924084f9bSBrian Somers 103059a7c613SBrian Somers { PptpAlias, 103159a7c613SBrian Somers 0, 103259a7c613SBrian Somers String, 103359a7c613SBrian Somers "src", 103459a7c613SBrian Somers "define inside machine for PPTP traffic", 103559a7c613SBrian Somers "pptpalias", 103659a7c613SBrian Somers NULL }, 103759a7c613SBrian Somers 103824084f9bSBrian Somers { ConfigFile, 103924084f9bSBrian Somers 0, 104024084f9bSBrian Somers String, 104124084f9bSBrian Somers "file_name", 104224084f9bSBrian Somers "read options from configuration file", 104324084f9bSBrian Somers "config", 104459a7c613SBrian Somers "f" }, 104559a7c613SBrian Somers 104659a7c613SBrian Somers { LogDenied, 104759a7c613SBrian Somers 0, 104859a7c613SBrian Somers YesNo, 104959a7c613SBrian Somers "[yes|no]", 105059a7c613SBrian Somers "enable logging of denied incoming packets", 105159a7c613SBrian Somers "log_denied", 105259a7c613SBrian Somers NULL }, 105359a7c613SBrian Somers 105459a7c613SBrian Somers { LogFacility, 105559a7c613SBrian Somers 0, 105659a7c613SBrian Somers String, 105759a7c613SBrian Somers "facility", 105859a7c613SBrian Somers "name of syslog facility to use for logging", 105959a7c613SBrian Somers "log_facility", 106059a7c613SBrian Somers NULL } 106159a7c613SBrian Somers 106224084f9bSBrian Somers }; 106324084f9bSBrian Somers 1064902cb50aSBrian Somers static void ParseOption (const char* option, const char* parms, int cmdLine) 106524084f9bSBrian Somers { 106624084f9bSBrian Somers int i; 106724084f9bSBrian Somers struct OptionInfo* info; 106824084f9bSBrian Somers int yesNoValue; 106924084f9bSBrian Somers int aliasValue; 107024084f9bSBrian Somers int numValue; 107167a886fbSBrian Somers u_short uNumValue; 1072902cb50aSBrian Somers const char* strValue; 107324084f9bSBrian Somers struct in_addr addrValue; 107424084f9bSBrian Somers int max; 107524084f9bSBrian Somers char* end; 107659a7c613SBrian Somers CODE* fac_record = NULL; 107724084f9bSBrian Somers /* 107824084f9bSBrian Somers * Find option from table. 107924084f9bSBrian Somers */ 108024084f9bSBrian Somers max = sizeof (optionTable) / sizeof (struct OptionInfo); 108124084f9bSBrian Somers for (i = 0, info = optionTable; i < max; i++, info++) { 108224084f9bSBrian Somers 108324084f9bSBrian Somers if (!strcmp (info->name, option)) 108424084f9bSBrian Somers break; 108524084f9bSBrian Somers 108624084f9bSBrian Somers if (info->shortName) 108724084f9bSBrian Somers if (!strcmp (info->shortName, option)) 108824084f9bSBrian Somers break; 108924084f9bSBrian Somers } 109024084f9bSBrian Somers 109124084f9bSBrian Somers if (i >= max) { 109224084f9bSBrian Somers 10930fc81af1SPhilippe Charnier warnx ("unknown option %s", option); 109424084f9bSBrian Somers Usage (); 109524084f9bSBrian Somers } 109624084f9bSBrian Somers 109767a886fbSBrian Somers uNumValue = 0; 109824084f9bSBrian Somers yesNoValue = 0; 109924084f9bSBrian Somers numValue = 0; 110024084f9bSBrian Somers strValue = NULL; 110124084f9bSBrian Somers /* 110224084f9bSBrian Somers * Check parameters. 110324084f9bSBrian Somers */ 110424084f9bSBrian Somers switch (info->parm) { 110524084f9bSBrian Somers case YesNo: 110624084f9bSBrian Somers if (!parms) 110724084f9bSBrian Somers parms = "yes"; 110824084f9bSBrian Somers 110924084f9bSBrian Somers if (!strcmp (parms, "yes")) 111024084f9bSBrian Somers yesNoValue = 1; 111124084f9bSBrian Somers else 111224084f9bSBrian Somers if (!strcmp (parms, "no")) 111324084f9bSBrian Somers yesNoValue = 0; 11140fc81af1SPhilippe Charnier else 11150fc81af1SPhilippe Charnier errx (1, "%s needs yes/no parameter", option); 111624084f9bSBrian Somers break; 111724084f9bSBrian Somers 111824084f9bSBrian Somers case Service: 11190fc81af1SPhilippe Charnier if (!parms) 112067a886fbSBrian Somers errx (1, "%s needs service name or " 112167a886fbSBrian Somers "port number parameter", 112267a886fbSBrian Somers option); 112324084f9bSBrian Somers 112467a886fbSBrian Somers uNumValue = StrToPort (parms, "divert"); 112524084f9bSBrian Somers break; 112624084f9bSBrian Somers 112724084f9bSBrian Somers case Numeric: 112824084f9bSBrian Somers if (parms) 112924084f9bSBrian Somers numValue = strtol (parms, &end, 10); 113024084f9bSBrian Somers else 1131902cb50aSBrian Somers end = NULL; 113224084f9bSBrian Somers 11330fc81af1SPhilippe Charnier if (end == parms) 11340fc81af1SPhilippe Charnier errx (1, "%s needs numeric parameter", option); 113524084f9bSBrian Somers break; 113624084f9bSBrian Somers 113724084f9bSBrian Somers case String: 113824084f9bSBrian Somers strValue = parms; 11390fc81af1SPhilippe Charnier if (!strValue) 11400fc81af1SPhilippe Charnier errx (1, "%s needs parameter", option); 114124084f9bSBrian Somers break; 114224084f9bSBrian Somers 114324084f9bSBrian Somers case None: 11440fc81af1SPhilippe Charnier if (parms) 11450fc81af1SPhilippe Charnier errx (1, "%s does not take parameters", option); 114624084f9bSBrian Somers break; 114724084f9bSBrian Somers 114824084f9bSBrian Somers case Address: 11490fc81af1SPhilippe Charnier if (!parms) 11500fc81af1SPhilippe Charnier errx (1, "%s needs address/host parameter", option); 115124084f9bSBrian Somers 115224084f9bSBrian Somers StrToAddr (parms, &addrValue); 115324084f9bSBrian Somers break; 115424084f9bSBrian Somers } 115524084f9bSBrian Somers 115624084f9bSBrian Somers switch (info->type) { 115724084f9bSBrian Somers case PacketAliasOption: 115824084f9bSBrian Somers 115924084f9bSBrian Somers aliasValue = yesNoValue ? info->packetAliasOpt : 0; 1160fb994b07SBrian Somers PacketAliasSetMode (aliasValue, info->packetAliasOpt); 116124084f9bSBrian Somers break; 116224084f9bSBrian Somers 116324084f9bSBrian Somers case Verbose: 116424084f9bSBrian Somers verbose = yesNoValue; 116524084f9bSBrian Somers break; 116624084f9bSBrian Somers 116724084f9bSBrian Somers case DynamicMode: 116824084f9bSBrian Somers dynamicMode = yesNoValue; 116924084f9bSBrian Somers break; 117024084f9bSBrian Somers 117124084f9bSBrian Somers case InPort: 117267a886fbSBrian Somers inPort = uNumValue; 117324084f9bSBrian Somers break; 117424084f9bSBrian Somers 117524084f9bSBrian Somers case OutPort: 117667a886fbSBrian Somers outPort = uNumValue; 117724084f9bSBrian Somers break; 117824084f9bSBrian Somers 117924084f9bSBrian Somers case Port: 118067a886fbSBrian Somers inOutPort = uNumValue; 118124084f9bSBrian Somers break; 118224084f9bSBrian Somers 118324084f9bSBrian Somers case AliasAddress: 118424084f9bSBrian Somers memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr)); 118524084f9bSBrian Somers break; 118624084f9bSBrian Somers 118724084f9bSBrian Somers case RedirectPort: 118824084f9bSBrian Somers SetupPortRedirect (strValue); 118924084f9bSBrian Somers break; 119024084f9bSBrian Somers 119124084f9bSBrian Somers case RedirectAddress: 119224084f9bSBrian Somers SetupAddressRedirect (strValue); 119324084f9bSBrian Somers break; 119424084f9bSBrian Somers 119559a7c613SBrian Somers case PptpAlias: 119659a7c613SBrian Somers SetupPptpAlias (strValue); 119759a7c613SBrian Somers break; 119859a7c613SBrian Somers 119959a7c613SBrian Somers case ProxyRule: 120059a7c613SBrian Somers PacketAliasProxyRule (strValue); 120159a7c613SBrian Somers break; 120259a7c613SBrian Somers 120324084f9bSBrian Somers case InterfaceName: 120424084f9bSBrian Somers if (ifName) 120524084f9bSBrian Somers free (ifName); 120624084f9bSBrian Somers 120724084f9bSBrian Somers ifName = strdup (strValue); 120824084f9bSBrian Somers assignAliasAddr = 1; 120924084f9bSBrian Somers break; 121024084f9bSBrian Somers 121124084f9bSBrian Somers case ConfigFile: 121224084f9bSBrian Somers ReadConfigFile (strValue); 121324084f9bSBrian Somers break; 121459a7c613SBrian Somers 121559a7c613SBrian Somers case LogDenied: 121659a7c613SBrian Somers logDropped = 1; 121759a7c613SBrian Somers break; 121859a7c613SBrian Somers 121959a7c613SBrian Somers case LogFacility: 122059a7c613SBrian Somers 122159a7c613SBrian Somers fac_record = facilitynames; 122259a7c613SBrian Somers while (fac_record->c_name != NULL) { 122359a7c613SBrian Somers 122459a7c613SBrian Somers if (!strcmp (fac_record->c_name, strValue)) { 122559a7c613SBrian Somers 122659a7c613SBrian Somers logFacility = fac_record->c_val; 122759a7c613SBrian Somers break; 122859a7c613SBrian Somers 122959a7c613SBrian Somers } 123059a7c613SBrian Somers else 123159a7c613SBrian Somers fac_record++; 123259a7c613SBrian Somers } 123359a7c613SBrian Somers 123459a7c613SBrian Somers if(fac_record->c_name == NULL) 123559a7c613SBrian Somers errx(1, "Unknown log facility name: %s", strValue); 123659a7c613SBrian Somers 123759a7c613SBrian Somers break; 123824084f9bSBrian Somers } 123924084f9bSBrian Somers } 124024084f9bSBrian Somers 1241902cb50aSBrian Somers void ReadConfigFile (const char* fileName) 124224084f9bSBrian Somers { 124324084f9bSBrian Somers FILE* file; 124424084f9bSBrian Somers char buf[128]; 124524084f9bSBrian Somers char* ptr; 124624084f9bSBrian Somers char* option; 124724084f9bSBrian Somers 124824084f9bSBrian Somers file = fopen (fileName, "r"); 124924084f9bSBrian Somers if (!file) { 125024084f9bSBrian Somers 125124084f9bSBrian Somers sprintf (buf, "Cannot open config file %s.\n", fileName); 125224084f9bSBrian Somers Quit (buf); 125324084f9bSBrian Somers } 125424084f9bSBrian Somers 125524084f9bSBrian Somers while (fgets (buf, sizeof (buf), file)) { 125624084f9bSBrian Somers 125724084f9bSBrian Somers ptr = strchr (buf, '\n'); 12580fc81af1SPhilippe Charnier if (!ptr) 125967a886fbSBrian Somers errx (1, "config line too long: %s", buf); 126024084f9bSBrian Somers 126124084f9bSBrian Somers *ptr = '\0'; 126224084f9bSBrian Somers if (buf[0] == '#') 126324084f9bSBrian Somers continue; 126424084f9bSBrian Somers 126524084f9bSBrian Somers ptr = buf; 126624084f9bSBrian Somers /* 126724084f9bSBrian Somers * Skip white space at beginning of line. 126824084f9bSBrian Somers */ 126924084f9bSBrian Somers while (*ptr && isspace (*ptr)) 127024084f9bSBrian Somers ++ptr; 127124084f9bSBrian Somers 127224084f9bSBrian Somers if (*ptr == '\0') 127324084f9bSBrian Somers continue; 127424084f9bSBrian Somers /* 127524084f9bSBrian Somers * Extract option name. 127624084f9bSBrian Somers */ 127724084f9bSBrian Somers option = ptr; 127824084f9bSBrian Somers while (*ptr && !isspace (*ptr)) 127924084f9bSBrian Somers ++ptr; 128024084f9bSBrian Somers 128124084f9bSBrian Somers if (*ptr != '\0') { 128224084f9bSBrian Somers 128324084f9bSBrian Somers *ptr = '\0'; 128424084f9bSBrian Somers ++ptr; 128524084f9bSBrian Somers } 128624084f9bSBrian Somers /* 128724084f9bSBrian Somers * Skip white space between name and parms. 128824084f9bSBrian Somers */ 128924084f9bSBrian Somers while (*ptr && isspace (*ptr)) 129024084f9bSBrian Somers ++ptr; 129124084f9bSBrian Somers 129224084f9bSBrian Somers ParseOption (option, *ptr ? ptr : NULL, 0); 129324084f9bSBrian Somers } 129424084f9bSBrian Somers 129524084f9bSBrian Somers fclose (file); 129624084f9bSBrian Somers } 129724084f9bSBrian Somers 129824084f9bSBrian Somers static void Usage () 129924084f9bSBrian Somers { 130024084f9bSBrian Somers int i; 130124084f9bSBrian Somers int max; 130224084f9bSBrian Somers struct OptionInfo* info; 130324084f9bSBrian Somers 130424084f9bSBrian Somers fprintf (stderr, "Recognized options:\n\n"); 130524084f9bSBrian Somers 130624084f9bSBrian Somers max = sizeof (optionTable) / sizeof (struct OptionInfo); 130724084f9bSBrian Somers for (i = 0, info = optionTable; i < max; i++, info++) { 130824084f9bSBrian Somers 130924084f9bSBrian Somers fprintf (stderr, "-%-20s %s\n", info->name, 131024084f9bSBrian Somers info->parmDescription); 131124084f9bSBrian Somers 131224084f9bSBrian Somers if (info->shortName) 131324084f9bSBrian Somers fprintf (stderr, "-%-20s %s\n", info->shortName, 131424084f9bSBrian Somers info->parmDescription); 131524084f9bSBrian Somers 131624084f9bSBrian Somers fprintf (stderr, " %s\n\n", info->description); 131724084f9bSBrian Somers } 131824084f9bSBrian Somers 131924084f9bSBrian Somers exit (1); 132024084f9bSBrian Somers } 132124084f9bSBrian Somers 1322902cb50aSBrian Somers void SetupPptpAlias (const char* parms) 132324084f9bSBrian Somers { 132424084f9bSBrian Somers char buf[128]; 132524084f9bSBrian Somers char* ptr; 132624084f9bSBrian Somers struct in_addr srcAddr; 132724084f9bSBrian Somers 132824084f9bSBrian Somers strcpy (buf, parms); 132924084f9bSBrian Somers 133024084f9bSBrian Somers /* 133124084f9bSBrian Somers * Extract source address. 133224084f9bSBrian Somers */ 133359a7c613SBrian Somers ptr = strtok (buf, " \t"); 13340fc81af1SPhilippe Charnier if (!ptr) 133559a7c613SBrian Somers errx(1, "pptpalias: missing src address"); 133624084f9bSBrian Somers 133759a7c613SBrian Somers StrToAddr (ptr, &srcAddr); 133859a7c613SBrian Somers PacketAliasPptp (srcAddr); 133924084f9bSBrian Somers } 134024084f9bSBrian Somers 1341902cb50aSBrian Somers void SetupPortRedirect (const char* parms) 134224084f9bSBrian Somers { 134324084f9bSBrian Somers char buf[128]; 134424084f9bSBrian Somers char* ptr; 134524084f9bSBrian Somers struct in_addr localAddr; 134624084f9bSBrian Somers struct in_addr publicAddr; 134724084f9bSBrian Somers struct in_addr remoteAddr; 13485d8ee958SBrian Somers port_range portRange; 13495d8ee958SBrian Somers u_short localPort = 0; 13505d8ee958SBrian Somers u_short publicPort = 0; 13515d8ee958SBrian Somers u_short remotePort = 0; 13525d8ee958SBrian Somers u_short numLocalPorts = 0; 13535d8ee958SBrian Somers u_short numPublicPorts = 0; 13545d8ee958SBrian Somers u_short numRemotePorts = 0; 135524084f9bSBrian Somers int proto; 135624084f9bSBrian Somers char* protoName; 135724084f9bSBrian Somers char* separator; 13585d8ee958SBrian Somers int i; 135924084f9bSBrian Somers 136024084f9bSBrian Somers strcpy (buf, parms); 136124084f9bSBrian Somers /* 136224084f9bSBrian Somers * Extract protocol. 136324084f9bSBrian Somers */ 136424084f9bSBrian Somers protoName = strtok (buf, " \t"); 13650fc81af1SPhilippe Charnier if (!protoName) 13660fc81af1SPhilippe Charnier errx (1, "redirect_port: missing protocol"); 136724084f9bSBrian Somers 136824084f9bSBrian Somers proto = StrToProto (protoName); 136924084f9bSBrian Somers /* 137024084f9bSBrian Somers * Extract local address. 137124084f9bSBrian Somers */ 137224084f9bSBrian Somers ptr = strtok (NULL, " \t"); 13730fc81af1SPhilippe Charnier if (!ptr) 13740fc81af1SPhilippe Charnier errx (1, "redirect_port: missing local address"); 137524084f9bSBrian Somers 13765d8ee958SBrian Somers if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 ) 13775d8ee958SBrian Somers errx (1, "redirect_port: invalid local port range"); 13785d8ee958SBrian Somers 13795d8ee958SBrian Somers localPort = GETLOPORT(portRange); 13805d8ee958SBrian Somers numLocalPorts = GETNUMPORTS(portRange); 13815d8ee958SBrian Somers 138224084f9bSBrian Somers /* 138324084f9bSBrian Somers * Extract public port and optinally address. 138424084f9bSBrian Somers */ 138524084f9bSBrian Somers ptr = strtok (NULL, " \t"); 13860fc81af1SPhilippe Charnier if (!ptr) 13870fc81af1SPhilippe Charnier errx (1, "redirect_port: missing public port"); 138824084f9bSBrian Somers 138924084f9bSBrian Somers separator = strchr (ptr, ':'); 13905d8ee958SBrian Somers if (separator) { 13915d8ee958SBrian Somers if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 ) 13925d8ee958SBrian Somers errx (1, "redirect_port: invalid public port range"); 139324084f9bSBrian Somers } 13945d8ee958SBrian Somers else { 13955d8ee958SBrian Somers publicAddr.s_addr = INADDR_ANY; 13965d8ee958SBrian Somers if (StrToPortRange (ptr, protoName, &portRange) != 0) 13975d8ee958SBrian Somers errx (1, "redirect_port: invalid public port range"); 13985d8ee958SBrian Somers } 13995d8ee958SBrian Somers 14005d8ee958SBrian Somers publicPort = GETLOPORT(portRange); 14015d8ee958SBrian Somers numPublicPorts = GETNUMPORTS(portRange); 140224084f9bSBrian Somers 140324084f9bSBrian Somers /* 140424084f9bSBrian Somers * Extract remote address and optionally port. 140524084f9bSBrian Somers */ 140624084f9bSBrian Somers ptr = strtok (NULL, " \t"); 140724084f9bSBrian Somers if (ptr) { 140824084f9bSBrian Somers separator = strchr (ptr, ':'); 140924084f9bSBrian Somers if (separator) 14105d8ee958SBrian Somers if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0) 14115d8ee958SBrian Somers errx (1, "redirect_port: invalid remote port range"); 141224084f9bSBrian Somers else { 14135d8ee958SBrian Somers SETLOPORT(portRange, 0); 14145d8ee958SBrian Somers SETNUMPORTS(portRange, 1); 141524084f9bSBrian Somers StrToAddr (ptr, &remoteAddr); 141624084f9bSBrian Somers } 141724084f9bSBrian Somers } 141824084f9bSBrian Somers else { 14195d8ee958SBrian Somers SETLOPORT(portRange, 0); 14205d8ee958SBrian Somers SETNUMPORTS(portRange, 1); 142124084f9bSBrian Somers remoteAddr.s_addr = INADDR_ANY; 142224084f9bSBrian Somers } 142324084f9bSBrian Somers 14245d8ee958SBrian Somers remotePort = GETLOPORT(portRange); 14255d8ee958SBrian Somers numRemotePorts = GETNUMPORTS(portRange); 14265d8ee958SBrian Somers 14275d8ee958SBrian Somers /* 14285d8ee958SBrian Somers * Make sure port ranges match up, then add the redirect ports. 14295d8ee958SBrian Somers */ 14305d8ee958SBrian Somers if (numLocalPorts != numPublicPorts) 14315d8ee958SBrian Somers errx (1, "redirect_port: port ranges must be equal in size"); 14325d8ee958SBrian Somers 14335d8ee958SBrian Somers /* Remote port range is allowed to be '0' which means all ports. */ 14345d8ee958SBrian Somers if (numRemotePorts != numLocalPorts && numRemotePorts != 1 && remotePort != 0) 14355d8ee958SBrian Somers errx (1, "redirect_port: remote port must be 0 or equal to local port range in size"); 14365d8ee958SBrian Somers 14375d8ee958SBrian Somers for (i = 0 ; i < numPublicPorts ; ++i) { 14385d8ee958SBrian Somers /* If remotePort is all ports, set it to 0. */ 14395d8ee958SBrian Somers u_short remotePortCopy = remotePort + i; 14405d8ee958SBrian Somers if (numRemotePorts == 1 && remotePort == 0) 14415d8ee958SBrian Somers remotePortCopy = 0; 14425d8ee958SBrian Somers 144324084f9bSBrian Somers PacketAliasRedirectPort (localAddr, 14445d8ee958SBrian Somers htons(localPort + i), 144524084f9bSBrian Somers remoteAddr, 14465d8ee958SBrian Somers htons(remotePortCopy), 144724084f9bSBrian Somers publicAddr, 14485d8ee958SBrian Somers htons(publicPort + i), 144924084f9bSBrian Somers proto); 145024084f9bSBrian Somers } 14515d8ee958SBrian Somers } 145224084f9bSBrian Somers 1453902cb50aSBrian Somers void SetupAddressRedirect (const char* parms) 145424084f9bSBrian Somers { 145524084f9bSBrian Somers char buf[128]; 145624084f9bSBrian Somers char* ptr; 145724084f9bSBrian Somers struct in_addr localAddr; 145824084f9bSBrian Somers struct in_addr publicAddr; 145924084f9bSBrian Somers 146024084f9bSBrian Somers strcpy (buf, parms); 146124084f9bSBrian Somers /* 146224084f9bSBrian Somers * Extract local address. 146324084f9bSBrian Somers */ 146424084f9bSBrian Somers ptr = strtok (buf, " \t"); 14650fc81af1SPhilippe Charnier if (!ptr) 14660fc81af1SPhilippe Charnier errx (1, "redirect_address: missing local address"); 146724084f9bSBrian Somers 146824084f9bSBrian Somers StrToAddr (ptr, &localAddr); 146924084f9bSBrian Somers /* 147024084f9bSBrian Somers * Extract public address. 147124084f9bSBrian Somers */ 147224084f9bSBrian Somers ptr = strtok (NULL, " \t"); 14730fc81af1SPhilippe Charnier if (!ptr) 14740fc81af1SPhilippe Charnier errx (1, "redirect_address: missing public address"); 147524084f9bSBrian Somers 147624084f9bSBrian Somers StrToAddr (ptr, &publicAddr); 147724084f9bSBrian Somers PacketAliasRedirectAddr (localAddr, publicAddr); 147824084f9bSBrian Somers } 147924084f9bSBrian Somers 1480902cb50aSBrian Somers void StrToAddr (const char* str, struct in_addr* addr) 148124084f9bSBrian Somers { 148224084f9bSBrian Somers struct hostent* hp; 148324084f9bSBrian Somers 148424084f9bSBrian Somers if (inet_aton (str, addr)) 148524084f9bSBrian Somers return; 148624084f9bSBrian Somers 148724084f9bSBrian Somers hp = gethostbyname (str); 14880fc81af1SPhilippe Charnier if (!hp) 14890fc81af1SPhilippe Charnier errx (1, "unknown host %s", str); 149024084f9bSBrian Somers 149124084f9bSBrian Somers memcpy (addr, hp->h_addr, sizeof (struct in_addr)); 149224084f9bSBrian Somers } 149324084f9bSBrian Somers 1494902cb50aSBrian Somers u_short StrToPort (const char* str, const char* proto) 149524084f9bSBrian Somers { 149667a886fbSBrian Somers u_short port; 149724084f9bSBrian Somers struct servent* sp; 149824084f9bSBrian Somers char* end; 149924084f9bSBrian Somers 150024084f9bSBrian Somers port = strtol (str, &end, 10); 150124084f9bSBrian Somers if (end != str) 150227c20503SBrian Somers return htons (port); 150324084f9bSBrian Somers 150424084f9bSBrian Somers sp = getservbyname (str, proto); 15050fc81af1SPhilippe Charnier if (!sp) 15060fc81af1SPhilippe Charnier errx (1, "unknown service %s/%s", str, proto); 150724084f9bSBrian Somers 150824084f9bSBrian Somers return sp->s_port; 150924084f9bSBrian Somers } 151024084f9bSBrian Somers 1511902cb50aSBrian Somers int StrToPortRange (const char* str, const char* proto, port_range *portRange) 15125d8ee958SBrian Somers { 15135d8ee958SBrian Somers char* sep; 15145d8ee958SBrian Somers struct servent* sp; 15155d8ee958SBrian Somers char* end; 15165d8ee958SBrian Somers u_short loPort; 15175d8ee958SBrian Somers u_short hiPort; 15185d8ee958SBrian Somers 15195d8ee958SBrian Somers /* First see if this is a service, return corresponding port if so. */ 15205d8ee958SBrian Somers sp = getservbyname (str,proto); 15215d8ee958SBrian Somers if (sp) { 15225d8ee958SBrian Somers SETLOPORT(*portRange, ntohs(sp->s_port)); 15235d8ee958SBrian Somers SETNUMPORTS(*portRange, 1); 15245d8ee958SBrian Somers return 0; 15255d8ee958SBrian Somers } 15265d8ee958SBrian Somers 15275d8ee958SBrian Somers /* Not a service, see if it's a single port or port range. */ 15285d8ee958SBrian Somers sep = strchr (str, '-'); 15295d8ee958SBrian Somers if (sep == NULL) { 15305d8ee958SBrian Somers SETLOPORT(*portRange, strtol(str, &end, 10)); 15315d8ee958SBrian Somers if (end != str) { 15325d8ee958SBrian Somers /* Single port. */ 15335d8ee958SBrian Somers SETNUMPORTS(*portRange, 1); 15345d8ee958SBrian Somers return 0; 15355d8ee958SBrian Somers } 15365d8ee958SBrian Somers 15375d8ee958SBrian Somers /* Error in port range field. */ 15385d8ee958SBrian Somers errx (1, "unknown service %s/%s", str, proto); 15395d8ee958SBrian Somers } 15405d8ee958SBrian Somers 15415d8ee958SBrian Somers /* Port range, get the values and sanity check. */ 15425d8ee958SBrian Somers sscanf (str, "%hu-%hu", &loPort, &hiPort); 15435d8ee958SBrian Somers SETLOPORT(*portRange, loPort); 15445d8ee958SBrian Somers SETNUMPORTS(*portRange, 0); /* Error by default */ 15455d8ee958SBrian Somers if (loPort <= hiPort) 15465d8ee958SBrian Somers SETNUMPORTS(*portRange, hiPort - loPort + 1); 15475d8ee958SBrian Somers 15485d8ee958SBrian Somers if (GETNUMPORTS(*portRange) == 0) 15495d8ee958SBrian Somers errx (1, "invalid port range %s", str); 15505d8ee958SBrian Somers 15515d8ee958SBrian Somers return 0; 15525d8ee958SBrian Somers } 15535d8ee958SBrian Somers 15545d8ee958SBrian Somers 1555902cb50aSBrian Somers int StrToProto (const char* str) 155624084f9bSBrian Somers { 155724084f9bSBrian Somers if (!strcmp (str, "tcp")) 155824084f9bSBrian Somers return IPPROTO_TCP; 155924084f9bSBrian Somers 156024084f9bSBrian Somers if (!strcmp (str, "udp")) 156124084f9bSBrian Somers return IPPROTO_UDP; 156224084f9bSBrian Somers 15630fc81af1SPhilippe Charnier errx (1, "unknown protocol %s. Expected tcp or udp", str); 156424084f9bSBrian Somers } 156524084f9bSBrian Somers 1566902cb50aSBrian Somers int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange) 156724084f9bSBrian Somers { 156824084f9bSBrian Somers char* ptr; 156924084f9bSBrian Somers 157024084f9bSBrian Somers ptr = strchr (str, ':'); 15710fc81af1SPhilippe Charnier if (!ptr) 15720fc81af1SPhilippe Charnier errx (1, "%s is missing port number", str); 157324084f9bSBrian Somers 157424084f9bSBrian Somers *ptr = '\0'; 157524084f9bSBrian Somers ++ptr; 157624084f9bSBrian Somers 157724084f9bSBrian Somers StrToAddr (str, addr); 15785d8ee958SBrian Somers return StrToPortRange (ptr, proto, portRange); 157924084f9bSBrian Somers } 1580