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 */ 1224084f9bSBrian Somers 1329e3edccSPhilippe Charnier #include <sys/cdefs.h> 1429e3edccSPhilippe Charnier __FBSDID("$FreeBSD$"); 1529e3edccSPhilippe Charnier 1659a7c613SBrian Somers #define SYSLOG_NAMES 1759a7c613SBrian Somers 1824084f9bSBrian Somers #include <sys/types.h> 1924084f9bSBrian Somers #include <sys/socket.h> 204c04fa4cSRuslan Ermilov #include <sys/sysctl.h> 2124084f9bSBrian Somers #include <sys/time.h> 2222c62477SPoul-Henning Kamp #include <sys/queue.h> 2324084f9bSBrian Somers 2424084f9bSBrian Somers #include <netinet/in.h> 2524084f9bSBrian Somers #include <netinet/in_systm.h> 2624084f9bSBrian Somers #include <netinet/ip.h> 2724084f9bSBrian Somers #include <machine/in_cksum.h> 2824084f9bSBrian Somers #include <netinet/tcp.h> 2959a7c613SBrian Somers #include <netinet/udp.h> 3059a7c613SBrian Somers #include <netinet/ip_icmp.h> 3124084f9bSBrian Somers #include <net/if.h> 324c04fa4cSRuslan Ermilov #include <net/if_dl.h> 3324084f9bSBrian Somers #include <net/route.h> 3424084f9bSBrian Somers #include <arpa/inet.h> 3524084f9bSBrian Somers 3624084f9bSBrian Somers #include <alias.h> 370fc81af1SPhilippe Charnier #include <ctype.h> 380fc81af1SPhilippe Charnier #include <err.h> 390fc81af1SPhilippe Charnier #include <errno.h> 400fc81af1SPhilippe Charnier #include <netdb.h> 410fc81af1SPhilippe Charnier #include <signal.h> 420fc81af1SPhilippe Charnier #include <stdio.h> 430fc81af1SPhilippe Charnier #include <stdlib.h> 440fc81af1SPhilippe Charnier #include <string.h> 450fc81af1SPhilippe Charnier #include <syslog.h> 460fc81af1SPhilippe Charnier #include <unistd.h> 4767a886fbSBrian Somers 4824084f9bSBrian Somers #include "natd.h" 4924084f9bSBrian Somers 5022c62477SPoul-Henning Kamp struct instance { 5122c62477SPoul-Henning Kamp const char *name; 5222c62477SPoul-Henning Kamp struct libalias *la; 5322c62477SPoul-Henning Kamp LIST_ENTRY(instance) list; 5422c62477SPoul-Henning Kamp 5522c62477SPoul-Henning Kamp int ifIndex; 5622c62477SPoul-Henning Kamp int assignAliasAddr; 5722c62477SPoul-Henning Kamp char* ifName; 5822c62477SPoul-Henning Kamp int logDropped; 5922c62477SPoul-Henning Kamp u_short inPort; 6022c62477SPoul-Henning Kamp u_short outPort; 6122c62477SPoul-Henning Kamp u_short inOutPort; 6222c62477SPoul-Henning Kamp struct in_addr aliasAddr; 6322c62477SPoul-Henning Kamp int ifMTU; 6422c62477SPoul-Henning Kamp int aliasOverhead; 6522c62477SPoul-Henning Kamp int dropIgnoredIncoming; 6622c62477SPoul-Henning Kamp int divertIn; 6722c62477SPoul-Henning Kamp int divertOut; 6822c62477SPoul-Henning Kamp int divertInOut; 6922c62477SPoul-Henning Kamp }; 7022c62477SPoul-Henning Kamp 7122c62477SPoul-Henning Kamp static LIST_HEAD(, instance) root = LIST_HEAD_INITIALIZER(&root); 7222c62477SPoul-Henning Kamp 7322c62477SPoul-Henning Kamp struct libalias *mla; 7422c62477SPoul-Henning Kamp struct instance *mip; 7522c62477SPoul-Henning Kamp int ninstance = 1; 7622c62477SPoul-Henning Kamp 7724084f9bSBrian Somers /* 7824084f9bSBrian Somers * Default values for input and output 7924084f9bSBrian Somers * divert socket ports. 8024084f9bSBrian Somers */ 8124084f9bSBrian Somers 8224084f9bSBrian Somers #define DEFAULT_SERVICE "natd" 8324084f9bSBrian Somers 8424084f9bSBrian Somers /* 855d8ee958SBrian Somers * Definition of a port range, and macros to deal with values. 865d8ee958SBrian Somers * FORMAT: HI 16-bits == first port in range, 0 == all ports. 875d8ee958SBrian Somers * LO 16-bits == number of ports in range 885d8ee958SBrian Somers * NOTES: - Port values are not stored in network byte order. 895d8ee958SBrian Somers */ 905d8ee958SBrian Somers 915d8ee958SBrian Somers typedef u_long port_range; 925d8ee958SBrian Somers 935d8ee958SBrian Somers #define GETLOPORT(x) ((x) >> 0x10) 945d8ee958SBrian Somers #define GETNUMPORTS(x) ((x) & 0x0000ffff) 955d8ee958SBrian Somers #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x))) 965d8ee958SBrian Somers 975d8ee958SBrian Somers /* Set y to be the low-port value in port_range variable x. */ 985d8ee958SBrian Somers #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10)) 995d8ee958SBrian Somers 1005d8ee958SBrian Somers /* Set y to be the number of ports in port_range variable x. */ 1015d8ee958SBrian Somers #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y)) 1025d8ee958SBrian Somers 1035d8ee958SBrian Somers /* 10424084f9bSBrian Somers * Function prototypes. 10524084f9bSBrian Somers */ 10624084f9bSBrian Somers 10759a7c613SBrian Somers static void DoAliasing (int fd, int direction); 108902cb50aSBrian Somers static void DaemonMode (void); 10924084f9bSBrian Somers static void HandleRoutingInfo (int fd); 110902cb50aSBrian Somers static void Usage (void); 11159a7c613SBrian Somers static char* FormatPacket (struct ip*); 11224084f9bSBrian Somers static void PrintPacket (struct ip*); 113902cb50aSBrian Somers static void SyslogPacket (struct ip*, int priority, const char *label); 1144c04fa4cSRuslan Ermilov static void SetAliasAddressFromIfName (const char *ifName); 115902cb50aSBrian Somers static void InitiateShutdown (int); 116902cb50aSBrian Somers static void Shutdown (int); 117902cb50aSBrian Somers static void RefreshAddr (int); 118b0f55af6SRuslan Ermilov static void ParseOption (const char* option, const char* parms); 119902cb50aSBrian Somers static void ReadConfigFile (const char* fileName); 120902cb50aSBrian Somers static void SetupPortRedirect (const char* parms); 1214330006dSRuslan Ermilov static void SetupProtoRedirect(const char* parms); 122902cb50aSBrian Somers static void SetupAddressRedirect (const char* parms); 123902cb50aSBrian Somers static void StrToAddr (const char* str, struct in_addr* addr); 124902cb50aSBrian Somers static u_short StrToPort (const char* str, const char* proto); 125902cb50aSBrian Somers static int StrToPortRange (const char* str, const char* proto, port_range *portRange); 126902cb50aSBrian Somers static int StrToProto (const char* str); 127902cb50aSBrian Somers static int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange); 12824084f9bSBrian Somers static void ParseArgs (int argc, char** argv); 129bc4ebb98SRuslan Ermilov static void SetupPunchFW(const char *strValue); 130b07fbc17SJoe Marcus Clarke static void SetupSkinnyPort(const char *strValue); 13122c62477SPoul-Henning Kamp static void NewInstance(const char *name); 13222c62477SPoul-Henning Kamp static void DoGlobal (int fd); 13324084f9bSBrian Somers 13424084f9bSBrian Somers /* 13524084f9bSBrian Somers * Globals. 13624084f9bSBrian Somers */ 13724084f9bSBrian Somers 13824084f9bSBrian Somers static int verbose; 13924084f9bSBrian Somers static int background; 14024084f9bSBrian Somers static int running; 14159a7c613SBrian Somers static int logFacility; 14222c62477SPoul-Henning Kamp 14322c62477SPoul-Henning Kamp static int dynamicMode; 14422c62477SPoul-Henning Kamp static int icmpSock; 1453843533eSRuslan Ermilov static int logIpfwDenied; 14648ce8ca1SXin LI static const char* pidName; 14722c62477SPoul-Henning Kamp static int routeSock; 14822c62477SPoul-Henning Kamp static int globalPort; 14922c62477SPoul-Henning Kamp static int divertGlobal; 15072cbe4adSAlexander Motin static int exitDelay; 15172cbe4adSAlexander Motin 15224084f9bSBrian Somers 15324084f9bSBrian Somers int main (int argc, char** argv) 15424084f9bSBrian Somers { 15524084f9bSBrian Somers struct sockaddr_in addr; 15624084f9bSBrian Somers fd_set readMask; 15724084f9bSBrian Somers int fdMax; 15824084f9bSBrian Somers /* 15924084f9bSBrian Somers * Initialize packet aliasing software. 16024084f9bSBrian Somers * Done already here to be able to alter option bits 16124084f9bSBrian Somers * during command line and configuration file processing. 16224084f9bSBrian Somers */ 16322c62477SPoul-Henning Kamp NewInstance("default"); 16422c62477SPoul-Henning Kamp 16524084f9bSBrian Somers /* 16624084f9bSBrian Somers * Parse options. 16724084f9bSBrian Somers */ 16824084f9bSBrian Somers verbose = 0; 16924084f9bSBrian Somers background = 0; 17024084f9bSBrian Somers running = 1; 17124084f9bSBrian Somers dynamicMode = 0; 17259a7c613SBrian Somers logFacility = LOG_DAEMON; 173c0956cf8SRuslan Ermilov logIpfwDenied = -1; 174b79840a6SRuslan Ermilov pidName = PIDFILE; 17522c62477SPoul-Henning Kamp routeSock = -1; 17622c62477SPoul-Henning Kamp icmpSock = -1; 17722c62477SPoul-Henning Kamp fdMax = -1; 17822c62477SPoul-Henning Kamp divertGlobal = -1; 17972cbe4adSAlexander Motin exitDelay = EXIT_DELAY; 18024084f9bSBrian Somers 18124084f9bSBrian Somers ParseArgs (argc, argv); 18224084f9bSBrian Somers /* 183c0956cf8SRuslan Ermilov * Log ipfw(8) denied packets by default in verbose mode. 184c0956cf8SRuslan Ermilov */ 185c0956cf8SRuslan Ermilov if (logIpfwDenied == -1) 186c0956cf8SRuslan Ermilov logIpfwDenied = verbose; 187c0956cf8SRuslan Ermilov /* 18859a7c613SBrian Somers * Open syslog channel. 18959a7c613SBrian Somers */ 1904c04fa4cSRuslan Ermilov openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0), 1914c04fa4cSRuslan Ermilov logFacility); 19222c62477SPoul-Henning Kamp 19322c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) { 19422c62477SPoul-Henning Kamp mla = mip->la; 19559a7c613SBrian Somers /* 1963d23e8b8SRuslan Ermilov * If not doing the transparent proxying only, 1973d23e8b8SRuslan Ermilov * check that valid aliasing address has been given. 19824084f9bSBrian Somers */ 19922c62477SPoul-Henning Kamp if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL && 20022c62477SPoul-Henning Kamp !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY)) 20122c62477SPoul-Henning Kamp errx (1, "instance %s: aliasing address not given", mip->name); 20224084f9bSBrian Somers 20322c62477SPoul-Henning Kamp if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL) 20467a886fbSBrian Somers errx (1, "both alias address and interface " 20567a886fbSBrian Somers "name are not allowed"); 20624084f9bSBrian Somers /* 20724084f9bSBrian Somers * Check that valid port number is known. 20824084f9bSBrian Somers */ 20922c62477SPoul-Henning Kamp if (mip->inPort != 0 || mip->outPort != 0) 21022c62477SPoul-Henning Kamp if (mip->inPort == 0 || mip->outPort == 0) 2110fc81af1SPhilippe Charnier errx (1, "both input and output ports are required"); 21224084f9bSBrian Somers 21322c62477SPoul-Henning Kamp if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0) 214b0f55af6SRuslan Ermilov ParseOption ("port", DEFAULT_SERVICE); 21524084f9bSBrian Somers 21624084f9bSBrian Somers /* 217f9b06d5cSBrian Somers * Check if ignored packets should be dropped. 218f9b06d5cSBrian Somers */ 21922c62477SPoul-Henning Kamp mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0); 22022c62477SPoul-Henning Kamp mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING; 221f9b06d5cSBrian Somers /* 22224084f9bSBrian Somers * Create divert sockets. Use only one socket if -p was specified 22324084f9bSBrian Somers * on command line. Otherwise, create separate sockets for 22424084f9bSBrian Somers * outgoing and incoming connnections. 22524084f9bSBrian Somers */ 22622c62477SPoul-Henning Kamp if (mip->inOutPort) { 22724084f9bSBrian Somers 22822c62477SPoul-Henning Kamp mip->divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 22922c62477SPoul-Henning Kamp if (mip->divertInOut == -1) 23024084f9bSBrian Somers Quit ("Unable to create divert socket."); 23122c62477SPoul-Henning Kamp if (mip->divertInOut > fdMax) 23222c62477SPoul-Henning Kamp fdMax = mip->divertInOut; 23324084f9bSBrian Somers 23422c62477SPoul-Henning Kamp mip->divertIn = -1; 23522c62477SPoul-Henning Kamp mip->divertOut = -1; 23624084f9bSBrian Somers /* 23724084f9bSBrian Somers * Bind socket. 23824084f9bSBrian Somers */ 23924084f9bSBrian Somers 24024084f9bSBrian Somers addr.sin_family = AF_INET; 24124084f9bSBrian Somers addr.sin_addr.s_addr = INADDR_ANY; 24222c62477SPoul-Henning Kamp addr.sin_port = mip->inOutPort; 24324084f9bSBrian Somers 24422c62477SPoul-Henning Kamp if (bind (mip->divertInOut, 24524084f9bSBrian Somers (struct sockaddr*) &addr, 24624084f9bSBrian Somers sizeof addr) == -1) 24724084f9bSBrian Somers Quit ("Unable to bind divert socket."); 24824084f9bSBrian Somers } 24924084f9bSBrian Somers else { 25024084f9bSBrian Somers 25122c62477SPoul-Henning Kamp mip->divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 25222c62477SPoul-Henning Kamp if (mip->divertIn == -1) 25324084f9bSBrian Somers Quit ("Unable to create incoming divert socket."); 25422c62477SPoul-Henning Kamp if (mip->divertIn > fdMax) 25522c62477SPoul-Henning Kamp fdMax = mip->divertIn; 25624084f9bSBrian Somers 25722c62477SPoul-Henning Kamp 25822c62477SPoul-Henning Kamp mip->divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 25922c62477SPoul-Henning Kamp if (mip->divertOut == -1) 26024084f9bSBrian Somers Quit ("Unable to create outgoing divert socket."); 26122c62477SPoul-Henning Kamp if (mip->divertOut > fdMax) 26222c62477SPoul-Henning Kamp fdMax = mip->divertOut; 26324084f9bSBrian Somers 26422c62477SPoul-Henning Kamp mip->divertInOut = -1; 26524084f9bSBrian Somers 26624084f9bSBrian Somers /* 26724084f9bSBrian Somers * Bind divert sockets. 26824084f9bSBrian Somers */ 26924084f9bSBrian Somers 27024084f9bSBrian Somers addr.sin_family = AF_INET; 27124084f9bSBrian Somers addr.sin_addr.s_addr = INADDR_ANY; 27222c62477SPoul-Henning Kamp addr.sin_port = mip->inPort; 27324084f9bSBrian Somers 27422c62477SPoul-Henning Kamp if (bind (mip->divertIn, 27524084f9bSBrian Somers (struct sockaddr*) &addr, 27624084f9bSBrian Somers sizeof addr) == -1) 27724084f9bSBrian Somers Quit ("Unable to bind incoming divert socket."); 27824084f9bSBrian Somers 27924084f9bSBrian Somers addr.sin_family = AF_INET; 28024084f9bSBrian Somers addr.sin_addr.s_addr = INADDR_ANY; 28122c62477SPoul-Henning Kamp addr.sin_port = mip->outPort; 28224084f9bSBrian Somers 28322c62477SPoul-Henning Kamp if (bind (mip->divertOut, 28424084f9bSBrian Somers (struct sockaddr*) &addr, 28524084f9bSBrian Somers sizeof addr) == -1) 28624084f9bSBrian Somers Quit ("Unable to bind outgoing divert socket."); 28724084f9bSBrian Somers } 28824084f9bSBrian Somers /* 289f2da55a2SRuslan Ermilov * Create routing socket if interface name specified and in dynamic mode. 29024084f9bSBrian Somers */ 29122c62477SPoul-Henning Kamp if (mip->ifName) { 292f2da55a2SRuslan Ermilov if (dynamicMode) { 29324084f9bSBrian Somers 29422c62477SPoul-Henning Kamp if (routeSock == -1) 29524084f9bSBrian Somers routeSock = socket (PF_ROUTE, SOCK_RAW, 0); 29624084f9bSBrian Somers if (routeSock == -1) 29724084f9bSBrian Somers Quit ("Unable to create routing info socket."); 29822c62477SPoul-Henning Kamp if (routeSock > fdMax) 29922c62477SPoul-Henning Kamp fdMax = routeSock; 300f2da55a2SRuslan Ermilov 30122c62477SPoul-Henning Kamp mip->assignAliasAddr = 1; 30224084f9bSBrian Somers } 30324084f9bSBrian Somers else 30422c62477SPoul-Henning Kamp SetAliasAddressFromIfName (mip->ifName); 30522c62477SPoul-Henning Kamp } 30622c62477SPoul-Henning Kamp 30722c62477SPoul-Henning Kamp } 30822c62477SPoul-Henning Kamp if (globalPort) { 30922c62477SPoul-Henning Kamp 31022c62477SPoul-Henning Kamp divertGlobal = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 31122c62477SPoul-Henning Kamp if (divertGlobal == -1) 31222c62477SPoul-Henning Kamp Quit ("Unable to create divert socket."); 31322c62477SPoul-Henning Kamp if (divertGlobal > fdMax) 31422c62477SPoul-Henning Kamp fdMax = divertGlobal; 31522c62477SPoul-Henning Kamp 31622c62477SPoul-Henning Kamp /* 31722c62477SPoul-Henning Kamp * Bind socket. 31822c62477SPoul-Henning Kamp */ 31922c62477SPoul-Henning Kamp 32022c62477SPoul-Henning Kamp addr.sin_family = AF_INET; 32122c62477SPoul-Henning Kamp addr.sin_addr.s_addr = INADDR_ANY; 32222c62477SPoul-Henning Kamp addr.sin_port = globalPort; 32322c62477SPoul-Henning Kamp 32422c62477SPoul-Henning Kamp if (bind (divertGlobal, 32522c62477SPoul-Henning Kamp (struct sockaddr*) &addr, 32622c62477SPoul-Henning Kamp sizeof addr) == -1) 32722c62477SPoul-Henning Kamp Quit ("Unable to bind global divert socket."); 328f2da55a2SRuslan Ermilov } 32924084f9bSBrian Somers /* 33024084f9bSBrian Somers * Create socket for sending ICMP messages. 33124084f9bSBrian Somers */ 33224084f9bSBrian Somers icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); 33324084f9bSBrian Somers if (icmpSock == -1) 33424084f9bSBrian Somers Quit ("Unable to create ICMP socket."); 335f3d64024SBrian Somers 336f3d64024SBrian Somers /* 337f3d64024SBrian Somers * And disable reads for the socket, otherwise it slowly fills 338f3d64024SBrian Somers * up with received icmps which we do not use. 339f3d64024SBrian Somers */ 340f3d64024SBrian Somers shutdown(icmpSock, SHUT_RD); 341f3d64024SBrian Somers 34224084f9bSBrian Somers /* 34324084f9bSBrian Somers * Become a daemon unless verbose mode was requested. 34424084f9bSBrian Somers */ 34524084f9bSBrian Somers if (!verbose) 34624084f9bSBrian Somers DaemonMode (); 34724084f9bSBrian Somers /* 34824084f9bSBrian Somers * Catch signals to manage shutdown and 34924084f9bSBrian Somers * refresh of interface address. 35024084f9bSBrian Somers */ 351cd45c931SRuslan Ermilov siginterrupt(SIGTERM, 1); 352cd45c931SRuslan Ermilov siginterrupt(SIGHUP, 1); 35372cbe4adSAlexander Motin if (exitDelay) 35424084f9bSBrian Somers signal(SIGTERM, InitiateShutdown); 35572cbe4adSAlexander Motin else 35672cbe4adSAlexander Motin signal(SIGTERM, Shutdown); 35724084f9bSBrian Somers signal (SIGHUP, RefreshAddr); 35824084f9bSBrian Somers /* 35924084f9bSBrian Somers * Set alias address if it has been given. 36024084f9bSBrian Somers */ 36122c62477SPoul-Henning Kamp mip = LIST_FIRST(&root); /* XXX: simon */ 36222c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) { 36322c62477SPoul-Henning Kamp mla = mip->la; 36422c62477SPoul-Henning Kamp if (mip->aliasAddr.s_addr != INADDR_NONE) 36522c62477SPoul-Henning Kamp LibAliasSetAddress (mla, mip->aliasAddr); 36622c62477SPoul-Henning Kamp } 36724084f9bSBrian Somers 36824084f9bSBrian Somers while (running) { 36922c62477SPoul-Henning Kamp mip = LIST_FIRST(&root); /* XXX: simon */ 370fb994b07SBrian Somers 37122c62477SPoul-Henning Kamp if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) { 372fb994b07SBrian Somers /* 373fb994b07SBrian Somers * When using only one socket, just call 374fb994b07SBrian Somers * DoAliasing repeatedly to process packets. 375fb994b07SBrian Somers */ 37622c62477SPoul-Henning Kamp DoAliasing (mip->divertInOut, DONT_KNOW); 377fb994b07SBrian Somers continue; 378fb994b07SBrian Somers } 37924084f9bSBrian Somers /* 38024084f9bSBrian Somers * Build read mask from socket descriptors to select. 38124084f9bSBrian Somers */ 38224084f9bSBrian Somers FD_ZERO (&readMask); 383fb994b07SBrian Somers /* 3843daff242SRuslan Ermilov * Check if new packets are available. 385fb994b07SBrian Somers */ 38622c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) { 38722c62477SPoul-Henning Kamp if (mip->divertIn != -1) 38822c62477SPoul-Henning Kamp FD_SET (mip->divertIn, &readMask); 38924084f9bSBrian Somers 39022c62477SPoul-Henning Kamp if (mip->divertOut != -1) 39122c62477SPoul-Henning Kamp FD_SET (mip->divertOut, &readMask); 39224084f9bSBrian Somers 39322c62477SPoul-Henning Kamp if (mip->divertInOut != -1) 39422c62477SPoul-Henning Kamp FD_SET (mip->divertInOut, &readMask); 39522c62477SPoul-Henning Kamp } 396fb994b07SBrian Somers /* 397fb994b07SBrian Somers * Routing info is processed always. 398fb994b07SBrian Somers */ 39924084f9bSBrian Somers if (routeSock != -1) 40024084f9bSBrian Somers FD_SET (routeSock, &readMask); 40124084f9bSBrian Somers 40222c62477SPoul-Henning Kamp if (divertGlobal != -1) 40322c62477SPoul-Henning Kamp FD_SET (divertGlobal, &readMask); 40422c62477SPoul-Henning Kamp 40524084f9bSBrian Somers if (select (fdMax + 1, 40624084f9bSBrian Somers &readMask, 4073daff242SRuslan Ermilov NULL, 40824084f9bSBrian Somers NULL, 40924084f9bSBrian Somers NULL) == -1) { 41024084f9bSBrian Somers 41124084f9bSBrian Somers if (errno == EINTR) 41224084f9bSBrian Somers continue; 41324084f9bSBrian Somers 41424084f9bSBrian Somers Quit ("Select failed."); 41524084f9bSBrian Somers } 41624084f9bSBrian Somers 41722c62477SPoul-Henning Kamp if (divertGlobal != -1) 41822c62477SPoul-Henning Kamp if (FD_ISSET (divertGlobal, &readMask)) 41922c62477SPoul-Henning Kamp DoGlobal (divertGlobal); 42022c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) { 42122c62477SPoul-Henning Kamp mla = mip->la; 42222c62477SPoul-Henning Kamp if (mip->divertIn != -1) 42322c62477SPoul-Henning Kamp if (FD_ISSET (mip->divertIn, &readMask)) 42422c62477SPoul-Henning Kamp DoAliasing (mip->divertIn, INPUT); 42524084f9bSBrian Somers 42622c62477SPoul-Henning Kamp if (mip->divertOut != -1) 42722c62477SPoul-Henning Kamp if (FD_ISSET (mip->divertOut, &readMask)) 42822c62477SPoul-Henning Kamp DoAliasing (mip->divertOut, OUTPUT); 42924084f9bSBrian Somers 43022c62477SPoul-Henning Kamp if (mip->divertInOut != -1) 43122c62477SPoul-Henning Kamp if (FD_ISSET (mip->divertInOut, &readMask)) 43222c62477SPoul-Henning Kamp DoAliasing (mip->divertInOut, DONT_KNOW); 43324084f9bSBrian Somers 43422c62477SPoul-Henning Kamp } 43524084f9bSBrian Somers if (routeSock != -1) 43624084f9bSBrian Somers if (FD_ISSET (routeSock, &readMask)) 43724084f9bSBrian Somers HandleRoutingInfo (routeSock); 43824084f9bSBrian Somers } 43924084f9bSBrian Somers 44024084f9bSBrian Somers if (background) 441b79840a6SRuslan Ermilov unlink (pidName); 44224084f9bSBrian Somers 44324084f9bSBrian Somers return 0; 44424084f9bSBrian Somers } 44524084f9bSBrian Somers 44624084f9bSBrian Somers static void DaemonMode () 44724084f9bSBrian Somers { 44824084f9bSBrian Somers FILE* pidFile; 44924084f9bSBrian Somers 45024084f9bSBrian Somers daemon (0, 0); 45124084f9bSBrian Somers background = 1; 45224084f9bSBrian Somers 453b79840a6SRuslan Ermilov pidFile = fopen (pidName, "w"); 45424084f9bSBrian Somers if (pidFile) { 45524084f9bSBrian Somers 45624084f9bSBrian Somers fprintf (pidFile, "%d\n", getpid ()); 45724084f9bSBrian Somers fclose (pidFile); 45824084f9bSBrian Somers } 45924084f9bSBrian Somers } 46024084f9bSBrian Somers 46124084f9bSBrian Somers static void ParseArgs (int argc, char** argv) 46224084f9bSBrian Somers { 46324084f9bSBrian Somers int arg; 46424084f9bSBrian Somers char* opt; 46524084f9bSBrian Somers char parmBuf[256]; 46630395bb5SJosef Karthauser int len; /* bounds checking */ 46724084f9bSBrian Somers 46824084f9bSBrian Somers for (arg = 1; arg < argc; arg++) { 46924084f9bSBrian Somers 47024084f9bSBrian Somers opt = argv[arg]; 47124084f9bSBrian Somers if (*opt != '-') { 47224084f9bSBrian Somers 4730fc81af1SPhilippe Charnier warnx ("invalid option %s", opt); 47424084f9bSBrian Somers Usage (); 47524084f9bSBrian Somers } 47624084f9bSBrian Somers 47724084f9bSBrian Somers parmBuf[0] = '\0'; 47830395bb5SJosef Karthauser len = 0; 47924084f9bSBrian Somers 48024084f9bSBrian Somers while (arg < argc - 1) { 48124084f9bSBrian Somers 48224084f9bSBrian Somers if (argv[arg + 1][0] == '-') 48324084f9bSBrian Somers break; 48424084f9bSBrian Somers 48530395bb5SJosef Karthauser if (len) { 48630395bb5SJosef Karthauser strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1)); 48730395bb5SJosef Karthauser len += strlen(parmBuf + len); 48824084f9bSBrian Somers } 48924084f9bSBrian Somers 49030395bb5SJosef Karthauser ++arg; 49130395bb5SJosef Karthauser strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1)); 49230395bb5SJosef Karthauser len += strlen(parmBuf + len); 49330395bb5SJosef Karthauser 49430395bb5SJosef Karthauser } 49530395bb5SJosef Karthauser 496b0f55af6SRuslan Ermilov ParseOption (opt + 1, (len ? parmBuf : NULL)); 49730395bb5SJosef Karthauser 49824084f9bSBrian Somers } 49924084f9bSBrian Somers } 50024084f9bSBrian Somers 50122c62477SPoul-Henning Kamp static void DoGlobal (int fd) 50222c62477SPoul-Henning Kamp { 50322c62477SPoul-Henning Kamp int bytes; 50422c62477SPoul-Henning Kamp int origBytes; 50522c62477SPoul-Henning Kamp char buf[IP_MAXPACKET]; 50622c62477SPoul-Henning Kamp struct sockaddr_in addr; 50722c62477SPoul-Henning Kamp int wrote; 50848ce8ca1SXin LI socklen_t addrSize; 50922c62477SPoul-Henning Kamp struct ip* ip; 51022c62477SPoul-Henning Kamp char msgBuf[80]; 51122c62477SPoul-Henning Kamp 51222c62477SPoul-Henning Kamp /* 51322c62477SPoul-Henning Kamp * Get packet from socket. 51422c62477SPoul-Henning Kamp */ 51522c62477SPoul-Henning Kamp addrSize = sizeof addr; 51622c62477SPoul-Henning Kamp origBytes = recvfrom (fd, 51722c62477SPoul-Henning Kamp buf, 51822c62477SPoul-Henning Kamp sizeof buf, 51922c62477SPoul-Henning Kamp 0, 52022c62477SPoul-Henning Kamp (struct sockaddr*) &addr, 52122c62477SPoul-Henning Kamp &addrSize); 52222c62477SPoul-Henning Kamp 52322c62477SPoul-Henning Kamp if (origBytes == -1) { 52422c62477SPoul-Henning Kamp 52522c62477SPoul-Henning Kamp if (errno != EINTR) 52622c62477SPoul-Henning Kamp Warn ("read from divert socket failed"); 52722c62477SPoul-Henning Kamp 52822c62477SPoul-Henning Kamp return; 52922c62477SPoul-Henning Kamp } 53022c62477SPoul-Henning Kamp 53122c62477SPoul-Henning Kamp #if 0 53222c62477SPoul-Henning Kamp if (mip->assignAliasAddr) { 53322c62477SPoul-Henning Kamp SetAliasAddressFromIfName (mip->ifName); 53422c62477SPoul-Henning Kamp mip->assignAliasAddr = 0; 53522c62477SPoul-Henning Kamp } 53622c62477SPoul-Henning Kamp #endif 53722c62477SPoul-Henning Kamp /* 53822c62477SPoul-Henning Kamp * This is an IP packet. 53922c62477SPoul-Henning Kamp */ 54022c62477SPoul-Henning Kamp ip = (struct ip*) buf; 54122c62477SPoul-Henning Kamp 54222c62477SPoul-Henning Kamp if (verbose) { 54322c62477SPoul-Henning Kamp /* 54422c62477SPoul-Henning Kamp * Print packet direction and protocol type. 54522c62477SPoul-Henning Kamp */ 54622c62477SPoul-Henning Kamp printf ("Glb "); 54722c62477SPoul-Henning Kamp 54822c62477SPoul-Henning Kamp switch (ip->ip_p) { 54922c62477SPoul-Henning Kamp case IPPROTO_TCP: 55022c62477SPoul-Henning Kamp printf ("[TCP] "); 55122c62477SPoul-Henning Kamp break; 55222c62477SPoul-Henning Kamp 55322c62477SPoul-Henning Kamp case IPPROTO_UDP: 55422c62477SPoul-Henning Kamp printf ("[UDP] "); 55522c62477SPoul-Henning Kamp break; 55622c62477SPoul-Henning Kamp 55722c62477SPoul-Henning Kamp case IPPROTO_ICMP: 55822c62477SPoul-Henning Kamp printf ("[ICMP] "); 55922c62477SPoul-Henning Kamp break; 56022c62477SPoul-Henning Kamp 56122c62477SPoul-Henning Kamp default: 56222c62477SPoul-Henning Kamp printf ("[%d] ", ip->ip_p); 56322c62477SPoul-Henning Kamp break; 56422c62477SPoul-Henning Kamp } 56522c62477SPoul-Henning Kamp /* 56622c62477SPoul-Henning Kamp * Print addresses. 56722c62477SPoul-Henning Kamp */ 56822c62477SPoul-Henning Kamp PrintPacket (ip); 56922c62477SPoul-Henning Kamp } 57022c62477SPoul-Henning Kamp 57122c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) { 57222c62477SPoul-Henning Kamp mla = mip->la; 57322c62477SPoul-Henning Kamp if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED) 57422c62477SPoul-Henning Kamp break; 57522c62477SPoul-Henning Kamp } 57622c62477SPoul-Henning Kamp /* 57722c62477SPoul-Henning Kamp * Length might have changed during aliasing. 57822c62477SPoul-Henning Kamp */ 57922c62477SPoul-Henning Kamp bytes = ntohs (ip->ip_len); 58022c62477SPoul-Henning Kamp /* 58122c62477SPoul-Henning Kamp * Update alias overhead size for outgoing packets. 58222c62477SPoul-Henning Kamp */ 58322c62477SPoul-Henning Kamp if (mip != NULL && bytes - origBytes > mip->aliasOverhead) 58422c62477SPoul-Henning Kamp mip->aliasOverhead = bytes - origBytes; 58522c62477SPoul-Henning Kamp 58622c62477SPoul-Henning Kamp if (verbose) { 58722c62477SPoul-Henning Kamp 58822c62477SPoul-Henning Kamp /* 58922c62477SPoul-Henning Kamp * Print addresses after aliasing. 59022c62477SPoul-Henning Kamp */ 59122c62477SPoul-Henning Kamp printf (" aliased to\n"); 59222c62477SPoul-Henning Kamp printf (" "); 59322c62477SPoul-Henning Kamp PrintPacket (ip); 59422c62477SPoul-Henning Kamp printf ("\n"); 59522c62477SPoul-Henning Kamp } 59622c62477SPoul-Henning Kamp 59722c62477SPoul-Henning Kamp /* 59822c62477SPoul-Henning Kamp * Put packet back for processing. 59922c62477SPoul-Henning Kamp */ 60022c62477SPoul-Henning Kamp wrote = sendto (fd, 60122c62477SPoul-Henning Kamp buf, 60222c62477SPoul-Henning Kamp bytes, 60322c62477SPoul-Henning Kamp 0, 60422c62477SPoul-Henning Kamp (struct sockaddr*) &addr, 60522c62477SPoul-Henning Kamp sizeof addr); 60622c62477SPoul-Henning Kamp 60722c62477SPoul-Henning Kamp if (wrote != bytes) { 60822c62477SPoul-Henning Kamp 60922c62477SPoul-Henning Kamp if (errno == EMSGSIZE) { 61022c62477SPoul-Henning Kamp 61122c62477SPoul-Henning Kamp if (mip->ifMTU != -1) 61222c62477SPoul-Henning Kamp SendNeedFragIcmp (icmpSock, 61322c62477SPoul-Henning Kamp (struct ip*) buf, 61422c62477SPoul-Henning Kamp mip->ifMTU - mip->aliasOverhead); 61522c62477SPoul-Henning Kamp } 61622c62477SPoul-Henning Kamp else if (errno == EACCES && logIpfwDenied) { 61722c62477SPoul-Henning Kamp 61822c62477SPoul-Henning Kamp sprintf (msgBuf, "failed to write packet back"); 61922c62477SPoul-Henning Kamp Warn (msgBuf); 62022c62477SPoul-Henning Kamp } 62122c62477SPoul-Henning Kamp } 62222c62477SPoul-Henning Kamp } 62322c62477SPoul-Henning Kamp 62422c62477SPoul-Henning Kamp 62559a7c613SBrian Somers static void DoAliasing (int fd, int direction) 62624084f9bSBrian Somers { 62724084f9bSBrian Somers int bytes; 62824084f9bSBrian Somers int origBytes; 6293daff242SRuslan Ermilov char buf[IP_MAXPACKET]; 6303daff242SRuslan Ermilov struct sockaddr_in addr; 6313daff242SRuslan Ermilov int wrote; 632f9b06d5cSBrian Somers int status; 63348ce8ca1SXin LI socklen_t addrSize; 63424084f9bSBrian Somers struct ip* ip; 6353daff242SRuslan Ermilov char msgBuf[80]; 63624084f9bSBrian Somers 63722c62477SPoul-Henning Kamp if (mip->assignAliasAddr) { 63824084f9bSBrian Somers 63922c62477SPoul-Henning Kamp SetAliasAddressFromIfName (mip->ifName); 64022c62477SPoul-Henning Kamp mip->assignAliasAddr = 0; 64124084f9bSBrian Somers } 64224084f9bSBrian Somers /* 64324084f9bSBrian Somers * Get packet from socket. 64424084f9bSBrian Somers */ 6453daff242SRuslan Ermilov addrSize = sizeof addr; 64624084f9bSBrian Somers origBytes = recvfrom (fd, 6473daff242SRuslan Ermilov buf, 6483daff242SRuslan Ermilov sizeof buf, 64924084f9bSBrian Somers 0, 6503daff242SRuslan Ermilov (struct sockaddr*) &addr, 65124084f9bSBrian Somers &addrSize); 65224084f9bSBrian Somers 65324084f9bSBrian Somers if (origBytes == -1) { 65424084f9bSBrian Somers 65524084f9bSBrian Somers if (errno != EINTR) 6560fc81af1SPhilippe Charnier Warn ("read from divert socket failed"); 65724084f9bSBrian Somers 65824084f9bSBrian Somers return; 65924084f9bSBrian Somers } 66024084f9bSBrian Somers /* 6619d5abbddSJens Schweikhardt * This is an IP packet. 66224084f9bSBrian Somers */ 6633daff242SRuslan Ermilov ip = (struct ip*) buf; 664ebe70c8fSWarner Losh if (direction == DONT_KNOW) { 6653daff242SRuslan Ermilov if (addr.sin_addr.s_addr == INADDR_ANY) 66659a7c613SBrian Somers direction = OUTPUT; 66759a7c613SBrian Somers else 66859a7c613SBrian Somers direction = INPUT; 669ebe70c8fSWarner Losh } 67024084f9bSBrian Somers 67124084f9bSBrian Somers if (verbose) { 67224084f9bSBrian Somers /* 67324084f9bSBrian Somers * Print packet direction and protocol type. 67424084f9bSBrian Somers */ 67559a7c613SBrian Somers printf (direction == OUTPUT ? "Out " : "In "); 67622c62477SPoul-Henning Kamp if (ninstance > 1) 67748ce8ca1SXin LI printf ("{%s}", mip->name); 67824084f9bSBrian Somers 67924084f9bSBrian Somers switch (ip->ip_p) { 68024084f9bSBrian Somers case IPPROTO_TCP: 68124084f9bSBrian Somers printf ("[TCP] "); 68224084f9bSBrian Somers break; 68324084f9bSBrian Somers 68424084f9bSBrian Somers case IPPROTO_UDP: 68524084f9bSBrian Somers printf ("[UDP] "); 68624084f9bSBrian Somers break; 68724084f9bSBrian Somers 68824084f9bSBrian Somers case IPPROTO_ICMP: 68924084f9bSBrian Somers printf ("[ICMP] "); 69024084f9bSBrian Somers break; 69124084f9bSBrian Somers 69224084f9bSBrian Somers default: 69359a7c613SBrian Somers printf ("[%d] ", ip->ip_p); 69424084f9bSBrian Somers break; 69524084f9bSBrian Somers } 69624084f9bSBrian Somers /* 69724084f9bSBrian Somers * Print addresses. 69824084f9bSBrian Somers */ 69924084f9bSBrian Somers PrintPacket (ip); 70024084f9bSBrian Somers } 70124084f9bSBrian Somers 70259a7c613SBrian Somers if (direction == OUTPUT) { 70324084f9bSBrian Somers /* 70424084f9bSBrian Somers * Outgoing packets. Do aliasing. 70524084f9bSBrian Somers */ 70622c62477SPoul-Henning Kamp LibAliasOut (mla, buf, IP_MAXPACKET); 70724084f9bSBrian Somers } 70824084f9bSBrian Somers else { 70959a7c613SBrian Somers 71024084f9bSBrian Somers /* 71124084f9bSBrian Somers * Do aliasing. 71224084f9bSBrian Somers */ 71322c62477SPoul-Henning Kamp status = LibAliasIn (mla, buf, IP_MAXPACKET); 714f9b06d5cSBrian Somers if (status == PKT_ALIAS_IGNORED && 71522c62477SPoul-Henning Kamp mip->dropIgnoredIncoming) { 716f9b06d5cSBrian Somers 71759a7c613SBrian Somers if (verbose) 718f9b06d5cSBrian Somers printf (" dropped.\n"); 71959a7c613SBrian Somers 72022c62477SPoul-Henning Kamp if (mip->logDropped) 72159a7c613SBrian Somers SyslogPacket (ip, LOG_WARNING, "denied"); 72259a7c613SBrian Somers 723f9b06d5cSBrian Somers return; 724f9b06d5cSBrian Somers } 72524084f9bSBrian Somers } 72624084f9bSBrian Somers /* 72724084f9bSBrian Somers * Length might have changed during aliasing. 72824084f9bSBrian Somers */ 72924084f9bSBrian Somers bytes = ntohs (ip->ip_len); 73024084f9bSBrian Somers /* 73124084f9bSBrian Somers * Update alias overhead size for outgoing packets. 73224084f9bSBrian Somers */ 73359a7c613SBrian Somers if (direction == OUTPUT && 73422c62477SPoul-Henning Kamp bytes - origBytes > mip->aliasOverhead) 73522c62477SPoul-Henning Kamp mip->aliasOverhead = bytes - origBytes; 73624084f9bSBrian Somers 73724084f9bSBrian Somers if (verbose) { 73824084f9bSBrian Somers 73924084f9bSBrian Somers /* 74024084f9bSBrian Somers * Print addresses after aliasing. 74124084f9bSBrian Somers */ 74224084f9bSBrian Somers printf (" aliased to\n"); 74324084f9bSBrian Somers printf (" "); 74424084f9bSBrian Somers PrintPacket (ip); 74524084f9bSBrian Somers printf ("\n"); 74624084f9bSBrian Somers } 747fb994b07SBrian Somers 74824084f9bSBrian Somers /* 74924084f9bSBrian Somers * Put packet back for processing. 75024084f9bSBrian Somers */ 75124084f9bSBrian Somers wrote = sendto (fd, 7523daff242SRuslan Ermilov buf, 7533daff242SRuslan Ermilov bytes, 75424084f9bSBrian Somers 0, 7553daff242SRuslan Ermilov (struct sockaddr*) &addr, 7563daff242SRuslan Ermilov sizeof addr); 75724084f9bSBrian Somers 7583daff242SRuslan Ermilov if (wrote != bytes) { 75924084f9bSBrian Somers 76024084f9bSBrian Somers if (errno == EMSGSIZE) { 76124084f9bSBrian Somers 7623daff242SRuslan Ermilov if (direction == OUTPUT && 76322c62477SPoul-Henning Kamp mip->ifMTU != -1) 76424084f9bSBrian Somers SendNeedFragIcmp (icmpSock, 7653daff242SRuslan Ermilov (struct ip*) buf, 76622c62477SPoul-Henning Kamp mip->ifMTU - mip->aliasOverhead); 76724084f9bSBrian Somers } 7683843533eSRuslan Ermilov else if (errno == EACCES && logIpfwDenied) { 76924084f9bSBrian Somers 770d782daf0SJosef Karthauser sprintf (msgBuf, "failed to write packet back"); 77124084f9bSBrian Somers Warn (msgBuf); 77224084f9bSBrian Somers } 77324084f9bSBrian Somers } 77424084f9bSBrian Somers } 77524084f9bSBrian Somers 77624084f9bSBrian Somers static void HandleRoutingInfo (int fd) 77724084f9bSBrian Somers { 77824084f9bSBrian Somers int bytes; 77924084f9bSBrian Somers struct if_msghdr ifMsg; 78024084f9bSBrian Somers /* 78124084f9bSBrian Somers * Get packet from socket. 78224084f9bSBrian Somers */ 78324084f9bSBrian Somers bytes = read (fd, &ifMsg, sizeof ifMsg); 78424084f9bSBrian Somers if (bytes == -1) { 78524084f9bSBrian Somers 7860fc81af1SPhilippe Charnier Warn ("read from routing socket failed"); 78724084f9bSBrian Somers return; 78824084f9bSBrian Somers } 78924084f9bSBrian Somers 79024084f9bSBrian Somers if (ifMsg.ifm_version != RTM_VERSION) { 79124084f9bSBrian Somers 7920fc81af1SPhilippe Charnier Warn ("unexpected packet read from routing socket"); 79324084f9bSBrian Somers return; 79424084f9bSBrian Somers } 79524084f9bSBrian Somers 79624084f9bSBrian Somers if (verbose) 7976f3dbe5eSRuslan Ermilov printf ("Routing message %#x received.\n", ifMsg.ifm_type); 79824084f9bSBrian Somers 79922c62477SPoul-Henning Kamp if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) { 80022c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) { 80122c62477SPoul-Henning Kamp mla = mip->la; 80222c62477SPoul-Henning Kamp if (ifMsg.ifm_index == mip->ifIndex) { 8036f3dbe5eSRuslan Ermilov if (verbose) 8046f3dbe5eSRuslan Ermilov printf("Interface address/MTU has probably changed.\n"); 80522c62477SPoul-Henning Kamp mip->assignAliasAddr = 1; 80622c62477SPoul-Henning Kamp } 80722c62477SPoul-Henning Kamp } 80824084f9bSBrian Somers } 8096f3dbe5eSRuslan Ermilov } 81024084f9bSBrian Somers 81124084f9bSBrian Somers static void PrintPacket (struct ip* ip) 81224084f9bSBrian Somers { 81359a7c613SBrian Somers printf ("%s", FormatPacket (ip)); 81459a7c613SBrian Somers } 81559a7c613SBrian Somers 816902cb50aSBrian Somers static void SyslogPacket (struct ip* ip, int priority, const char *label) 81759a7c613SBrian Somers { 81859a7c613SBrian Somers syslog (priority, "%s %s", label, FormatPacket (ip)); 81959a7c613SBrian Somers } 82059a7c613SBrian Somers 82159a7c613SBrian Somers static char* FormatPacket (struct ip* ip) 82259a7c613SBrian Somers { 82359a7c613SBrian Somers static char buf[256]; 82424084f9bSBrian Somers struct tcphdr* tcphdr; 82559a7c613SBrian Somers struct udphdr* udphdr; 82659a7c613SBrian Somers struct icmp* icmphdr; 82759a7c613SBrian Somers char src[20]; 82859a7c613SBrian Somers char dst[20]; 82924084f9bSBrian Somers 83059a7c613SBrian Somers strcpy (src, inet_ntoa (ip->ip_src)); 83159a7c613SBrian Somers strcpy (dst, inet_ntoa (ip->ip_dst)); 83259a7c613SBrian Somers 83359a7c613SBrian Somers switch (ip->ip_p) { 83459a7c613SBrian Somers case IPPROTO_TCP: 83524084f9bSBrian Somers tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2)); 83659a7c613SBrian Somers sprintf (buf, "[TCP] %s:%d -> %s:%d", 83759a7c613SBrian Somers src, 83859a7c613SBrian Somers ntohs (tcphdr->th_sport), 83959a7c613SBrian Somers dst, 84059a7c613SBrian Somers ntohs (tcphdr->th_dport)); 84159a7c613SBrian Somers break; 84224084f9bSBrian Somers 84359a7c613SBrian Somers case IPPROTO_UDP: 84459a7c613SBrian Somers udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2)); 84559a7c613SBrian Somers sprintf (buf, "[UDP] %s:%d -> %s:%d", 84659a7c613SBrian Somers src, 84759a7c613SBrian Somers ntohs (udphdr->uh_sport), 84859a7c613SBrian Somers dst, 84959a7c613SBrian Somers ntohs (udphdr->uh_dport)); 85059a7c613SBrian Somers break; 85124084f9bSBrian Somers 85259a7c613SBrian Somers case IPPROTO_ICMP: 85359a7c613SBrian Somers icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2)); 854b71e869dSBrian Somers sprintf (buf, "[ICMP] %s -> %s %u(%u)", 85559a7c613SBrian Somers src, 85659a7c613SBrian Somers dst, 857b71e869dSBrian Somers icmphdr->icmp_type, 858b71e869dSBrian Somers icmphdr->icmp_code); 85959a7c613SBrian Somers break; 86059a7c613SBrian Somers 86159a7c613SBrian Somers default: 86259a7c613SBrian Somers sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst); 86359a7c613SBrian Somers break; 86459a7c613SBrian Somers } 86559a7c613SBrian Somers 86659a7c613SBrian Somers return buf; 86724084f9bSBrian Somers } 86824084f9bSBrian Somers 8694c04fa4cSRuslan Ermilov static void 8704c04fa4cSRuslan Ermilov SetAliasAddressFromIfName(const char *ifn) 87124084f9bSBrian Somers { 8724c04fa4cSRuslan Ermilov size_t needed; 8734c04fa4cSRuslan Ermilov int mib[6]; 8744c04fa4cSRuslan Ermilov char *buf, *lim, *next; 8754c04fa4cSRuslan Ermilov struct if_msghdr *ifm; 8764c04fa4cSRuslan Ermilov struct ifa_msghdr *ifam; 8774c04fa4cSRuslan Ermilov struct sockaddr_dl *sdl; 8784c04fa4cSRuslan Ermilov struct sockaddr_in *sin; 87924084f9bSBrian Somers 8804c04fa4cSRuslan Ermilov mib[0] = CTL_NET; 8814c04fa4cSRuslan Ermilov mib[1] = PF_ROUTE; 8824c04fa4cSRuslan Ermilov mib[2] = 0; 8834c04fa4cSRuslan Ermilov mib[3] = AF_INET; /* Only IP addresses please */ 8844c04fa4cSRuslan Ermilov mib[4] = NET_RT_IFLIST; 8854c04fa4cSRuslan Ermilov mib[5] = 0; /* ifIndex??? */ 88624084f9bSBrian Somers /* 88724084f9bSBrian Somers * Get interface data. 88824084f9bSBrian Somers */ 8894c04fa4cSRuslan Ermilov if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) 8904c04fa4cSRuslan Ermilov err(1, "iflist-sysctl-estimate"); 8914c04fa4cSRuslan Ermilov if ((buf = malloc(needed)) == NULL) 8924c04fa4cSRuslan Ermilov errx(1, "malloc failed"); 893ec95e4c2SBrian Somers if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1 && errno != ENOMEM) 8944c04fa4cSRuslan Ermilov err(1, "iflist-sysctl-get"); 8954c04fa4cSRuslan Ermilov lim = buf + needed; 89624084f9bSBrian Somers /* 89724084f9bSBrian Somers * Loop through interfaces until one with 89824084f9bSBrian Somers * given name is found. This is done to 89924084f9bSBrian Somers * find correct interface index for routing 90024084f9bSBrian Somers * message processing. 90124084f9bSBrian Somers */ 90222c62477SPoul-Henning Kamp mip->ifIndex = 0; 9034c04fa4cSRuslan Ermilov next = buf; 9044c04fa4cSRuslan Ermilov while (next < lim) { 9054c04fa4cSRuslan Ermilov ifm = (struct if_msghdr *)next; 9064c04fa4cSRuslan Ermilov next += ifm->ifm_msglen; 9074c04fa4cSRuslan Ermilov if (ifm->ifm_version != RTM_VERSION) { 9084c04fa4cSRuslan Ermilov if (verbose) 9094c04fa4cSRuslan Ermilov warnx("routing message version %d " 9104c04fa4cSRuslan Ermilov "not understood", ifm->ifm_version); 9114c04fa4cSRuslan Ermilov continue; 9124c04fa4cSRuslan Ermilov } 9134c04fa4cSRuslan Ermilov if (ifm->ifm_type == RTM_IFINFO) { 9144c04fa4cSRuslan Ermilov sdl = (struct sockaddr_dl *)(ifm + 1); 9154c04fa4cSRuslan Ermilov if (strlen(ifn) == sdl->sdl_nlen && 9164c04fa4cSRuslan Ermilov strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) { 91722c62477SPoul-Henning Kamp mip->ifIndex = ifm->ifm_index; 91822c62477SPoul-Henning Kamp mip->ifMTU = ifm->ifm_data.ifi_mtu; 91924084f9bSBrian Somers break; 92024084f9bSBrian Somers } 92124084f9bSBrian Somers } 92224084f9bSBrian Somers } 92322c62477SPoul-Henning Kamp if (!mip->ifIndex) 9244c04fa4cSRuslan Ermilov errx(1, "unknown interface name %s", ifn); 92524084f9bSBrian Somers /* 92624084f9bSBrian Somers * Get interface address. 92724084f9bSBrian Somers */ 9284c04fa4cSRuslan Ermilov sin = NULL; 9294c04fa4cSRuslan Ermilov while (next < lim) { 9304c04fa4cSRuslan Ermilov ifam = (struct ifa_msghdr *)next; 9314c04fa4cSRuslan Ermilov next += ifam->ifam_msglen; 9324c04fa4cSRuslan Ermilov if (ifam->ifam_version != RTM_VERSION) { 9334c04fa4cSRuslan Ermilov if (verbose) 9344c04fa4cSRuslan Ermilov warnx("routing message version %d " 9354c04fa4cSRuslan Ermilov "not understood", ifam->ifam_version); 9364c04fa4cSRuslan Ermilov continue; 9374c04fa4cSRuslan Ermilov } 9384c04fa4cSRuslan Ermilov if (ifam->ifam_type != RTM_NEWADDR) 9394c04fa4cSRuslan Ermilov break; 9404c04fa4cSRuslan Ermilov if (ifam->ifam_addrs & RTA_IFA) { 9414c04fa4cSRuslan Ermilov int i; 9424c04fa4cSRuslan Ermilov char *cp = (char *)(ifam + 1); 94324084f9bSBrian Somers 9444c04fa4cSRuslan Ermilov for (i = 1; i < RTA_IFA; i <<= 1) 9454c04fa4cSRuslan Ermilov if (ifam->ifam_addrs & i) 9460b46c085SLuigi Rizzo cp += SA_SIZE((struct sockaddr *)cp); 9474c04fa4cSRuslan Ermilov if (((struct sockaddr *)cp)->sa_family == AF_INET) { 9484c04fa4cSRuslan Ermilov sin = (struct sockaddr_in *)cp; 9494c04fa4cSRuslan Ermilov break; 9504c04fa4cSRuslan Ermilov } 9514c04fa4cSRuslan Ermilov } 9524c04fa4cSRuslan Ermilov } 9534c04fa4cSRuslan Ermilov if (sin == NULL) 9544c04fa4cSRuslan Ermilov errx(1, "%s: cannot get interface address", ifn); 9554c04fa4cSRuslan Ermilov 95622c62477SPoul-Henning Kamp LibAliasSetAddress(mla, sin->sin_addr); 95724084f9bSBrian Somers syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes", 95822c62477SPoul-Henning Kamp inet_ntoa(sin->sin_addr), mip->ifMTU); 95924084f9bSBrian Somers 9604c04fa4cSRuslan Ermilov free(buf); 96124084f9bSBrian Somers } 96224084f9bSBrian Somers 963902cb50aSBrian Somers void Quit (const char* msg) 96424084f9bSBrian Somers { 96524084f9bSBrian Somers Warn (msg); 96624084f9bSBrian Somers exit (1); 96724084f9bSBrian Somers } 96824084f9bSBrian Somers 969902cb50aSBrian Somers void Warn (const char* msg) 97024084f9bSBrian Somers { 97124084f9bSBrian Somers if (background) 97224084f9bSBrian Somers syslog (LOG_ALERT, "%s (%m)", msg); 97324084f9bSBrian Somers else 97404d06bb6SKris Kennaway warn ("%s", msg); 97524084f9bSBrian Somers } 97624084f9bSBrian Somers 97748ce8ca1SXin LI static void RefreshAddr (int sig __unused) 97824084f9bSBrian Somers { 979be4f3cd0SPaolo Pisati LibAliasRefreshModules(); 980be4f3cd0SPaolo Pisati if (mip != NULL && mip->ifName != NULL) 98122c62477SPoul-Henning Kamp mip->assignAliasAddr = 1; 98224084f9bSBrian Somers } 98324084f9bSBrian Somers 98448ce8ca1SXin LI static void InitiateShutdown (int sig __unused) 98524084f9bSBrian Somers { 98624084f9bSBrian Somers /* 98724084f9bSBrian Somers * Start timer to allow kernel gracefully 98824084f9bSBrian Somers * shutdown existing connections when system 98924084f9bSBrian Somers * is shut down. 99024084f9bSBrian Somers */ 991cd45c931SRuslan Ermilov siginterrupt(SIGALRM, 1); 99224084f9bSBrian Somers signal (SIGALRM, Shutdown); 99372cbe4adSAlexander Motin ualarm(exitDelay*1000, 1000); 99424084f9bSBrian Somers } 99524084f9bSBrian Somers 99648ce8ca1SXin LI static void Shutdown (int sig __unused) 99724084f9bSBrian Somers { 99824084f9bSBrian Somers running = 0; 99924084f9bSBrian Somers } 100024084f9bSBrian Somers 100124084f9bSBrian Somers /* 100224084f9bSBrian Somers * Different options recognized by this program. 100324084f9bSBrian Somers */ 100424084f9bSBrian Somers 100524084f9bSBrian Somers enum Option { 100624084f9bSBrian Somers 100722c62477SPoul-Henning Kamp LibAliasOption, 100822c62477SPoul-Henning Kamp Instance, 100924084f9bSBrian Somers Verbose, 101024084f9bSBrian Somers InPort, 101124084f9bSBrian Somers OutPort, 101224084f9bSBrian Somers Port, 101322c62477SPoul-Henning Kamp GlobalPort, 101424084f9bSBrian Somers AliasAddress, 101511c2b3bfSRuslan Ermilov TargetAddress, 101624084f9bSBrian Somers InterfaceName, 101724084f9bSBrian Somers RedirectPort, 10184330006dSRuslan Ermilov RedirectProto, 101924084f9bSBrian Somers RedirectAddress, 102024084f9bSBrian Somers ConfigFile, 102159a7c613SBrian Somers DynamicMode, 102259a7c613SBrian Somers ProxyRule, 102359a7c613SBrian Somers LogDenied, 1024bc4ebb98SRuslan Ermilov LogFacility, 102584ef95bdSPoul-Henning Kamp PunchFW, 1026b07fbc17SJoe Marcus Clarke SkinnyPort, 1027b79840a6SRuslan Ermilov LogIpfwDenied, 102872cbe4adSAlexander Motin PidFile, 102972cbe4adSAlexander Motin ExitDelay 103024084f9bSBrian Somers }; 103124084f9bSBrian Somers 103224084f9bSBrian Somers enum Param { 103324084f9bSBrian Somers 103424084f9bSBrian Somers YesNo, 103524084f9bSBrian Somers Numeric, 103624084f9bSBrian Somers String, 103724084f9bSBrian Somers None, 103824084f9bSBrian Somers Address, 103924084f9bSBrian Somers Service 104024084f9bSBrian Somers }; 104124084f9bSBrian Somers 104224084f9bSBrian Somers /* 104324084f9bSBrian Somers * Option information structure (used by ParseOption). 104424084f9bSBrian Somers */ 104524084f9bSBrian Somers 104624084f9bSBrian Somers struct OptionInfo { 104724084f9bSBrian Somers 104824084f9bSBrian Somers enum Option type; 104924084f9bSBrian Somers int packetAliasOpt; 105024084f9bSBrian Somers enum Param parm; 1051902cb50aSBrian Somers const char* parmDescription; 1052902cb50aSBrian Somers const char* description; 1053902cb50aSBrian Somers const char* name; 1054902cb50aSBrian Somers const char* shortName; 105524084f9bSBrian Somers }; 105624084f9bSBrian Somers 105724084f9bSBrian Somers /* 105824084f9bSBrian Somers * Table of known options. 105924084f9bSBrian Somers */ 106024084f9bSBrian Somers 106124084f9bSBrian Somers static struct OptionInfo optionTable[] = { 106224084f9bSBrian Somers 106322c62477SPoul-Henning Kamp { LibAliasOption, 106424084f9bSBrian Somers PKT_ALIAS_UNREGISTERED_ONLY, 106524084f9bSBrian Somers YesNo, 106624084f9bSBrian Somers "[yes|no]", 106724084f9bSBrian Somers "alias only unregistered addresses", 106824084f9bSBrian Somers "unregistered_only", 106924084f9bSBrian Somers "u" }, 107024084f9bSBrian Somers 107122c62477SPoul-Henning Kamp { LibAliasOption, 107224084f9bSBrian Somers PKT_ALIAS_LOG, 107324084f9bSBrian Somers YesNo, 107424084f9bSBrian Somers "[yes|no]", 107524084f9bSBrian Somers "enable logging", 107624084f9bSBrian Somers "log", 107724084f9bSBrian Somers "l" }, 107824084f9bSBrian Somers 107922c62477SPoul-Henning Kamp { LibAliasOption, 108059a7c613SBrian Somers PKT_ALIAS_PROXY_ONLY, 108159a7c613SBrian Somers YesNo, 108259a7c613SBrian Somers "[yes|no]", 108359a7c613SBrian Somers "proxy only", 108459a7c613SBrian Somers "proxy_only", 108559a7c613SBrian Somers NULL }, 108659a7c613SBrian Somers 108722c62477SPoul-Henning Kamp { LibAliasOption, 108859a7c613SBrian Somers PKT_ALIAS_REVERSE, 108959a7c613SBrian Somers YesNo, 109059a7c613SBrian Somers "[yes|no]", 109159a7c613SBrian Somers "operate in reverse mode", 109259a7c613SBrian Somers "reverse", 109359a7c613SBrian Somers NULL }, 109459a7c613SBrian Somers 109522c62477SPoul-Henning Kamp { LibAliasOption, 109624084f9bSBrian Somers PKT_ALIAS_DENY_INCOMING, 109724084f9bSBrian Somers YesNo, 109824084f9bSBrian Somers "[yes|no]", 109924084f9bSBrian Somers "allow incoming connections", 110024084f9bSBrian Somers "deny_incoming", 110124084f9bSBrian Somers "d" }, 110224084f9bSBrian Somers 110322c62477SPoul-Henning Kamp { LibAliasOption, 110424084f9bSBrian Somers PKT_ALIAS_USE_SOCKETS, 110524084f9bSBrian Somers YesNo, 110624084f9bSBrian Somers "[yes|no]", 110724084f9bSBrian Somers "use sockets to inhibit port conflict", 110824084f9bSBrian Somers "use_sockets", 110924084f9bSBrian Somers "s" }, 111024084f9bSBrian Somers 111122c62477SPoul-Henning Kamp { LibAliasOption, 111224084f9bSBrian Somers PKT_ALIAS_SAME_PORTS, 111324084f9bSBrian Somers YesNo, 111424084f9bSBrian Somers "[yes|no]", 111524084f9bSBrian Somers "try to keep original port numbers for connections", 111624084f9bSBrian Somers "same_ports", 111724084f9bSBrian Somers "m" }, 111824084f9bSBrian Somers 111924084f9bSBrian Somers { Verbose, 112024084f9bSBrian Somers 0, 112124084f9bSBrian Somers YesNo, 112224084f9bSBrian Somers "[yes|no]", 112324084f9bSBrian Somers "verbose mode, dump packet information", 112424084f9bSBrian Somers "verbose", 112524084f9bSBrian Somers "v" }, 112624084f9bSBrian Somers 112724084f9bSBrian Somers { DynamicMode, 112824084f9bSBrian Somers 0, 112924084f9bSBrian Somers YesNo, 113024084f9bSBrian Somers "[yes|no]", 113124084f9bSBrian Somers "dynamic mode, automatically detect interface address changes", 113224084f9bSBrian Somers "dynamic", 113324084f9bSBrian Somers NULL }, 113424084f9bSBrian Somers 113524084f9bSBrian Somers { InPort, 113624084f9bSBrian Somers 0, 113724084f9bSBrian Somers Service, 113824084f9bSBrian Somers "number|service_name", 113924084f9bSBrian Somers "set port for incoming packets", 114024084f9bSBrian Somers "in_port", 114124084f9bSBrian Somers "i" }, 114224084f9bSBrian Somers 114324084f9bSBrian Somers { OutPort, 114424084f9bSBrian Somers 0, 114524084f9bSBrian Somers Service, 114624084f9bSBrian Somers "number|service_name", 114724084f9bSBrian Somers "set port for outgoing packets", 114824084f9bSBrian Somers "out_port", 114924084f9bSBrian Somers "o" }, 115024084f9bSBrian Somers 115124084f9bSBrian Somers { Port, 115224084f9bSBrian Somers 0, 115324084f9bSBrian Somers Service, 115424084f9bSBrian Somers "number|service_name", 115524084f9bSBrian Somers "set port (defaults to natd/divert)", 115624084f9bSBrian Somers "port", 115724084f9bSBrian Somers "p" }, 115824084f9bSBrian Somers 115922c62477SPoul-Henning Kamp { GlobalPort, 116022c62477SPoul-Henning Kamp 0, 116122c62477SPoul-Henning Kamp Service, 116222c62477SPoul-Henning Kamp "number|service_name", 116322c62477SPoul-Henning Kamp "set globalport", 116422c62477SPoul-Henning Kamp "globalport", 116522c62477SPoul-Henning Kamp NULL }, 116622c62477SPoul-Henning Kamp 116724084f9bSBrian Somers { AliasAddress, 116824084f9bSBrian Somers 0, 116924084f9bSBrian Somers Address, 117024084f9bSBrian Somers "x.x.x.x", 117124084f9bSBrian Somers "address to use for aliasing", 117224084f9bSBrian Somers "alias_address", 117324084f9bSBrian Somers "a" }, 117424084f9bSBrian Somers 117511c2b3bfSRuslan Ermilov { TargetAddress, 117611c2b3bfSRuslan Ermilov 0, 117711c2b3bfSRuslan Ermilov Address, 117811c2b3bfSRuslan Ermilov "x.x.x.x", 117911c2b3bfSRuslan Ermilov "address to use for incoming sessions", 118011c2b3bfSRuslan Ermilov "target_address", 118111c2b3bfSRuslan Ermilov "t" }, 118211c2b3bfSRuslan Ermilov 118324084f9bSBrian Somers { InterfaceName, 118424084f9bSBrian Somers 0, 118524084f9bSBrian Somers String, 118624084f9bSBrian Somers "network_if_name", 118724084f9bSBrian Somers "take aliasing address from interface", 118824084f9bSBrian Somers "interface", 118924084f9bSBrian Somers "n" }, 119024084f9bSBrian Somers 119159a7c613SBrian Somers { ProxyRule, 119224084f9bSBrian Somers 0, 119324084f9bSBrian Somers String, 119459a7c613SBrian Somers "[type encode_ip_hdr|encode_tcp_stream] port xxxx server " 119559a7c613SBrian Somers "a.b.c.d:yyyy", 119659a7c613SBrian Somers "add transparent proxying / destination NAT", 119759a7c613SBrian Somers "proxy_rule", 119824084f9bSBrian Somers NULL }, 119924084f9bSBrian Somers 120024084f9bSBrian Somers { RedirectPort, 120124084f9bSBrian Somers 0, 120224084f9bSBrian Somers String, 1203bd690510SRuslan Ermilov "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range" 12045d8ee958SBrian Somers " [remote_addr[:remote_port_range]]", 12055d8ee958SBrian Somers "redirect a port (or ports) for incoming traffic", 120624084f9bSBrian Somers "redirect_port", 120724084f9bSBrian Somers NULL }, 120824084f9bSBrian Somers 12094330006dSRuslan Ermilov { RedirectProto, 12104330006dSRuslan Ermilov 0, 12114330006dSRuslan Ermilov String, 12124330006dSRuslan Ermilov "proto local_addr [public_addr] [remote_addr]", 12134330006dSRuslan Ermilov "redirect packets of a given proto", 12144330006dSRuslan Ermilov "redirect_proto", 12154330006dSRuslan Ermilov NULL }, 12164330006dSRuslan Ermilov 121724084f9bSBrian Somers { RedirectAddress, 121824084f9bSBrian Somers 0, 121924084f9bSBrian Somers String, 1220bd690510SRuslan Ermilov "local_addr[,...] public_addr", 122124084f9bSBrian Somers "define mapping between local and public addresses", 122224084f9bSBrian Somers "redirect_address", 122324084f9bSBrian Somers NULL }, 122424084f9bSBrian Somers 122524084f9bSBrian Somers { ConfigFile, 122624084f9bSBrian Somers 0, 122724084f9bSBrian Somers String, 122824084f9bSBrian Somers "file_name", 122924084f9bSBrian Somers "read options from configuration file", 123024084f9bSBrian Somers "config", 123159a7c613SBrian Somers "f" }, 123259a7c613SBrian Somers 123359a7c613SBrian Somers { LogDenied, 123459a7c613SBrian Somers 0, 123559a7c613SBrian Somers YesNo, 123659a7c613SBrian Somers "[yes|no]", 123759a7c613SBrian Somers "enable logging of denied incoming packets", 123859a7c613SBrian Somers "log_denied", 123959a7c613SBrian Somers NULL }, 124059a7c613SBrian Somers 124159a7c613SBrian Somers { LogFacility, 124259a7c613SBrian Somers 0, 124359a7c613SBrian Somers String, 124459a7c613SBrian Somers "facility", 124559a7c613SBrian Somers "name of syslog facility to use for logging", 124659a7c613SBrian Somers "log_facility", 1247bc4ebb98SRuslan Ermilov NULL }, 124859a7c613SBrian Somers 1249bc4ebb98SRuslan Ermilov { PunchFW, 1250bc4ebb98SRuslan Ermilov 0, 1251bc4ebb98SRuslan Ermilov String, 1252bc4ebb98SRuslan Ermilov "basenumber:count", 1253bc4ebb98SRuslan Ermilov "punch holes in the firewall for incoming FTP/IRC DCC connections", 1254bc4ebb98SRuslan Ermilov "punch_fw", 125584ef95bdSPoul-Henning Kamp NULL }, 125684ef95bdSPoul-Henning Kamp 1257b07fbc17SJoe Marcus Clarke { SkinnyPort, 1258b07fbc17SJoe Marcus Clarke 0, 1259b07fbc17SJoe Marcus Clarke String, 1260b07fbc17SJoe Marcus Clarke "port", 1261b07fbc17SJoe Marcus Clarke "set the TCP port for use with the Skinny Station protocol", 1262b07fbc17SJoe Marcus Clarke "skinny_port", 1263b07fbc17SJoe Marcus Clarke NULL }, 1264b07fbc17SJoe Marcus Clarke 126584ef95bdSPoul-Henning Kamp { LogIpfwDenied, 126684ef95bdSPoul-Henning Kamp 0, 126784ef95bdSPoul-Henning Kamp YesNo, 126884ef95bdSPoul-Henning Kamp "[yes|no]", 126984ef95bdSPoul-Henning Kamp "log packets converted by natd, but denied by ipfw", 127084ef95bdSPoul-Henning Kamp "log_ipfw_denied", 127184ef95bdSPoul-Henning Kamp NULL }, 1272b79840a6SRuslan Ermilov 1273b79840a6SRuslan Ermilov { PidFile, 1274b79840a6SRuslan Ermilov 0, 1275b79840a6SRuslan Ermilov String, 1276b79840a6SRuslan Ermilov "file_name", 1277b79840a6SRuslan Ermilov "store PID in an alternate file", 1278b79840a6SRuslan Ermilov "pid_file", 1279b79840a6SRuslan Ermilov "P" }, 128022c62477SPoul-Henning Kamp { Instance, 128122c62477SPoul-Henning Kamp 0, 128222c62477SPoul-Henning Kamp String, 128322c62477SPoul-Henning Kamp "instance name", 128422c62477SPoul-Henning Kamp "name of aliasing engine instance", 128522c62477SPoul-Henning Kamp "instance", 128622c62477SPoul-Henning Kamp NULL }, 128772cbe4adSAlexander Motin { ExitDelay, 128872cbe4adSAlexander Motin 0, 128972cbe4adSAlexander Motin Numeric, 129072cbe4adSAlexander Motin "ms", 129172cbe4adSAlexander Motin "delay in ms before daemon exit after signal", 129272cbe4adSAlexander Motin "exit_delay", 129372cbe4adSAlexander Motin NULL }, 129424084f9bSBrian Somers }; 129524084f9bSBrian Somers 1296b0f55af6SRuslan Ermilov static void ParseOption (const char* option, const char* parms) 129724084f9bSBrian Somers { 129824084f9bSBrian Somers int i; 129924084f9bSBrian Somers struct OptionInfo* info; 130024084f9bSBrian Somers int yesNoValue; 130124084f9bSBrian Somers int aliasValue; 130224084f9bSBrian Somers int numValue; 130367a886fbSBrian Somers u_short uNumValue; 1304902cb50aSBrian Somers const char* strValue; 130524084f9bSBrian Somers struct in_addr addrValue; 130624084f9bSBrian Somers int max; 130724084f9bSBrian Somers char* end; 130859a7c613SBrian Somers CODE* fac_record = NULL; 130924084f9bSBrian Somers /* 131024084f9bSBrian Somers * Find option from table. 131124084f9bSBrian Somers */ 131224084f9bSBrian Somers max = sizeof (optionTable) / sizeof (struct OptionInfo); 131324084f9bSBrian Somers for (i = 0, info = optionTable; i < max; i++, info++) { 131424084f9bSBrian Somers 131524084f9bSBrian Somers if (!strcmp (info->name, option)) 131624084f9bSBrian Somers break; 131724084f9bSBrian Somers 131824084f9bSBrian Somers if (info->shortName) 131924084f9bSBrian Somers if (!strcmp (info->shortName, option)) 132024084f9bSBrian Somers break; 132124084f9bSBrian Somers } 132224084f9bSBrian Somers 132324084f9bSBrian Somers if (i >= max) { 132424084f9bSBrian Somers 13250fc81af1SPhilippe Charnier warnx ("unknown option %s", option); 132624084f9bSBrian Somers Usage (); 132724084f9bSBrian Somers } 132824084f9bSBrian Somers 132967a886fbSBrian Somers uNumValue = 0; 133024084f9bSBrian Somers yesNoValue = 0; 133124084f9bSBrian Somers numValue = 0; 133224084f9bSBrian Somers strValue = NULL; 133324084f9bSBrian Somers /* 133424084f9bSBrian Somers * Check parameters. 133524084f9bSBrian Somers */ 133624084f9bSBrian Somers switch (info->parm) { 133724084f9bSBrian Somers case YesNo: 133824084f9bSBrian Somers if (!parms) 133924084f9bSBrian Somers parms = "yes"; 134024084f9bSBrian Somers 134124084f9bSBrian Somers if (!strcmp (parms, "yes")) 134224084f9bSBrian Somers yesNoValue = 1; 134324084f9bSBrian Somers else 134424084f9bSBrian Somers if (!strcmp (parms, "no")) 134524084f9bSBrian Somers yesNoValue = 0; 13460fc81af1SPhilippe Charnier else 13470fc81af1SPhilippe Charnier errx (1, "%s needs yes/no parameter", option); 134824084f9bSBrian Somers break; 134924084f9bSBrian Somers 135024084f9bSBrian Somers case Service: 13510fc81af1SPhilippe Charnier if (!parms) 135267a886fbSBrian Somers errx (1, "%s needs service name or " 135367a886fbSBrian Somers "port number parameter", 135467a886fbSBrian Somers option); 135524084f9bSBrian Somers 135667a886fbSBrian Somers uNumValue = StrToPort (parms, "divert"); 135724084f9bSBrian Somers break; 135824084f9bSBrian Somers 135924084f9bSBrian Somers case Numeric: 136024084f9bSBrian Somers if (parms) 136124084f9bSBrian Somers numValue = strtol (parms, &end, 10); 136224084f9bSBrian Somers else 1363902cb50aSBrian Somers end = NULL; 136424084f9bSBrian Somers 13650fc81af1SPhilippe Charnier if (end == parms) 13660fc81af1SPhilippe Charnier errx (1, "%s needs numeric parameter", option); 136724084f9bSBrian Somers break; 136824084f9bSBrian Somers 136924084f9bSBrian Somers case String: 137024084f9bSBrian Somers strValue = parms; 13710fc81af1SPhilippe Charnier if (!strValue) 13720fc81af1SPhilippe Charnier errx (1, "%s needs parameter", option); 137324084f9bSBrian Somers break; 137424084f9bSBrian Somers 137524084f9bSBrian Somers case None: 13760fc81af1SPhilippe Charnier if (parms) 13770fc81af1SPhilippe Charnier errx (1, "%s does not take parameters", option); 137824084f9bSBrian Somers break; 137924084f9bSBrian Somers 138024084f9bSBrian Somers case Address: 13810fc81af1SPhilippe Charnier if (!parms) 13820fc81af1SPhilippe Charnier errx (1, "%s needs address/host parameter", option); 138324084f9bSBrian Somers 138424084f9bSBrian Somers StrToAddr (parms, &addrValue); 138524084f9bSBrian Somers break; 138624084f9bSBrian Somers } 138724084f9bSBrian Somers 138824084f9bSBrian Somers switch (info->type) { 138922c62477SPoul-Henning Kamp case LibAliasOption: 139024084f9bSBrian Somers 139124084f9bSBrian Somers aliasValue = yesNoValue ? info->packetAliasOpt : 0; 139222c62477SPoul-Henning Kamp LibAliasSetMode (mla, aliasValue, info->packetAliasOpt); 139324084f9bSBrian Somers break; 139424084f9bSBrian Somers 139524084f9bSBrian Somers case Verbose: 139624084f9bSBrian Somers verbose = yesNoValue; 139724084f9bSBrian Somers break; 139824084f9bSBrian Somers 139924084f9bSBrian Somers case DynamicMode: 140024084f9bSBrian Somers dynamicMode = yesNoValue; 140124084f9bSBrian Somers break; 140224084f9bSBrian Somers 140324084f9bSBrian Somers case InPort: 140422c62477SPoul-Henning Kamp mip->inPort = uNumValue; 140524084f9bSBrian Somers break; 140624084f9bSBrian Somers 140724084f9bSBrian Somers case OutPort: 140822c62477SPoul-Henning Kamp mip->outPort = uNumValue; 140924084f9bSBrian Somers break; 141024084f9bSBrian Somers 141124084f9bSBrian Somers case Port: 141222c62477SPoul-Henning Kamp mip->inOutPort = uNumValue; 141322c62477SPoul-Henning Kamp break; 141422c62477SPoul-Henning Kamp 141522c62477SPoul-Henning Kamp case GlobalPort: 141622c62477SPoul-Henning Kamp globalPort = uNumValue; 141724084f9bSBrian Somers break; 141824084f9bSBrian Somers 141924084f9bSBrian Somers case AliasAddress: 142022c62477SPoul-Henning Kamp memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr)); 142124084f9bSBrian Somers break; 142224084f9bSBrian Somers 142311c2b3bfSRuslan Ermilov case TargetAddress: 142422c62477SPoul-Henning Kamp LibAliasSetTarget(mla, addrValue); 142511c2b3bfSRuslan Ermilov break; 142611c2b3bfSRuslan Ermilov 142724084f9bSBrian Somers case RedirectPort: 142824084f9bSBrian Somers SetupPortRedirect (strValue); 142924084f9bSBrian Somers break; 143024084f9bSBrian Somers 14314330006dSRuslan Ermilov case RedirectProto: 14324330006dSRuslan Ermilov SetupProtoRedirect(strValue); 14334330006dSRuslan Ermilov break; 14344330006dSRuslan Ermilov 143524084f9bSBrian Somers case RedirectAddress: 143624084f9bSBrian Somers SetupAddressRedirect (strValue); 143724084f9bSBrian Somers break; 143824084f9bSBrian Somers 143959a7c613SBrian Somers case ProxyRule: 144022c62477SPoul-Henning Kamp LibAliasProxyRule (mla, strValue); 144159a7c613SBrian Somers break; 144259a7c613SBrian Somers 144324084f9bSBrian Somers case InterfaceName: 144422c62477SPoul-Henning Kamp if (mip->ifName) 144522c62477SPoul-Henning Kamp free (mip->ifName); 144624084f9bSBrian Somers 144722c62477SPoul-Henning Kamp mip->ifName = strdup (strValue); 144824084f9bSBrian Somers break; 144924084f9bSBrian Somers 145024084f9bSBrian Somers case ConfigFile: 145124084f9bSBrian Somers ReadConfigFile (strValue); 145224084f9bSBrian Somers break; 145359a7c613SBrian Somers 145459a7c613SBrian Somers case LogDenied: 145522c62477SPoul-Henning Kamp mip->logDropped = yesNoValue; 145659a7c613SBrian Somers break; 145759a7c613SBrian Somers 145859a7c613SBrian Somers case LogFacility: 145959a7c613SBrian Somers 146059a7c613SBrian Somers fac_record = facilitynames; 146159a7c613SBrian Somers while (fac_record->c_name != NULL) { 146259a7c613SBrian Somers 146359a7c613SBrian Somers if (!strcmp (fac_record->c_name, strValue)) { 146459a7c613SBrian Somers 146559a7c613SBrian Somers logFacility = fac_record->c_val; 146659a7c613SBrian Somers break; 146759a7c613SBrian Somers 146859a7c613SBrian Somers } 146959a7c613SBrian Somers else 147059a7c613SBrian Somers fac_record++; 147159a7c613SBrian Somers } 147259a7c613SBrian Somers 147359a7c613SBrian Somers if(fac_record->c_name == NULL) 147459a7c613SBrian Somers errx(1, "Unknown log facility name: %s", strValue); 147559a7c613SBrian Somers 147659a7c613SBrian Somers break; 1477bc4ebb98SRuslan Ermilov 1478bc4ebb98SRuslan Ermilov case PunchFW: 1479bc4ebb98SRuslan Ermilov SetupPunchFW(strValue); 1480bc4ebb98SRuslan Ermilov break; 14813843533eSRuslan Ermilov 1482b07fbc17SJoe Marcus Clarke case SkinnyPort: 1483b07fbc17SJoe Marcus Clarke SetupSkinnyPort(strValue); 1484b07fbc17SJoe Marcus Clarke break; 1485b07fbc17SJoe Marcus Clarke 148684ef95bdSPoul-Henning Kamp case LogIpfwDenied: 14873843533eSRuslan Ermilov logIpfwDenied = yesNoValue;; 14883843533eSRuslan Ermilov break; 1489b79840a6SRuslan Ermilov 1490b79840a6SRuslan Ermilov case PidFile: 1491b79840a6SRuslan Ermilov pidName = strdup (strValue); 1492b79840a6SRuslan Ermilov break; 149322c62477SPoul-Henning Kamp case Instance: 149422c62477SPoul-Henning Kamp NewInstance(strValue); 149522c62477SPoul-Henning Kamp break; 149672cbe4adSAlexander Motin case ExitDelay: 149772cbe4adSAlexander Motin if (numValue < 0 || numValue > MAX_EXIT_DELAY) 149872cbe4adSAlexander Motin errx(1, "Incorrect exit delay: %d", numValue); 149972cbe4adSAlexander Motin exitDelay = numValue; 150072cbe4adSAlexander Motin break; 150124084f9bSBrian Somers } 150224084f9bSBrian Somers } 150324084f9bSBrian Somers 1504902cb50aSBrian Somers void ReadConfigFile (const char* fileName) 150524084f9bSBrian Somers { 150624084f9bSBrian Somers FILE* file; 1507d99cc1daSRuslan Ermilov char *buf; 1508d99cc1daSRuslan Ermilov size_t len; 15092e7e7c71SRuslan Ermilov char *ptr, *p; 151024084f9bSBrian Somers char* option; 151124084f9bSBrian Somers 151224084f9bSBrian Somers file = fopen (fileName, "r"); 1513d99cc1daSRuslan Ermilov if (!file) 1514d99cc1daSRuslan Ermilov err(1, "cannot open config file %s", fileName); 151524084f9bSBrian Somers 1516d99cc1daSRuslan Ermilov while ((buf = fgetln(file, &len)) != NULL) { 1517d99cc1daSRuslan Ermilov if (buf[len - 1] == '\n') 1518d99cc1daSRuslan Ermilov buf[len - 1] = '\0'; 1519d99cc1daSRuslan Ermilov else 1520d99cc1daSRuslan Ermilov errx(1, "config file format error: " 1521d99cc1daSRuslan Ermilov "last line should end with newline"); 152224084f9bSBrian Somers 152324084f9bSBrian Somers /* 15242e7e7c71SRuslan Ermilov * Check for comments, strip off trailing spaces. 152524084f9bSBrian Somers */ 15262e7e7c71SRuslan Ermilov if ((ptr = strchr(buf, '#'))) 15272e7e7c71SRuslan Ermilov *ptr = '\0'; 15282e7e7c71SRuslan Ermilov for (ptr = buf; isspace(*ptr); ++ptr) 15292e7e7c71SRuslan Ermilov continue; 153024084f9bSBrian Somers if (*ptr == '\0') 153124084f9bSBrian Somers continue; 15322e7e7c71SRuslan Ermilov for (p = strchr(buf, '\0'); isspace(*--p);) 15332e7e7c71SRuslan Ermilov continue; 15342e7e7c71SRuslan Ermilov *++p = '\0'; 15352e7e7c71SRuslan Ermilov 153624084f9bSBrian Somers /* 153724084f9bSBrian Somers * Extract option name. 153824084f9bSBrian Somers */ 153924084f9bSBrian Somers option = ptr; 154024084f9bSBrian Somers while (*ptr && !isspace (*ptr)) 154124084f9bSBrian Somers ++ptr; 154224084f9bSBrian Somers 154324084f9bSBrian Somers if (*ptr != '\0') { 154424084f9bSBrian Somers 154524084f9bSBrian Somers *ptr = '\0'; 154624084f9bSBrian Somers ++ptr; 154724084f9bSBrian Somers } 154824084f9bSBrian Somers /* 154924084f9bSBrian Somers * Skip white space between name and parms. 155024084f9bSBrian Somers */ 155124084f9bSBrian Somers while (*ptr && isspace (*ptr)) 155224084f9bSBrian Somers ++ptr; 155324084f9bSBrian Somers 1554b0f55af6SRuslan Ermilov ParseOption (option, *ptr ? ptr : NULL); 155524084f9bSBrian Somers } 155624084f9bSBrian Somers 155724084f9bSBrian Somers fclose (file); 155824084f9bSBrian Somers } 155924084f9bSBrian Somers 156024084f9bSBrian Somers static void Usage () 156124084f9bSBrian Somers { 156224084f9bSBrian Somers int i; 156324084f9bSBrian Somers int max; 156424084f9bSBrian Somers struct OptionInfo* info; 156524084f9bSBrian Somers 156624084f9bSBrian Somers fprintf (stderr, "Recognized options:\n\n"); 156724084f9bSBrian Somers 156824084f9bSBrian Somers max = sizeof (optionTable) / sizeof (struct OptionInfo); 156924084f9bSBrian Somers for (i = 0, info = optionTable; i < max; i++, info++) { 157024084f9bSBrian Somers 157124084f9bSBrian Somers fprintf (stderr, "-%-20s %s\n", info->name, 157224084f9bSBrian Somers info->parmDescription); 157324084f9bSBrian Somers 157424084f9bSBrian Somers if (info->shortName) 157524084f9bSBrian Somers fprintf (stderr, "-%-20s %s\n", info->shortName, 157624084f9bSBrian Somers info->parmDescription); 157724084f9bSBrian Somers 157824084f9bSBrian Somers fprintf (stderr, " %s\n\n", info->description); 157924084f9bSBrian Somers } 158024084f9bSBrian Somers 158124084f9bSBrian Somers exit (1); 158224084f9bSBrian Somers } 158324084f9bSBrian Somers 1584902cb50aSBrian Somers void SetupPortRedirect (const char* parms) 158524084f9bSBrian Somers { 1586b6365f95SAlexander Motin char *buf; 158724084f9bSBrian Somers char* ptr; 1588bd690510SRuslan Ermilov char* serverPool; 158924084f9bSBrian Somers struct in_addr localAddr; 159024084f9bSBrian Somers struct in_addr publicAddr; 159124084f9bSBrian Somers struct in_addr remoteAddr; 15925d8ee958SBrian Somers port_range portRange; 15935d8ee958SBrian Somers u_short localPort = 0; 15945d8ee958SBrian Somers u_short publicPort = 0; 15955d8ee958SBrian Somers u_short remotePort = 0; 15965d8ee958SBrian Somers u_short numLocalPorts = 0; 15975d8ee958SBrian Somers u_short numPublicPorts = 0; 15985d8ee958SBrian Somers u_short numRemotePorts = 0; 159924084f9bSBrian Somers int proto; 160024084f9bSBrian Somers char* protoName; 160124084f9bSBrian Somers char* separator; 16025d8ee958SBrian Somers int i; 160348ce8ca1SXin LI struct alias_link *aliaslink = NULL; 160424084f9bSBrian Somers 1605b6365f95SAlexander Motin buf = strdup (parms); 1606b6365f95SAlexander Motin if (!buf) 1607b6365f95SAlexander Motin errx (1, "redirect_port: strdup() failed"); 160824084f9bSBrian Somers /* 160924084f9bSBrian Somers * Extract protocol. 161024084f9bSBrian Somers */ 161124084f9bSBrian Somers protoName = strtok (buf, " \t"); 16120fc81af1SPhilippe Charnier if (!protoName) 16130fc81af1SPhilippe Charnier errx (1, "redirect_port: missing protocol"); 161424084f9bSBrian Somers 161524084f9bSBrian Somers proto = StrToProto (protoName); 161624084f9bSBrian Somers /* 161724084f9bSBrian Somers * Extract local address. 161824084f9bSBrian Somers */ 161924084f9bSBrian Somers ptr = strtok (NULL, " \t"); 16200fc81af1SPhilippe Charnier if (!ptr) 16210fc81af1SPhilippe Charnier errx (1, "redirect_port: missing local address"); 162224084f9bSBrian Somers 1623bd690510SRuslan Ermilov separator = strchr(ptr, ','); 1624bd690510SRuslan Ermilov if (separator) { /* LSNAT redirection syntax. */ 1625bd690510SRuslan Ermilov localAddr.s_addr = INADDR_NONE; 1626bd690510SRuslan Ermilov localPort = ~0; 1627bd690510SRuslan Ermilov numLocalPorts = 1; 1628bd690510SRuslan Ermilov serverPool = ptr; 1629bd690510SRuslan Ermilov } else { 16305d8ee958SBrian Somers if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 ) 16315d8ee958SBrian Somers errx (1, "redirect_port: invalid local port range"); 16325d8ee958SBrian Somers 16335d8ee958SBrian Somers localPort = GETLOPORT(portRange); 16345d8ee958SBrian Somers numLocalPorts = GETNUMPORTS(portRange); 1635bd690510SRuslan Ermilov serverPool = NULL; 1636bd690510SRuslan Ermilov } 16375d8ee958SBrian Somers 163824084f9bSBrian Somers /* 16399c501140SBrian Somers * Extract public port and optionally address. 164024084f9bSBrian Somers */ 164124084f9bSBrian Somers ptr = strtok (NULL, " \t"); 16420fc81af1SPhilippe Charnier if (!ptr) 16430fc81af1SPhilippe Charnier errx (1, "redirect_port: missing public port"); 164424084f9bSBrian Somers 164524084f9bSBrian Somers separator = strchr (ptr, ':'); 16465d8ee958SBrian Somers if (separator) { 16475d8ee958SBrian Somers if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 ) 16485d8ee958SBrian Somers errx (1, "redirect_port: invalid public port range"); 164924084f9bSBrian Somers } 16505d8ee958SBrian Somers else { 16515d8ee958SBrian Somers publicAddr.s_addr = INADDR_ANY; 16525d8ee958SBrian Somers if (StrToPortRange (ptr, protoName, &portRange) != 0) 16535d8ee958SBrian Somers errx (1, "redirect_port: invalid public port range"); 16545d8ee958SBrian Somers } 16555d8ee958SBrian Somers 16565d8ee958SBrian Somers publicPort = GETLOPORT(portRange); 16575d8ee958SBrian Somers numPublicPorts = GETNUMPORTS(portRange); 165824084f9bSBrian Somers 165924084f9bSBrian Somers /* 166024084f9bSBrian Somers * Extract remote address and optionally port. 166124084f9bSBrian Somers */ 166224084f9bSBrian Somers ptr = strtok (NULL, " \t"); 166324084f9bSBrian Somers if (ptr) { 166424084f9bSBrian Somers separator = strchr (ptr, ':'); 1665ebe70c8fSWarner Losh if (separator) { 16665d8ee958SBrian Somers if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0) 16675d8ee958SBrian Somers errx (1, "redirect_port: invalid remote port range"); 1668ebe70c8fSWarner Losh } else { 16695d8ee958SBrian Somers SETLOPORT(portRange, 0); 16705d8ee958SBrian Somers SETNUMPORTS(portRange, 1); 167124084f9bSBrian Somers StrToAddr (ptr, &remoteAddr); 167224084f9bSBrian Somers } 167324084f9bSBrian Somers } 167424084f9bSBrian Somers else { 16755d8ee958SBrian Somers SETLOPORT(portRange, 0); 16765d8ee958SBrian Somers SETNUMPORTS(portRange, 1); 167724084f9bSBrian Somers remoteAddr.s_addr = INADDR_ANY; 167824084f9bSBrian Somers } 167924084f9bSBrian Somers 16805d8ee958SBrian Somers remotePort = GETLOPORT(portRange); 16815d8ee958SBrian Somers numRemotePorts = GETNUMPORTS(portRange); 16825d8ee958SBrian Somers 16835d8ee958SBrian Somers /* 16845d8ee958SBrian Somers * Make sure port ranges match up, then add the redirect ports. 16855d8ee958SBrian Somers */ 16865d8ee958SBrian Somers if (numLocalPorts != numPublicPorts) 16875d8ee958SBrian Somers errx (1, "redirect_port: port ranges must be equal in size"); 16885d8ee958SBrian Somers 16895d8ee958SBrian Somers /* Remote port range is allowed to be '0' which means all ports. */ 169029d97436SBrian Somers if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0)) 16915d8ee958SBrian Somers errx (1, "redirect_port: remote port must be 0 or equal to local port range in size"); 16925d8ee958SBrian Somers 16935d8ee958SBrian Somers for (i = 0 ; i < numPublicPorts ; ++i) { 16945d8ee958SBrian Somers /* If remotePort is all ports, set it to 0. */ 16955d8ee958SBrian Somers u_short remotePortCopy = remotePort + i; 16965d8ee958SBrian Somers if (numRemotePorts == 1 && remotePort == 0) 16975d8ee958SBrian Somers remotePortCopy = 0; 16985d8ee958SBrian Somers 169948ce8ca1SXin LI aliaslink = LibAliasRedirectPort (mla, localAddr, 17005d8ee958SBrian Somers htons(localPort + i), 170124084f9bSBrian Somers remoteAddr, 17025d8ee958SBrian Somers htons(remotePortCopy), 170324084f9bSBrian Somers publicAddr, 17045d8ee958SBrian Somers htons(publicPort + i), 170524084f9bSBrian Somers proto); 170624084f9bSBrian Somers } 1707bd690510SRuslan Ermilov 1708bd690510SRuslan Ermilov /* 1709bd690510SRuslan Ermilov * Setup LSNAT server pool. 1710bd690510SRuslan Ermilov */ 171148ce8ca1SXin LI if (serverPool != NULL && aliaslink != NULL) { 1712bd690510SRuslan Ermilov ptr = strtok(serverPool, ","); 1713bd690510SRuslan Ermilov while (ptr != NULL) { 1714bd690510SRuslan Ermilov if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0) 1715bd690510SRuslan Ermilov errx(1, "redirect_port: invalid local port range"); 1716bd690510SRuslan Ermilov 1717bd690510SRuslan Ermilov localPort = GETLOPORT(portRange); 1718bd690510SRuslan Ermilov if (GETNUMPORTS(portRange) != 1) 1719bd690510SRuslan Ermilov errx(1, "redirect_port: local port must be single in this context"); 172048ce8ca1SXin LI LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort)); 1721bd690510SRuslan Ermilov ptr = strtok(NULL, ","); 1722bd690510SRuslan Ermilov } 1723bd690510SRuslan Ermilov } 1724b6365f95SAlexander Motin 1725b6365f95SAlexander Motin free (buf); 17265d8ee958SBrian Somers } 172724084f9bSBrian Somers 17284330006dSRuslan Ermilov void 17294330006dSRuslan Ermilov SetupProtoRedirect(const char* parms) 17304330006dSRuslan Ermilov { 1731b6365f95SAlexander Motin char *buf; 17324330006dSRuslan Ermilov char* ptr; 17334330006dSRuslan Ermilov struct in_addr localAddr; 17344330006dSRuslan Ermilov struct in_addr publicAddr; 17354330006dSRuslan Ermilov struct in_addr remoteAddr; 17364330006dSRuslan Ermilov int proto; 17374330006dSRuslan Ermilov char* protoName; 17384330006dSRuslan Ermilov struct protoent *protoent; 17394330006dSRuslan Ermilov 1740b6365f95SAlexander Motin buf = strdup (parms); 1741b6365f95SAlexander Motin if (!buf) 1742b6365f95SAlexander Motin errx (1, "redirect_port: strdup() failed"); 17434330006dSRuslan Ermilov /* 17444330006dSRuslan Ermilov * Extract protocol. 17454330006dSRuslan Ermilov */ 17464330006dSRuslan Ermilov protoName = strtok(buf, " \t"); 17474330006dSRuslan Ermilov if (!protoName) 17484330006dSRuslan Ermilov errx(1, "redirect_proto: missing protocol"); 17494330006dSRuslan Ermilov 17504330006dSRuslan Ermilov protoent = getprotobyname(protoName); 17514330006dSRuslan Ermilov if (protoent == NULL) 17524330006dSRuslan Ermilov errx(1, "redirect_proto: unknown protocol %s", protoName); 17534330006dSRuslan Ermilov else 17544330006dSRuslan Ermilov proto = protoent->p_proto; 17554330006dSRuslan Ermilov /* 17564330006dSRuslan Ermilov * Extract local address. 17574330006dSRuslan Ermilov */ 17584330006dSRuslan Ermilov ptr = strtok(NULL, " \t"); 17594330006dSRuslan Ermilov if (!ptr) 17604330006dSRuslan Ermilov errx(1, "redirect_proto: missing local address"); 17614330006dSRuslan Ermilov else 17624330006dSRuslan Ermilov StrToAddr(ptr, &localAddr); 17634330006dSRuslan Ermilov /* 17644330006dSRuslan Ermilov * Extract optional public address. 17654330006dSRuslan Ermilov */ 17664330006dSRuslan Ermilov ptr = strtok(NULL, " \t"); 17674330006dSRuslan Ermilov if (ptr) 17684330006dSRuslan Ermilov StrToAddr(ptr, &publicAddr); 17694330006dSRuslan Ermilov else 17704330006dSRuslan Ermilov publicAddr.s_addr = INADDR_ANY; 17714330006dSRuslan Ermilov /* 17724330006dSRuslan Ermilov * Extract optional remote address. 17734330006dSRuslan Ermilov */ 17744330006dSRuslan Ermilov ptr = strtok(NULL, " \t"); 17754330006dSRuslan Ermilov if (ptr) 17764330006dSRuslan Ermilov StrToAddr(ptr, &remoteAddr); 17774330006dSRuslan Ermilov else 17784330006dSRuslan Ermilov remoteAddr.s_addr = INADDR_ANY; 17794330006dSRuslan Ermilov /* 17804330006dSRuslan Ermilov * Create aliasing link. 17814330006dSRuslan Ermilov */ 178222c62477SPoul-Henning Kamp (void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr, 17834330006dSRuslan Ermilov proto); 1784b6365f95SAlexander Motin 1785b6365f95SAlexander Motin free (buf); 17864330006dSRuslan Ermilov } 17874330006dSRuslan Ermilov 1788902cb50aSBrian Somers void SetupAddressRedirect (const char* parms) 178924084f9bSBrian Somers { 1790b6365f95SAlexander Motin char *buf; 179124084f9bSBrian Somers char* ptr; 1792bd690510SRuslan Ermilov char* separator; 179324084f9bSBrian Somers struct in_addr localAddr; 179424084f9bSBrian Somers struct in_addr publicAddr; 1795bd690510SRuslan Ermilov char* serverPool; 179648ce8ca1SXin LI struct alias_link *aliaslink; 179724084f9bSBrian Somers 1798b6365f95SAlexander Motin buf = strdup (parms); 1799b6365f95SAlexander Motin if (!buf) 1800b6365f95SAlexander Motin errx (1, "redirect_port: strdup() failed"); 180124084f9bSBrian Somers /* 180224084f9bSBrian Somers * Extract local address. 180324084f9bSBrian Somers */ 180424084f9bSBrian Somers ptr = strtok (buf, " \t"); 18050fc81af1SPhilippe Charnier if (!ptr) 18060fc81af1SPhilippe Charnier errx (1, "redirect_address: missing local address"); 180724084f9bSBrian Somers 1808bd690510SRuslan Ermilov separator = strchr(ptr, ','); 1809bd690510SRuslan Ermilov if (separator) { /* LSNAT redirection syntax. */ 1810bd690510SRuslan Ermilov localAddr.s_addr = INADDR_NONE; 1811bd690510SRuslan Ermilov serverPool = ptr; 1812bd690510SRuslan Ermilov } else { 181324084f9bSBrian Somers StrToAddr (ptr, &localAddr); 1814bd690510SRuslan Ermilov serverPool = NULL; 1815bd690510SRuslan Ermilov } 181624084f9bSBrian Somers /* 181724084f9bSBrian Somers * Extract public address. 181824084f9bSBrian Somers */ 181924084f9bSBrian Somers ptr = strtok (NULL, " \t"); 18200fc81af1SPhilippe Charnier if (!ptr) 18210fc81af1SPhilippe Charnier errx (1, "redirect_address: missing public address"); 182224084f9bSBrian Somers 182324084f9bSBrian Somers StrToAddr (ptr, &publicAddr); 182448ce8ca1SXin LI aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr); 1825bd690510SRuslan Ermilov 1826bd690510SRuslan Ermilov /* 1827bd690510SRuslan Ermilov * Setup LSNAT server pool. 1828bd690510SRuslan Ermilov */ 182948ce8ca1SXin LI if (serverPool != NULL && aliaslink != NULL) { 1830bd690510SRuslan Ermilov ptr = strtok(serverPool, ","); 1831bd690510SRuslan Ermilov while (ptr != NULL) { 1832bd690510SRuslan Ermilov StrToAddr(ptr, &localAddr); 183348ce8ca1SXin LI LibAliasAddServer(mla, aliaslink, localAddr, htons(~0)); 1834bd690510SRuslan Ermilov ptr = strtok(NULL, ","); 1835bd690510SRuslan Ermilov } 1836bd690510SRuslan Ermilov } 1837b6365f95SAlexander Motin 1838b6365f95SAlexander Motin free (buf); 183924084f9bSBrian Somers } 184024084f9bSBrian Somers 1841902cb50aSBrian Somers void StrToAddr (const char* str, struct in_addr* addr) 184224084f9bSBrian Somers { 184324084f9bSBrian Somers struct hostent* hp; 184424084f9bSBrian Somers 184524084f9bSBrian Somers if (inet_aton (str, addr)) 184624084f9bSBrian Somers return; 184724084f9bSBrian Somers 184824084f9bSBrian Somers hp = gethostbyname (str); 18490fc81af1SPhilippe Charnier if (!hp) 18500fc81af1SPhilippe Charnier errx (1, "unknown host %s", str); 185124084f9bSBrian Somers 185224084f9bSBrian Somers memcpy (addr, hp->h_addr, sizeof (struct in_addr)); 185324084f9bSBrian Somers } 185424084f9bSBrian Somers 1855902cb50aSBrian Somers u_short StrToPort (const char* str, const char* proto) 185624084f9bSBrian Somers { 185767a886fbSBrian Somers u_short port; 185824084f9bSBrian Somers struct servent* sp; 185924084f9bSBrian Somers char* end; 186024084f9bSBrian Somers 186124084f9bSBrian Somers port = strtol (str, &end, 10); 186224084f9bSBrian Somers if (end != str) 186327c20503SBrian Somers return htons (port); 186424084f9bSBrian Somers 186524084f9bSBrian Somers sp = getservbyname (str, proto); 18660fc81af1SPhilippe Charnier if (!sp) 186729e3edccSPhilippe Charnier errx (1, "%s/%s: unknown service", str, proto); 186824084f9bSBrian Somers 186924084f9bSBrian Somers return sp->s_port; 187024084f9bSBrian Somers } 187124084f9bSBrian Somers 1872902cb50aSBrian Somers int StrToPortRange (const char* str, const char* proto, port_range *portRange) 18735d8ee958SBrian Somers { 18745d8ee958SBrian Somers char* sep; 18755d8ee958SBrian Somers struct servent* sp; 18765d8ee958SBrian Somers char* end; 18775d8ee958SBrian Somers u_short loPort; 18785d8ee958SBrian Somers u_short hiPort; 18795d8ee958SBrian Somers 18805d8ee958SBrian Somers /* First see if this is a service, return corresponding port if so. */ 18815d8ee958SBrian Somers sp = getservbyname (str,proto); 18825d8ee958SBrian Somers if (sp) { 18835d8ee958SBrian Somers SETLOPORT(*portRange, ntohs(sp->s_port)); 18845d8ee958SBrian Somers SETNUMPORTS(*portRange, 1); 18855d8ee958SBrian Somers return 0; 18865d8ee958SBrian Somers } 18875d8ee958SBrian Somers 18885d8ee958SBrian Somers /* Not a service, see if it's a single port or port range. */ 18895d8ee958SBrian Somers sep = strchr (str, '-'); 18905d8ee958SBrian Somers if (sep == NULL) { 18915d8ee958SBrian Somers SETLOPORT(*portRange, strtol(str, &end, 10)); 18925d8ee958SBrian Somers if (end != str) { 18935d8ee958SBrian Somers /* Single port. */ 18945d8ee958SBrian Somers SETNUMPORTS(*portRange, 1); 18955d8ee958SBrian Somers return 0; 18965d8ee958SBrian Somers } 18975d8ee958SBrian Somers 18985d8ee958SBrian Somers /* Error in port range field. */ 189929e3edccSPhilippe Charnier errx (1, "%s/%s: unknown service", str, proto); 19005d8ee958SBrian Somers } 19015d8ee958SBrian Somers 19025d8ee958SBrian Somers /* Port range, get the values and sanity check. */ 19035d8ee958SBrian Somers sscanf (str, "%hu-%hu", &loPort, &hiPort); 19045d8ee958SBrian Somers SETLOPORT(*portRange, loPort); 19055d8ee958SBrian Somers SETNUMPORTS(*portRange, 0); /* Error by default */ 19065d8ee958SBrian Somers if (loPort <= hiPort) 19075d8ee958SBrian Somers SETNUMPORTS(*portRange, hiPort - loPort + 1); 19085d8ee958SBrian Somers 19095d8ee958SBrian Somers if (GETNUMPORTS(*portRange) == 0) 19105d8ee958SBrian Somers errx (1, "invalid port range %s", str); 19115d8ee958SBrian Somers 19125d8ee958SBrian Somers return 0; 19135d8ee958SBrian Somers } 19145d8ee958SBrian Somers 19155d8ee958SBrian Somers 1916902cb50aSBrian Somers int StrToProto (const char* str) 191724084f9bSBrian Somers { 191824084f9bSBrian Somers if (!strcmp (str, "tcp")) 191924084f9bSBrian Somers return IPPROTO_TCP; 192024084f9bSBrian Somers 192124084f9bSBrian Somers if (!strcmp (str, "udp")) 192224084f9bSBrian Somers return IPPROTO_UDP; 192324084f9bSBrian Somers 19240fc81af1SPhilippe Charnier errx (1, "unknown protocol %s. Expected tcp or udp", str); 192524084f9bSBrian Somers } 192624084f9bSBrian Somers 1927902cb50aSBrian Somers int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange) 192824084f9bSBrian Somers { 192924084f9bSBrian Somers char* ptr; 193024084f9bSBrian Somers 193124084f9bSBrian Somers ptr = strchr (str, ':'); 19320fc81af1SPhilippe Charnier if (!ptr) 19330fc81af1SPhilippe Charnier errx (1, "%s is missing port number", str); 193424084f9bSBrian Somers 193524084f9bSBrian Somers *ptr = '\0'; 193624084f9bSBrian Somers ++ptr; 193724084f9bSBrian Somers 193824084f9bSBrian Somers StrToAddr (str, addr); 19395d8ee958SBrian Somers return StrToPortRange (ptr, proto, portRange); 194024084f9bSBrian Somers } 1941bc4ebb98SRuslan Ermilov 1942bc4ebb98SRuslan Ermilov static void 1943bc4ebb98SRuslan Ermilov SetupPunchFW(const char *strValue) 1944bc4ebb98SRuslan Ermilov { 1945bc4ebb98SRuslan Ermilov unsigned int base, num; 1946bc4ebb98SRuslan Ermilov 1947bc4ebb98SRuslan Ermilov if (sscanf(strValue, "%u:%u", &base, &num) != 2) 1948bc4ebb98SRuslan Ermilov errx(1, "punch_fw: basenumber:count parameter required"); 1949bc4ebb98SRuslan Ermilov 195022c62477SPoul-Henning Kamp LibAliasSetFWBase(mla, base, num); 195122c62477SPoul-Henning Kamp (void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW); 1952bc4ebb98SRuslan Ermilov } 1953b07fbc17SJoe Marcus Clarke 1954b07fbc17SJoe Marcus Clarke static void 1955b07fbc17SJoe Marcus Clarke SetupSkinnyPort(const char *strValue) 1956b07fbc17SJoe Marcus Clarke { 1957b07fbc17SJoe Marcus Clarke unsigned int port; 1958b07fbc17SJoe Marcus Clarke 1959b07fbc17SJoe Marcus Clarke if (sscanf(strValue, "%u", &port) != 1) 1960b07fbc17SJoe Marcus Clarke errx(1, "skinny_port: port parameter required"); 1961b07fbc17SJoe Marcus Clarke 196222c62477SPoul-Henning Kamp LibAliasSetSkinnyPort(mla, port); 196322c62477SPoul-Henning Kamp } 196422c62477SPoul-Henning Kamp 196522c62477SPoul-Henning Kamp static void 196622c62477SPoul-Henning Kamp NewInstance(const char *name) 196722c62477SPoul-Henning Kamp { 196822c62477SPoul-Henning Kamp struct instance *ip; 196922c62477SPoul-Henning Kamp 197022c62477SPoul-Henning Kamp LIST_FOREACH(ip, &root, list) { 197122c62477SPoul-Henning Kamp if (!strcmp(ip->name, name)) { 197222c62477SPoul-Henning Kamp mla = ip->la; 197322c62477SPoul-Henning Kamp mip = ip; 197422c62477SPoul-Henning Kamp return; 197522c62477SPoul-Henning Kamp } 197622c62477SPoul-Henning Kamp } 197722c62477SPoul-Henning Kamp ninstance++; 197822c62477SPoul-Henning Kamp ip = calloc(sizeof *ip, 1); 197922c62477SPoul-Henning Kamp ip->name = strdup(name); 198022c62477SPoul-Henning Kamp ip->la = LibAliasInit (ip->la); 198122c62477SPoul-Henning Kamp ip->assignAliasAddr = 0; 198222c62477SPoul-Henning Kamp ip->ifName = NULL; 198322c62477SPoul-Henning Kamp ip->logDropped = 0; 198422c62477SPoul-Henning Kamp ip->inPort = 0; 198522c62477SPoul-Henning Kamp ip->outPort = 0; 198622c62477SPoul-Henning Kamp ip->inOutPort = 0; 198722c62477SPoul-Henning Kamp ip->aliasAddr.s_addr = INADDR_NONE; 198822c62477SPoul-Henning Kamp ip->ifMTU = -1; 198922c62477SPoul-Henning Kamp ip->aliasOverhead = 12; 199022c62477SPoul-Henning Kamp LIST_INSERT_HEAD(&root, ip, list); 199122c62477SPoul-Henning Kamp mla = ip->la; 199222c62477SPoul-Henning Kamp mip = ip; 1993b07fbc17SJoe Marcus Clarke } 1994