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 7113e403fdSAntoine Brodin 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); 1140afb958bSMaxim Sobolev static int 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); 133d53fe710SRoman Kurakin static int CheckIpfwRulenum(unsigned int rnum); 13424084f9bSBrian Somers 13524084f9bSBrian Somers /* 13624084f9bSBrian Somers * Globals. 13724084f9bSBrian Somers */ 13824084f9bSBrian Somers 13924084f9bSBrian Somers static int verbose; 14024084f9bSBrian Somers static int background; 14124084f9bSBrian Somers static int running; 14259a7c613SBrian Somers static int logFacility; 14322c62477SPoul-Henning Kamp 14422c62477SPoul-Henning Kamp static int dynamicMode; 14522c62477SPoul-Henning Kamp static int icmpSock; 1463843533eSRuslan Ermilov static int logIpfwDenied; 14748ce8ca1SXin LI static const char* pidName; 14822c62477SPoul-Henning Kamp static int routeSock; 14922c62477SPoul-Henning Kamp static int globalPort; 15022c62477SPoul-Henning Kamp static int divertGlobal; 15172cbe4adSAlexander Motin static int exitDelay; 15272cbe4adSAlexander Motin 15324084f9bSBrian Somers 15424084f9bSBrian Somers int main (int argc, char** argv) 15524084f9bSBrian Somers { 15624084f9bSBrian Somers struct sockaddr_in addr; 15724084f9bSBrian Somers fd_set readMask; 15824084f9bSBrian Somers int fdMax; 1590afb958bSMaxim Sobolev int rval; 16024084f9bSBrian Somers /* 16124084f9bSBrian Somers * Initialize packet aliasing software. 16224084f9bSBrian Somers * Done already here to be able to alter option bits 16324084f9bSBrian Somers * during command line and configuration file processing. 16424084f9bSBrian Somers */ 16522c62477SPoul-Henning Kamp NewInstance("default"); 16622c62477SPoul-Henning Kamp 16724084f9bSBrian Somers /* 16824084f9bSBrian Somers * Parse options. 16924084f9bSBrian Somers */ 17024084f9bSBrian Somers verbose = 0; 17124084f9bSBrian Somers background = 0; 17224084f9bSBrian Somers running = 1; 17324084f9bSBrian Somers dynamicMode = 0; 17459a7c613SBrian Somers logFacility = LOG_DAEMON; 175c0956cf8SRuslan Ermilov logIpfwDenied = -1; 176b79840a6SRuslan Ermilov pidName = PIDFILE; 17722c62477SPoul-Henning Kamp routeSock = -1; 17822c62477SPoul-Henning Kamp icmpSock = -1; 17922c62477SPoul-Henning Kamp fdMax = -1; 18022c62477SPoul-Henning Kamp divertGlobal = -1; 18172cbe4adSAlexander Motin exitDelay = EXIT_DELAY; 18224084f9bSBrian Somers 18324084f9bSBrian Somers ParseArgs (argc, argv); 18424084f9bSBrian Somers /* 185c0956cf8SRuslan Ermilov * Log ipfw(8) denied packets by default in verbose mode. 186c0956cf8SRuslan Ermilov */ 187c0956cf8SRuslan Ermilov if (logIpfwDenied == -1) 188c0956cf8SRuslan Ermilov logIpfwDenied = verbose; 189c0956cf8SRuslan Ermilov /* 19059a7c613SBrian Somers * Open syslog channel. 19159a7c613SBrian Somers */ 1924c04fa4cSRuslan Ermilov openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0), 1934c04fa4cSRuslan Ermilov logFacility); 19422c62477SPoul-Henning Kamp 19522c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) { 19622c62477SPoul-Henning Kamp mla = mip->la; 19759a7c613SBrian Somers /* 1983d23e8b8SRuslan Ermilov * If not doing the transparent proxying only, 1993d23e8b8SRuslan Ermilov * check that valid aliasing address has been given. 20024084f9bSBrian Somers */ 20122c62477SPoul-Henning Kamp if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL && 20222c62477SPoul-Henning Kamp !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY)) 20322c62477SPoul-Henning Kamp errx (1, "instance %s: aliasing address not given", mip->name); 20424084f9bSBrian Somers 20522c62477SPoul-Henning Kamp if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL) 20667a886fbSBrian Somers errx (1, "both alias address and interface " 20767a886fbSBrian Somers "name are not allowed"); 20824084f9bSBrian Somers /* 20924084f9bSBrian Somers * Check that valid port number is known. 21024084f9bSBrian Somers */ 21122c62477SPoul-Henning Kamp if (mip->inPort != 0 || mip->outPort != 0) 21222c62477SPoul-Henning Kamp if (mip->inPort == 0 || mip->outPort == 0) 2130fc81af1SPhilippe Charnier errx (1, "both input and output ports are required"); 21424084f9bSBrian Somers 21522c62477SPoul-Henning Kamp if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0) 216b0f55af6SRuslan Ermilov ParseOption ("port", DEFAULT_SERVICE); 21724084f9bSBrian Somers 21824084f9bSBrian Somers /* 219f9b06d5cSBrian Somers * Check if ignored packets should be dropped. 220f9b06d5cSBrian Somers */ 22122c62477SPoul-Henning Kamp mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0); 22222c62477SPoul-Henning Kamp mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING; 223f9b06d5cSBrian Somers /* 22424084f9bSBrian Somers * Create divert sockets. Use only one socket if -p was specified 22524084f9bSBrian Somers * on command line. Otherwise, create separate sockets for 22624084f9bSBrian Somers * outgoing and incoming connnections. 22724084f9bSBrian Somers */ 22822c62477SPoul-Henning Kamp if (mip->inOutPort) { 22924084f9bSBrian Somers 23022c62477SPoul-Henning Kamp mip->divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 23122c62477SPoul-Henning Kamp if (mip->divertInOut == -1) 23224084f9bSBrian Somers Quit ("Unable to create divert socket."); 23322c62477SPoul-Henning Kamp if (mip->divertInOut > fdMax) 23422c62477SPoul-Henning Kamp fdMax = mip->divertInOut; 23524084f9bSBrian Somers 23622c62477SPoul-Henning Kamp mip->divertIn = -1; 23722c62477SPoul-Henning Kamp mip->divertOut = -1; 23824084f9bSBrian Somers /* 23924084f9bSBrian Somers * Bind socket. 24024084f9bSBrian Somers */ 24124084f9bSBrian Somers 24224084f9bSBrian Somers addr.sin_family = AF_INET; 24324084f9bSBrian Somers addr.sin_addr.s_addr = INADDR_ANY; 24422c62477SPoul-Henning Kamp addr.sin_port = mip->inOutPort; 24524084f9bSBrian Somers 24622c62477SPoul-Henning Kamp if (bind (mip->divertInOut, 24724084f9bSBrian Somers (struct sockaddr*) &addr, 24824084f9bSBrian Somers sizeof addr) == -1) 24924084f9bSBrian Somers Quit ("Unable to bind divert socket."); 25024084f9bSBrian Somers } 25124084f9bSBrian Somers else { 25224084f9bSBrian Somers 25322c62477SPoul-Henning Kamp mip->divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 25422c62477SPoul-Henning Kamp if (mip->divertIn == -1) 25524084f9bSBrian Somers Quit ("Unable to create incoming divert socket."); 25622c62477SPoul-Henning Kamp if (mip->divertIn > fdMax) 25722c62477SPoul-Henning Kamp fdMax = mip->divertIn; 25824084f9bSBrian Somers 25922c62477SPoul-Henning Kamp 26022c62477SPoul-Henning Kamp mip->divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 26122c62477SPoul-Henning Kamp if (mip->divertOut == -1) 26224084f9bSBrian Somers Quit ("Unable to create outgoing divert socket."); 26322c62477SPoul-Henning Kamp if (mip->divertOut > fdMax) 26422c62477SPoul-Henning Kamp fdMax = mip->divertOut; 26524084f9bSBrian Somers 26622c62477SPoul-Henning Kamp mip->divertInOut = -1; 26724084f9bSBrian Somers 26824084f9bSBrian Somers /* 26924084f9bSBrian Somers * Bind divert sockets. 27024084f9bSBrian Somers */ 27124084f9bSBrian Somers 27224084f9bSBrian Somers addr.sin_family = AF_INET; 27324084f9bSBrian Somers addr.sin_addr.s_addr = INADDR_ANY; 27422c62477SPoul-Henning Kamp addr.sin_port = mip->inPort; 27524084f9bSBrian Somers 27622c62477SPoul-Henning Kamp if (bind (mip->divertIn, 27724084f9bSBrian Somers (struct sockaddr*) &addr, 27824084f9bSBrian Somers sizeof addr) == -1) 27924084f9bSBrian Somers Quit ("Unable to bind incoming divert socket."); 28024084f9bSBrian Somers 28124084f9bSBrian Somers addr.sin_family = AF_INET; 28224084f9bSBrian Somers addr.sin_addr.s_addr = INADDR_ANY; 28322c62477SPoul-Henning Kamp addr.sin_port = mip->outPort; 28424084f9bSBrian Somers 28522c62477SPoul-Henning Kamp if (bind (mip->divertOut, 28624084f9bSBrian Somers (struct sockaddr*) &addr, 28724084f9bSBrian Somers sizeof addr) == -1) 28824084f9bSBrian Somers Quit ("Unable to bind outgoing divert socket."); 28924084f9bSBrian Somers } 29024084f9bSBrian Somers /* 291f2da55a2SRuslan Ermilov * Create routing socket if interface name specified and in dynamic mode. 29224084f9bSBrian Somers */ 29322c62477SPoul-Henning Kamp if (mip->ifName) { 294f2da55a2SRuslan Ermilov if (dynamicMode) { 29524084f9bSBrian Somers 29622c62477SPoul-Henning Kamp if (routeSock == -1) 29724084f9bSBrian Somers routeSock = socket (PF_ROUTE, SOCK_RAW, 0); 29824084f9bSBrian Somers if (routeSock == -1) 29924084f9bSBrian Somers Quit ("Unable to create routing info socket."); 30022c62477SPoul-Henning Kamp if (routeSock > fdMax) 30122c62477SPoul-Henning Kamp fdMax = routeSock; 302f2da55a2SRuslan Ermilov 30322c62477SPoul-Henning Kamp mip->assignAliasAddr = 1; 30424084f9bSBrian Somers } 3050afb958bSMaxim Sobolev else { 3060afb958bSMaxim Sobolev do { 3070afb958bSMaxim Sobolev rval = SetAliasAddressFromIfName (mip->ifName); 308*74def44dSMaxim Sobolev if (background != 0 && rval == EAGAIN) 3090afb958bSMaxim Sobolev sleep(1); 310*74def44dSMaxim Sobolev } while (background != 0 && rval == EAGAIN); 3110afb958bSMaxim Sobolev if (rval != 0) 3120afb958bSMaxim Sobolev exit(1); 3130afb958bSMaxim Sobolev } 31422c62477SPoul-Henning Kamp } 31522c62477SPoul-Henning Kamp 31622c62477SPoul-Henning Kamp } 31722c62477SPoul-Henning Kamp if (globalPort) { 31822c62477SPoul-Henning Kamp 31922c62477SPoul-Henning Kamp divertGlobal = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 32022c62477SPoul-Henning Kamp if (divertGlobal == -1) 32122c62477SPoul-Henning Kamp Quit ("Unable to create divert socket."); 32222c62477SPoul-Henning Kamp if (divertGlobal > fdMax) 32322c62477SPoul-Henning Kamp fdMax = divertGlobal; 32422c62477SPoul-Henning Kamp 32522c62477SPoul-Henning Kamp /* 32622c62477SPoul-Henning Kamp * Bind socket. 32722c62477SPoul-Henning Kamp */ 32822c62477SPoul-Henning Kamp 32922c62477SPoul-Henning Kamp addr.sin_family = AF_INET; 33022c62477SPoul-Henning Kamp addr.sin_addr.s_addr = INADDR_ANY; 33122c62477SPoul-Henning Kamp addr.sin_port = globalPort; 33222c62477SPoul-Henning Kamp 33322c62477SPoul-Henning Kamp if (bind (divertGlobal, 33422c62477SPoul-Henning Kamp (struct sockaddr*) &addr, 33522c62477SPoul-Henning Kamp sizeof addr) == -1) 33622c62477SPoul-Henning Kamp Quit ("Unable to bind global divert socket."); 337f2da55a2SRuslan Ermilov } 33824084f9bSBrian Somers /* 33924084f9bSBrian Somers * Create socket for sending ICMP messages. 34024084f9bSBrian Somers */ 34124084f9bSBrian Somers icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); 34224084f9bSBrian Somers if (icmpSock == -1) 34324084f9bSBrian Somers Quit ("Unable to create ICMP socket."); 344f3d64024SBrian Somers 345f3d64024SBrian Somers /* 346f3d64024SBrian Somers * And disable reads for the socket, otherwise it slowly fills 347f3d64024SBrian Somers * up with received icmps which we do not use. 348f3d64024SBrian Somers */ 349f3d64024SBrian Somers shutdown(icmpSock, SHUT_RD); 350f3d64024SBrian Somers 35124084f9bSBrian Somers /* 35224084f9bSBrian Somers * Become a daemon unless verbose mode was requested. 35324084f9bSBrian Somers */ 35424084f9bSBrian Somers if (!verbose) 35524084f9bSBrian Somers DaemonMode (); 35624084f9bSBrian Somers /* 35724084f9bSBrian Somers * Catch signals to manage shutdown and 35824084f9bSBrian Somers * refresh of interface address. 35924084f9bSBrian Somers */ 360cd45c931SRuslan Ermilov siginterrupt(SIGTERM, 1); 361cd45c931SRuslan Ermilov siginterrupt(SIGHUP, 1); 36272cbe4adSAlexander Motin if (exitDelay) 36324084f9bSBrian Somers signal(SIGTERM, InitiateShutdown); 36472cbe4adSAlexander Motin else 36572cbe4adSAlexander Motin signal(SIGTERM, Shutdown); 36624084f9bSBrian Somers signal (SIGHUP, RefreshAddr); 36724084f9bSBrian Somers /* 36824084f9bSBrian Somers * Set alias address if it has been given. 36924084f9bSBrian Somers */ 37022c62477SPoul-Henning Kamp mip = LIST_FIRST(&root); /* XXX: simon */ 37122c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) { 37222c62477SPoul-Henning Kamp mla = mip->la; 37322c62477SPoul-Henning Kamp if (mip->aliasAddr.s_addr != INADDR_NONE) 37422c62477SPoul-Henning Kamp LibAliasSetAddress (mla, mip->aliasAddr); 37522c62477SPoul-Henning Kamp } 37624084f9bSBrian Somers 37724084f9bSBrian Somers while (running) { 37822c62477SPoul-Henning Kamp mip = LIST_FIRST(&root); /* XXX: simon */ 379fb994b07SBrian Somers 38022c62477SPoul-Henning Kamp if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) { 381fb994b07SBrian Somers /* 382fb994b07SBrian Somers * When using only one socket, just call 383fb994b07SBrian Somers * DoAliasing repeatedly to process packets. 384fb994b07SBrian Somers */ 38522c62477SPoul-Henning Kamp DoAliasing (mip->divertInOut, DONT_KNOW); 386fb994b07SBrian Somers continue; 387fb994b07SBrian Somers } 38824084f9bSBrian Somers /* 38924084f9bSBrian Somers * Build read mask from socket descriptors to select. 39024084f9bSBrian Somers */ 39124084f9bSBrian Somers FD_ZERO (&readMask); 392fb994b07SBrian Somers /* 3933daff242SRuslan Ermilov * Check if new packets are available. 394fb994b07SBrian Somers */ 39522c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) { 39622c62477SPoul-Henning Kamp if (mip->divertIn != -1) 39722c62477SPoul-Henning Kamp FD_SET (mip->divertIn, &readMask); 39824084f9bSBrian Somers 39922c62477SPoul-Henning Kamp if (mip->divertOut != -1) 40022c62477SPoul-Henning Kamp FD_SET (mip->divertOut, &readMask); 40124084f9bSBrian Somers 40222c62477SPoul-Henning Kamp if (mip->divertInOut != -1) 40322c62477SPoul-Henning Kamp FD_SET (mip->divertInOut, &readMask); 40422c62477SPoul-Henning Kamp } 405fb994b07SBrian Somers /* 406fb994b07SBrian Somers * Routing info is processed always. 407fb994b07SBrian Somers */ 40824084f9bSBrian Somers if (routeSock != -1) 40924084f9bSBrian Somers FD_SET (routeSock, &readMask); 41024084f9bSBrian Somers 41122c62477SPoul-Henning Kamp if (divertGlobal != -1) 41222c62477SPoul-Henning Kamp FD_SET (divertGlobal, &readMask); 41322c62477SPoul-Henning Kamp 41424084f9bSBrian Somers if (select (fdMax + 1, 41524084f9bSBrian Somers &readMask, 4163daff242SRuslan Ermilov NULL, 41724084f9bSBrian Somers NULL, 41824084f9bSBrian Somers NULL) == -1) { 41924084f9bSBrian Somers 42024084f9bSBrian Somers if (errno == EINTR) 42124084f9bSBrian Somers continue; 42224084f9bSBrian Somers 42324084f9bSBrian Somers Quit ("Select failed."); 42424084f9bSBrian Somers } 42524084f9bSBrian Somers 42622c62477SPoul-Henning Kamp if (divertGlobal != -1) 42722c62477SPoul-Henning Kamp if (FD_ISSET (divertGlobal, &readMask)) 42822c62477SPoul-Henning Kamp DoGlobal (divertGlobal); 42922c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) { 43022c62477SPoul-Henning Kamp mla = mip->la; 43122c62477SPoul-Henning Kamp if (mip->divertIn != -1) 43222c62477SPoul-Henning Kamp if (FD_ISSET (mip->divertIn, &readMask)) 43322c62477SPoul-Henning Kamp DoAliasing (mip->divertIn, INPUT); 43424084f9bSBrian Somers 43522c62477SPoul-Henning Kamp if (mip->divertOut != -1) 43622c62477SPoul-Henning Kamp if (FD_ISSET (mip->divertOut, &readMask)) 43722c62477SPoul-Henning Kamp DoAliasing (mip->divertOut, OUTPUT); 43824084f9bSBrian Somers 43922c62477SPoul-Henning Kamp if (mip->divertInOut != -1) 44022c62477SPoul-Henning Kamp if (FD_ISSET (mip->divertInOut, &readMask)) 44122c62477SPoul-Henning Kamp DoAliasing (mip->divertInOut, DONT_KNOW); 44224084f9bSBrian Somers 44322c62477SPoul-Henning Kamp } 44424084f9bSBrian Somers if (routeSock != -1) 44524084f9bSBrian Somers if (FD_ISSET (routeSock, &readMask)) 44624084f9bSBrian Somers HandleRoutingInfo (routeSock); 44724084f9bSBrian Somers } 44824084f9bSBrian Somers 44924084f9bSBrian Somers if (background) 450b79840a6SRuslan Ermilov unlink (pidName); 45124084f9bSBrian Somers 45224084f9bSBrian Somers return 0; 45324084f9bSBrian Somers } 45424084f9bSBrian Somers 4557154ce64SEd Schouten static void DaemonMode(void) 45624084f9bSBrian Somers { 45724084f9bSBrian Somers FILE* pidFile; 45824084f9bSBrian Somers 45924084f9bSBrian Somers daemon (0, 0); 46024084f9bSBrian Somers background = 1; 46124084f9bSBrian Somers 462b79840a6SRuslan Ermilov pidFile = fopen (pidName, "w"); 46324084f9bSBrian Somers if (pidFile) { 46424084f9bSBrian Somers 46524084f9bSBrian Somers fprintf (pidFile, "%d\n", getpid ()); 46624084f9bSBrian Somers fclose (pidFile); 46724084f9bSBrian Somers } 46824084f9bSBrian Somers } 46924084f9bSBrian Somers 47024084f9bSBrian Somers static void ParseArgs (int argc, char** argv) 47124084f9bSBrian Somers { 47224084f9bSBrian Somers int arg; 47324084f9bSBrian Somers char* opt; 47424084f9bSBrian Somers char parmBuf[256]; 47530395bb5SJosef Karthauser int len; /* bounds checking */ 47624084f9bSBrian Somers 47724084f9bSBrian Somers for (arg = 1; arg < argc; arg++) { 47824084f9bSBrian Somers 47924084f9bSBrian Somers opt = argv[arg]; 48024084f9bSBrian Somers if (*opt != '-') { 48124084f9bSBrian Somers 4820fc81af1SPhilippe Charnier warnx ("invalid option %s", opt); 48324084f9bSBrian Somers Usage (); 48424084f9bSBrian Somers } 48524084f9bSBrian Somers 48624084f9bSBrian Somers parmBuf[0] = '\0'; 48730395bb5SJosef Karthauser len = 0; 48824084f9bSBrian Somers 48924084f9bSBrian Somers while (arg < argc - 1) { 49024084f9bSBrian Somers 49124084f9bSBrian Somers if (argv[arg + 1][0] == '-') 49224084f9bSBrian Somers break; 49324084f9bSBrian Somers 49430395bb5SJosef Karthauser if (len) { 49530395bb5SJosef Karthauser strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1)); 49630395bb5SJosef Karthauser len += strlen(parmBuf + len); 49724084f9bSBrian Somers } 49824084f9bSBrian Somers 49930395bb5SJosef Karthauser ++arg; 50030395bb5SJosef Karthauser strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1)); 50130395bb5SJosef Karthauser len += strlen(parmBuf + len); 50230395bb5SJosef Karthauser 50330395bb5SJosef Karthauser } 50430395bb5SJosef Karthauser 505b0f55af6SRuslan Ermilov ParseOption (opt + 1, (len ? parmBuf : NULL)); 50630395bb5SJosef Karthauser 50724084f9bSBrian Somers } 50824084f9bSBrian Somers } 50924084f9bSBrian Somers 51022c62477SPoul-Henning Kamp static void DoGlobal (int fd) 51122c62477SPoul-Henning Kamp { 51222c62477SPoul-Henning Kamp int bytes; 51322c62477SPoul-Henning Kamp int origBytes; 51422c62477SPoul-Henning Kamp char buf[IP_MAXPACKET]; 51522c62477SPoul-Henning Kamp struct sockaddr_in addr; 51622c62477SPoul-Henning Kamp int wrote; 51748ce8ca1SXin LI socklen_t addrSize; 51822c62477SPoul-Henning Kamp struct ip* ip; 51922c62477SPoul-Henning Kamp char msgBuf[80]; 52022c62477SPoul-Henning Kamp 52122c62477SPoul-Henning Kamp /* 52222c62477SPoul-Henning Kamp * Get packet from socket. 52322c62477SPoul-Henning Kamp */ 52422c62477SPoul-Henning Kamp addrSize = sizeof addr; 52522c62477SPoul-Henning Kamp origBytes = recvfrom (fd, 52622c62477SPoul-Henning Kamp buf, 52722c62477SPoul-Henning Kamp sizeof buf, 52822c62477SPoul-Henning Kamp 0, 52922c62477SPoul-Henning Kamp (struct sockaddr*) &addr, 53022c62477SPoul-Henning Kamp &addrSize); 53122c62477SPoul-Henning Kamp 53222c62477SPoul-Henning Kamp if (origBytes == -1) { 53322c62477SPoul-Henning Kamp 53422c62477SPoul-Henning Kamp if (errno != EINTR) 53522c62477SPoul-Henning Kamp Warn ("read from divert socket failed"); 53622c62477SPoul-Henning Kamp 53722c62477SPoul-Henning Kamp return; 53822c62477SPoul-Henning Kamp } 53922c62477SPoul-Henning Kamp 54022c62477SPoul-Henning Kamp #if 0 54122c62477SPoul-Henning Kamp if (mip->assignAliasAddr) { 5420afb958bSMaxim Sobolev if (SetAliasAddressFromIfName (mip->ifName) != 0) 5430afb958bSMaxim Sobolev exit(1); 54422c62477SPoul-Henning Kamp mip->assignAliasAddr = 0; 54522c62477SPoul-Henning Kamp } 54622c62477SPoul-Henning Kamp #endif 54722c62477SPoul-Henning Kamp /* 54822c62477SPoul-Henning Kamp * This is an IP packet. 54922c62477SPoul-Henning Kamp */ 55022c62477SPoul-Henning Kamp ip = (struct ip*) buf; 55122c62477SPoul-Henning Kamp 55222c62477SPoul-Henning Kamp if (verbose) { 55322c62477SPoul-Henning Kamp /* 55422c62477SPoul-Henning Kamp * Print packet direction and protocol type. 55522c62477SPoul-Henning Kamp */ 55622c62477SPoul-Henning Kamp printf ("Glb "); 55722c62477SPoul-Henning Kamp 55822c62477SPoul-Henning Kamp switch (ip->ip_p) { 55922c62477SPoul-Henning Kamp case IPPROTO_TCP: 56022c62477SPoul-Henning Kamp printf ("[TCP] "); 56122c62477SPoul-Henning Kamp break; 56222c62477SPoul-Henning Kamp 56322c62477SPoul-Henning Kamp case IPPROTO_UDP: 56422c62477SPoul-Henning Kamp printf ("[UDP] "); 56522c62477SPoul-Henning Kamp break; 56622c62477SPoul-Henning Kamp 56722c62477SPoul-Henning Kamp case IPPROTO_ICMP: 56822c62477SPoul-Henning Kamp printf ("[ICMP] "); 56922c62477SPoul-Henning Kamp break; 57022c62477SPoul-Henning Kamp 57122c62477SPoul-Henning Kamp default: 57222c62477SPoul-Henning Kamp printf ("[%d] ", ip->ip_p); 57322c62477SPoul-Henning Kamp break; 57422c62477SPoul-Henning Kamp } 57522c62477SPoul-Henning Kamp /* 57622c62477SPoul-Henning Kamp * Print addresses. 57722c62477SPoul-Henning Kamp */ 57822c62477SPoul-Henning Kamp PrintPacket (ip); 57922c62477SPoul-Henning Kamp } 58022c62477SPoul-Henning Kamp 58122c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) { 58222c62477SPoul-Henning Kamp mla = mip->la; 58322c62477SPoul-Henning Kamp if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED) 58422c62477SPoul-Henning Kamp break; 58522c62477SPoul-Henning Kamp } 58622c62477SPoul-Henning Kamp /* 58722c62477SPoul-Henning Kamp * Length might have changed during aliasing. 58822c62477SPoul-Henning Kamp */ 58922c62477SPoul-Henning Kamp bytes = ntohs (ip->ip_len); 59022c62477SPoul-Henning Kamp /* 59122c62477SPoul-Henning Kamp * Update alias overhead size for outgoing packets. 59222c62477SPoul-Henning Kamp */ 59322c62477SPoul-Henning Kamp if (mip != NULL && bytes - origBytes > mip->aliasOverhead) 59422c62477SPoul-Henning Kamp mip->aliasOverhead = bytes - origBytes; 59522c62477SPoul-Henning Kamp 59622c62477SPoul-Henning Kamp if (verbose) { 59722c62477SPoul-Henning Kamp 59822c62477SPoul-Henning Kamp /* 59922c62477SPoul-Henning Kamp * Print addresses after aliasing. 60022c62477SPoul-Henning Kamp */ 60122c62477SPoul-Henning Kamp printf (" aliased to\n"); 60222c62477SPoul-Henning Kamp printf (" "); 60322c62477SPoul-Henning Kamp PrintPacket (ip); 60422c62477SPoul-Henning Kamp printf ("\n"); 60522c62477SPoul-Henning Kamp } 60622c62477SPoul-Henning Kamp 60722c62477SPoul-Henning Kamp /* 60822c62477SPoul-Henning Kamp * Put packet back for processing. 60922c62477SPoul-Henning Kamp */ 61022c62477SPoul-Henning Kamp wrote = sendto (fd, 61122c62477SPoul-Henning Kamp buf, 61222c62477SPoul-Henning Kamp bytes, 61322c62477SPoul-Henning Kamp 0, 61422c62477SPoul-Henning Kamp (struct sockaddr*) &addr, 61522c62477SPoul-Henning Kamp sizeof addr); 61622c62477SPoul-Henning Kamp 61722c62477SPoul-Henning Kamp if (wrote != bytes) { 61822c62477SPoul-Henning Kamp 61922c62477SPoul-Henning Kamp if (errno == EMSGSIZE) { 62022c62477SPoul-Henning Kamp 62122c62477SPoul-Henning Kamp if (mip->ifMTU != -1) 62222c62477SPoul-Henning Kamp SendNeedFragIcmp (icmpSock, 62322c62477SPoul-Henning Kamp (struct ip*) buf, 62422c62477SPoul-Henning Kamp mip->ifMTU - mip->aliasOverhead); 62522c62477SPoul-Henning Kamp } 62622c62477SPoul-Henning Kamp else if (errno == EACCES && logIpfwDenied) { 62722c62477SPoul-Henning Kamp 62822c62477SPoul-Henning Kamp sprintf (msgBuf, "failed to write packet back"); 62922c62477SPoul-Henning Kamp Warn (msgBuf); 63022c62477SPoul-Henning Kamp } 63122c62477SPoul-Henning Kamp } 63222c62477SPoul-Henning Kamp } 63322c62477SPoul-Henning Kamp 63422c62477SPoul-Henning Kamp 63559a7c613SBrian Somers static void DoAliasing (int fd, int direction) 63624084f9bSBrian Somers { 63724084f9bSBrian Somers int bytes; 63824084f9bSBrian Somers int origBytes; 6393daff242SRuslan Ermilov char buf[IP_MAXPACKET]; 6403daff242SRuslan Ermilov struct sockaddr_in addr; 6413daff242SRuslan Ermilov int wrote; 642f9b06d5cSBrian Somers int status; 64348ce8ca1SXin LI socklen_t addrSize; 64424084f9bSBrian Somers struct ip* ip; 6453daff242SRuslan Ermilov char msgBuf[80]; 6460afb958bSMaxim Sobolev int rval; 64724084f9bSBrian Somers 64822c62477SPoul-Henning Kamp if (mip->assignAliasAddr) { 6490afb958bSMaxim Sobolev do { 6500afb958bSMaxim Sobolev rval = SetAliasAddressFromIfName (mip->ifName); 651*74def44dSMaxim Sobolev if (background != 0 && rval == EAGAIN) 6520afb958bSMaxim Sobolev sleep(1); 653*74def44dSMaxim Sobolev } while (background != 0 && rval == EAGAIN); 6540afb958bSMaxim Sobolev if (rval != 0) 6550afb958bSMaxim Sobolev exit(1); 65622c62477SPoul-Henning Kamp mip->assignAliasAddr = 0; 65724084f9bSBrian Somers } 65824084f9bSBrian Somers /* 65924084f9bSBrian Somers * Get packet from socket. 66024084f9bSBrian Somers */ 6613daff242SRuslan Ermilov addrSize = sizeof addr; 66224084f9bSBrian Somers origBytes = recvfrom (fd, 6633daff242SRuslan Ermilov buf, 6643daff242SRuslan Ermilov sizeof buf, 66524084f9bSBrian Somers 0, 6663daff242SRuslan Ermilov (struct sockaddr*) &addr, 66724084f9bSBrian Somers &addrSize); 66824084f9bSBrian Somers 66924084f9bSBrian Somers if (origBytes == -1) { 67024084f9bSBrian Somers 67124084f9bSBrian Somers if (errno != EINTR) 6720fc81af1SPhilippe Charnier Warn ("read from divert socket failed"); 67324084f9bSBrian Somers 67424084f9bSBrian Somers return; 67524084f9bSBrian Somers } 67624084f9bSBrian Somers /* 6779d5abbddSJens Schweikhardt * This is an IP packet. 67824084f9bSBrian Somers */ 6793daff242SRuslan Ermilov ip = (struct ip*) buf; 680ebe70c8fSWarner Losh if (direction == DONT_KNOW) { 6813daff242SRuslan Ermilov if (addr.sin_addr.s_addr == INADDR_ANY) 68259a7c613SBrian Somers direction = OUTPUT; 68359a7c613SBrian Somers else 68459a7c613SBrian Somers direction = INPUT; 685ebe70c8fSWarner Losh } 68624084f9bSBrian Somers 68724084f9bSBrian Somers if (verbose) { 68824084f9bSBrian Somers /* 68924084f9bSBrian Somers * Print packet direction and protocol type. 69024084f9bSBrian Somers */ 69159a7c613SBrian Somers printf (direction == OUTPUT ? "Out " : "In "); 69222c62477SPoul-Henning Kamp if (ninstance > 1) 69348ce8ca1SXin LI printf ("{%s}", mip->name); 69424084f9bSBrian Somers 69524084f9bSBrian Somers switch (ip->ip_p) { 69624084f9bSBrian Somers case IPPROTO_TCP: 69724084f9bSBrian Somers printf ("[TCP] "); 69824084f9bSBrian Somers break; 69924084f9bSBrian Somers 70024084f9bSBrian Somers case IPPROTO_UDP: 70124084f9bSBrian Somers printf ("[UDP] "); 70224084f9bSBrian Somers break; 70324084f9bSBrian Somers 70424084f9bSBrian Somers case IPPROTO_ICMP: 70524084f9bSBrian Somers printf ("[ICMP] "); 70624084f9bSBrian Somers break; 70724084f9bSBrian Somers 70824084f9bSBrian Somers default: 70959a7c613SBrian Somers printf ("[%d] ", ip->ip_p); 71024084f9bSBrian Somers break; 71124084f9bSBrian Somers } 71224084f9bSBrian Somers /* 71324084f9bSBrian Somers * Print addresses. 71424084f9bSBrian Somers */ 71524084f9bSBrian Somers PrintPacket (ip); 71624084f9bSBrian Somers } 71724084f9bSBrian Somers 71859a7c613SBrian Somers if (direction == OUTPUT) { 71924084f9bSBrian Somers /* 72024084f9bSBrian Somers * Outgoing packets. Do aliasing. 72124084f9bSBrian Somers */ 72222c62477SPoul-Henning Kamp LibAliasOut (mla, buf, IP_MAXPACKET); 72324084f9bSBrian Somers } 72424084f9bSBrian Somers else { 72559a7c613SBrian Somers 72624084f9bSBrian Somers /* 72724084f9bSBrian Somers * Do aliasing. 72824084f9bSBrian Somers */ 72922c62477SPoul-Henning Kamp status = LibAliasIn (mla, buf, IP_MAXPACKET); 730f9b06d5cSBrian Somers if (status == PKT_ALIAS_IGNORED && 73122c62477SPoul-Henning Kamp mip->dropIgnoredIncoming) { 732f9b06d5cSBrian Somers 73359a7c613SBrian Somers if (verbose) 734f9b06d5cSBrian Somers printf (" dropped.\n"); 73559a7c613SBrian Somers 73622c62477SPoul-Henning Kamp if (mip->logDropped) 73759a7c613SBrian Somers SyslogPacket (ip, LOG_WARNING, "denied"); 73859a7c613SBrian Somers 739f9b06d5cSBrian Somers return; 740f9b06d5cSBrian Somers } 74124084f9bSBrian Somers } 74224084f9bSBrian Somers /* 74324084f9bSBrian Somers * Length might have changed during aliasing. 74424084f9bSBrian Somers */ 74524084f9bSBrian Somers bytes = ntohs (ip->ip_len); 74624084f9bSBrian Somers /* 74724084f9bSBrian Somers * Update alias overhead size for outgoing packets. 74824084f9bSBrian Somers */ 74959a7c613SBrian Somers if (direction == OUTPUT && 75022c62477SPoul-Henning Kamp bytes - origBytes > mip->aliasOverhead) 75122c62477SPoul-Henning Kamp mip->aliasOverhead = bytes - origBytes; 75224084f9bSBrian Somers 75324084f9bSBrian Somers if (verbose) { 75424084f9bSBrian Somers 75524084f9bSBrian Somers /* 75624084f9bSBrian Somers * Print addresses after aliasing. 75724084f9bSBrian Somers */ 75824084f9bSBrian Somers printf (" aliased to\n"); 75924084f9bSBrian Somers printf (" "); 76024084f9bSBrian Somers PrintPacket (ip); 76124084f9bSBrian Somers printf ("\n"); 76224084f9bSBrian Somers } 763fb994b07SBrian Somers 76424084f9bSBrian Somers /* 76524084f9bSBrian Somers * Put packet back for processing. 76624084f9bSBrian Somers */ 76724084f9bSBrian Somers wrote = sendto (fd, 7683daff242SRuslan Ermilov buf, 7693daff242SRuslan Ermilov bytes, 77024084f9bSBrian Somers 0, 7713daff242SRuslan Ermilov (struct sockaddr*) &addr, 7723daff242SRuslan Ermilov sizeof addr); 77324084f9bSBrian Somers 7743daff242SRuslan Ermilov if (wrote != bytes) { 77524084f9bSBrian Somers 77624084f9bSBrian Somers if (errno == EMSGSIZE) { 77724084f9bSBrian Somers 7783daff242SRuslan Ermilov if (direction == OUTPUT && 77922c62477SPoul-Henning Kamp mip->ifMTU != -1) 78024084f9bSBrian Somers SendNeedFragIcmp (icmpSock, 7813daff242SRuslan Ermilov (struct ip*) buf, 78222c62477SPoul-Henning Kamp mip->ifMTU - mip->aliasOverhead); 78324084f9bSBrian Somers } 7843843533eSRuslan Ermilov else if (errno == EACCES && logIpfwDenied) { 78524084f9bSBrian Somers 786d782daf0SJosef Karthauser sprintf (msgBuf, "failed to write packet back"); 78724084f9bSBrian Somers Warn (msgBuf); 78824084f9bSBrian Somers } 78924084f9bSBrian Somers } 79024084f9bSBrian Somers } 79124084f9bSBrian Somers 79224084f9bSBrian Somers static void HandleRoutingInfo (int fd) 79324084f9bSBrian Somers { 79424084f9bSBrian Somers int bytes; 79524084f9bSBrian Somers struct if_msghdr ifMsg; 79624084f9bSBrian Somers /* 79724084f9bSBrian Somers * Get packet from socket. 79824084f9bSBrian Somers */ 79924084f9bSBrian Somers bytes = read (fd, &ifMsg, sizeof ifMsg); 80024084f9bSBrian Somers if (bytes == -1) { 80124084f9bSBrian Somers 8020fc81af1SPhilippe Charnier Warn ("read from routing socket failed"); 80324084f9bSBrian Somers return; 80424084f9bSBrian Somers } 80524084f9bSBrian Somers 80624084f9bSBrian Somers if (ifMsg.ifm_version != RTM_VERSION) { 80724084f9bSBrian Somers 8080fc81af1SPhilippe Charnier Warn ("unexpected packet read from routing socket"); 80924084f9bSBrian Somers return; 81024084f9bSBrian Somers } 81124084f9bSBrian Somers 81224084f9bSBrian Somers if (verbose) 8136f3dbe5eSRuslan Ermilov printf ("Routing message %#x received.\n", ifMsg.ifm_type); 81424084f9bSBrian Somers 81522c62477SPoul-Henning Kamp if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) { 81622c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) { 81722c62477SPoul-Henning Kamp mla = mip->la; 81822c62477SPoul-Henning Kamp if (ifMsg.ifm_index == mip->ifIndex) { 8196f3dbe5eSRuslan Ermilov if (verbose) 8206f3dbe5eSRuslan Ermilov printf("Interface address/MTU has probably changed.\n"); 82122c62477SPoul-Henning Kamp mip->assignAliasAddr = 1; 82222c62477SPoul-Henning Kamp } 82322c62477SPoul-Henning Kamp } 82424084f9bSBrian Somers } 8256f3dbe5eSRuslan Ermilov } 82624084f9bSBrian Somers 82724084f9bSBrian Somers static void PrintPacket (struct ip* ip) 82824084f9bSBrian Somers { 82959a7c613SBrian Somers printf ("%s", FormatPacket (ip)); 83059a7c613SBrian Somers } 83159a7c613SBrian Somers 832902cb50aSBrian Somers static void SyslogPacket (struct ip* ip, int priority, const char *label) 83359a7c613SBrian Somers { 83459a7c613SBrian Somers syslog (priority, "%s %s", label, FormatPacket (ip)); 83559a7c613SBrian Somers } 83659a7c613SBrian Somers 83759a7c613SBrian Somers static char* FormatPacket (struct ip* ip) 83859a7c613SBrian Somers { 83959a7c613SBrian Somers static char buf[256]; 84024084f9bSBrian Somers struct tcphdr* tcphdr; 84159a7c613SBrian Somers struct udphdr* udphdr; 84259a7c613SBrian Somers struct icmp* icmphdr; 84359a7c613SBrian Somers char src[20]; 84459a7c613SBrian Somers char dst[20]; 84524084f9bSBrian Somers 84659a7c613SBrian Somers strcpy (src, inet_ntoa (ip->ip_src)); 84759a7c613SBrian Somers strcpy (dst, inet_ntoa (ip->ip_dst)); 84859a7c613SBrian Somers 84959a7c613SBrian Somers switch (ip->ip_p) { 85059a7c613SBrian Somers case IPPROTO_TCP: 85124084f9bSBrian Somers tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2)); 85259a7c613SBrian Somers sprintf (buf, "[TCP] %s:%d -> %s:%d", 85359a7c613SBrian Somers src, 85459a7c613SBrian Somers ntohs (tcphdr->th_sport), 85559a7c613SBrian Somers dst, 85659a7c613SBrian Somers ntohs (tcphdr->th_dport)); 85759a7c613SBrian Somers break; 85824084f9bSBrian Somers 85959a7c613SBrian Somers case IPPROTO_UDP: 86059a7c613SBrian Somers udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2)); 86159a7c613SBrian Somers sprintf (buf, "[UDP] %s:%d -> %s:%d", 86259a7c613SBrian Somers src, 86359a7c613SBrian Somers ntohs (udphdr->uh_sport), 86459a7c613SBrian Somers dst, 86559a7c613SBrian Somers ntohs (udphdr->uh_dport)); 86659a7c613SBrian Somers break; 86724084f9bSBrian Somers 86859a7c613SBrian Somers case IPPROTO_ICMP: 86959a7c613SBrian Somers icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2)); 870b71e869dSBrian Somers sprintf (buf, "[ICMP] %s -> %s %u(%u)", 87159a7c613SBrian Somers src, 87259a7c613SBrian Somers dst, 873b71e869dSBrian Somers icmphdr->icmp_type, 874b71e869dSBrian Somers icmphdr->icmp_code); 87559a7c613SBrian Somers break; 87659a7c613SBrian Somers 87759a7c613SBrian Somers default: 87859a7c613SBrian Somers sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst); 87959a7c613SBrian Somers break; 88059a7c613SBrian Somers } 88159a7c613SBrian Somers 88259a7c613SBrian Somers return buf; 88324084f9bSBrian Somers } 88424084f9bSBrian Somers 8850afb958bSMaxim Sobolev static int 8864c04fa4cSRuslan Ermilov SetAliasAddressFromIfName(const char *ifn) 88724084f9bSBrian Somers { 8884c04fa4cSRuslan Ermilov size_t needed; 8894c04fa4cSRuslan Ermilov int mib[6]; 8904c04fa4cSRuslan Ermilov char *buf, *lim, *next; 8914c04fa4cSRuslan Ermilov struct if_msghdr *ifm; 8924c04fa4cSRuslan Ermilov struct ifa_msghdr *ifam; 8934c04fa4cSRuslan Ermilov struct sockaddr_dl *sdl; 8944c04fa4cSRuslan Ermilov struct sockaddr_in *sin; 89524084f9bSBrian Somers 8964c04fa4cSRuslan Ermilov mib[0] = CTL_NET; 8974c04fa4cSRuslan Ermilov mib[1] = PF_ROUTE; 8984c04fa4cSRuslan Ermilov mib[2] = 0; 8994c04fa4cSRuslan Ermilov mib[3] = AF_INET; /* Only IP addresses please */ 9004c04fa4cSRuslan Ermilov mib[4] = NET_RT_IFLIST; 9014c04fa4cSRuslan Ermilov mib[5] = 0; /* ifIndex??? */ 90224084f9bSBrian Somers /* 90324084f9bSBrian Somers * Get interface data. 90424084f9bSBrian Somers */ 9054c04fa4cSRuslan Ermilov if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) 9064c04fa4cSRuslan Ermilov err(1, "iflist-sysctl-estimate"); 9074c04fa4cSRuslan Ermilov if ((buf = malloc(needed)) == NULL) 9084c04fa4cSRuslan Ermilov errx(1, "malloc failed"); 909ec95e4c2SBrian Somers if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1 && errno != ENOMEM) 9104c04fa4cSRuslan Ermilov err(1, "iflist-sysctl-get"); 9114c04fa4cSRuslan Ermilov lim = buf + needed; 91224084f9bSBrian Somers /* 91324084f9bSBrian Somers * Loop through interfaces until one with 91424084f9bSBrian Somers * given name is found. This is done to 91524084f9bSBrian Somers * find correct interface index for routing 91624084f9bSBrian Somers * message processing. 91724084f9bSBrian Somers */ 91822c62477SPoul-Henning Kamp mip->ifIndex = 0; 9194c04fa4cSRuslan Ermilov next = buf; 9204c04fa4cSRuslan Ermilov while (next < lim) { 9214c04fa4cSRuslan Ermilov ifm = (struct if_msghdr *)next; 9224c04fa4cSRuslan Ermilov next += ifm->ifm_msglen; 9234c04fa4cSRuslan Ermilov if (ifm->ifm_version != RTM_VERSION) { 9244c04fa4cSRuslan Ermilov if (verbose) 9254c04fa4cSRuslan Ermilov warnx("routing message version %d " 9264c04fa4cSRuslan Ermilov "not understood", ifm->ifm_version); 9274c04fa4cSRuslan Ermilov continue; 9284c04fa4cSRuslan Ermilov } 9294c04fa4cSRuslan Ermilov if (ifm->ifm_type == RTM_IFINFO) { 9304c04fa4cSRuslan Ermilov sdl = (struct sockaddr_dl *)(ifm + 1); 9314c04fa4cSRuslan Ermilov if (strlen(ifn) == sdl->sdl_nlen && 9324c04fa4cSRuslan Ermilov strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) { 93322c62477SPoul-Henning Kamp mip->ifIndex = ifm->ifm_index; 93422c62477SPoul-Henning Kamp mip->ifMTU = ifm->ifm_data.ifi_mtu; 93524084f9bSBrian Somers break; 93624084f9bSBrian Somers } 93724084f9bSBrian Somers } 93824084f9bSBrian Somers } 93922c62477SPoul-Henning Kamp if (!mip->ifIndex) 9404c04fa4cSRuslan Ermilov errx(1, "unknown interface name %s", ifn); 94124084f9bSBrian Somers /* 94224084f9bSBrian Somers * Get interface address. 94324084f9bSBrian Somers */ 9444c04fa4cSRuslan Ermilov sin = NULL; 9454c04fa4cSRuslan Ermilov while (next < lim) { 9464c04fa4cSRuslan Ermilov ifam = (struct ifa_msghdr *)next; 9474c04fa4cSRuslan Ermilov next += ifam->ifam_msglen; 9484c04fa4cSRuslan Ermilov if (ifam->ifam_version != RTM_VERSION) { 9494c04fa4cSRuslan Ermilov if (verbose) 9504c04fa4cSRuslan Ermilov warnx("routing message version %d " 9514c04fa4cSRuslan Ermilov "not understood", ifam->ifam_version); 9524c04fa4cSRuslan Ermilov continue; 9534c04fa4cSRuslan Ermilov } 9544c04fa4cSRuslan Ermilov if (ifam->ifam_type != RTM_NEWADDR) 9554c04fa4cSRuslan Ermilov break; 9564c04fa4cSRuslan Ermilov if (ifam->ifam_addrs & RTA_IFA) { 9574c04fa4cSRuslan Ermilov int i; 9584c04fa4cSRuslan Ermilov char *cp = (char *)(ifam + 1); 95924084f9bSBrian Somers 9604c04fa4cSRuslan Ermilov for (i = 1; i < RTA_IFA; i <<= 1) 9614c04fa4cSRuslan Ermilov if (ifam->ifam_addrs & i) 9620b46c085SLuigi Rizzo cp += SA_SIZE((struct sockaddr *)cp); 9634c04fa4cSRuslan Ermilov if (((struct sockaddr *)cp)->sa_family == AF_INET) { 9644c04fa4cSRuslan Ermilov sin = (struct sockaddr_in *)cp; 9654c04fa4cSRuslan Ermilov break; 9664c04fa4cSRuslan Ermilov } 9674c04fa4cSRuslan Ermilov } 9684c04fa4cSRuslan Ermilov } 9690afb958bSMaxim Sobolev if (sin == NULL) { 9700afb958bSMaxim Sobolev warnx("%s: cannot get interface address", ifn); 9710afb958bSMaxim Sobolev free(buf); 972*74def44dSMaxim Sobolev return EAGAIN; 9730afb958bSMaxim Sobolev } 9744c04fa4cSRuslan Ermilov 97522c62477SPoul-Henning Kamp LibAliasSetAddress(mla, sin->sin_addr); 97624084f9bSBrian Somers syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes", 97722c62477SPoul-Henning Kamp inet_ntoa(sin->sin_addr), mip->ifMTU); 97824084f9bSBrian Somers 9794c04fa4cSRuslan Ermilov free(buf); 9800afb958bSMaxim Sobolev 9810afb958bSMaxim Sobolev return 0; 98224084f9bSBrian Somers } 98324084f9bSBrian Somers 984902cb50aSBrian Somers void Quit (const char* msg) 98524084f9bSBrian Somers { 98624084f9bSBrian Somers Warn (msg); 98724084f9bSBrian Somers exit (1); 98824084f9bSBrian Somers } 98924084f9bSBrian Somers 990902cb50aSBrian Somers void Warn (const char* msg) 99124084f9bSBrian Somers { 99224084f9bSBrian Somers if (background) 99324084f9bSBrian Somers syslog (LOG_ALERT, "%s (%m)", msg); 99424084f9bSBrian Somers else 99504d06bb6SKris Kennaway warn ("%s", msg); 99624084f9bSBrian Somers } 99724084f9bSBrian Somers 99848ce8ca1SXin LI static void RefreshAddr (int sig __unused) 99924084f9bSBrian Somers { 1000be4f3cd0SPaolo Pisati LibAliasRefreshModules(); 1001be4f3cd0SPaolo Pisati if (mip != NULL && mip->ifName != NULL) 100222c62477SPoul-Henning Kamp mip->assignAliasAddr = 1; 100324084f9bSBrian Somers } 100424084f9bSBrian Somers 100548ce8ca1SXin LI static void InitiateShutdown (int sig __unused) 100624084f9bSBrian Somers { 100724084f9bSBrian Somers /* 100824084f9bSBrian Somers * Start timer to allow kernel gracefully 100924084f9bSBrian Somers * shutdown existing connections when system 101024084f9bSBrian Somers * is shut down. 101124084f9bSBrian Somers */ 1012cd45c931SRuslan Ermilov siginterrupt(SIGALRM, 1); 101324084f9bSBrian Somers signal (SIGALRM, Shutdown); 101472cbe4adSAlexander Motin ualarm(exitDelay*1000, 1000); 101524084f9bSBrian Somers } 101624084f9bSBrian Somers 101748ce8ca1SXin LI static void Shutdown (int sig __unused) 101824084f9bSBrian Somers { 101924084f9bSBrian Somers running = 0; 102024084f9bSBrian Somers } 102124084f9bSBrian Somers 102224084f9bSBrian Somers /* 102324084f9bSBrian Somers * Different options recognized by this program. 102424084f9bSBrian Somers */ 102524084f9bSBrian Somers 102624084f9bSBrian Somers enum Option { 102724084f9bSBrian Somers 102822c62477SPoul-Henning Kamp LibAliasOption, 102922c62477SPoul-Henning Kamp Instance, 103024084f9bSBrian Somers Verbose, 103124084f9bSBrian Somers InPort, 103224084f9bSBrian Somers OutPort, 103324084f9bSBrian Somers Port, 103422c62477SPoul-Henning Kamp GlobalPort, 103524084f9bSBrian Somers AliasAddress, 103611c2b3bfSRuslan Ermilov TargetAddress, 103724084f9bSBrian Somers InterfaceName, 103824084f9bSBrian Somers RedirectPort, 10394330006dSRuslan Ermilov RedirectProto, 104024084f9bSBrian Somers RedirectAddress, 104124084f9bSBrian Somers ConfigFile, 104259a7c613SBrian Somers DynamicMode, 104359a7c613SBrian Somers ProxyRule, 104459a7c613SBrian Somers LogDenied, 1045bc4ebb98SRuslan Ermilov LogFacility, 104684ef95bdSPoul-Henning Kamp PunchFW, 1047b07fbc17SJoe Marcus Clarke SkinnyPort, 1048b79840a6SRuslan Ermilov LogIpfwDenied, 104972cbe4adSAlexander Motin PidFile, 105072cbe4adSAlexander Motin ExitDelay 105124084f9bSBrian Somers }; 105224084f9bSBrian Somers 105324084f9bSBrian Somers enum Param { 105424084f9bSBrian Somers 105524084f9bSBrian Somers YesNo, 105624084f9bSBrian Somers Numeric, 105724084f9bSBrian Somers String, 105824084f9bSBrian Somers None, 105924084f9bSBrian Somers Address, 106024084f9bSBrian Somers Service 106124084f9bSBrian Somers }; 106224084f9bSBrian Somers 106324084f9bSBrian Somers /* 106424084f9bSBrian Somers * Option information structure (used by ParseOption). 106524084f9bSBrian Somers */ 106624084f9bSBrian Somers 106724084f9bSBrian Somers struct OptionInfo { 106824084f9bSBrian Somers 106924084f9bSBrian Somers enum Option type; 107024084f9bSBrian Somers int packetAliasOpt; 107124084f9bSBrian Somers enum Param parm; 1072902cb50aSBrian Somers const char* parmDescription; 1073902cb50aSBrian Somers const char* description; 1074902cb50aSBrian Somers const char* name; 1075902cb50aSBrian Somers const char* shortName; 107624084f9bSBrian Somers }; 107724084f9bSBrian Somers 107824084f9bSBrian Somers /* 107924084f9bSBrian Somers * Table of known options. 108024084f9bSBrian Somers */ 108124084f9bSBrian Somers 108224084f9bSBrian Somers static struct OptionInfo optionTable[] = { 108324084f9bSBrian Somers 108422c62477SPoul-Henning Kamp { LibAliasOption, 108524084f9bSBrian Somers PKT_ALIAS_UNREGISTERED_ONLY, 108624084f9bSBrian Somers YesNo, 108724084f9bSBrian Somers "[yes|no]", 108824084f9bSBrian Somers "alias only unregistered addresses", 108924084f9bSBrian Somers "unregistered_only", 109024084f9bSBrian Somers "u" }, 109124084f9bSBrian Somers 109222c62477SPoul-Henning Kamp { LibAliasOption, 109324084f9bSBrian Somers PKT_ALIAS_LOG, 109424084f9bSBrian Somers YesNo, 109524084f9bSBrian Somers "[yes|no]", 109624084f9bSBrian Somers "enable logging", 109724084f9bSBrian Somers "log", 109824084f9bSBrian Somers "l" }, 109924084f9bSBrian Somers 110022c62477SPoul-Henning Kamp { LibAliasOption, 110159a7c613SBrian Somers PKT_ALIAS_PROXY_ONLY, 110259a7c613SBrian Somers YesNo, 110359a7c613SBrian Somers "[yes|no]", 110459a7c613SBrian Somers "proxy only", 110559a7c613SBrian Somers "proxy_only", 110659a7c613SBrian Somers NULL }, 110759a7c613SBrian Somers 110822c62477SPoul-Henning Kamp { LibAliasOption, 110959a7c613SBrian Somers PKT_ALIAS_REVERSE, 111059a7c613SBrian Somers YesNo, 111159a7c613SBrian Somers "[yes|no]", 111259a7c613SBrian Somers "operate in reverse mode", 111359a7c613SBrian Somers "reverse", 111459a7c613SBrian Somers NULL }, 111559a7c613SBrian Somers 111622c62477SPoul-Henning Kamp { LibAliasOption, 111724084f9bSBrian Somers PKT_ALIAS_DENY_INCOMING, 111824084f9bSBrian Somers YesNo, 111924084f9bSBrian Somers "[yes|no]", 112024084f9bSBrian Somers "allow incoming connections", 112124084f9bSBrian Somers "deny_incoming", 112224084f9bSBrian Somers "d" }, 112324084f9bSBrian Somers 112422c62477SPoul-Henning Kamp { LibAliasOption, 112524084f9bSBrian Somers PKT_ALIAS_USE_SOCKETS, 112624084f9bSBrian Somers YesNo, 112724084f9bSBrian Somers "[yes|no]", 112824084f9bSBrian Somers "use sockets to inhibit port conflict", 112924084f9bSBrian Somers "use_sockets", 113024084f9bSBrian Somers "s" }, 113124084f9bSBrian Somers 113222c62477SPoul-Henning Kamp { LibAliasOption, 113324084f9bSBrian Somers PKT_ALIAS_SAME_PORTS, 113424084f9bSBrian Somers YesNo, 113524084f9bSBrian Somers "[yes|no]", 113624084f9bSBrian Somers "try to keep original port numbers for connections", 113724084f9bSBrian Somers "same_ports", 113824084f9bSBrian Somers "m" }, 113924084f9bSBrian Somers 114024084f9bSBrian Somers { Verbose, 114124084f9bSBrian Somers 0, 114224084f9bSBrian Somers YesNo, 114324084f9bSBrian Somers "[yes|no]", 114424084f9bSBrian Somers "verbose mode, dump packet information", 114524084f9bSBrian Somers "verbose", 114624084f9bSBrian Somers "v" }, 114724084f9bSBrian Somers 114824084f9bSBrian Somers { DynamicMode, 114924084f9bSBrian Somers 0, 115024084f9bSBrian Somers YesNo, 115124084f9bSBrian Somers "[yes|no]", 115224084f9bSBrian Somers "dynamic mode, automatically detect interface address changes", 115324084f9bSBrian Somers "dynamic", 115424084f9bSBrian Somers NULL }, 115524084f9bSBrian Somers 115624084f9bSBrian Somers { InPort, 115724084f9bSBrian Somers 0, 115824084f9bSBrian Somers Service, 115924084f9bSBrian Somers "number|service_name", 116024084f9bSBrian Somers "set port for incoming packets", 116124084f9bSBrian Somers "in_port", 116224084f9bSBrian Somers "i" }, 116324084f9bSBrian Somers 116424084f9bSBrian Somers { OutPort, 116524084f9bSBrian Somers 0, 116624084f9bSBrian Somers Service, 116724084f9bSBrian Somers "number|service_name", 116824084f9bSBrian Somers "set port for outgoing packets", 116924084f9bSBrian Somers "out_port", 117024084f9bSBrian Somers "o" }, 117124084f9bSBrian Somers 117224084f9bSBrian Somers { Port, 117324084f9bSBrian Somers 0, 117424084f9bSBrian Somers Service, 117524084f9bSBrian Somers "number|service_name", 117624084f9bSBrian Somers "set port (defaults to natd/divert)", 117724084f9bSBrian Somers "port", 117824084f9bSBrian Somers "p" }, 117924084f9bSBrian Somers 118022c62477SPoul-Henning Kamp { GlobalPort, 118122c62477SPoul-Henning Kamp 0, 118222c62477SPoul-Henning Kamp Service, 118322c62477SPoul-Henning Kamp "number|service_name", 118422c62477SPoul-Henning Kamp "set globalport", 118522c62477SPoul-Henning Kamp "globalport", 118622c62477SPoul-Henning Kamp NULL }, 118722c62477SPoul-Henning Kamp 118824084f9bSBrian Somers { AliasAddress, 118924084f9bSBrian Somers 0, 119024084f9bSBrian Somers Address, 119124084f9bSBrian Somers "x.x.x.x", 119224084f9bSBrian Somers "address to use for aliasing", 119324084f9bSBrian Somers "alias_address", 119424084f9bSBrian Somers "a" }, 119524084f9bSBrian Somers 119611c2b3bfSRuslan Ermilov { TargetAddress, 119711c2b3bfSRuslan Ermilov 0, 119811c2b3bfSRuslan Ermilov Address, 119911c2b3bfSRuslan Ermilov "x.x.x.x", 120011c2b3bfSRuslan Ermilov "address to use for incoming sessions", 120111c2b3bfSRuslan Ermilov "target_address", 120211c2b3bfSRuslan Ermilov "t" }, 120311c2b3bfSRuslan Ermilov 120424084f9bSBrian Somers { InterfaceName, 120524084f9bSBrian Somers 0, 120624084f9bSBrian Somers String, 120724084f9bSBrian Somers "network_if_name", 120824084f9bSBrian Somers "take aliasing address from interface", 120924084f9bSBrian Somers "interface", 121024084f9bSBrian Somers "n" }, 121124084f9bSBrian Somers 121259a7c613SBrian Somers { ProxyRule, 121324084f9bSBrian Somers 0, 121424084f9bSBrian Somers String, 121559a7c613SBrian Somers "[type encode_ip_hdr|encode_tcp_stream] port xxxx server " 121659a7c613SBrian Somers "a.b.c.d:yyyy", 121759a7c613SBrian Somers "add transparent proxying / destination NAT", 121859a7c613SBrian Somers "proxy_rule", 121924084f9bSBrian Somers NULL }, 122024084f9bSBrian Somers 122124084f9bSBrian Somers { RedirectPort, 122224084f9bSBrian Somers 0, 122324084f9bSBrian Somers String, 1224bd690510SRuslan Ermilov "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range" 12255d8ee958SBrian Somers " [remote_addr[:remote_port_range]]", 12265d8ee958SBrian Somers "redirect a port (or ports) for incoming traffic", 122724084f9bSBrian Somers "redirect_port", 122824084f9bSBrian Somers NULL }, 122924084f9bSBrian Somers 12304330006dSRuslan Ermilov { RedirectProto, 12314330006dSRuslan Ermilov 0, 12324330006dSRuslan Ermilov String, 12334330006dSRuslan Ermilov "proto local_addr [public_addr] [remote_addr]", 12344330006dSRuslan Ermilov "redirect packets of a given proto", 12354330006dSRuslan Ermilov "redirect_proto", 12364330006dSRuslan Ermilov NULL }, 12374330006dSRuslan Ermilov 123824084f9bSBrian Somers { RedirectAddress, 123924084f9bSBrian Somers 0, 124024084f9bSBrian Somers String, 1241bd690510SRuslan Ermilov "local_addr[,...] public_addr", 124224084f9bSBrian Somers "define mapping between local and public addresses", 124324084f9bSBrian Somers "redirect_address", 124424084f9bSBrian Somers NULL }, 124524084f9bSBrian Somers 124624084f9bSBrian Somers { ConfigFile, 124724084f9bSBrian Somers 0, 124824084f9bSBrian Somers String, 124924084f9bSBrian Somers "file_name", 125024084f9bSBrian Somers "read options from configuration file", 125124084f9bSBrian Somers "config", 125259a7c613SBrian Somers "f" }, 125359a7c613SBrian Somers 125459a7c613SBrian Somers { LogDenied, 125559a7c613SBrian Somers 0, 125659a7c613SBrian Somers YesNo, 125759a7c613SBrian Somers "[yes|no]", 125859a7c613SBrian Somers "enable logging of denied incoming packets", 125959a7c613SBrian Somers "log_denied", 126059a7c613SBrian Somers NULL }, 126159a7c613SBrian Somers 126259a7c613SBrian Somers { LogFacility, 126359a7c613SBrian Somers 0, 126459a7c613SBrian Somers String, 126559a7c613SBrian Somers "facility", 126659a7c613SBrian Somers "name of syslog facility to use for logging", 126759a7c613SBrian Somers "log_facility", 1268bc4ebb98SRuslan Ermilov NULL }, 126959a7c613SBrian Somers 1270bc4ebb98SRuslan Ermilov { PunchFW, 1271bc4ebb98SRuslan Ermilov 0, 1272bc4ebb98SRuslan Ermilov String, 1273bc4ebb98SRuslan Ermilov "basenumber:count", 1274bc4ebb98SRuslan Ermilov "punch holes in the firewall for incoming FTP/IRC DCC connections", 1275bc4ebb98SRuslan Ermilov "punch_fw", 127684ef95bdSPoul-Henning Kamp NULL }, 127784ef95bdSPoul-Henning Kamp 1278b07fbc17SJoe Marcus Clarke { SkinnyPort, 1279b07fbc17SJoe Marcus Clarke 0, 1280b07fbc17SJoe Marcus Clarke String, 1281b07fbc17SJoe Marcus Clarke "port", 1282b07fbc17SJoe Marcus Clarke "set the TCP port for use with the Skinny Station protocol", 1283b07fbc17SJoe Marcus Clarke "skinny_port", 1284b07fbc17SJoe Marcus Clarke NULL }, 1285b07fbc17SJoe Marcus Clarke 128684ef95bdSPoul-Henning Kamp { LogIpfwDenied, 128784ef95bdSPoul-Henning Kamp 0, 128884ef95bdSPoul-Henning Kamp YesNo, 128984ef95bdSPoul-Henning Kamp "[yes|no]", 129084ef95bdSPoul-Henning Kamp "log packets converted by natd, but denied by ipfw", 129184ef95bdSPoul-Henning Kamp "log_ipfw_denied", 129284ef95bdSPoul-Henning Kamp NULL }, 1293b79840a6SRuslan Ermilov 1294b79840a6SRuslan Ermilov { PidFile, 1295b79840a6SRuslan Ermilov 0, 1296b79840a6SRuslan Ermilov String, 1297b79840a6SRuslan Ermilov "file_name", 1298b79840a6SRuslan Ermilov "store PID in an alternate file", 1299b79840a6SRuslan Ermilov "pid_file", 1300b79840a6SRuslan Ermilov "P" }, 130122c62477SPoul-Henning Kamp { Instance, 130222c62477SPoul-Henning Kamp 0, 130322c62477SPoul-Henning Kamp String, 130422c62477SPoul-Henning Kamp "instance name", 130522c62477SPoul-Henning Kamp "name of aliasing engine instance", 130622c62477SPoul-Henning Kamp "instance", 130722c62477SPoul-Henning Kamp NULL }, 130872cbe4adSAlexander Motin { ExitDelay, 130972cbe4adSAlexander Motin 0, 131072cbe4adSAlexander Motin Numeric, 131172cbe4adSAlexander Motin "ms", 131272cbe4adSAlexander Motin "delay in ms before daemon exit after signal", 131372cbe4adSAlexander Motin "exit_delay", 131472cbe4adSAlexander Motin NULL }, 131524084f9bSBrian Somers }; 131624084f9bSBrian Somers 1317b0f55af6SRuslan Ermilov static void ParseOption (const char* option, const char* parms) 131824084f9bSBrian Somers { 131924084f9bSBrian Somers int i; 132024084f9bSBrian Somers struct OptionInfo* info; 132124084f9bSBrian Somers int yesNoValue; 132224084f9bSBrian Somers int aliasValue; 132324084f9bSBrian Somers int numValue; 132467a886fbSBrian Somers u_short uNumValue; 1325902cb50aSBrian Somers const char* strValue; 132624084f9bSBrian Somers struct in_addr addrValue; 132724084f9bSBrian Somers int max; 132824084f9bSBrian Somers char* end; 132959a7c613SBrian Somers CODE* fac_record = NULL; 133024084f9bSBrian Somers /* 133124084f9bSBrian Somers * Find option from table. 133224084f9bSBrian Somers */ 133324084f9bSBrian Somers max = sizeof (optionTable) / sizeof (struct OptionInfo); 133424084f9bSBrian Somers for (i = 0, info = optionTable; i < max; i++, info++) { 133524084f9bSBrian Somers 133624084f9bSBrian Somers if (!strcmp (info->name, option)) 133724084f9bSBrian Somers break; 133824084f9bSBrian Somers 133924084f9bSBrian Somers if (info->shortName) 134024084f9bSBrian Somers if (!strcmp (info->shortName, option)) 134124084f9bSBrian Somers break; 134224084f9bSBrian Somers } 134324084f9bSBrian Somers 134424084f9bSBrian Somers if (i >= max) { 134524084f9bSBrian Somers 13460fc81af1SPhilippe Charnier warnx ("unknown option %s", option); 134724084f9bSBrian Somers Usage (); 134824084f9bSBrian Somers } 134924084f9bSBrian Somers 135067a886fbSBrian Somers uNumValue = 0; 135124084f9bSBrian Somers yesNoValue = 0; 135224084f9bSBrian Somers numValue = 0; 135324084f9bSBrian Somers strValue = NULL; 135424084f9bSBrian Somers /* 135524084f9bSBrian Somers * Check parameters. 135624084f9bSBrian Somers */ 135724084f9bSBrian Somers switch (info->parm) { 135824084f9bSBrian Somers case YesNo: 135924084f9bSBrian Somers if (!parms) 136024084f9bSBrian Somers parms = "yes"; 136124084f9bSBrian Somers 136224084f9bSBrian Somers if (!strcmp (parms, "yes")) 136324084f9bSBrian Somers yesNoValue = 1; 136424084f9bSBrian Somers else 136524084f9bSBrian Somers if (!strcmp (parms, "no")) 136624084f9bSBrian Somers yesNoValue = 0; 13670fc81af1SPhilippe Charnier else 13680fc81af1SPhilippe Charnier errx (1, "%s needs yes/no parameter", option); 136924084f9bSBrian Somers break; 137024084f9bSBrian Somers 137124084f9bSBrian Somers case Service: 13720fc81af1SPhilippe Charnier if (!parms) 137367a886fbSBrian Somers errx (1, "%s needs service name or " 137467a886fbSBrian Somers "port number parameter", 137567a886fbSBrian Somers option); 137624084f9bSBrian Somers 137767a886fbSBrian Somers uNumValue = StrToPort (parms, "divert"); 137824084f9bSBrian Somers break; 137924084f9bSBrian Somers 138024084f9bSBrian Somers case Numeric: 138124084f9bSBrian Somers if (parms) 138224084f9bSBrian Somers numValue = strtol (parms, &end, 10); 138324084f9bSBrian Somers else 1384902cb50aSBrian Somers end = NULL; 138524084f9bSBrian Somers 13860fc81af1SPhilippe Charnier if (end == parms) 13870fc81af1SPhilippe Charnier errx (1, "%s needs numeric parameter", option); 138824084f9bSBrian Somers break; 138924084f9bSBrian Somers 139024084f9bSBrian Somers case String: 139124084f9bSBrian Somers strValue = parms; 13920fc81af1SPhilippe Charnier if (!strValue) 13930fc81af1SPhilippe Charnier errx (1, "%s needs parameter", option); 139424084f9bSBrian Somers break; 139524084f9bSBrian Somers 139624084f9bSBrian Somers case None: 13970fc81af1SPhilippe Charnier if (parms) 13980fc81af1SPhilippe Charnier errx (1, "%s does not take parameters", option); 139924084f9bSBrian Somers break; 140024084f9bSBrian Somers 140124084f9bSBrian Somers case Address: 14020fc81af1SPhilippe Charnier if (!parms) 14030fc81af1SPhilippe Charnier errx (1, "%s needs address/host parameter", option); 140424084f9bSBrian Somers 140524084f9bSBrian Somers StrToAddr (parms, &addrValue); 140624084f9bSBrian Somers break; 140724084f9bSBrian Somers } 140824084f9bSBrian Somers 140924084f9bSBrian Somers switch (info->type) { 141022c62477SPoul-Henning Kamp case LibAliasOption: 141124084f9bSBrian Somers 141224084f9bSBrian Somers aliasValue = yesNoValue ? info->packetAliasOpt : 0; 141322c62477SPoul-Henning Kamp LibAliasSetMode (mla, aliasValue, info->packetAliasOpt); 141424084f9bSBrian Somers break; 141524084f9bSBrian Somers 141624084f9bSBrian Somers case Verbose: 141724084f9bSBrian Somers verbose = yesNoValue; 141824084f9bSBrian Somers break; 141924084f9bSBrian Somers 142024084f9bSBrian Somers case DynamicMode: 142124084f9bSBrian Somers dynamicMode = yesNoValue; 142224084f9bSBrian Somers break; 142324084f9bSBrian Somers 142424084f9bSBrian Somers case InPort: 142522c62477SPoul-Henning Kamp mip->inPort = uNumValue; 142624084f9bSBrian Somers break; 142724084f9bSBrian Somers 142824084f9bSBrian Somers case OutPort: 142922c62477SPoul-Henning Kamp mip->outPort = uNumValue; 143024084f9bSBrian Somers break; 143124084f9bSBrian Somers 143224084f9bSBrian Somers case Port: 143322c62477SPoul-Henning Kamp mip->inOutPort = uNumValue; 143422c62477SPoul-Henning Kamp break; 143522c62477SPoul-Henning Kamp 143622c62477SPoul-Henning Kamp case GlobalPort: 143722c62477SPoul-Henning Kamp globalPort = uNumValue; 143824084f9bSBrian Somers break; 143924084f9bSBrian Somers 144024084f9bSBrian Somers case AliasAddress: 144122c62477SPoul-Henning Kamp memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr)); 144224084f9bSBrian Somers break; 144324084f9bSBrian Somers 144411c2b3bfSRuslan Ermilov case TargetAddress: 144522c62477SPoul-Henning Kamp LibAliasSetTarget(mla, addrValue); 144611c2b3bfSRuslan Ermilov break; 144711c2b3bfSRuslan Ermilov 144824084f9bSBrian Somers case RedirectPort: 144924084f9bSBrian Somers SetupPortRedirect (strValue); 145024084f9bSBrian Somers break; 145124084f9bSBrian Somers 14524330006dSRuslan Ermilov case RedirectProto: 14534330006dSRuslan Ermilov SetupProtoRedirect(strValue); 14544330006dSRuslan Ermilov break; 14554330006dSRuslan Ermilov 145624084f9bSBrian Somers case RedirectAddress: 145724084f9bSBrian Somers SetupAddressRedirect (strValue); 145824084f9bSBrian Somers break; 145924084f9bSBrian Somers 146059a7c613SBrian Somers case ProxyRule: 146122c62477SPoul-Henning Kamp LibAliasProxyRule (mla, strValue); 146259a7c613SBrian Somers break; 146359a7c613SBrian Somers 146424084f9bSBrian Somers case InterfaceName: 146522c62477SPoul-Henning Kamp if (mip->ifName) 146622c62477SPoul-Henning Kamp free (mip->ifName); 146724084f9bSBrian Somers 146822c62477SPoul-Henning Kamp mip->ifName = strdup (strValue); 146924084f9bSBrian Somers break; 147024084f9bSBrian Somers 147124084f9bSBrian Somers case ConfigFile: 147224084f9bSBrian Somers ReadConfigFile (strValue); 147324084f9bSBrian Somers break; 147459a7c613SBrian Somers 147559a7c613SBrian Somers case LogDenied: 147622c62477SPoul-Henning Kamp mip->logDropped = yesNoValue; 147759a7c613SBrian Somers break; 147859a7c613SBrian Somers 147959a7c613SBrian Somers case LogFacility: 148059a7c613SBrian Somers 148159a7c613SBrian Somers fac_record = facilitynames; 148259a7c613SBrian Somers while (fac_record->c_name != NULL) { 148359a7c613SBrian Somers 148459a7c613SBrian Somers if (!strcmp (fac_record->c_name, strValue)) { 148559a7c613SBrian Somers 148659a7c613SBrian Somers logFacility = fac_record->c_val; 148759a7c613SBrian Somers break; 148859a7c613SBrian Somers 148959a7c613SBrian Somers } 149059a7c613SBrian Somers else 149159a7c613SBrian Somers fac_record++; 149259a7c613SBrian Somers } 149359a7c613SBrian Somers 149459a7c613SBrian Somers if(fac_record->c_name == NULL) 149559a7c613SBrian Somers errx(1, "Unknown log facility name: %s", strValue); 149659a7c613SBrian Somers 149759a7c613SBrian Somers break; 1498bc4ebb98SRuslan Ermilov 1499bc4ebb98SRuslan Ermilov case PunchFW: 1500bc4ebb98SRuslan Ermilov SetupPunchFW(strValue); 1501bc4ebb98SRuslan Ermilov break; 15023843533eSRuslan Ermilov 1503b07fbc17SJoe Marcus Clarke case SkinnyPort: 1504b07fbc17SJoe Marcus Clarke SetupSkinnyPort(strValue); 1505b07fbc17SJoe Marcus Clarke break; 1506b07fbc17SJoe Marcus Clarke 150784ef95bdSPoul-Henning Kamp case LogIpfwDenied: 15083843533eSRuslan Ermilov logIpfwDenied = yesNoValue;; 15093843533eSRuslan Ermilov break; 1510b79840a6SRuslan Ermilov 1511b79840a6SRuslan Ermilov case PidFile: 1512b79840a6SRuslan Ermilov pidName = strdup (strValue); 1513b79840a6SRuslan Ermilov break; 151422c62477SPoul-Henning Kamp case Instance: 151522c62477SPoul-Henning Kamp NewInstance(strValue); 151622c62477SPoul-Henning Kamp break; 151772cbe4adSAlexander Motin case ExitDelay: 151872cbe4adSAlexander Motin if (numValue < 0 || numValue > MAX_EXIT_DELAY) 151972cbe4adSAlexander Motin errx(1, "Incorrect exit delay: %d", numValue); 152072cbe4adSAlexander Motin exitDelay = numValue; 152172cbe4adSAlexander Motin break; 152224084f9bSBrian Somers } 152324084f9bSBrian Somers } 152424084f9bSBrian Somers 1525902cb50aSBrian Somers void ReadConfigFile (const char* fileName) 152624084f9bSBrian Somers { 152724084f9bSBrian Somers FILE* file; 1528d99cc1daSRuslan Ermilov char *buf; 1529d99cc1daSRuslan Ermilov size_t len; 15302e7e7c71SRuslan Ermilov char *ptr, *p; 153124084f9bSBrian Somers char* option; 153224084f9bSBrian Somers 153324084f9bSBrian Somers file = fopen (fileName, "r"); 1534d99cc1daSRuslan Ermilov if (!file) 1535d99cc1daSRuslan Ermilov err(1, "cannot open config file %s", fileName); 153624084f9bSBrian Somers 1537d99cc1daSRuslan Ermilov while ((buf = fgetln(file, &len)) != NULL) { 1538d99cc1daSRuslan Ermilov if (buf[len - 1] == '\n') 1539d99cc1daSRuslan Ermilov buf[len - 1] = '\0'; 1540d99cc1daSRuslan Ermilov else 1541d99cc1daSRuslan Ermilov errx(1, "config file format error: " 1542d99cc1daSRuslan Ermilov "last line should end with newline"); 154324084f9bSBrian Somers 154424084f9bSBrian Somers /* 15452e7e7c71SRuslan Ermilov * Check for comments, strip off trailing spaces. 154624084f9bSBrian Somers */ 15472e7e7c71SRuslan Ermilov if ((ptr = strchr(buf, '#'))) 15482e7e7c71SRuslan Ermilov *ptr = '\0'; 15492e7e7c71SRuslan Ermilov for (ptr = buf; isspace(*ptr); ++ptr) 15502e7e7c71SRuslan Ermilov continue; 155124084f9bSBrian Somers if (*ptr == '\0') 155224084f9bSBrian Somers continue; 15532e7e7c71SRuslan Ermilov for (p = strchr(buf, '\0'); isspace(*--p);) 15542e7e7c71SRuslan Ermilov continue; 15552e7e7c71SRuslan Ermilov *++p = '\0'; 15562e7e7c71SRuslan Ermilov 155724084f9bSBrian Somers /* 155824084f9bSBrian Somers * Extract option name. 155924084f9bSBrian Somers */ 156024084f9bSBrian Somers option = ptr; 156124084f9bSBrian Somers while (*ptr && !isspace (*ptr)) 156224084f9bSBrian Somers ++ptr; 156324084f9bSBrian Somers 156424084f9bSBrian Somers if (*ptr != '\0') { 156524084f9bSBrian Somers 156624084f9bSBrian Somers *ptr = '\0'; 156724084f9bSBrian Somers ++ptr; 156824084f9bSBrian Somers } 156924084f9bSBrian Somers /* 157024084f9bSBrian Somers * Skip white space between name and parms. 157124084f9bSBrian Somers */ 157224084f9bSBrian Somers while (*ptr && isspace (*ptr)) 157324084f9bSBrian Somers ++ptr; 157424084f9bSBrian Somers 1575b0f55af6SRuslan Ermilov ParseOption (option, *ptr ? ptr : NULL); 157624084f9bSBrian Somers } 157724084f9bSBrian Somers 157824084f9bSBrian Somers fclose (file); 157924084f9bSBrian Somers } 158024084f9bSBrian Somers 15817154ce64SEd Schouten static void Usage(void) 158224084f9bSBrian Somers { 158324084f9bSBrian Somers int i; 158424084f9bSBrian Somers int max; 158524084f9bSBrian Somers struct OptionInfo* info; 158624084f9bSBrian Somers 158724084f9bSBrian Somers fprintf (stderr, "Recognized options:\n\n"); 158824084f9bSBrian Somers 158924084f9bSBrian Somers max = sizeof (optionTable) / sizeof (struct OptionInfo); 159024084f9bSBrian Somers for (i = 0, info = optionTable; i < max; i++, info++) { 159124084f9bSBrian Somers 159224084f9bSBrian Somers fprintf (stderr, "-%-20s %s\n", info->name, 159324084f9bSBrian Somers info->parmDescription); 159424084f9bSBrian Somers 159524084f9bSBrian Somers if (info->shortName) 159624084f9bSBrian Somers fprintf (stderr, "-%-20s %s\n", info->shortName, 159724084f9bSBrian Somers info->parmDescription); 159824084f9bSBrian Somers 159924084f9bSBrian Somers fprintf (stderr, " %s\n\n", info->description); 160024084f9bSBrian Somers } 160124084f9bSBrian Somers 160224084f9bSBrian Somers exit (1); 160324084f9bSBrian Somers } 160424084f9bSBrian Somers 1605902cb50aSBrian Somers void SetupPortRedirect (const char* parms) 160624084f9bSBrian Somers { 1607b6365f95SAlexander Motin char *buf; 160824084f9bSBrian Somers char* ptr; 1609bd690510SRuslan Ermilov char* serverPool; 161024084f9bSBrian Somers struct in_addr localAddr; 161124084f9bSBrian Somers struct in_addr publicAddr; 161224084f9bSBrian Somers struct in_addr remoteAddr; 16135d8ee958SBrian Somers port_range portRange; 16145d8ee958SBrian Somers u_short localPort = 0; 16155d8ee958SBrian Somers u_short publicPort = 0; 16165d8ee958SBrian Somers u_short remotePort = 0; 16175d8ee958SBrian Somers u_short numLocalPorts = 0; 16185d8ee958SBrian Somers u_short numPublicPorts = 0; 16195d8ee958SBrian Somers u_short numRemotePorts = 0; 162024084f9bSBrian Somers int proto; 162124084f9bSBrian Somers char* protoName; 162224084f9bSBrian Somers char* separator; 16235d8ee958SBrian Somers int i; 162448ce8ca1SXin LI struct alias_link *aliaslink = NULL; 162524084f9bSBrian Somers 1626b6365f95SAlexander Motin buf = strdup (parms); 1627b6365f95SAlexander Motin if (!buf) 1628b6365f95SAlexander Motin errx (1, "redirect_port: strdup() failed"); 162924084f9bSBrian Somers /* 163024084f9bSBrian Somers * Extract protocol. 163124084f9bSBrian Somers */ 163224084f9bSBrian Somers protoName = strtok (buf, " \t"); 16330fc81af1SPhilippe Charnier if (!protoName) 16340fc81af1SPhilippe Charnier errx (1, "redirect_port: missing protocol"); 163524084f9bSBrian Somers 163624084f9bSBrian Somers proto = StrToProto (protoName); 163724084f9bSBrian Somers /* 163824084f9bSBrian Somers * Extract local address. 163924084f9bSBrian Somers */ 164024084f9bSBrian Somers ptr = strtok (NULL, " \t"); 16410fc81af1SPhilippe Charnier if (!ptr) 16420fc81af1SPhilippe Charnier errx (1, "redirect_port: missing local address"); 164324084f9bSBrian Somers 1644bd690510SRuslan Ermilov separator = strchr(ptr, ','); 1645bd690510SRuslan Ermilov if (separator) { /* LSNAT redirection syntax. */ 1646bd690510SRuslan Ermilov localAddr.s_addr = INADDR_NONE; 1647bd690510SRuslan Ermilov localPort = ~0; 1648bd690510SRuslan Ermilov numLocalPorts = 1; 1649bd690510SRuslan Ermilov serverPool = ptr; 1650bd690510SRuslan Ermilov } else { 16515d8ee958SBrian Somers if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 ) 16525d8ee958SBrian Somers errx (1, "redirect_port: invalid local port range"); 16535d8ee958SBrian Somers 16545d8ee958SBrian Somers localPort = GETLOPORT(portRange); 16555d8ee958SBrian Somers numLocalPorts = GETNUMPORTS(portRange); 1656bd690510SRuslan Ermilov serverPool = NULL; 1657bd690510SRuslan Ermilov } 16585d8ee958SBrian Somers 165924084f9bSBrian Somers /* 16609c501140SBrian Somers * Extract public port and optionally address. 166124084f9bSBrian Somers */ 166224084f9bSBrian Somers ptr = strtok (NULL, " \t"); 16630fc81af1SPhilippe Charnier if (!ptr) 16640fc81af1SPhilippe Charnier errx (1, "redirect_port: missing public port"); 166524084f9bSBrian Somers 166624084f9bSBrian Somers separator = strchr (ptr, ':'); 16675d8ee958SBrian Somers if (separator) { 16685d8ee958SBrian Somers if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 ) 16695d8ee958SBrian Somers errx (1, "redirect_port: invalid public port range"); 167024084f9bSBrian Somers } 16715d8ee958SBrian Somers else { 16725d8ee958SBrian Somers publicAddr.s_addr = INADDR_ANY; 16735d8ee958SBrian Somers if (StrToPortRange (ptr, protoName, &portRange) != 0) 16745d8ee958SBrian Somers errx (1, "redirect_port: invalid public port range"); 16755d8ee958SBrian Somers } 16765d8ee958SBrian Somers 16775d8ee958SBrian Somers publicPort = GETLOPORT(portRange); 16785d8ee958SBrian Somers numPublicPorts = GETNUMPORTS(portRange); 167924084f9bSBrian Somers 168024084f9bSBrian Somers /* 168124084f9bSBrian Somers * Extract remote address and optionally port. 168224084f9bSBrian Somers */ 168324084f9bSBrian Somers ptr = strtok (NULL, " \t"); 168424084f9bSBrian Somers if (ptr) { 168524084f9bSBrian Somers separator = strchr (ptr, ':'); 1686ebe70c8fSWarner Losh if (separator) { 16875d8ee958SBrian Somers if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0) 16885d8ee958SBrian Somers errx (1, "redirect_port: invalid remote port range"); 1689ebe70c8fSWarner Losh } else { 16905d8ee958SBrian Somers SETLOPORT(portRange, 0); 16915d8ee958SBrian Somers SETNUMPORTS(portRange, 1); 169224084f9bSBrian Somers StrToAddr (ptr, &remoteAddr); 169324084f9bSBrian Somers } 169424084f9bSBrian Somers } 169524084f9bSBrian Somers else { 16965d8ee958SBrian Somers SETLOPORT(portRange, 0); 16975d8ee958SBrian Somers SETNUMPORTS(portRange, 1); 169824084f9bSBrian Somers remoteAddr.s_addr = INADDR_ANY; 169924084f9bSBrian Somers } 170024084f9bSBrian Somers 17015d8ee958SBrian Somers remotePort = GETLOPORT(portRange); 17025d8ee958SBrian Somers numRemotePorts = GETNUMPORTS(portRange); 17035d8ee958SBrian Somers 17045d8ee958SBrian Somers /* 17055d8ee958SBrian Somers * Make sure port ranges match up, then add the redirect ports. 17065d8ee958SBrian Somers */ 17075d8ee958SBrian Somers if (numLocalPorts != numPublicPorts) 17085d8ee958SBrian Somers errx (1, "redirect_port: port ranges must be equal in size"); 17095d8ee958SBrian Somers 17105d8ee958SBrian Somers /* Remote port range is allowed to be '0' which means all ports. */ 171129d97436SBrian Somers if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0)) 17125d8ee958SBrian Somers errx (1, "redirect_port: remote port must be 0 or equal to local port range in size"); 17135d8ee958SBrian Somers 17145d8ee958SBrian Somers for (i = 0 ; i < numPublicPorts ; ++i) { 17155d8ee958SBrian Somers /* If remotePort is all ports, set it to 0. */ 17165d8ee958SBrian Somers u_short remotePortCopy = remotePort + i; 17175d8ee958SBrian Somers if (numRemotePorts == 1 && remotePort == 0) 17185d8ee958SBrian Somers remotePortCopy = 0; 17195d8ee958SBrian Somers 172048ce8ca1SXin LI aliaslink = LibAliasRedirectPort (mla, localAddr, 17215d8ee958SBrian Somers htons(localPort + i), 172224084f9bSBrian Somers remoteAddr, 17235d8ee958SBrian Somers htons(remotePortCopy), 172424084f9bSBrian Somers publicAddr, 17255d8ee958SBrian Somers htons(publicPort + i), 172624084f9bSBrian Somers proto); 172724084f9bSBrian Somers } 1728bd690510SRuslan Ermilov 1729bd690510SRuslan Ermilov /* 1730bd690510SRuslan Ermilov * Setup LSNAT server pool. 1731bd690510SRuslan Ermilov */ 173248ce8ca1SXin LI if (serverPool != NULL && aliaslink != NULL) { 1733bd690510SRuslan Ermilov ptr = strtok(serverPool, ","); 1734bd690510SRuslan Ermilov while (ptr != NULL) { 1735bd690510SRuslan Ermilov if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0) 1736bd690510SRuslan Ermilov errx(1, "redirect_port: invalid local port range"); 1737bd690510SRuslan Ermilov 1738bd690510SRuslan Ermilov localPort = GETLOPORT(portRange); 1739bd690510SRuslan Ermilov if (GETNUMPORTS(portRange) != 1) 1740bd690510SRuslan Ermilov errx(1, "redirect_port: local port must be single in this context"); 174148ce8ca1SXin LI LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort)); 1742bd690510SRuslan Ermilov ptr = strtok(NULL, ","); 1743bd690510SRuslan Ermilov } 1744bd690510SRuslan Ermilov } 1745b6365f95SAlexander Motin 1746b6365f95SAlexander Motin free (buf); 17475d8ee958SBrian Somers } 174824084f9bSBrian Somers 17494330006dSRuslan Ermilov void 17504330006dSRuslan Ermilov SetupProtoRedirect(const char* parms) 17514330006dSRuslan Ermilov { 1752b6365f95SAlexander Motin char *buf; 17534330006dSRuslan Ermilov char* ptr; 17544330006dSRuslan Ermilov struct in_addr localAddr; 17554330006dSRuslan Ermilov struct in_addr publicAddr; 17564330006dSRuslan Ermilov struct in_addr remoteAddr; 17574330006dSRuslan Ermilov int proto; 17584330006dSRuslan Ermilov char* protoName; 17594330006dSRuslan Ermilov struct protoent *protoent; 17604330006dSRuslan Ermilov 1761b6365f95SAlexander Motin buf = strdup (parms); 1762b6365f95SAlexander Motin if (!buf) 1763b6365f95SAlexander Motin errx (1, "redirect_port: strdup() failed"); 17644330006dSRuslan Ermilov /* 17654330006dSRuslan Ermilov * Extract protocol. 17664330006dSRuslan Ermilov */ 17674330006dSRuslan Ermilov protoName = strtok(buf, " \t"); 17684330006dSRuslan Ermilov if (!protoName) 17694330006dSRuslan Ermilov errx(1, "redirect_proto: missing protocol"); 17704330006dSRuslan Ermilov 17714330006dSRuslan Ermilov protoent = getprotobyname(protoName); 17724330006dSRuslan Ermilov if (protoent == NULL) 17734330006dSRuslan Ermilov errx(1, "redirect_proto: unknown protocol %s", protoName); 17744330006dSRuslan Ermilov else 17754330006dSRuslan Ermilov proto = protoent->p_proto; 17764330006dSRuslan Ermilov /* 17774330006dSRuslan Ermilov * Extract local address. 17784330006dSRuslan Ermilov */ 17794330006dSRuslan Ermilov ptr = strtok(NULL, " \t"); 17804330006dSRuslan Ermilov if (!ptr) 17814330006dSRuslan Ermilov errx(1, "redirect_proto: missing local address"); 17824330006dSRuslan Ermilov else 17834330006dSRuslan Ermilov StrToAddr(ptr, &localAddr); 17844330006dSRuslan Ermilov /* 17854330006dSRuslan Ermilov * Extract optional public address. 17864330006dSRuslan Ermilov */ 17874330006dSRuslan Ermilov ptr = strtok(NULL, " \t"); 17884330006dSRuslan Ermilov if (ptr) 17894330006dSRuslan Ermilov StrToAddr(ptr, &publicAddr); 17904330006dSRuslan Ermilov else 17914330006dSRuslan Ermilov publicAddr.s_addr = INADDR_ANY; 17924330006dSRuslan Ermilov /* 17934330006dSRuslan Ermilov * Extract optional remote address. 17944330006dSRuslan Ermilov */ 17954330006dSRuslan Ermilov ptr = strtok(NULL, " \t"); 17964330006dSRuslan Ermilov if (ptr) 17974330006dSRuslan Ermilov StrToAddr(ptr, &remoteAddr); 17984330006dSRuslan Ermilov else 17994330006dSRuslan Ermilov remoteAddr.s_addr = INADDR_ANY; 18004330006dSRuslan Ermilov /* 18014330006dSRuslan Ermilov * Create aliasing link. 18024330006dSRuslan Ermilov */ 180322c62477SPoul-Henning Kamp (void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr, 18044330006dSRuslan Ermilov proto); 1805b6365f95SAlexander Motin 1806b6365f95SAlexander Motin free (buf); 18074330006dSRuslan Ermilov } 18084330006dSRuslan Ermilov 1809902cb50aSBrian Somers void SetupAddressRedirect (const char* parms) 181024084f9bSBrian Somers { 1811b6365f95SAlexander Motin char *buf; 181224084f9bSBrian Somers char* ptr; 1813bd690510SRuslan Ermilov char* separator; 181424084f9bSBrian Somers struct in_addr localAddr; 181524084f9bSBrian Somers struct in_addr publicAddr; 1816bd690510SRuslan Ermilov char* serverPool; 181748ce8ca1SXin LI struct alias_link *aliaslink; 181824084f9bSBrian Somers 1819b6365f95SAlexander Motin buf = strdup (parms); 1820b6365f95SAlexander Motin if (!buf) 1821b6365f95SAlexander Motin errx (1, "redirect_port: strdup() failed"); 182224084f9bSBrian Somers /* 182324084f9bSBrian Somers * Extract local address. 182424084f9bSBrian Somers */ 182524084f9bSBrian Somers ptr = strtok (buf, " \t"); 18260fc81af1SPhilippe Charnier if (!ptr) 18270fc81af1SPhilippe Charnier errx (1, "redirect_address: missing local address"); 182824084f9bSBrian Somers 1829bd690510SRuslan Ermilov separator = strchr(ptr, ','); 1830bd690510SRuslan Ermilov if (separator) { /* LSNAT redirection syntax. */ 1831bd690510SRuslan Ermilov localAddr.s_addr = INADDR_NONE; 1832bd690510SRuslan Ermilov serverPool = ptr; 1833bd690510SRuslan Ermilov } else { 183424084f9bSBrian Somers StrToAddr (ptr, &localAddr); 1835bd690510SRuslan Ermilov serverPool = NULL; 1836bd690510SRuslan Ermilov } 183724084f9bSBrian Somers /* 183824084f9bSBrian Somers * Extract public address. 183924084f9bSBrian Somers */ 184024084f9bSBrian Somers ptr = strtok (NULL, " \t"); 18410fc81af1SPhilippe Charnier if (!ptr) 18420fc81af1SPhilippe Charnier errx (1, "redirect_address: missing public address"); 184324084f9bSBrian Somers 184424084f9bSBrian Somers StrToAddr (ptr, &publicAddr); 184548ce8ca1SXin LI aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr); 1846bd690510SRuslan Ermilov 1847bd690510SRuslan Ermilov /* 1848bd690510SRuslan Ermilov * Setup LSNAT server pool. 1849bd690510SRuslan Ermilov */ 185048ce8ca1SXin LI if (serverPool != NULL && aliaslink != NULL) { 1851bd690510SRuslan Ermilov ptr = strtok(serverPool, ","); 1852bd690510SRuslan Ermilov while (ptr != NULL) { 1853bd690510SRuslan Ermilov StrToAddr(ptr, &localAddr); 185448ce8ca1SXin LI LibAliasAddServer(mla, aliaslink, localAddr, htons(~0)); 1855bd690510SRuslan Ermilov ptr = strtok(NULL, ","); 1856bd690510SRuslan Ermilov } 1857bd690510SRuslan Ermilov } 1858b6365f95SAlexander Motin 1859b6365f95SAlexander Motin free (buf); 186024084f9bSBrian Somers } 186124084f9bSBrian Somers 1862902cb50aSBrian Somers void StrToAddr (const char* str, struct in_addr* addr) 186324084f9bSBrian Somers { 186424084f9bSBrian Somers struct hostent* hp; 186524084f9bSBrian Somers 186624084f9bSBrian Somers if (inet_aton (str, addr)) 186724084f9bSBrian Somers return; 186824084f9bSBrian Somers 186924084f9bSBrian Somers hp = gethostbyname (str); 18700fc81af1SPhilippe Charnier if (!hp) 18710fc81af1SPhilippe Charnier errx (1, "unknown host %s", str); 187224084f9bSBrian Somers 187324084f9bSBrian Somers memcpy (addr, hp->h_addr, sizeof (struct in_addr)); 187424084f9bSBrian Somers } 187524084f9bSBrian Somers 1876902cb50aSBrian Somers u_short StrToPort (const char* str, const char* proto) 187724084f9bSBrian Somers { 187867a886fbSBrian Somers u_short port; 187924084f9bSBrian Somers struct servent* sp; 188024084f9bSBrian Somers char* end; 188124084f9bSBrian Somers 188224084f9bSBrian Somers port = strtol (str, &end, 10); 188324084f9bSBrian Somers if (end != str) 188427c20503SBrian Somers return htons (port); 188524084f9bSBrian Somers 188624084f9bSBrian Somers sp = getservbyname (str, proto); 18870fc81af1SPhilippe Charnier if (!sp) 188829e3edccSPhilippe Charnier errx (1, "%s/%s: unknown service", str, proto); 188924084f9bSBrian Somers 189024084f9bSBrian Somers return sp->s_port; 189124084f9bSBrian Somers } 189224084f9bSBrian Somers 1893902cb50aSBrian Somers int StrToPortRange (const char* str, const char* proto, port_range *portRange) 18945d8ee958SBrian Somers { 18955d8ee958SBrian Somers char* sep; 18965d8ee958SBrian Somers struct servent* sp; 18975d8ee958SBrian Somers char* end; 18985d8ee958SBrian Somers u_short loPort; 18995d8ee958SBrian Somers u_short hiPort; 19005d8ee958SBrian Somers 19015d8ee958SBrian Somers /* First see if this is a service, return corresponding port if so. */ 19025d8ee958SBrian Somers sp = getservbyname (str,proto); 19035d8ee958SBrian Somers if (sp) { 19045d8ee958SBrian Somers SETLOPORT(*portRange, ntohs(sp->s_port)); 19055d8ee958SBrian Somers SETNUMPORTS(*portRange, 1); 19065d8ee958SBrian Somers return 0; 19075d8ee958SBrian Somers } 19085d8ee958SBrian Somers 19095d8ee958SBrian Somers /* Not a service, see if it's a single port or port range. */ 19105d8ee958SBrian Somers sep = strchr (str, '-'); 19115d8ee958SBrian Somers if (sep == NULL) { 19125d8ee958SBrian Somers SETLOPORT(*portRange, strtol(str, &end, 10)); 19135d8ee958SBrian Somers if (end != str) { 19145d8ee958SBrian Somers /* Single port. */ 19155d8ee958SBrian Somers SETNUMPORTS(*portRange, 1); 19165d8ee958SBrian Somers return 0; 19175d8ee958SBrian Somers } 19185d8ee958SBrian Somers 19195d8ee958SBrian Somers /* Error in port range field. */ 192029e3edccSPhilippe Charnier errx (1, "%s/%s: unknown service", str, proto); 19215d8ee958SBrian Somers } 19225d8ee958SBrian Somers 19235d8ee958SBrian Somers /* Port range, get the values and sanity check. */ 19245d8ee958SBrian Somers sscanf (str, "%hu-%hu", &loPort, &hiPort); 19255d8ee958SBrian Somers SETLOPORT(*portRange, loPort); 19265d8ee958SBrian Somers SETNUMPORTS(*portRange, 0); /* Error by default */ 19275d8ee958SBrian Somers if (loPort <= hiPort) 19285d8ee958SBrian Somers SETNUMPORTS(*portRange, hiPort - loPort + 1); 19295d8ee958SBrian Somers 19305d8ee958SBrian Somers if (GETNUMPORTS(*portRange) == 0) 19315d8ee958SBrian Somers errx (1, "invalid port range %s", str); 19325d8ee958SBrian Somers 19335d8ee958SBrian Somers return 0; 19345d8ee958SBrian Somers } 19355d8ee958SBrian Somers 19365d8ee958SBrian Somers 1937902cb50aSBrian Somers int StrToProto (const char* str) 193824084f9bSBrian Somers { 193924084f9bSBrian Somers if (!strcmp (str, "tcp")) 194024084f9bSBrian Somers return IPPROTO_TCP; 194124084f9bSBrian Somers 194224084f9bSBrian Somers if (!strcmp (str, "udp")) 194324084f9bSBrian Somers return IPPROTO_UDP; 194424084f9bSBrian Somers 19450fc81af1SPhilippe Charnier errx (1, "unknown protocol %s. Expected tcp or udp", str); 194624084f9bSBrian Somers } 194724084f9bSBrian Somers 1948902cb50aSBrian Somers int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange) 194924084f9bSBrian Somers { 195024084f9bSBrian Somers char* ptr; 195124084f9bSBrian Somers 195224084f9bSBrian Somers ptr = strchr (str, ':'); 19530fc81af1SPhilippe Charnier if (!ptr) 19540fc81af1SPhilippe Charnier errx (1, "%s is missing port number", str); 195524084f9bSBrian Somers 195624084f9bSBrian Somers *ptr = '\0'; 195724084f9bSBrian Somers ++ptr; 195824084f9bSBrian Somers 195924084f9bSBrian Somers StrToAddr (str, addr); 19605d8ee958SBrian Somers return StrToPortRange (ptr, proto, portRange); 196124084f9bSBrian Somers } 1962bc4ebb98SRuslan Ermilov 1963bc4ebb98SRuslan Ermilov static void 1964bc4ebb98SRuslan Ermilov SetupPunchFW(const char *strValue) 1965bc4ebb98SRuslan Ermilov { 1966bc4ebb98SRuslan Ermilov unsigned int base, num; 1967bc4ebb98SRuslan Ermilov 1968bc4ebb98SRuslan Ermilov if (sscanf(strValue, "%u:%u", &base, &num) != 2) 1969bc4ebb98SRuslan Ermilov errx(1, "punch_fw: basenumber:count parameter required"); 1970bc4ebb98SRuslan Ermilov 1971d53fe710SRoman Kurakin if (CheckIpfwRulenum(base + num - 1) == -1) 1972d53fe710SRoman Kurakin errx(1, "punch_fw: basenumber:count parameter should fit " 1973d53fe710SRoman Kurakin "the maximum allowed rule numbers"); 1974d53fe710SRoman Kurakin 197522c62477SPoul-Henning Kamp LibAliasSetFWBase(mla, base, num); 197622c62477SPoul-Henning Kamp (void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW); 1977bc4ebb98SRuslan Ermilov } 1978b07fbc17SJoe Marcus Clarke 1979b07fbc17SJoe Marcus Clarke static void 1980b07fbc17SJoe Marcus Clarke SetupSkinnyPort(const char *strValue) 1981b07fbc17SJoe Marcus Clarke { 1982b07fbc17SJoe Marcus Clarke unsigned int port; 1983b07fbc17SJoe Marcus Clarke 1984b07fbc17SJoe Marcus Clarke if (sscanf(strValue, "%u", &port) != 1) 1985b07fbc17SJoe Marcus Clarke errx(1, "skinny_port: port parameter required"); 1986b07fbc17SJoe Marcus Clarke 198722c62477SPoul-Henning Kamp LibAliasSetSkinnyPort(mla, port); 198822c62477SPoul-Henning Kamp } 198922c62477SPoul-Henning Kamp 199022c62477SPoul-Henning Kamp static void 199122c62477SPoul-Henning Kamp NewInstance(const char *name) 199222c62477SPoul-Henning Kamp { 199322c62477SPoul-Henning Kamp struct instance *ip; 199422c62477SPoul-Henning Kamp 199522c62477SPoul-Henning Kamp LIST_FOREACH(ip, &root, list) { 199622c62477SPoul-Henning Kamp if (!strcmp(ip->name, name)) { 199722c62477SPoul-Henning Kamp mla = ip->la; 199822c62477SPoul-Henning Kamp mip = ip; 199922c62477SPoul-Henning Kamp return; 200022c62477SPoul-Henning Kamp } 200122c62477SPoul-Henning Kamp } 200222c62477SPoul-Henning Kamp ninstance++; 200322c62477SPoul-Henning Kamp ip = calloc(sizeof *ip, 1); 200422c62477SPoul-Henning Kamp ip->name = strdup(name); 200522c62477SPoul-Henning Kamp ip->la = LibAliasInit (ip->la); 200622c62477SPoul-Henning Kamp ip->assignAliasAddr = 0; 200722c62477SPoul-Henning Kamp ip->ifName = NULL; 200822c62477SPoul-Henning Kamp ip->logDropped = 0; 200922c62477SPoul-Henning Kamp ip->inPort = 0; 201022c62477SPoul-Henning Kamp ip->outPort = 0; 201122c62477SPoul-Henning Kamp ip->inOutPort = 0; 201222c62477SPoul-Henning Kamp ip->aliasAddr.s_addr = INADDR_NONE; 201322c62477SPoul-Henning Kamp ip->ifMTU = -1; 201422c62477SPoul-Henning Kamp ip->aliasOverhead = 12; 201522c62477SPoul-Henning Kamp LIST_INSERT_HEAD(&root, ip, list); 201622c62477SPoul-Henning Kamp mla = ip->la; 201722c62477SPoul-Henning Kamp mip = ip; 2018b07fbc17SJoe Marcus Clarke } 2019d53fe710SRoman Kurakin 2020d53fe710SRoman Kurakin static int 2021d53fe710SRoman Kurakin CheckIpfwRulenum(unsigned int rnum) 2022d53fe710SRoman Kurakin { 2023d53fe710SRoman Kurakin unsigned int default_rule; 2024d53fe710SRoman Kurakin size_t len = sizeof(default_rule); 2025d53fe710SRoman Kurakin 2026d53fe710SRoman Kurakin if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len, 2027d53fe710SRoman Kurakin NULL, 0) == -1) { 2028d53fe710SRoman Kurakin warn("Failed to get the default ipfw rule number, using " 2029d53fe710SRoman Kurakin "default historical value 65535. The reason was"); 2030d53fe710SRoman Kurakin default_rule = 65535; 2031d53fe710SRoman Kurakin } 2032d53fe710SRoman Kurakin if (rnum >= default_rule) { 2033d53fe710SRoman Kurakin return -1; 2034d53fe710SRoman Kurakin } 2035d53fe710SRoman Kurakin 2036d53fe710SRoman Kurakin return 0; 2037d53fe710SRoman Kurakin } 2038