126781Sbrian/* 226781Sbrian * natd - Network Address Translation Daemon for FreeBSD. 326781Sbrian * 432026Salex * This software is provided free of charge, with no 526781Sbrian * warranty of any kind, either expressed or implied. 626781Sbrian * Use at your own risk. 726781Sbrian * 826781Sbrian * You may copy, modify and distribute this software (natd.c) freely. 926781Sbrian * 1028045Sbrian * Ari Suutari <suutari@iki.fi> 1126781Sbrian */ 1226781Sbrian 13110415Scharnier#include <sys/cdefs.h> 14110415Scharnier__FBSDID("$FreeBSD$"); 15110415Scharnier 1644558Sbrian#define SYSLOG_NAMES 1744558Sbrian 1826781Sbrian#include <sys/types.h> 1926781Sbrian#include <sys/socket.h> 2052200Sru#include <sys/sysctl.h> 2126781Sbrian#include <sys/time.h> 22131567Sphk#include <sys/queue.h> 2326781Sbrian 2426781Sbrian#include <netinet/in.h> 2526781Sbrian#include <netinet/in_systm.h> 2626781Sbrian#include <netinet/ip.h> 2726781Sbrian#include <machine/in_cksum.h> 2826781Sbrian#include <netinet/tcp.h> 2944558Sbrian#include <netinet/udp.h> 3044558Sbrian#include <netinet/ip_icmp.h> 3126781Sbrian#include <net/if.h> 3252200Sru#include <net/if_dl.h> 3326781Sbrian#include <net/route.h> 3426781Sbrian#include <arpa/inet.h> 3526781Sbrian 3630059Scharnier#include <alias.h> 3730059Scharnier#include <ctype.h> 3830059Scharnier#include <err.h> 3930059Scharnier#include <errno.h> 4030059Scharnier#include <netdb.h> 4130059Scharnier#include <signal.h> 4230059Scharnier#include <stdio.h> 4330059Scharnier#include <stdlib.h> 4430059Scharnier#include <string.h> 4526781Sbrian#include <syslog.h> 4630059Scharnier#include <unistd.h> 4731660Sbrian 4826781Sbrian#include "natd.h" 4926781Sbrian 50131567Sphkstruct instance { 51131567Sphk const char *name; 52131567Sphk struct libalias *la; 53131567Sphk LIST_ENTRY(instance) list; 54131567Sphk 55131567Sphk int ifIndex; 56131567Sphk int assignAliasAddr; 57131567Sphk char* ifName; 58131567Sphk int logDropped; 59131567Sphk u_short inPort; 60131567Sphk u_short outPort; 61131567Sphk u_short inOutPort; 62131567Sphk struct in_addr aliasAddr; 63131567Sphk int ifMTU; 64131567Sphk int aliasOverhead; 65131567Sphk int dropIgnoredIncoming; 66131567Sphk int divertIn; 67131567Sphk int divertOut; 68131567Sphk int divertInOut; 69131567Sphk}; 70131567Sphk 71201145Santoinestatic LIST_HEAD(, instance) root = LIST_HEAD_INITIALIZER(root); 72131567Sphk 73131567Sphkstruct libalias *mla; 74227081Sedstatic struct instance *mip; 75227081Sedstatic int ninstance = 1; 76131567Sphk 7726781Sbrian/* 7826781Sbrian * Default values for input and output 7926781Sbrian * divert socket ports. 8026781Sbrian */ 8126781Sbrian 8226781Sbrian#define DEFAULT_SERVICE "natd" 8326781Sbrian 8426781Sbrian/* 8545010Sbrian * Definition of a port range, and macros to deal with values. 8645010Sbrian * FORMAT: HI 16-bits == first port in range, 0 == all ports. 8745010Sbrian * LO 16-bits == number of ports in range 8845010Sbrian * NOTES: - Port values are not stored in network byte order. 8945010Sbrian */ 9045010Sbrian 9145010Sbriantypedef u_long port_range; 9245010Sbrian 9345010Sbrian#define GETLOPORT(x) ((x) >> 0x10) 9445010Sbrian#define GETNUMPORTS(x) ((x) & 0x0000ffff) 9545010Sbrian#define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x))) 9645010Sbrian 9745010Sbrian/* Set y to be the low-port value in port_range variable x. */ 9845010Sbrian#define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10)) 9945010Sbrian 10045010Sbrian/* Set y to be the number of ports in port_range variable x. */ 10145010Sbrian#define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y)) 10245010Sbrian 10345010Sbrian/* 10426781Sbrian * Function prototypes. 10526781Sbrian */ 10626781Sbrian 10744558Sbrianstatic void DoAliasing (int fd, int direction); 10845011Sbrianstatic void DaemonMode (void); 10931660Sbrianstatic void HandleRoutingInfo (int fd); 11045011Sbrianstatic void Usage (void); 11144558Sbrianstatic char* FormatPacket (struct ip*); 11231660Sbrianstatic void PrintPacket (struct ip*); 11345011Sbrianstatic void SyslogPacket (struct ip*, int priority, const char *label); 114220736Ssobomaxstatic int SetAliasAddressFromIfName (const char *ifName); 11545011Sbrianstatic void InitiateShutdown (int); 11645011Sbrianstatic void Shutdown (int); 11745011Sbrianstatic void RefreshAddr (int); 11861726Srustatic void ParseOption (const char* option, const char* parms); 11945011Sbrianstatic void ReadConfigFile (const char* fileName); 12045011Sbrianstatic void SetupPortRedirect (const char* parms); 12159921Srustatic void SetupProtoRedirect(const char* parms); 12245011Sbrianstatic void SetupAddressRedirect (const char* parms); 12345011Sbrianstatic void StrToAddr (const char* str, struct in_addr* addr); 12445011Sbrianstatic u_short StrToPort (const char* str, const char* proto); 12545011Sbrianstatic int StrToPortRange (const char* str, const char* proto, port_range *portRange); 12645011Sbrianstatic int StrToProto (const char* str); 12745011Sbrianstatic int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange); 12831660Sbrianstatic void ParseArgs (int argc, char** argv); 12962160Srustatic void SetupPunchFW(const char *strValue); 130120372Smarcusstatic void SetupSkinnyPort(const char *strValue); 131131567Sphkstatic void NewInstance(const char *name); 132131567Sphkstatic void DoGlobal (int fd); 133182825Srikstatic int CheckIpfwRulenum(unsigned int rnum); 13426781Sbrian 13526781Sbrian/* 13626781Sbrian * Globals. 13726781Sbrian */ 13826781Sbrian 13928045Sbrianstatic int verbose; 14028045Sbrianstatic int background; 14128045Sbrianstatic int running; 142131567Sphkstatic int logFacility; 143131567Sphk 14428045Sbrianstatic int dynamicMode; 14528045Sbrianstatic int icmpSock; 14686954Srustatic int logIpfwDenied; 147145797Sdelphijstatic const char* pidName; 148131567Sphkstatic int routeSock; 149131567Sphkstatic int globalPort; 150131567Sphkstatic int divertGlobal; 151179937Smavstatic int exitDelay; 15226781Sbrian 153179937Smav 15426781Sbrianint main (int argc, char** argv) 15526781Sbrian{ 15626781Sbrian struct sockaddr_in addr; 15726781Sbrian fd_set readMask; 15826781Sbrian int fdMax; 159220736Ssobomax int rval; 16026781Sbrian/* 16126781Sbrian * Initialize packet aliasing software. 16226781Sbrian * Done already here to be able to alter option bits 16326781Sbrian * during command line and configuration file processing. 16426781Sbrian */ 165131567Sphk NewInstance("default"); 166131567Sphk 16726781Sbrian/* 16826781Sbrian * Parse options. 16926781Sbrian */ 17026781Sbrian verbose = 0; 17126781Sbrian background = 0; 17226781Sbrian running = 1; 17326781Sbrian dynamicMode = 0; 17444558Sbrian logFacility = LOG_DAEMON; 17586955Sru logIpfwDenied = -1; 176118873Sru pidName = PIDFILE; 177131567Sphk routeSock = -1; 178131567Sphk icmpSock = -1; 179131567Sphk fdMax = -1; 180131567Sphk divertGlobal = -1; 181179937Smav exitDelay = EXIT_DELAY; 18226781Sbrian 18326781Sbrian ParseArgs (argc, argv); 18426781Sbrian/* 18586955Sru * Log ipfw(8) denied packets by default in verbose mode. 18686955Sru */ 18786955Sru if (logIpfwDenied == -1) 18886955Sru logIpfwDenied = verbose; 18986955Sru/* 19044558Sbrian * Open syslog channel. 19144558Sbrian */ 19252200Sru openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0), 19352200Sru logFacility); 194131567Sphk 195131567Sphk LIST_FOREACH(mip, &root, list) { 196131567Sphk mla = mip->la; 19744558Sbrian/* 198116319Sru * If not doing the transparent proxying only, 199116319Sru * check that valid aliasing address has been given. 20026781Sbrian */ 201131567Sphk if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL && 202131567Sphk !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY)) 203131567Sphk errx (1, "instance %s: aliasing address not given", mip->name); 20426781Sbrian 205131567Sphk if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL) 206131567Sphk errx (1, "both alias address and interface " 207131567Sphk "name are not allowed"); 20826781Sbrian/* 20926781Sbrian * Check that valid port number is known. 21026781Sbrian */ 211131567Sphk if (mip->inPort != 0 || mip->outPort != 0) 212131567Sphk if (mip->inPort == 0 || mip->outPort == 0) 213131567Sphk errx (1, "both input and output ports are required"); 21426781Sbrian 215131567Sphk if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0) 216131567Sphk ParseOption ("port", DEFAULT_SERVICE); 21726781Sbrian 21826781Sbrian/* 21929163Sbrian * Check if ignored packets should be dropped. 22029163Sbrian */ 221131567Sphk mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0); 222131567Sphk mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING; 22329163Sbrian/* 22426781Sbrian * Create divert sockets. Use only one socket if -p was specified 22526781Sbrian * on command line. Otherwise, create separate sockets for 226293290Sbdrewery * outgoing and incoming connections. 22726781Sbrian */ 228131567Sphk if (mip->inOutPort) { 22926781Sbrian 230131567Sphk mip->divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 231131567Sphk if (mip->divertInOut == -1) 232131567Sphk Quit ("Unable to create divert socket."); 233131567Sphk if (mip->divertInOut > fdMax) 234131567Sphk fdMax = mip->divertInOut; 23526781Sbrian 236131567Sphk mip->divertIn = -1; 237131567Sphk mip->divertOut = -1; 23826781Sbrian/* 23926781Sbrian * Bind socket. 24026781Sbrian */ 24126781Sbrian 242131567Sphk addr.sin_family = AF_INET; 243131567Sphk addr.sin_addr.s_addr = INADDR_ANY; 244131567Sphk addr.sin_port = mip->inOutPort; 24526781Sbrian 246131567Sphk if (bind (mip->divertInOut, 247131567Sphk (struct sockaddr*) &addr, 248131567Sphk sizeof addr) == -1) 249131567Sphk Quit ("Unable to bind divert socket."); 250131567Sphk } 251131567Sphk else { 25226781Sbrian 253131567Sphk mip->divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 254131567Sphk if (mip->divertIn == -1) 255131567Sphk Quit ("Unable to create incoming divert socket."); 256131567Sphk if (mip->divertIn > fdMax) 257131567Sphk fdMax = mip->divertIn; 25826781Sbrian 25926781Sbrian 260131567Sphk mip->divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 261131567Sphk if (mip->divertOut == -1) 262131567Sphk Quit ("Unable to create outgoing divert socket."); 263131567Sphk if (mip->divertOut > fdMax) 264131567Sphk fdMax = mip->divertOut; 26526781Sbrian 266131567Sphk mip->divertInOut = -1; 267131567Sphk 26826781Sbrian/* 26926781Sbrian * Bind divert sockets. 27026781Sbrian */ 27126781Sbrian 272131567Sphk addr.sin_family = AF_INET; 273131567Sphk addr.sin_addr.s_addr = INADDR_ANY; 274131567Sphk addr.sin_port = mip->inPort; 27526781Sbrian 276131567Sphk if (bind (mip->divertIn, 277131567Sphk (struct sockaddr*) &addr, 278131567Sphk sizeof addr) == -1) 279131567Sphk Quit ("Unable to bind incoming divert socket."); 28026781Sbrian 281131567Sphk addr.sin_family = AF_INET; 282131567Sphk addr.sin_addr.s_addr = INADDR_ANY; 283131567Sphk addr.sin_port = mip->outPort; 28426781Sbrian 285131567Sphk if (bind (mip->divertOut, 286131567Sphk (struct sockaddr*) &addr, 287131567Sphk sizeof addr) == -1) 288131567Sphk Quit ("Unable to bind outgoing divert socket."); 289131567Sphk } 29026781Sbrian/* 29151751Sru * Create routing socket if interface name specified and in dynamic mode. 29226781Sbrian */ 293131567Sphk if (mip->ifName) { 294131567Sphk if (dynamicMode) { 29526781Sbrian 296131567Sphk if (routeSock == -1) 297131567Sphk routeSock = socket (PF_ROUTE, SOCK_RAW, 0); 298131567Sphk if (routeSock == -1) 299131567Sphk Quit ("Unable to create routing info socket."); 300131567Sphk if (routeSock > fdMax) 301131567Sphk fdMax = routeSock; 30251751Sru 303131567Sphk mip->assignAliasAddr = 1; 304131567Sphk } 305220736Ssobomax else { 306220736Ssobomax do { 307220736Ssobomax rval = SetAliasAddressFromIfName (mip->ifName); 308220808Ssobomax if (background == 0 || dynamicMode == 0) 309220808Ssobomax break; 310220808Ssobomax if (rval == EAGAIN) 311220736Ssobomax sleep(1); 312220808Ssobomax } while (rval == EAGAIN); 313220736Ssobomax if (rval != 0) 314220736Ssobomax exit(1); 315220736Ssobomax } 31651751Sru } 317131567Sphk 31826781Sbrian } 319131567Sphk if (globalPort) { 320131567Sphk 321131567Sphk divertGlobal = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 322131567Sphk if (divertGlobal == -1) 323131567Sphk Quit ("Unable to create divert socket."); 324131567Sphk if (divertGlobal > fdMax) 325131567Sphk fdMax = divertGlobal; 326131567Sphk 32726781Sbrian/* 328131567Sphk* Bind socket. 329131567Sphk*/ 330131567Sphk 331131567Sphk addr.sin_family = AF_INET; 332131567Sphk addr.sin_addr.s_addr = INADDR_ANY; 333131567Sphk addr.sin_port = globalPort; 334131567Sphk 335131567Sphk if (bind (divertGlobal, 336131567Sphk (struct sockaddr*) &addr, 337131567Sphk sizeof addr) == -1) 338131567Sphk Quit ("Unable to bind global divert socket."); 339131567Sphk } 340131567Sphk/* 34126781Sbrian * Create socket for sending ICMP messages. 34226781Sbrian */ 34326781Sbrian icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); 34426781Sbrian if (icmpSock == -1) 34526781Sbrian Quit ("Unable to create ICMP socket."); 34645143Sbrian 34726781Sbrian/* 34845143Sbrian * And disable reads for the socket, otherwise it slowly fills 34945143Sbrian * up with received icmps which we do not use. 35045143Sbrian */ 35145143Sbrian shutdown(icmpSock, SHUT_RD); 35245143Sbrian 35345143Sbrian/* 35426781Sbrian * Become a daemon unless verbose mode was requested. 35526781Sbrian */ 35626781Sbrian if (!verbose) 35726781Sbrian DaemonMode (); 35826781Sbrian/* 35926781Sbrian * Catch signals to manage shutdown and 36026781Sbrian * refresh of interface address. 36126781Sbrian */ 36250810Sru siginterrupt(SIGTERM, 1); 36350810Sru siginterrupt(SIGHUP, 1); 364179937Smav if (exitDelay) 365179937Smav signal(SIGTERM, InitiateShutdown); 366179937Smav else 367179937Smav signal(SIGTERM, Shutdown); 36826781Sbrian signal (SIGHUP, RefreshAddr); 36926781Sbrian/* 37026781Sbrian * Set alias address if it has been given. 37126781Sbrian */ 372131567Sphk mip = LIST_FIRST(&root); /* XXX: simon */ 373131567Sphk LIST_FOREACH(mip, &root, list) { 374131567Sphk mla = mip->la; 375131567Sphk if (mip->aliasAddr.s_addr != INADDR_NONE) 376131567Sphk LibAliasSetAddress (mla, mip->aliasAddr); 377131567Sphk } 37826781Sbrian 37928045Sbrian while (running) { 380131567Sphk mip = LIST_FIRST(&root); /* XXX: simon */ 38128045Sbrian 382131567Sphk if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) { 38328045Sbrian/* 38428045Sbrian * When using only one socket, just call 38528045Sbrian * DoAliasing repeatedly to process packets. 38628045Sbrian */ 387131567Sphk DoAliasing (mip->divertInOut, DONT_KNOW); 38828045Sbrian continue; 38928045Sbrian } 39026781Sbrian/* 39126781Sbrian * Build read mask from socket descriptors to select. 39226781Sbrian */ 39328045Sbrian FD_ZERO (&readMask); 39428045Sbrian/* 39589396Sru * Check if new packets are available. 39628045Sbrian */ 397131567Sphk LIST_FOREACH(mip, &root, list) { 398131567Sphk if (mip->divertIn != -1) 399131567Sphk FD_SET (mip->divertIn, &readMask); 40028045Sbrian 401131567Sphk if (mip->divertOut != -1) 402131567Sphk FD_SET (mip->divertOut, &readMask); 40326781Sbrian 404131567Sphk if (mip->divertInOut != -1) 405131567Sphk FD_SET (mip->divertInOut, &readMask); 406131567Sphk } 40728045Sbrian/* 40828045Sbrian * Routing info is processed always. 40928045Sbrian */ 41028045Sbrian if (routeSock != -1) 41128045Sbrian FD_SET (routeSock, &readMask); 41226781Sbrian 413131567Sphk if (divertGlobal != -1) 414131567Sphk FD_SET (divertGlobal, &readMask); 415131567Sphk 41628045Sbrian if (select (fdMax + 1, 41728045Sbrian &readMask, 41828045Sbrian NULL, 41989396Sru NULL, 42028045Sbrian NULL) == -1) { 42126781Sbrian 42228045Sbrian if (errno == EINTR) 42328045Sbrian continue; 42426781Sbrian 42528045Sbrian Quit ("Select failed."); 42628045Sbrian } 42726781Sbrian 428131567Sphk if (divertGlobal != -1) 429131567Sphk if (FD_ISSET (divertGlobal, &readMask)) 430131567Sphk DoGlobal (divertGlobal); 431131567Sphk LIST_FOREACH(mip, &root, list) { 432131567Sphk mla = mip->la; 433131567Sphk if (mip->divertIn != -1) 434131567Sphk if (FD_ISSET (mip->divertIn, &readMask)) 435131567Sphk DoAliasing (mip->divertIn, INPUT); 43626781Sbrian 437131567Sphk if (mip->divertOut != -1) 438131567Sphk if (FD_ISSET (mip->divertOut, &readMask)) 439131567Sphk DoAliasing (mip->divertOut, OUTPUT); 44026781Sbrian 441131567Sphk if (mip->divertInOut != -1) 442131567Sphk if (FD_ISSET (mip->divertInOut, &readMask)) 443131567Sphk DoAliasing (mip->divertInOut, DONT_KNOW); 44426781Sbrian 445131567Sphk } 44628045Sbrian if (routeSock != -1) 44728045Sbrian if (FD_ISSET (routeSock, &readMask)) 44828045Sbrian HandleRoutingInfo (routeSock); 44926781Sbrian } 45026781Sbrian 45126781Sbrian if (background) 452118873Sru unlink (pidName); 45326781Sbrian 45426781Sbrian return 0; 45526781Sbrian} 45626781Sbrian 457202531Sedstatic void DaemonMode(void) 45826781Sbrian{ 45926781Sbrian FILE* pidFile; 46026781Sbrian 46126781Sbrian daemon (0, 0); 46226781Sbrian background = 1; 46326781Sbrian 464118873Sru pidFile = fopen (pidName, "w"); 46526781Sbrian if (pidFile) { 46626781Sbrian 46726781Sbrian fprintf (pidFile, "%d\n", getpid ()); 46826781Sbrian fclose (pidFile); 46926781Sbrian } 47026781Sbrian} 47126781Sbrian 47226781Sbrianstatic void ParseArgs (int argc, char** argv) 47326781Sbrian{ 47426781Sbrian int arg; 47526781Sbrian char* opt; 47626781Sbrian char parmBuf[256]; 47759798Sjoe int len; /* bounds checking */ 47826781Sbrian 47926781Sbrian for (arg = 1; arg < argc; arg++) { 48026781Sbrian 48126781Sbrian opt = argv[arg]; 48226781Sbrian if (*opt != '-') { 48326781Sbrian 48430059Scharnier warnx ("invalid option %s", opt); 48526781Sbrian Usage (); 48626781Sbrian } 48726781Sbrian 48826781Sbrian parmBuf[0] = '\0'; 48959798Sjoe len = 0; 49026781Sbrian 49126781Sbrian while (arg < argc - 1) { 49226781Sbrian 49326781Sbrian if (argv[arg + 1][0] == '-') 49426781Sbrian break; 49526781Sbrian 49661726Sru if (len) { 49759798Sjoe strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1)); 49859798Sjoe len += strlen(parmBuf + len); 49959798Sjoe } 50026781Sbrian 50126781Sbrian ++arg; 50259798Sjoe strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1)); 50359798Sjoe len += strlen(parmBuf + len); 50459798Sjoe 50526781Sbrian } 50626781Sbrian 50761726Sru ParseOption (opt + 1, (len ? parmBuf : NULL)); 50859798Sjoe 50926781Sbrian } 51026781Sbrian} 51126781Sbrian 512131567Sphkstatic void DoGlobal (int fd) 513131567Sphk{ 514131567Sphk int bytes; 515131567Sphk int origBytes; 516131567Sphk char buf[IP_MAXPACKET]; 517131567Sphk struct sockaddr_in addr; 518131567Sphk int wrote; 519145797Sdelphij socklen_t addrSize; 520131567Sphk struct ip* ip; 521131567Sphk char msgBuf[80]; 522131567Sphk 523131567Sphk/* 524131567Sphk * Get packet from socket. 525131567Sphk */ 526131567Sphk addrSize = sizeof addr; 527131567Sphk origBytes = recvfrom (fd, 528131567Sphk buf, 529131567Sphk sizeof buf, 530131567Sphk 0, 531131567Sphk (struct sockaddr*) &addr, 532131567Sphk &addrSize); 533131567Sphk 534131567Sphk if (origBytes == -1) { 535131567Sphk 536131567Sphk if (errno != EINTR) 537131567Sphk Warn ("read from divert socket failed"); 538131567Sphk 539131567Sphk return; 540131567Sphk } 541131567Sphk 542131567Sphk#if 0 543131567Sphk if (mip->assignAliasAddr) { 544220736Ssobomax if (SetAliasAddressFromIfName (mip->ifName) != 0) 545220736Ssobomax exit(1); 546131567Sphk mip->assignAliasAddr = 0; 547131567Sphk } 548131567Sphk#endif 549131567Sphk/* 550131567Sphk * This is an IP packet. 551131567Sphk */ 552131567Sphk ip = (struct ip*) buf; 553131567Sphk 554131567Sphk if (verbose) { 555131567Sphk/* 556131567Sphk * Print packet direction and protocol type. 557131567Sphk */ 558131567Sphk printf ("Glb "); 559131567Sphk 560131567Sphk switch (ip->ip_p) { 561131567Sphk case IPPROTO_TCP: 562131567Sphk printf ("[TCP] "); 563131567Sphk break; 564131567Sphk 565131567Sphk case IPPROTO_UDP: 566131567Sphk printf ("[UDP] "); 567131567Sphk break; 568131567Sphk 569131567Sphk case IPPROTO_ICMP: 570131567Sphk printf ("[ICMP] "); 571131567Sphk break; 572131567Sphk 573131567Sphk default: 574131567Sphk printf ("[%d] ", ip->ip_p); 575131567Sphk break; 576131567Sphk } 577131567Sphk/* 578131567Sphk * Print addresses. 579131567Sphk */ 580131567Sphk PrintPacket (ip); 581131567Sphk } 582131567Sphk 583131567Sphk LIST_FOREACH(mip, &root, list) { 584131567Sphk mla = mip->la; 585131567Sphk if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED) 586131567Sphk break; 587131567Sphk } 588131567Sphk/* 589131567Sphk * Length might have changed during aliasing. 590131567Sphk */ 591131567Sphk bytes = ntohs (ip->ip_len); 592131567Sphk/* 593131567Sphk * Update alias overhead size for outgoing packets. 594131567Sphk */ 595131567Sphk if (mip != NULL && bytes - origBytes > mip->aliasOverhead) 596131567Sphk mip->aliasOverhead = bytes - origBytes; 597131567Sphk 598131567Sphk if (verbose) { 599131567Sphk 600131567Sphk/* 601131567Sphk * Print addresses after aliasing. 602131567Sphk */ 603131567Sphk printf (" aliased to\n"); 604131567Sphk printf (" "); 605131567Sphk PrintPacket (ip); 606131567Sphk printf ("\n"); 607131567Sphk } 608131567Sphk 609131567Sphk/* 610131567Sphk * Put packet back for processing. 611131567Sphk */ 612131567Sphk wrote = sendto (fd, 613131567Sphk buf, 614131567Sphk bytes, 615131567Sphk 0, 616131567Sphk (struct sockaddr*) &addr, 617131567Sphk sizeof addr); 618131567Sphk 619131567Sphk if (wrote != bytes) { 620131567Sphk 621131567Sphk if (errno == EMSGSIZE) { 622131567Sphk 623131567Sphk if (mip->ifMTU != -1) 624131567Sphk SendNeedFragIcmp (icmpSock, 625131567Sphk (struct ip*) buf, 626131567Sphk mip->ifMTU - mip->aliasOverhead); 627131567Sphk } 628131567Sphk else if (errno == EACCES && logIpfwDenied) { 629131567Sphk 630131567Sphk sprintf (msgBuf, "failed to write packet back"); 631131567Sphk Warn (msgBuf); 632131567Sphk } 633131567Sphk } 634131567Sphk} 635131567Sphk 636131567Sphk 63744558Sbrianstatic void DoAliasing (int fd, int direction) 63826781Sbrian{ 63926781Sbrian int bytes; 64026781Sbrian int origBytes; 64189396Sru char buf[IP_MAXPACKET]; 64289396Sru struct sockaddr_in addr; 64389396Sru int wrote; 64429163Sbrian int status; 645145797Sdelphij socklen_t addrSize; 64626781Sbrian struct ip* ip; 64789396Sru char msgBuf[80]; 648220736Ssobomax int rval; 64926781Sbrian 650131567Sphk if (mip->assignAliasAddr) { 651220736Ssobomax do { 652220736Ssobomax rval = SetAliasAddressFromIfName (mip->ifName); 653220808Ssobomax if (background == 0 || dynamicMode == 0) 654220808Ssobomax break; 655220808Ssobomax if (rval == EAGAIN) 656220736Ssobomax sleep(1); 657220808Ssobomax } while (rval == EAGAIN); 658220736Ssobomax if (rval != 0) 659220736Ssobomax exit(1); 660131567Sphk mip->assignAliasAddr = 0; 66126781Sbrian } 66226781Sbrian/* 66326781Sbrian * Get packet from socket. 66426781Sbrian */ 66589396Sru addrSize = sizeof addr; 66626781Sbrian origBytes = recvfrom (fd, 66789396Sru buf, 66889396Sru sizeof buf, 66926781Sbrian 0, 67089396Sru (struct sockaddr*) &addr, 67126781Sbrian &addrSize); 67226781Sbrian 67326781Sbrian if (origBytes == -1) { 67426781Sbrian 67526781Sbrian if (errno != EINTR) 67630059Scharnier Warn ("read from divert socket failed"); 67726781Sbrian 67826781Sbrian return; 67926781Sbrian } 68026781Sbrian/* 681108533Sschweikh * This is an IP packet. 68226781Sbrian */ 68389396Sru ip = (struct ip*) buf; 68446080Simp if (direction == DONT_KNOW) { 68589396Sru if (addr.sin_addr.s_addr == INADDR_ANY) 68644558Sbrian direction = OUTPUT; 68744558Sbrian else 68844558Sbrian direction = INPUT; 68946080Simp } 69026781Sbrian 69126781Sbrian if (verbose) { 69226781Sbrian/* 69326781Sbrian * Print packet direction and protocol type. 69426781Sbrian */ 69544558Sbrian printf (direction == OUTPUT ? "Out " : "In "); 696131567Sphk if (ninstance > 1) 697145797Sdelphij printf ("{%s}", mip->name); 69826781Sbrian 69926781Sbrian switch (ip->ip_p) { 70026781Sbrian case IPPROTO_TCP: 70126781Sbrian printf ("[TCP] "); 70226781Sbrian break; 70326781Sbrian 70426781Sbrian case IPPROTO_UDP: 70526781Sbrian printf ("[UDP] "); 70626781Sbrian break; 70726781Sbrian 70826781Sbrian case IPPROTO_ICMP: 70926781Sbrian printf ("[ICMP] "); 71026781Sbrian break; 71126781Sbrian 71226781Sbrian default: 71344558Sbrian printf ("[%d] ", ip->ip_p); 71426781Sbrian break; 71526781Sbrian } 71626781Sbrian/* 71726781Sbrian * Print addresses. 71826781Sbrian */ 71926781Sbrian PrintPacket (ip); 72026781Sbrian } 72126781Sbrian 72244558Sbrian if (direction == OUTPUT) { 72326781Sbrian/* 72426781Sbrian * Outgoing packets. Do aliasing. 72526781Sbrian */ 726131567Sphk LibAliasOut (mla, buf, IP_MAXPACKET); 72726781Sbrian } 72826781Sbrian else { 72944558Sbrian 73026781Sbrian/* 73126781Sbrian * Do aliasing. 73226781Sbrian */ 733131567Sphk status = LibAliasIn (mla, buf, IP_MAXPACKET); 73429163Sbrian if (status == PKT_ALIAS_IGNORED && 735131567Sphk mip->dropIgnoredIncoming) { 73629163Sbrian 73744558Sbrian if (verbose) 73844558Sbrian printf (" dropped.\n"); 73944558Sbrian 740131567Sphk if (mip->logDropped) 74144558Sbrian SyslogPacket (ip, LOG_WARNING, "denied"); 74244558Sbrian 74329163Sbrian return; 74429163Sbrian } 74526781Sbrian } 74626781Sbrian/* 74726781Sbrian * Length might have changed during aliasing. 74826781Sbrian */ 74926781Sbrian bytes = ntohs (ip->ip_len); 75026781Sbrian/* 75126781Sbrian * Update alias overhead size for outgoing packets. 75226781Sbrian */ 75344558Sbrian if (direction == OUTPUT && 754131567Sphk bytes - origBytes > mip->aliasOverhead) 755131567Sphk mip->aliasOverhead = bytes - origBytes; 75626781Sbrian 75726781Sbrian if (verbose) { 75826781Sbrian 75926781Sbrian/* 76026781Sbrian * Print addresses after aliasing. 76126781Sbrian */ 76226781Sbrian printf (" aliased to\n"); 76326781Sbrian printf (" "); 76426781Sbrian PrintPacket (ip); 76526781Sbrian printf ("\n"); 76626781Sbrian } 76728045Sbrian 76826781Sbrian/* 76926781Sbrian * Put packet back for processing. 77026781Sbrian */ 77126781Sbrian wrote = sendto (fd, 77289396Sru buf, 77389396Sru bytes, 77426781Sbrian 0, 77589396Sru (struct sockaddr*) &addr, 77689396Sru sizeof addr); 77726781Sbrian 77889396Sru if (wrote != bytes) { 77926781Sbrian 78026781Sbrian if (errno == EMSGSIZE) { 78126781Sbrian 78289396Sru if (direction == OUTPUT && 783131567Sphk mip->ifMTU != -1) 78426781Sbrian SendNeedFragIcmp (icmpSock, 78589396Sru (struct ip*) buf, 786131567Sphk mip->ifMTU - mip->aliasOverhead); 78726781Sbrian } 78886954Sru else if (errno == EACCES && logIpfwDenied) { 78926781Sbrian 79078549Sjoe sprintf (msgBuf, "failed to write packet back"); 79126781Sbrian Warn (msgBuf); 79226781Sbrian } 79326781Sbrian } 79426781Sbrian} 79526781Sbrian 79626781Sbrianstatic void HandleRoutingInfo (int fd) 79726781Sbrian{ 79826781Sbrian int bytes; 79926781Sbrian struct if_msghdr ifMsg; 80026781Sbrian/* 80126781Sbrian * Get packet from socket. 80226781Sbrian */ 80326781Sbrian bytes = read (fd, &ifMsg, sizeof ifMsg); 80426781Sbrian if (bytes == -1) { 80526781Sbrian 80630059Scharnier Warn ("read from routing socket failed"); 80726781Sbrian return; 80826781Sbrian } 80926781Sbrian 81026781Sbrian if (ifMsg.ifm_version != RTM_VERSION) { 81126781Sbrian 81230059Scharnier Warn ("unexpected packet read from routing socket"); 81326781Sbrian return; 81426781Sbrian } 81526781Sbrian 81626781Sbrian if (verbose) 81756587Sru printf ("Routing message %#x received.\n", ifMsg.ifm_type); 81826781Sbrian 819131567Sphk if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) { 820131567Sphk LIST_FOREACH(mip, &root, list) { 821131567Sphk mla = mip->la; 822131567Sphk if (ifMsg.ifm_index == mip->ifIndex) { 823131567Sphk if (verbose) 824131567Sphk printf("Interface address/MTU has probably changed.\n"); 825131567Sphk mip->assignAliasAddr = 1; 826131567Sphk } 827131567Sphk } 82856587Sru } 82926781Sbrian} 83026781Sbrian 83126781Sbrianstatic void PrintPacket (struct ip* ip) 83226781Sbrian{ 83344558Sbrian printf ("%s", FormatPacket (ip)); 83444558Sbrian} 83544558Sbrian 83645011Sbrianstatic void SyslogPacket (struct ip* ip, int priority, const char *label) 83744558Sbrian{ 83844558Sbrian syslog (priority, "%s %s", label, FormatPacket (ip)); 83944558Sbrian} 84044558Sbrian 84144558Sbrianstatic char* FormatPacket (struct ip* ip) 84244558Sbrian{ 84344558Sbrian static char buf[256]; 84426781Sbrian struct tcphdr* tcphdr; 84544558Sbrian struct udphdr* udphdr; 84644558Sbrian struct icmp* icmphdr; 84744558Sbrian char src[20]; 84844558Sbrian char dst[20]; 84926781Sbrian 85044558Sbrian strcpy (src, inet_ntoa (ip->ip_src)); 85144558Sbrian strcpy (dst, inet_ntoa (ip->ip_dst)); 85244558Sbrian 85344558Sbrian switch (ip->ip_p) { 85444558Sbrian case IPPROTO_TCP: 85526781Sbrian tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2)); 85644558Sbrian sprintf (buf, "[TCP] %s:%d -> %s:%d", 85744558Sbrian src, 85844558Sbrian ntohs (tcphdr->th_sport), 85944558Sbrian dst, 86044558Sbrian ntohs (tcphdr->th_dport)); 86144558Sbrian break; 86226781Sbrian 86344558Sbrian case IPPROTO_UDP: 86444558Sbrian udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2)); 86544558Sbrian sprintf (buf, "[UDP] %s:%d -> %s:%d", 86644558Sbrian src, 86744558Sbrian ntohs (udphdr->uh_sport), 86844558Sbrian dst, 86944558Sbrian ntohs (udphdr->uh_dport)); 87044558Sbrian break; 87126781Sbrian 87244558Sbrian case IPPROTO_ICMP: 87344558Sbrian icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2)); 87444654Sbrian sprintf (buf, "[ICMP] %s -> %s %u(%u)", 87544558Sbrian src, 87644558Sbrian dst, 87744654Sbrian icmphdr->icmp_type, 87844654Sbrian icmphdr->icmp_code); 87944558Sbrian break; 88044558Sbrian 88144558Sbrian default: 88244558Sbrian sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst); 88344558Sbrian break; 88444558Sbrian } 88544558Sbrian 88644558Sbrian return buf; 88726781Sbrian} 88826781Sbrian 889220736Ssobomaxstatic int 89052200SruSetAliasAddressFromIfName(const char *ifn) 89126781Sbrian{ 89252200Sru size_t needed; 89352200Sru int mib[6]; 89452200Sru char *buf, *lim, *next; 89552200Sru struct if_msghdr *ifm; 89652200Sru struct ifa_msghdr *ifam; 89752200Sru struct sockaddr_dl *sdl; 89852200Sru struct sockaddr_in *sin; 89926781Sbrian 90052200Sru mib[0] = CTL_NET; 90152200Sru mib[1] = PF_ROUTE; 90252200Sru mib[2] = 0; 90352200Sru mib[3] = AF_INET; /* Only IP addresses please */ 90452200Sru mib[4] = NET_RT_IFLIST; 90552200Sru mib[5] = 0; /* ifIndex??? */ 90626781Sbrian/* 90726781Sbrian * Get interface data. 90826781Sbrian */ 90952200Sru if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) 91052200Sru err(1, "iflist-sysctl-estimate"); 91152200Sru if ((buf = malloc(needed)) == NULL) 91252200Sru errx(1, "malloc failed"); 913179607Sbrian if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1 && errno != ENOMEM) 91452200Sru err(1, "iflist-sysctl-get"); 91552200Sru lim = buf + needed; 91626781Sbrian/* 91726781Sbrian * Loop through interfaces until one with 91826781Sbrian * given name is found. This is done to 91926781Sbrian * find correct interface index for routing 92026781Sbrian * message processing. 92126781Sbrian */ 922131567Sphk mip->ifIndex = 0; 92352200Sru next = buf; 92452200Sru while (next < lim) { 92552200Sru ifm = (struct if_msghdr *)next; 92652200Sru next += ifm->ifm_msglen; 92752200Sru if (ifm->ifm_version != RTM_VERSION) { 92852200Sru if (verbose) 92952200Sru warnx("routing message version %d " 93052200Sru "not understood", ifm->ifm_version); 93152200Sru continue; 93226781Sbrian } 93352200Sru if (ifm->ifm_type == RTM_IFINFO) { 93452200Sru sdl = (struct sockaddr_dl *)(ifm + 1); 93552200Sru if (strlen(ifn) == sdl->sdl_nlen && 93652200Sru strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) { 937131567Sphk mip->ifIndex = ifm->ifm_index; 938131567Sphk mip->ifMTU = ifm->ifm_data.ifi_mtu; 93952200Sru break; 94052200Sru } 94126781Sbrian } 94226781Sbrian } 943131567Sphk if (!mip->ifIndex) 94452200Sru errx(1, "unknown interface name %s", ifn); 94526781Sbrian/* 94652200Sru * Get interface address. 94726781Sbrian */ 94852200Sru sin = NULL; 94952200Sru while (next < lim) { 95052200Sru ifam = (struct ifa_msghdr *)next; 95152200Sru next += ifam->ifam_msglen; 95252200Sru if (ifam->ifam_version != RTM_VERSION) { 95352200Sru if (verbose) 95452200Sru warnx("routing message version %d " 95552200Sru "not understood", ifam->ifam_version); 95652200Sru continue; 95752200Sru } 95852200Sru if (ifam->ifam_type != RTM_NEWADDR) 95952200Sru break; 96052200Sru if (ifam->ifam_addrs & RTA_IFA) { 96152200Sru int i; 96252200Sru char *cp = (char *)(ifam + 1); 96326781Sbrian 96452200Sru for (i = 1; i < RTA_IFA; i <<= 1) 96552200Sru if (ifam->ifam_addrs & i) 966128186Sluigi cp += SA_SIZE((struct sockaddr *)cp); 96752200Sru if (((struct sockaddr *)cp)->sa_family == AF_INET) { 96852200Sru sin = (struct sockaddr_in *)cp; 96952200Sru break; 97052200Sru } 97152200Sru } 97252200Sru } 973220736Ssobomax if (sin == NULL) { 974220736Ssobomax warnx("%s: cannot get interface address", ifn); 975220736Ssobomax free(buf); 976220806Ssobomax return EAGAIN; 977220736Ssobomax } 97826781Sbrian 979131567Sphk LibAliasSetAddress(mla, sin->sin_addr); 98052200Sru syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes", 981131567Sphk inet_ntoa(sin->sin_addr), mip->ifMTU); 98226781Sbrian 98352200Sru free(buf); 984220736Ssobomax 985220736Ssobomax return 0; 98626781Sbrian} 98726781Sbrian 98845011Sbrianvoid Quit (const char* msg) 98926781Sbrian{ 99026781Sbrian Warn (msg); 99126781Sbrian exit (1); 99226781Sbrian} 99326781Sbrian 99445011Sbrianvoid Warn (const char* msg) 99526781Sbrian{ 99626781Sbrian if (background) 99726781Sbrian syslog (LOG_ALERT, "%s (%m)", msg); 99826781Sbrian else 99962882Skris warn ("%s", msg); 100026781Sbrian} 100126781Sbrian 1002145797Sdelphijstatic void RefreshAddr (int sig __unused) 100326781Sbrian{ 1004162674Spiso LibAliasRefreshModules(); 1005162674Spiso if (mip != NULL && mip->ifName != NULL) 1006131567Sphk mip->assignAliasAddr = 1; 100726781Sbrian} 100826781Sbrian 1009145797Sdelphijstatic void InitiateShutdown (int sig __unused) 101026781Sbrian{ 101126781Sbrian/* 101226781Sbrian * Start timer to allow kernel gracefully 101326781Sbrian * shutdown existing connections when system 101426781Sbrian * is shut down. 101526781Sbrian */ 101650810Sru siginterrupt(SIGALRM, 1); 101726781Sbrian signal (SIGALRM, Shutdown); 1018179937Smav ualarm(exitDelay*1000, 1000); 101926781Sbrian} 102026781Sbrian 1021145797Sdelphijstatic void Shutdown (int sig __unused) 102226781Sbrian{ 102326781Sbrian running = 0; 102426781Sbrian} 102526781Sbrian 102626781Sbrian/* 102726781Sbrian * Different options recognized by this program. 102826781Sbrian */ 102926781Sbrian 103026781Sbrianenum Option { 103126781Sbrian 1032131567Sphk LibAliasOption, 1033131567Sphk Instance, 103426781Sbrian Verbose, 103526781Sbrian InPort, 103626781Sbrian OutPort, 103726781Sbrian Port, 1038131567Sphk GlobalPort, 103926781Sbrian AliasAddress, 104060683Sru TargetAddress, 104126781Sbrian InterfaceName, 104226781Sbrian RedirectPort, 104359921Sru RedirectProto, 104426781Sbrian RedirectAddress, 104526781Sbrian ConfigFile, 104644558Sbrian DynamicMode, 104744558Sbrian ProxyRule, 104844558Sbrian LogDenied, 104962160Sru LogFacility, 105085770Sphk PunchFW, 1051120372Smarcus SkinnyPort, 1052118873Sru LogIpfwDenied, 1053179937Smav PidFile, 1054179937Smav ExitDelay 105526781Sbrian}; 105626781Sbrian 105726781Sbrianenum Param { 105826781Sbrian 105926781Sbrian YesNo, 106026781Sbrian Numeric, 106126781Sbrian String, 106226781Sbrian None, 106326781Sbrian Address, 106426781Sbrian Service 106526781Sbrian}; 106626781Sbrian 106726781Sbrian/* 106826781Sbrian * Option information structure (used by ParseOption). 106926781Sbrian */ 107026781Sbrian 107126781Sbrianstruct OptionInfo { 107226781Sbrian 107326781Sbrian enum Option type; 107426781Sbrian int packetAliasOpt; 107526781Sbrian enum Param parm; 107645011Sbrian const char* parmDescription; 107745011Sbrian const char* description; 107845011Sbrian const char* name; 107945011Sbrian const char* shortName; 108026781Sbrian}; 108126781Sbrian 108226781Sbrian/* 108326781Sbrian * Table of known options. 108426781Sbrian */ 108526781Sbrian 108626781Sbrianstatic struct OptionInfo optionTable[] = { 108726781Sbrian 1088131567Sphk { LibAliasOption, 108926781Sbrian PKT_ALIAS_UNREGISTERED_ONLY, 109026781Sbrian YesNo, 109126781Sbrian "[yes|no]", 109226781Sbrian "alias only unregistered addresses", 109326781Sbrian "unregistered_only", 109426781Sbrian "u" }, 109526781Sbrian 1096131567Sphk { LibAliasOption, 109726781Sbrian PKT_ALIAS_LOG, 109826781Sbrian YesNo, 109926781Sbrian "[yes|no]", 110026781Sbrian "enable logging", 110126781Sbrian "log", 110226781Sbrian "l" }, 110326781Sbrian 1104131567Sphk { LibAliasOption, 110544558Sbrian PKT_ALIAS_PROXY_ONLY, 110644558Sbrian YesNo, 110744558Sbrian "[yes|no]", 110844558Sbrian "proxy only", 110944558Sbrian "proxy_only", 111044558Sbrian NULL }, 111144558Sbrian 1112131567Sphk { LibAliasOption, 111344558Sbrian PKT_ALIAS_REVERSE, 111444558Sbrian YesNo, 111544558Sbrian "[yes|no]", 111644558Sbrian "operate in reverse mode", 111744558Sbrian "reverse", 111844558Sbrian NULL }, 111944558Sbrian 1120131567Sphk { LibAliasOption, 112126781Sbrian PKT_ALIAS_DENY_INCOMING, 112226781Sbrian YesNo, 112326781Sbrian "[yes|no]", 112426781Sbrian "allow incoming connections", 112526781Sbrian "deny_incoming", 112626781Sbrian "d" }, 112726781Sbrian 1128131567Sphk { LibAliasOption, 112926781Sbrian PKT_ALIAS_USE_SOCKETS, 113026781Sbrian YesNo, 113126781Sbrian "[yes|no]", 113226781Sbrian "use sockets to inhibit port conflict", 113326781Sbrian "use_sockets", 113426781Sbrian "s" }, 113526781Sbrian 1136131567Sphk { LibAliasOption, 113726781Sbrian PKT_ALIAS_SAME_PORTS, 113826781Sbrian YesNo, 113926781Sbrian "[yes|no]", 114026781Sbrian "try to keep original port numbers for connections", 114126781Sbrian "same_ports", 114226781Sbrian "m" }, 114326781Sbrian 114426781Sbrian { Verbose, 114526781Sbrian 0, 114626781Sbrian YesNo, 114726781Sbrian "[yes|no]", 114826781Sbrian "verbose mode, dump packet information", 114926781Sbrian "verbose", 115026781Sbrian "v" }, 115126781Sbrian 115226781Sbrian { DynamicMode, 115326781Sbrian 0, 115426781Sbrian YesNo, 115526781Sbrian "[yes|no]", 115626781Sbrian "dynamic mode, automatically detect interface address changes", 115726781Sbrian "dynamic", 115826781Sbrian NULL }, 115926781Sbrian 116026781Sbrian { InPort, 116126781Sbrian 0, 116226781Sbrian Service, 116326781Sbrian "number|service_name", 116426781Sbrian "set port for incoming packets", 116526781Sbrian "in_port", 116626781Sbrian "i" }, 116726781Sbrian 116826781Sbrian { OutPort, 116926781Sbrian 0, 117026781Sbrian Service, 117126781Sbrian "number|service_name", 117226781Sbrian "set port for outgoing packets", 117326781Sbrian "out_port", 117426781Sbrian "o" }, 117526781Sbrian 117626781Sbrian { Port, 117726781Sbrian 0, 117826781Sbrian Service, 117926781Sbrian "number|service_name", 118026781Sbrian "set port (defaults to natd/divert)", 118126781Sbrian "port", 118226781Sbrian "p" }, 118326781Sbrian 1184131567Sphk { GlobalPort, 1185131567Sphk 0, 1186131567Sphk Service, 1187131567Sphk "number|service_name", 1188131567Sphk "set globalport", 1189131567Sphk "globalport", 1190131567Sphk NULL }, 1191131567Sphk 119226781Sbrian { AliasAddress, 119326781Sbrian 0, 119426781Sbrian Address, 119526781Sbrian "x.x.x.x", 119626781Sbrian "address to use for aliasing", 119726781Sbrian "alias_address", 119826781Sbrian "a" }, 119926781Sbrian 120060683Sru { TargetAddress, 120160683Sru 0, 120260683Sru Address, 120360683Sru "x.x.x.x", 120460683Sru "address to use for incoming sessions", 120560683Sru "target_address", 120660683Sru "t" }, 120760683Sru 120826781Sbrian { InterfaceName, 120926781Sbrian 0, 121026781Sbrian String, 121126781Sbrian "network_if_name", 121226781Sbrian "take aliasing address from interface", 121326781Sbrian "interface", 121426781Sbrian "n" }, 121526781Sbrian 121644558Sbrian { ProxyRule, 121726781Sbrian 0, 121826781Sbrian String, 121944558Sbrian "[type encode_ip_hdr|encode_tcp_stream] port xxxx server " 122044558Sbrian "a.b.c.d:yyyy", 122144558Sbrian "add transparent proxying / destination NAT", 122244558Sbrian "proxy_rule", 122326781Sbrian NULL }, 122426781Sbrian 122526781Sbrian { RedirectPort, 122626781Sbrian 0, 122726781Sbrian String, 122859703Sru "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range" 122945010Sbrian " [remote_addr[:remote_port_range]]", 123045010Sbrian "redirect a port (or ports) for incoming traffic", 123126781Sbrian "redirect_port", 123226781Sbrian NULL }, 123326781Sbrian 123459921Sru { RedirectProto, 123559921Sru 0, 123659921Sru String, 123759921Sru "proto local_addr [public_addr] [remote_addr]", 123859921Sru "redirect packets of a given proto", 123959921Sru "redirect_proto", 124059921Sru NULL }, 124159921Sru 124226781Sbrian { RedirectAddress, 124326781Sbrian 0, 124426781Sbrian String, 124559703Sru "local_addr[,...] public_addr", 124626781Sbrian "define mapping between local and public addresses", 124726781Sbrian "redirect_address", 124826781Sbrian NULL }, 124926781Sbrian 125026781Sbrian { ConfigFile, 125126781Sbrian 0, 125226781Sbrian String, 125326781Sbrian "file_name", 125426781Sbrian "read options from configuration file", 125526781Sbrian "config", 125644558Sbrian "f" }, 125744558Sbrian 125844558Sbrian { LogDenied, 125944558Sbrian 0, 126044558Sbrian YesNo, 126144558Sbrian "[yes|no]", 126244558Sbrian "enable logging of denied incoming packets", 126344558Sbrian "log_denied", 126444558Sbrian NULL }, 126544558Sbrian 126644558Sbrian { LogFacility, 126744558Sbrian 0, 126844558Sbrian String, 126944558Sbrian "facility", 127044558Sbrian "name of syslog facility to use for logging", 127144558Sbrian "log_facility", 127262160Sru NULL }, 127362160Sru 127462160Sru { PunchFW, 127562160Sru 0, 127662160Sru String, 127762160Sru "basenumber:count", 127862160Sru "punch holes in the firewall for incoming FTP/IRC DCC connections", 127962160Sru "punch_fw", 128085770Sphk NULL }, 128185770Sphk 1282120372Smarcus { SkinnyPort, 1283120372Smarcus 0, 1284120372Smarcus String, 1285120372Smarcus "port", 1286120372Smarcus "set the TCP port for use with the Skinny Station protocol", 1287120372Smarcus "skinny_port", 1288120372Smarcus NULL }, 1289120372Smarcus 129085770Sphk { LogIpfwDenied, 129185770Sphk 0, 129285770Sphk YesNo, 129385770Sphk "[yes|no]", 129485770Sphk "log packets converted by natd, but denied by ipfw", 129585770Sphk "log_ipfw_denied", 129685770Sphk NULL }, 1297118873Sru 1298118873Sru { PidFile, 1299118873Sru 0, 1300118873Sru String, 1301118873Sru "file_name", 1302118873Sru "store PID in an alternate file", 1303118873Sru "pid_file", 1304118873Sru "P" }, 1305131567Sphk { Instance, 1306131567Sphk 0, 1307131567Sphk String, 1308131567Sphk "instance name", 1309131567Sphk "name of aliasing engine instance", 1310131567Sphk "instance", 1311131567Sphk NULL }, 1312179937Smav { ExitDelay, 1313179937Smav 0, 1314179937Smav Numeric, 1315179937Smav "ms", 1316179937Smav "delay in ms before daemon exit after signal", 1317179937Smav "exit_delay", 1318179937Smav NULL }, 131926781Sbrian}; 132026781Sbrian 132161726Srustatic void ParseOption (const char* option, const char* parms) 132226781Sbrian{ 132326781Sbrian int i; 132426781Sbrian struct OptionInfo* info; 132526781Sbrian int yesNoValue; 132626781Sbrian int aliasValue; 132726781Sbrian int numValue; 132831660Sbrian u_short uNumValue; 132945011Sbrian const char* strValue; 133026781Sbrian struct in_addr addrValue; 133126781Sbrian int max; 133226781Sbrian char* end; 1333241736Sed const CODE* fac_record = NULL; 133426781Sbrian/* 133526781Sbrian * Find option from table. 133626781Sbrian */ 133726781Sbrian max = sizeof (optionTable) / sizeof (struct OptionInfo); 133826781Sbrian for (i = 0, info = optionTable; i < max; i++, info++) { 133926781Sbrian 134026781Sbrian if (!strcmp (info->name, option)) 134126781Sbrian break; 134226781Sbrian 134326781Sbrian if (info->shortName) 134426781Sbrian if (!strcmp (info->shortName, option)) 134526781Sbrian break; 134626781Sbrian } 134726781Sbrian 134826781Sbrian if (i >= max) { 134926781Sbrian 135030059Scharnier warnx ("unknown option %s", option); 135126781Sbrian Usage (); 135226781Sbrian } 135326781Sbrian 135431660Sbrian uNumValue = 0; 135526781Sbrian yesNoValue = 0; 135626781Sbrian numValue = 0; 135726781Sbrian strValue = NULL; 135826781Sbrian/* 135926781Sbrian * Check parameters. 136026781Sbrian */ 136126781Sbrian switch (info->parm) { 136226781Sbrian case YesNo: 136326781Sbrian if (!parms) 136426781Sbrian parms = "yes"; 136526781Sbrian 136626781Sbrian if (!strcmp (parms, "yes")) 136726781Sbrian yesNoValue = 1; 136826781Sbrian else 136926781Sbrian if (!strcmp (parms, "no")) 137026781Sbrian yesNoValue = 0; 137130059Scharnier else 137231660Sbrian errx (1, "%s needs yes/no parameter", option); 137326781Sbrian break; 137426781Sbrian 137526781Sbrian case Service: 137630059Scharnier if (!parms) 137731660Sbrian errx (1, "%s needs service name or " 137831660Sbrian "port number parameter", 137931660Sbrian option); 138026781Sbrian 138131660Sbrian uNumValue = StrToPort (parms, "divert"); 138226781Sbrian break; 138326781Sbrian 138426781Sbrian case Numeric: 138526781Sbrian if (parms) 138626781Sbrian numValue = strtol (parms, &end, 10); 138726781Sbrian else 138845011Sbrian end = NULL; 138926781Sbrian 139030059Scharnier if (end == parms) 139131660Sbrian errx (1, "%s needs numeric parameter", option); 139226781Sbrian break; 139326781Sbrian 139426781Sbrian case String: 139526781Sbrian strValue = parms; 139630059Scharnier if (!strValue) 139731660Sbrian errx (1, "%s needs parameter", option); 139826781Sbrian break; 139926781Sbrian 140026781Sbrian case None: 140130059Scharnier if (parms) 140231660Sbrian errx (1, "%s does not take parameters", option); 140326781Sbrian break; 140426781Sbrian 140526781Sbrian case Address: 140630059Scharnier if (!parms) 140731660Sbrian errx (1, "%s needs address/host parameter", option); 140826781Sbrian 140926781Sbrian StrToAddr (parms, &addrValue); 141026781Sbrian break; 141126781Sbrian } 141226781Sbrian 141326781Sbrian switch (info->type) { 1414131567Sphk case LibAliasOption: 141526781Sbrian 141626781Sbrian aliasValue = yesNoValue ? info->packetAliasOpt : 0; 1417131567Sphk LibAliasSetMode (mla, aliasValue, info->packetAliasOpt); 141826781Sbrian break; 141926781Sbrian 142026781Sbrian case Verbose: 142126781Sbrian verbose = yesNoValue; 142226781Sbrian break; 142326781Sbrian 142426781Sbrian case DynamicMode: 142526781Sbrian dynamicMode = yesNoValue; 142626781Sbrian break; 142726781Sbrian 142826781Sbrian case InPort: 1429131567Sphk mip->inPort = uNumValue; 143026781Sbrian break; 143126781Sbrian 143226781Sbrian case OutPort: 1433131567Sphk mip->outPort = uNumValue; 143426781Sbrian break; 143526781Sbrian 143626781Sbrian case Port: 1437131567Sphk mip->inOutPort = uNumValue; 143826781Sbrian break; 143926781Sbrian 1440131567Sphk case GlobalPort: 1441131567Sphk globalPort = uNumValue; 1442131567Sphk break; 1443131567Sphk 144426781Sbrian case AliasAddress: 1445131567Sphk memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr)); 144626781Sbrian break; 144726781Sbrian 144860683Sru case TargetAddress: 1449131567Sphk LibAliasSetTarget(mla, addrValue); 145060683Sru break; 145160683Sru 145226781Sbrian case RedirectPort: 145326781Sbrian SetupPortRedirect (strValue); 145426781Sbrian break; 145526781Sbrian 145659921Sru case RedirectProto: 145759921Sru SetupProtoRedirect(strValue); 145859921Sru break; 145959921Sru 146026781Sbrian case RedirectAddress: 146126781Sbrian SetupAddressRedirect (strValue); 146226781Sbrian break; 146326781Sbrian 146444558Sbrian case ProxyRule: 1465131567Sphk LibAliasProxyRule (mla, strValue); 146644558Sbrian break; 146744558Sbrian 146826781Sbrian case InterfaceName: 1469131567Sphk if (mip->ifName) 1470131567Sphk free (mip->ifName); 147126781Sbrian 1472131567Sphk mip->ifName = strdup (strValue); 147326781Sbrian break; 147426781Sbrian 147526781Sbrian case ConfigFile: 147626781Sbrian ReadConfigFile (strValue); 147726781Sbrian break; 147844558Sbrian 147944558Sbrian case LogDenied: 1480131567Sphk mip->logDropped = yesNoValue; 148144558Sbrian break; 148244558Sbrian 148344558Sbrian case LogFacility: 148444558Sbrian 148544558Sbrian fac_record = facilitynames; 148644558Sbrian while (fac_record->c_name != NULL) { 148744558Sbrian 148844558Sbrian if (!strcmp (fac_record->c_name, strValue)) { 148944558Sbrian 149044558Sbrian logFacility = fac_record->c_val; 149144558Sbrian break; 149244558Sbrian 149344558Sbrian } 149444558Sbrian else 149544558Sbrian fac_record++; 149644558Sbrian } 149744558Sbrian 149844558Sbrian if(fac_record->c_name == NULL) 149944558Sbrian errx(1, "Unknown log facility name: %s", strValue); 150044558Sbrian 150144558Sbrian break; 150262160Sru 150362160Sru case PunchFW: 150462160Sru SetupPunchFW(strValue); 150562160Sru break; 150686954Sru 1507120372Smarcus case SkinnyPort: 1508120372Smarcus SetupSkinnyPort(strValue); 1509120372Smarcus break; 1510120372Smarcus 151185770Sphk case LogIpfwDenied: 1512241844Seadler logIpfwDenied = yesNoValue; 151386954Sru break; 1514118873Sru 1515118873Sru case PidFile: 1516118873Sru pidName = strdup (strValue); 1517118873Sru break; 1518131567Sphk case Instance: 1519131567Sphk NewInstance(strValue); 1520131567Sphk break; 1521179937Smav case ExitDelay: 1522179937Smav if (numValue < 0 || numValue > MAX_EXIT_DELAY) 1523179937Smav errx(1, "Incorrect exit delay: %d", numValue); 1524179937Smav exitDelay = numValue; 1525179937Smav break; 152626781Sbrian } 152726781Sbrian} 152826781Sbrian 152945011Sbrianvoid ReadConfigFile (const char* fileName) 153026781Sbrian{ 153126781Sbrian FILE* file; 153257480Sru char *buf; 153357480Sru size_t len; 153451063Sru char *ptr, *p; 153526781Sbrian char* option; 153626781Sbrian 153726781Sbrian file = fopen (fileName, "r"); 153857480Sru if (!file) 153957480Sru err(1, "cannot open config file %s", fileName); 154026781Sbrian 154157480Sru while ((buf = fgetln(file, &len)) != NULL) { 154257480Sru if (buf[len - 1] == '\n') 154357480Sru buf[len - 1] = '\0'; 154457480Sru else 154557480Sru errx(1, "config file format error: " 154657480Sru "last line should end with newline"); 154726781Sbrian 154826781Sbrian/* 154951063Sru * Check for comments, strip off trailing spaces. 155026781Sbrian */ 155151063Sru if ((ptr = strchr(buf, '#'))) 155251063Sru *ptr = '\0'; 155351063Sru for (ptr = buf; isspace(*ptr); ++ptr) 155451063Sru continue; 155526781Sbrian if (*ptr == '\0') 155626781Sbrian continue; 155751063Sru for (p = strchr(buf, '\0'); isspace(*--p);) 155851063Sru continue; 155951063Sru *++p = '\0'; 156051063Sru 156126781Sbrian/* 156226781Sbrian * Extract option name. 156326781Sbrian */ 156426781Sbrian option = ptr; 156526781Sbrian while (*ptr && !isspace (*ptr)) 156626781Sbrian ++ptr; 156726781Sbrian 156826781Sbrian if (*ptr != '\0') { 156926781Sbrian 157026781Sbrian *ptr = '\0'; 157126781Sbrian ++ptr; 157226781Sbrian } 157326781Sbrian/* 157426781Sbrian * Skip white space between name and parms. 157526781Sbrian */ 157626781Sbrian while (*ptr && isspace (*ptr)) 157726781Sbrian ++ptr; 157826781Sbrian 157961726Sru ParseOption (option, *ptr ? ptr : NULL); 158026781Sbrian } 158126781Sbrian 158226781Sbrian fclose (file); 158326781Sbrian} 158426781Sbrian 1585202531Sedstatic void Usage(void) 158626781Sbrian{ 158726781Sbrian int i; 158826781Sbrian int max; 158926781Sbrian struct OptionInfo* info; 159026781Sbrian 159126781Sbrian fprintf (stderr, "Recognized options:\n\n"); 159226781Sbrian 159326781Sbrian max = sizeof (optionTable) / sizeof (struct OptionInfo); 159426781Sbrian for (i = 0, info = optionTable; i < max; i++, info++) { 159526781Sbrian 159626781Sbrian fprintf (stderr, "-%-20s %s\n", info->name, 159726781Sbrian info->parmDescription); 159826781Sbrian 159926781Sbrian if (info->shortName) 160026781Sbrian fprintf (stderr, "-%-20s %s\n", info->shortName, 160126781Sbrian info->parmDescription); 160226781Sbrian 160326781Sbrian fprintf (stderr, " %s\n\n", info->description); 160426781Sbrian } 160526781Sbrian 160626781Sbrian exit (1); 160726781Sbrian} 160826781Sbrian 160945011Sbrianvoid SetupPortRedirect (const char* parms) 161026781Sbrian{ 1611179935Smav char *buf; 161226781Sbrian char* ptr; 161359703Sru char* serverPool; 161426781Sbrian struct in_addr localAddr; 161526781Sbrian struct in_addr publicAddr; 161626781Sbrian struct in_addr remoteAddr; 161745010Sbrian port_range portRange; 161845010Sbrian u_short localPort = 0; 161945010Sbrian u_short publicPort = 0; 162045010Sbrian u_short remotePort = 0; 162145010Sbrian u_short numLocalPorts = 0; 162245010Sbrian u_short numPublicPorts = 0; 162345010Sbrian u_short numRemotePorts = 0; 162426781Sbrian int proto; 162526781Sbrian char* protoName; 162626781Sbrian char* separator; 162745010Sbrian int i; 1628145797Sdelphij struct alias_link *aliaslink = NULL; 162926781Sbrian 1630179935Smav buf = strdup (parms); 1631179935Smav if (!buf) 1632179935Smav errx (1, "redirect_port: strdup() failed"); 163326781Sbrian/* 163426781Sbrian * Extract protocol. 163526781Sbrian */ 163626781Sbrian protoName = strtok (buf, " \t"); 163730059Scharnier if (!protoName) 163831660Sbrian errx (1, "redirect_port: missing protocol"); 163926781Sbrian 164026781Sbrian proto = StrToProto (protoName); 164126781Sbrian/* 164226781Sbrian * Extract local address. 164326781Sbrian */ 164426781Sbrian ptr = strtok (NULL, " \t"); 164530059Scharnier if (!ptr) 164631660Sbrian errx (1, "redirect_port: missing local address"); 164726781Sbrian 164859703Sru separator = strchr(ptr, ','); 164959703Sru if (separator) { /* LSNAT redirection syntax. */ 165059703Sru localAddr.s_addr = INADDR_NONE; 165159703Sru localPort = ~0; 165259703Sru numLocalPorts = 1; 165359703Sru serverPool = ptr; 165459703Sru } else { 165559703Sru if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 ) 165659703Sru errx (1, "redirect_port: invalid local port range"); 165745010Sbrian 165859703Sru localPort = GETLOPORT(portRange); 165959703Sru numLocalPorts = GETNUMPORTS(portRange); 166059703Sru serverPool = NULL; 166159703Sru } 166245010Sbrian 166326781Sbrian/* 166447121Sbrian * Extract public port and optionally address. 166526781Sbrian */ 166626781Sbrian ptr = strtok (NULL, " \t"); 166730059Scharnier if (!ptr) 166831660Sbrian errx (1, "redirect_port: missing public port"); 166926781Sbrian 167026781Sbrian separator = strchr (ptr, ':'); 167145010Sbrian if (separator) { 167245010Sbrian if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 ) 167345010Sbrian errx (1, "redirect_port: invalid public port range"); 167445010Sbrian } 167526781Sbrian else { 167626781Sbrian publicAddr.s_addr = INADDR_ANY; 167745010Sbrian if (StrToPortRange (ptr, protoName, &portRange) != 0) 167845010Sbrian errx (1, "redirect_port: invalid public port range"); 167926781Sbrian } 168026781Sbrian 168145010Sbrian publicPort = GETLOPORT(portRange); 168245010Sbrian numPublicPorts = GETNUMPORTS(portRange); 168345010Sbrian 168426781Sbrian/* 168526781Sbrian * Extract remote address and optionally port. 168626781Sbrian */ 168726781Sbrian ptr = strtok (NULL, " \t"); 168826781Sbrian if (ptr) { 168926781Sbrian separator = strchr (ptr, ':'); 169046080Simp if (separator) { 169145010Sbrian if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0) 169245010Sbrian errx (1, "redirect_port: invalid remote port range"); 169346080Simp } else { 169445010Sbrian SETLOPORT(portRange, 0); 169545010Sbrian SETNUMPORTS(portRange, 1); 169626781Sbrian StrToAddr (ptr, &remoteAddr); 169726781Sbrian } 169826781Sbrian } 169926781Sbrian else { 170045010Sbrian SETLOPORT(portRange, 0); 170145010Sbrian SETNUMPORTS(portRange, 1); 170226781Sbrian remoteAddr.s_addr = INADDR_ANY; 170326781Sbrian } 170426781Sbrian 170545010Sbrian remotePort = GETLOPORT(portRange); 170645010Sbrian numRemotePorts = GETNUMPORTS(portRange); 170745010Sbrian 170845010Sbrian/* 170945010Sbrian * Make sure port ranges match up, then add the redirect ports. 171045010Sbrian */ 171145010Sbrian if (numLocalPorts != numPublicPorts) 171245010Sbrian errx (1, "redirect_port: port ranges must be equal in size"); 171345010Sbrian 171445010Sbrian /* Remote port range is allowed to be '0' which means all ports. */ 171547122Sbrian if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0)) 171645010Sbrian errx (1, "redirect_port: remote port must be 0 or equal to local port range in size"); 171745010Sbrian 171845010Sbrian for (i = 0 ; i < numPublicPorts ; ++i) { 171945010Sbrian /* If remotePort is all ports, set it to 0. */ 172045010Sbrian u_short remotePortCopy = remotePort + i; 172145010Sbrian if (numRemotePorts == 1 && remotePort == 0) 172245010Sbrian remotePortCopy = 0; 172345010Sbrian 1724145797Sdelphij aliaslink = LibAliasRedirectPort (mla, localAddr, 172559703Sru htons(localPort + i), 172659703Sru remoteAddr, 172759703Sru htons(remotePortCopy), 172859703Sru publicAddr, 172959703Sru htons(publicPort + i), 173059703Sru proto); 173145010Sbrian } 173259703Sru 173359703Sru/* 173459703Sru * Setup LSNAT server pool. 173559703Sru */ 1736145797Sdelphij if (serverPool != NULL && aliaslink != NULL) { 173759703Sru ptr = strtok(serverPool, ","); 173859703Sru while (ptr != NULL) { 173959703Sru if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0) 174059703Sru errx(1, "redirect_port: invalid local port range"); 174159703Sru 174259703Sru localPort = GETLOPORT(portRange); 174359703Sru if (GETNUMPORTS(portRange) != 1) 174459703Sru errx(1, "redirect_port: local port must be single in this context"); 1745145797Sdelphij LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort)); 174659703Sru ptr = strtok(NULL, ","); 174759703Sru } 174859703Sru } 1749179935Smav 1750179935Smav free (buf); 175126781Sbrian} 175226781Sbrian 175359921Sruvoid 175459921SruSetupProtoRedirect(const char* parms) 175559921Sru{ 1756179935Smav char *buf; 175759921Sru char* ptr; 175859921Sru struct in_addr localAddr; 175959921Sru struct in_addr publicAddr; 176059921Sru struct in_addr remoteAddr; 176159921Sru int proto; 176259921Sru char* protoName; 176359921Sru struct protoent *protoent; 176459921Sru 1765179935Smav buf = strdup (parms); 1766179935Smav if (!buf) 1767179935Smav errx (1, "redirect_port: strdup() failed"); 176859921Sru/* 176959921Sru * Extract protocol. 177059921Sru */ 177159921Sru protoName = strtok(buf, " \t"); 177259921Sru if (!protoName) 177359921Sru errx(1, "redirect_proto: missing protocol"); 177459921Sru 177559921Sru protoent = getprotobyname(protoName); 177659921Sru if (protoent == NULL) 177759921Sru errx(1, "redirect_proto: unknown protocol %s", protoName); 177859921Sru else 177959921Sru proto = protoent->p_proto; 178059921Sru/* 178159921Sru * Extract local address. 178259921Sru */ 178359921Sru ptr = strtok(NULL, " \t"); 178459921Sru if (!ptr) 178559921Sru errx(1, "redirect_proto: missing local address"); 178659921Sru else 178759921Sru StrToAddr(ptr, &localAddr); 178859921Sru/* 178959921Sru * Extract optional public address. 179059921Sru */ 179159921Sru ptr = strtok(NULL, " \t"); 179259921Sru if (ptr) 179359921Sru StrToAddr(ptr, &publicAddr); 179459921Sru else 179559921Sru publicAddr.s_addr = INADDR_ANY; 179659921Sru/* 179759921Sru * Extract optional remote address. 179859921Sru */ 179959921Sru ptr = strtok(NULL, " \t"); 180059921Sru if (ptr) 180159921Sru StrToAddr(ptr, &remoteAddr); 180259921Sru else 180359921Sru remoteAddr.s_addr = INADDR_ANY; 180459921Sru/* 180559921Sru * Create aliasing link. 180659921Sru */ 1807131567Sphk (void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr, 180859921Sru proto); 1809179935Smav 1810179935Smav free (buf); 181159921Sru} 181259921Sru 181345011Sbrianvoid SetupAddressRedirect (const char* parms) 181426781Sbrian{ 1815179935Smav char *buf; 181626781Sbrian char* ptr; 181759703Sru char* separator; 181826781Sbrian struct in_addr localAddr; 181926781Sbrian struct in_addr publicAddr; 182059703Sru char* serverPool; 1821145797Sdelphij struct alias_link *aliaslink; 182226781Sbrian 1823179935Smav buf = strdup (parms); 1824179935Smav if (!buf) 1825179935Smav errx (1, "redirect_port: strdup() failed"); 182626781Sbrian/* 182726781Sbrian * Extract local address. 182826781Sbrian */ 182926781Sbrian ptr = strtok (buf, " \t"); 183030059Scharnier if (!ptr) 183131660Sbrian errx (1, "redirect_address: missing local address"); 183226781Sbrian 183359703Sru separator = strchr(ptr, ','); 183459703Sru if (separator) { /* LSNAT redirection syntax. */ 183559703Sru localAddr.s_addr = INADDR_NONE; 183659703Sru serverPool = ptr; 183759703Sru } else { 183859703Sru StrToAddr (ptr, &localAddr); 183959703Sru serverPool = NULL; 184059703Sru } 184126781Sbrian/* 184226781Sbrian * Extract public address. 184326781Sbrian */ 184426781Sbrian ptr = strtok (NULL, " \t"); 184530059Scharnier if (!ptr) 184631660Sbrian errx (1, "redirect_address: missing public address"); 184726781Sbrian 184826781Sbrian StrToAddr (ptr, &publicAddr); 1849145797Sdelphij aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr); 185059703Sru 185159703Sru/* 185259703Sru * Setup LSNAT server pool. 185359703Sru */ 1854145797Sdelphij if (serverPool != NULL && aliaslink != NULL) { 185559703Sru ptr = strtok(serverPool, ","); 185659703Sru while (ptr != NULL) { 185759703Sru StrToAddr(ptr, &localAddr); 1858145797Sdelphij LibAliasAddServer(mla, aliaslink, localAddr, htons(~0)); 185959703Sru ptr = strtok(NULL, ","); 186059703Sru } 186159703Sru } 1862179935Smav 1863179935Smav free (buf); 186426781Sbrian} 186526781Sbrian 186645011Sbrianvoid StrToAddr (const char* str, struct in_addr* addr) 186726781Sbrian{ 186826781Sbrian struct hostent* hp; 186926781Sbrian 187026781Sbrian if (inet_aton (str, addr)) 187126781Sbrian return; 187226781Sbrian 187326781Sbrian hp = gethostbyname (str); 187430059Scharnier if (!hp) 187531660Sbrian errx (1, "unknown host %s", str); 187626781Sbrian 187726781Sbrian memcpy (addr, hp->h_addr, sizeof (struct in_addr)); 187826781Sbrian} 187926781Sbrian 188045011Sbrianu_short StrToPort (const char* str, const char* proto) 188126781Sbrian{ 188231660Sbrian u_short port; 188326781Sbrian struct servent* sp; 188426781Sbrian char* end; 188526781Sbrian 188626781Sbrian port = strtol (str, &end, 10); 188726781Sbrian if (end != str) 188831576Sbrian return htons (port); 188926781Sbrian 189026781Sbrian sp = getservbyname (str, proto); 189130059Scharnier if (!sp) 1892110415Scharnier errx (1, "%s/%s: unknown service", str, proto); 189326781Sbrian 189426781Sbrian return sp->s_port; 189526781Sbrian} 189626781Sbrian 189745011Sbrianint StrToPortRange (const char* str, const char* proto, port_range *portRange) 189845010Sbrian{ 189945010Sbrian char* sep; 190045010Sbrian struct servent* sp; 190145010Sbrian char* end; 190245010Sbrian u_short loPort; 190345010Sbrian u_short hiPort; 190445010Sbrian 190545010Sbrian /* First see if this is a service, return corresponding port if so. */ 190645010Sbrian sp = getservbyname (str,proto); 190745010Sbrian if (sp) { 190845010Sbrian SETLOPORT(*portRange, ntohs(sp->s_port)); 190945010Sbrian SETNUMPORTS(*portRange, 1); 191045010Sbrian return 0; 191145010Sbrian } 191245010Sbrian 191345010Sbrian /* Not a service, see if it's a single port or port range. */ 191445010Sbrian sep = strchr (str, '-'); 191545010Sbrian if (sep == NULL) { 191645010Sbrian SETLOPORT(*portRange, strtol(str, &end, 10)); 191745010Sbrian if (end != str) { 191845010Sbrian /* Single port. */ 191945010Sbrian SETNUMPORTS(*portRange, 1); 192045010Sbrian return 0; 192145010Sbrian } 192245010Sbrian 192345010Sbrian /* Error in port range field. */ 1924110415Scharnier errx (1, "%s/%s: unknown service", str, proto); 192545010Sbrian } 192645010Sbrian 192745010Sbrian /* Port range, get the values and sanity check. */ 192845010Sbrian sscanf (str, "%hu-%hu", &loPort, &hiPort); 192945010Sbrian SETLOPORT(*portRange, loPort); 193045010Sbrian SETNUMPORTS(*portRange, 0); /* Error by default */ 193145010Sbrian if (loPort <= hiPort) 193245010Sbrian SETNUMPORTS(*portRange, hiPort - loPort + 1); 193345010Sbrian 193445010Sbrian if (GETNUMPORTS(*portRange) == 0) 193545010Sbrian errx (1, "invalid port range %s", str); 193645010Sbrian 193745010Sbrian return 0; 193845010Sbrian} 193945010Sbrian 194045010Sbrian 194145011Sbrianint StrToProto (const char* str) 194226781Sbrian{ 194326781Sbrian if (!strcmp (str, "tcp")) 194426781Sbrian return IPPROTO_TCP; 194526781Sbrian 194626781Sbrian if (!strcmp (str, "udp")) 194726781Sbrian return IPPROTO_UDP; 194826781Sbrian 194931660Sbrian errx (1, "unknown protocol %s. Expected tcp or udp", str); 195026781Sbrian} 195126781Sbrian 195245011Sbrianint StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange) 195326781Sbrian{ 195426781Sbrian char* ptr; 195526781Sbrian 195626781Sbrian ptr = strchr (str, ':'); 195730059Scharnier if (!ptr) 195831660Sbrian errx (1, "%s is missing port number", str); 195926781Sbrian 196026781Sbrian *ptr = '\0'; 196126781Sbrian ++ptr; 196226781Sbrian 196326781Sbrian StrToAddr (str, addr); 196445010Sbrian return StrToPortRange (ptr, proto, portRange); 196526781Sbrian} 196662160Sru 196762160Srustatic void 196862160SruSetupPunchFW(const char *strValue) 196962160Sru{ 197062160Sru unsigned int base, num; 197162160Sru 197262160Sru if (sscanf(strValue, "%u:%u", &base, &num) != 2) 197362160Sru errx(1, "punch_fw: basenumber:count parameter required"); 197462160Sru 1975182825Srik if (CheckIpfwRulenum(base + num - 1) == -1) 1976182825Srik errx(1, "punch_fw: basenumber:count parameter should fit " 1977182825Srik "the maximum allowed rule numbers"); 1978182825Srik 1979131567Sphk LibAliasSetFWBase(mla, base, num); 1980131567Sphk (void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW); 198162160Sru} 1982120372Smarcus 1983120372Smarcusstatic void 1984120372SmarcusSetupSkinnyPort(const char *strValue) 1985120372Smarcus{ 1986120372Smarcus unsigned int port; 1987120372Smarcus 1988120372Smarcus if (sscanf(strValue, "%u", &port) != 1) 1989120372Smarcus errx(1, "skinny_port: port parameter required"); 1990120372Smarcus 1991131567Sphk LibAliasSetSkinnyPort(mla, port); 1992120372Smarcus} 1993131567Sphk 1994131567Sphkstatic void 1995131567SphkNewInstance(const char *name) 1996131567Sphk{ 1997131567Sphk struct instance *ip; 1998131567Sphk 1999131567Sphk LIST_FOREACH(ip, &root, list) { 2000131567Sphk if (!strcmp(ip->name, name)) { 2001131567Sphk mla = ip->la; 2002131567Sphk mip = ip; 2003131567Sphk return; 2004131567Sphk } 2005131567Sphk } 2006131567Sphk ninstance++; 2007131567Sphk ip = calloc(sizeof *ip, 1); 2008131567Sphk ip->name = strdup(name); 2009131567Sphk ip->la = LibAliasInit (ip->la); 2010131567Sphk ip->assignAliasAddr = 0; 2011131567Sphk ip->ifName = NULL; 2012131567Sphk ip->logDropped = 0; 2013131567Sphk ip->inPort = 0; 2014131567Sphk ip->outPort = 0; 2015131567Sphk ip->inOutPort = 0; 2016131567Sphk ip->aliasAddr.s_addr = INADDR_NONE; 2017131567Sphk ip->ifMTU = -1; 2018131567Sphk ip->aliasOverhead = 12; 2019131567Sphk LIST_INSERT_HEAD(&root, ip, list); 2020131567Sphk mla = ip->la; 2021131567Sphk mip = ip; 2022131567Sphk} 2023182825Srik 2024182825Srikstatic int 2025182825SrikCheckIpfwRulenum(unsigned int rnum) 2026182825Srik{ 2027182825Srik unsigned int default_rule; 2028182825Srik size_t len = sizeof(default_rule); 2029182825Srik 2030182825Srik if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len, 2031182825Srik NULL, 0) == -1) { 2032182825Srik warn("Failed to get the default ipfw rule number, using " 2033182825Srik "default historical value 65535. The reason was"); 2034182825Srik default_rule = 65535; 2035182825Srik } 2036182825Srik if (rnum >= default_rule) { 2037182825Srik return -1; 2038182825Srik } 2039182825Srik 2040182825Srik return 0; 2041182825Srik} 2042