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>
1459a7c613SBrian Somers #define SYSLOG_NAMES
1559a7c613SBrian Somers
1624084f9bSBrian Somers #include <sys/types.h>
1724084f9bSBrian Somers #include <sys/socket.h>
184c04fa4cSRuslan Ermilov #include <sys/sysctl.h>
1924084f9bSBrian Somers #include <sys/time.h>
2022c62477SPoul-Henning Kamp #include <sys/queue.h>
2124084f9bSBrian Somers
2224084f9bSBrian Somers #include <netinet/in.h>
2324084f9bSBrian Somers #include <netinet/in_systm.h>
2424084f9bSBrian Somers #include <netinet/ip.h>
2524084f9bSBrian Somers #include <netinet/tcp.h>
2659a7c613SBrian Somers #include <netinet/udp.h>
2759a7c613SBrian Somers #include <netinet/ip_icmp.h>
2824084f9bSBrian Somers #include <net/if.h>
294c04fa4cSRuslan Ermilov #include <net/if_dl.h>
3024084f9bSBrian Somers #include <net/route.h>
3124084f9bSBrian Somers #include <arpa/inet.h>
3224084f9bSBrian Somers
3324084f9bSBrian Somers #include <alias.h>
340fc81af1SPhilippe Charnier #include <ctype.h>
350fc81af1SPhilippe Charnier #include <err.h>
360fc81af1SPhilippe Charnier #include <errno.h>
370fc81af1SPhilippe Charnier #include <netdb.h>
380fc81af1SPhilippe Charnier #include <signal.h>
390fc81af1SPhilippe Charnier #include <stdio.h>
400fc81af1SPhilippe Charnier #include <stdlib.h>
410fc81af1SPhilippe Charnier #include <string.h>
420fc81af1SPhilippe Charnier #include <syslog.h>
430fc81af1SPhilippe Charnier #include <unistd.h>
4467a886fbSBrian Somers
4524084f9bSBrian Somers #include "natd.h"
4624084f9bSBrian Somers
4722c62477SPoul-Henning Kamp struct instance {
4822c62477SPoul-Henning Kamp const char *name;
4922c62477SPoul-Henning Kamp struct libalias *la;
5022c62477SPoul-Henning Kamp LIST_ENTRY(instance) list;
5122c62477SPoul-Henning Kamp
5222c62477SPoul-Henning Kamp int ifIndex;
5322c62477SPoul-Henning Kamp int assignAliasAddr;
5422c62477SPoul-Henning Kamp char* ifName;
5522c62477SPoul-Henning Kamp int logDropped;
5622c62477SPoul-Henning Kamp u_short inPort;
5722c62477SPoul-Henning Kamp u_short outPort;
5822c62477SPoul-Henning Kamp u_short inOutPort;
5922c62477SPoul-Henning Kamp struct in_addr aliasAddr;
6022c62477SPoul-Henning Kamp int ifMTU;
6122c62477SPoul-Henning Kamp int aliasOverhead;
6222c62477SPoul-Henning Kamp int dropIgnoredIncoming;
6322c62477SPoul-Henning Kamp int divertIn;
6422c62477SPoul-Henning Kamp int divertOut;
6522c62477SPoul-Henning Kamp int divertInOut;
6622c62477SPoul-Henning Kamp };
6722c62477SPoul-Henning Kamp
6813e403fdSAntoine Brodin static LIST_HEAD(, instance) root = LIST_HEAD_INITIALIZER(root);
6922c62477SPoul-Henning Kamp
7022c62477SPoul-Henning Kamp struct libalias *mla;
711efe3c6bSEd Schouten static struct instance *mip;
721efe3c6bSEd Schouten static int ninstance = 1;
7322c62477SPoul-Henning Kamp
7424084f9bSBrian Somers /*
7524084f9bSBrian Somers * Default values for input and output
7624084f9bSBrian Somers * divert socket ports.
7724084f9bSBrian Somers */
7824084f9bSBrian Somers
7924084f9bSBrian Somers #define DEFAULT_SERVICE "natd"
8024084f9bSBrian Somers
8124084f9bSBrian Somers /*
825d8ee958SBrian Somers * Definition of a port range, and macros to deal with values.
835d8ee958SBrian Somers * FORMAT: HI 16-bits == first port in range, 0 == all ports.
845d8ee958SBrian Somers * LO 16-bits == number of ports in range
855d8ee958SBrian Somers * NOTES: - Port values are not stored in network byte order.
865d8ee958SBrian Somers */
875d8ee958SBrian Somers
885d8ee958SBrian Somers typedef u_long port_range;
895d8ee958SBrian Somers
905d8ee958SBrian Somers #define GETLOPORT(x) ((x) >> 0x10)
915d8ee958SBrian Somers #define GETNUMPORTS(x) ((x) & 0x0000ffff)
925d8ee958SBrian Somers #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x)))
935d8ee958SBrian Somers
945d8ee958SBrian Somers /* Set y to be the low-port value in port_range variable x. */
955d8ee958SBrian Somers #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
965d8ee958SBrian Somers
975d8ee958SBrian Somers /* Set y to be the number of ports in port_range variable x. */
985d8ee958SBrian Somers #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
995d8ee958SBrian Somers
1005d8ee958SBrian Somers /*
10124084f9bSBrian Somers * Function prototypes.
10224084f9bSBrian Somers */
10324084f9bSBrian Somers
10459a7c613SBrian Somers static void DoAliasing (int fd, int direction);
105902cb50aSBrian Somers static void DaemonMode (void);
10624084f9bSBrian Somers static void HandleRoutingInfo (int fd);
107902cb50aSBrian Somers static void Usage (void);
10859a7c613SBrian Somers static char* FormatPacket (struct ip*);
10924084f9bSBrian Somers static void PrintPacket (struct ip*);
110902cb50aSBrian Somers static void SyslogPacket (struct ip*, int priority, const char *label);
1110afb958bSMaxim Sobolev static int SetAliasAddressFromIfName (const char *ifName);
112902cb50aSBrian Somers static void InitiateShutdown (int);
113902cb50aSBrian Somers static void Shutdown (int);
114902cb50aSBrian Somers static void RefreshAddr (int);
115b0f55af6SRuslan Ermilov static void ParseOption (const char* option, const char* parms);
116902cb50aSBrian Somers static void ReadConfigFile (const char* fileName);
117902cb50aSBrian Somers static void SetupPortRedirect (const char* parms);
1184330006dSRuslan Ermilov static void SetupProtoRedirect(const char* parms);
119902cb50aSBrian Somers static void SetupAddressRedirect (const char* parms);
120902cb50aSBrian Somers static void StrToAddr (const char* str, struct in_addr* addr);
121902cb50aSBrian Somers static u_short StrToPort (const char* str, const char* proto);
122902cb50aSBrian Somers static int StrToPortRange (const char* str, const char* proto, port_range *portRange);
123902cb50aSBrian Somers static int StrToProto (const char* str);
124ef02f85cSPoul-Henning Kamp static int StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange);
12524084f9bSBrian Somers static void ParseArgs (int argc, char** argv);
126bc4ebb98SRuslan Ermilov static void SetupPunchFW(const char *strValue);
127b07fbc17SJoe Marcus Clarke static void SetupSkinnyPort(const char *strValue);
12822c62477SPoul-Henning Kamp static void NewInstance(const char *name);
12922c62477SPoul-Henning Kamp static void DoGlobal (int fd);
130d53fe710SRoman Kurakin static int CheckIpfwRulenum(unsigned int rnum);
13124084f9bSBrian Somers
13224084f9bSBrian Somers /*
13324084f9bSBrian Somers * Globals.
13424084f9bSBrian Somers */
13524084f9bSBrian Somers
13624084f9bSBrian Somers static int verbose;
13724084f9bSBrian Somers static int background;
13824084f9bSBrian Somers static int running;
13959a7c613SBrian Somers static int logFacility;
14022c62477SPoul-Henning Kamp
14122c62477SPoul-Henning Kamp static int dynamicMode;
14222c62477SPoul-Henning Kamp static int icmpSock;
1433843533eSRuslan Ermilov static int logIpfwDenied;
14448ce8ca1SXin LI static const char* pidName;
14522c62477SPoul-Henning Kamp static int routeSock;
14622c62477SPoul-Henning Kamp static int globalPort;
14722c62477SPoul-Henning Kamp static int divertGlobal;
14872cbe4adSAlexander Motin static int exitDelay;
14972cbe4adSAlexander Motin
15024084f9bSBrian Somers
main(int argc,char ** argv)15124084f9bSBrian Somers int main (int argc, char** argv)
15224084f9bSBrian Somers {
15324084f9bSBrian Somers struct sockaddr_in addr;
15424084f9bSBrian Somers fd_set readMask;
15524084f9bSBrian Somers int fdMax;
1560afb958bSMaxim Sobolev int rval;
15724084f9bSBrian Somers /*
15824084f9bSBrian Somers * Initialize packet aliasing software.
15924084f9bSBrian Somers * Done already here to be able to alter option bits
16024084f9bSBrian Somers * during command line and configuration file processing.
16124084f9bSBrian Somers */
16222c62477SPoul-Henning Kamp NewInstance("default");
16322c62477SPoul-Henning Kamp
16424084f9bSBrian Somers /*
16524084f9bSBrian Somers * Parse options.
16624084f9bSBrian Somers */
16724084f9bSBrian Somers verbose = 0;
16824084f9bSBrian Somers background = 0;
16924084f9bSBrian Somers running = 1;
17024084f9bSBrian Somers dynamicMode = 0;
17159a7c613SBrian Somers logFacility = LOG_DAEMON;
172c0956cf8SRuslan Ermilov logIpfwDenied = -1;
173b79840a6SRuslan Ermilov pidName = PIDFILE;
17422c62477SPoul-Henning Kamp routeSock = -1;
17522c62477SPoul-Henning Kamp icmpSock = -1;
17622c62477SPoul-Henning Kamp fdMax = -1;
17722c62477SPoul-Henning Kamp divertGlobal = -1;
17872cbe4adSAlexander Motin exitDelay = EXIT_DELAY;
17924084f9bSBrian Somers
18024084f9bSBrian Somers ParseArgs (argc, argv);
18124084f9bSBrian Somers /*
182c0956cf8SRuslan Ermilov * Log ipfw(8) denied packets by default in verbose mode.
183c0956cf8SRuslan Ermilov */
184c0956cf8SRuslan Ermilov if (logIpfwDenied == -1)
185c0956cf8SRuslan Ermilov logIpfwDenied = verbose;
186c0956cf8SRuslan Ermilov /*
18759a7c613SBrian Somers * Open syslog channel.
18859a7c613SBrian Somers */
1894c04fa4cSRuslan Ermilov openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
1904c04fa4cSRuslan Ermilov logFacility);
19122c62477SPoul-Henning Kamp
19222c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) {
19322c62477SPoul-Henning Kamp mla = mip->la;
19459a7c613SBrian Somers /*
1953d23e8b8SRuslan Ermilov * If not doing the transparent proxying only,
1963d23e8b8SRuslan Ermilov * check that valid aliasing address has been given.
19724084f9bSBrian Somers */
19822c62477SPoul-Henning Kamp if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL &&
19922c62477SPoul-Henning Kamp !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY))
20022c62477SPoul-Henning Kamp errx (1, "instance %s: aliasing address not given", mip->name);
20124084f9bSBrian Somers
20222c62477SPoul-Henning Kamp if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL)
20367a886fbSBrian Somers errx (1, "both alias address and interface "
20467a886fbSBrian Somers "name are not allowed");
20524084f9bSBrian Somers /*
20624084f9bSBrian Somers * Check that valid port number is known.
20724084f9bSBrian Somers */
20822c62477SPoul-Henning Kamp if (mip->inPort != 0 || mip->outPort != 0)
20922c62477SPoul-Henning Kamp if (mip->inPort == 0 || mip->outPort == 0)
2100fc81af1SPhilippe Charnier errx (1, "both input and output ports are required");
21124084f9bSBrian Somers
21222c62477SPoul-Henning Kamp if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0)
213b0f55af6SRuslan Ermilov ParseOption ("port", DEFAULT_SERVICE);
21424084f9bSBrian Somers
21524084f9bSBrian Somers /*
216f9b06d5cSBrian Somers * Check if ignored packets should be dropped.
217f9b06d5cSBrian Somers */
21822c62477SPoul-Henning Kamp mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0);
21922c62477SPoul-Henning Kamp mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
220f9b06d5cSBrian Somers /*
22124084f9bSBrian Somers * Create divert sockets. Use only one socket if -p was specified
22224084f9bSBrian Somers * on command line. Otherwise, create separate sockets for
223463a577bSEitan Adler * outgoing and incoming connections.
22424084f9bSBrian Somers */
22522c62477SPoul-Henning Kamp if (mip->inOutPort) {
22624084f9bSBrian Somers
2271df08e90SGleb Smirnoff mip->divertInOut = socket(PF_DIVERT, SOCK_RAW, 0);
22822c62477SPoul-Henning Kamp if (mip->divertInOut == -1)
22924084f9bSBrian Somers Quit ("Unable to create divert socket.");
23022c62477SPoul-Henning Kamp if (mip->divertInOut > fdMax)
23122c62477SPoul-Henning Kamp fdMax = mip->divertInOut;
23224084f9bSBrian Somers
23322c62477SPoul-Henning Kamp mip->divertIn = -1;
23422c62477SPoul-Henning Kamp mip->divertOut = -1;
23524084f9bSBrian Somers /*
23624084f9bSBrian Somers * Bind socket.
23724084f9bSBrian Somers */
23824084f9bSBrian Somers
23924084f9bSBrian Somers addr.sin_family = AF_INET;
24024084f9bSBrian Somers addr.sin_addr.s_addr = INADDR_ANY;
24122c62477SPoul-Henning Kamp addr.sin_port = mip->inOutPort;
24224084f9bSBrian Somers
24322c62477SPoul-Henning Kamp if (bind (mip->divertInOut,
24424084f9bSBrian Somers (struct sockaddr*) &addr,
24524084f9bSBrian Somers sizeof addr) == -1)
24624084f9bSBrian Somers Quit ("Unable to bind divert socket.");
24724084f9bSBrian Somers }
24824084f9bSBrian Somers else {
24924084f9bSBrian Somers
2501df08e90SGleb Smirnoff mip->divertIn = socket(PF_DIVERT, SOCK_RAW, 0);
25122c62477SPoul-Henning Kamp if (mip->divertIn == -1)
25224084f9bSBrian Somers Quit ("Unable to create incoming divert socket.");
25322c62477SPoul-Henning Kamp if (mip->divertIn > fdMax)
25422c62477SPoul-Henning Kamp fdMax = mip->divertIn;
25524084f9bSBrian Somers
25622c62477SPoul-Henning Kamp
2571df08e90SGleb Smirnoff mip->divertOut = socket(PF_DIVERT, SOCK_RAW, 0);
25822c62477SPoul-Henning Kamp if (mip->divertOut == -1)
25924084f9bSBrian Somers Quit ("Unable to create outgoing divert socket.");
26022c62477SPoul-Henning Kamp if (mip->divertOut > fdMax)
26122c62477SPoul-Henning Kamp fdMax = mip->divertOut;
26224084f9bSBrian Somers
26322c62477SPoul-Henning Kamp mip->divertInOut = -1;
26424084f9bSBrian Somers
26524084f9bSBrian Somers /*
26624084f9bSBrian Somers * Bind divert sockets.
26724084f9bSBrian Somers */
26824084f9bSBrian Somers
26924084f9bSBrian Somers addr.sin_family = AF_INET;
27024084f9bSBrian Somers addr.sin_addr.s_addr = INADDR_ANY;
27122c62477SPoul-Henning Kamp addr.sin_port = mip->inPort;
27224084f9bSBrian Somers
27322c62477SPoul-Henning Kamp if (bind (mip->divertIn,
27424084f9bSBrian Somers (struct sockaddr*) &addr,
27524084f9bSBrian Somers sizeof addr) == -1)
27624084f9bSBrian Somers Quit ("Unable to bind incoming divert socket.");
27724084f9bSBrian Somers
27824084f9bSBrian Somers addr.sin_family = AF_INET;
27924084f9bSBrian Somers addr.sin_addr.s_addr = INADDR_ANY;
28022c62477SPoul-Henning Kamp addr.sin_port = mip->outPort;
28124084f9bSBrian Somers
28222c62477SPoul-Henning Kamp if (bind (mip->divertOut,
28324084f9bSBrian Somers (struct sockaddr*) &addr,
28424084f9bSBrian Somers sizeof addr) == -1)
28524084f9bSBrian Somers Quit ("Unable to bind outgoing divert socket.");
28624084f9bSBrian Somers }
28724084f9bSBrian Somers /*
288f2da55a2SRuslan Ermilov * Create routing socket if interface name specified and in dynamic mode.
28924084f9bSBrian Somers */
29022c62477SPoul-Henning Kamp if (mip->ifName) {
291f2da55a2SRuslan Ermilov if (dynamicMode) {
29224084f9bSBrian Somers
29322c62477SPoul-Henning Kamp if (routeSock == -1)
29424084f9bSBrian Somers routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
29524084f9bSBrian Somers if (routeSock == -1)
29624084f9bSBrian Somers Quit ("Unable to create routing info socket.");
29722c62477SPoul-Henning Kamp if (routeSock > fdMax)
29822c62477SPoul-Henning Kamp fdMax = routeSock;
299f2da55a2SRuslan Ermilov
30022c62477SPoul-Henning Kamp mip->assignAliasAddr = 1;
30124084f9bSBrian Somers }
3020afb958bSMaxim Sobolev else {
3030afb958bSMaxim Sobolev do {
3040afb958bSMaxim Sobolev rval = SetAliasAddressFromIfName (mip->ifName);
305dde269c9SMaxim Sobolev if (background == 0 || dynamicMode == 0)
306dde269c9SMaxim Sobolev break;
307dde269c9SMaxim Sobolev if (rval == EAGAIN)
3080afb958bSMaxim Sobolev sleep(1);
309dde269c9SMaxim Sobolev } while (rval == EAGAIN);
3100afb958bSMaxim Sobolev if (rval != 0)
3110afb958bSMaxim Sobolev exit(1);
3120afb958bSMaxim Sobolev }
31322c62477SPoul-Henning Kamp }
31422c62477SPoul-Henning Kamp
31522c62477SPoul-Henning Kamp }
31622c62477SPoul-Henning Kamp if (globalPort) {
31722c62477SPoul-Henning Kamp
3181df08e90SGleb Smirnoff divertGlobal = socket(PF_DIVERT, SOCK_RAW, 0);
31922c62477SPoul-Henning Kamp if (divertGlobal == -1)
32022c62477SPoul-Henning Kamp Quit ("Unable to create divert socket.");
32122c62477SPoul-Henning Kamp if (divertGlobal > fdMax)
32222c62477SPoul-Henning Kamp fdMax = divertGlobal;
32322c62477SPoul-Henning Kamp
32422c62477SPoul-Henning Kamp /*
32522c62477SPoul-Henning Kamp * Bind socket.
32622c62477SPoul-Henning Kamp */
32722c62477SPoul-Henning Kamp
32822c62477SPoul-Henning Kamp addr.sin_family = AF_INET;
32922c62477SPoul-Henning Kamp addr.sin_addr.s_addr = INADDR_ANY;
33022c62477SPoul-Henning Kamp addr.sin_port = globalPort;
33122c62477SPoul-Henning Kamp
33222c62477SPoul-Henning Kamp if (bind (divertGlobal,
33322c62477SPoul-Henning Kamp (struct sockaddr*) &addr,
33422c62477SPoul-Henning Kamp sizeof addr) == -1)
33522c62477SPoul-Henning Kamp Quit ("Unable to bind global divert socket.");
336f2da55a2SRuslan Ermilov }
33724084f9bSBrian Somers /*
33824084f9bSBrian Somers * Create socket for sending ICMP messages.
33924084f9bSBrian Somers */
34024084f9bSBrian Somers icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
34124084f9bSBrian Somers if (icmpSock == -1)
34224084f9bSBrian Somers Quit ("Unable to create ICMP socket.");
343f3d64024SBrian Somers
344f3d64024SBrian Somers /*
345f3d64024SBrian Somers * And disable reads for the socket, otherwise it slowly fills
346f3d64024SBrian Somers * up with received icmps which we do not use.
347f3d64024SBrian Somers */
348f3d64024SBrian Somers shutdown(icmpSock, SHUT_RD);
349f3d64024SBrian Somers
35024084f9bSBrian Somers /*
35124084f9bSBrian Somers * Become a daemon unless verbose mode was requested.
35224084f9bSBrian Somers */
35324084f9bSBrian Somers if (!verbose)
35424084f9bSBrian Somers DaemonMode ();
35524084f9bSBrian Somers /*
35624084f9bSBrian Somers * Catch signals to manage shutdown and
35724084f9bSBrian Somers * refresh of interface address.
35824084f9bSBrian Somers */
359cd45c931SRuslan Ermilov siginterrupt(SIGTERM, 1);
360cd45c931SRuslan Ermilov siginterrupt(SIGHUP, 1);
36172cbe4adSAlexander Motin if (exitDelay)
36224084f9bSBrian Somers signal(SIGTERM, InitiateShutdown);
36372cbe4adSAlexander Motin else
36472cbe4adSAlexander Motin signal(SIGTERM, Shutdown);
36524084f9bSBrian Somers signal (SIGHUP, RefreshAddr);
36624084f9bSBrian Somers /*
36724084f9bSBrian Somers * Set alias address if it has been given.
36824084f9bSBrian Somers */
36922c62477SPoul-Henning Kamp mip = LIST_FIRST(&root); /* XXX: simon */
37022c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) {
37122c62477SPoul-Henning Kamp mla = mip->la;
37222c62477SPoul-Henning Kamp if (mip->aliasAddr.s_addr != INADDR_NONE)
37322c62477SPoul-Henning Kamp LibAliasSetAddress (mla, mip->aliasAddr);
37422c62477SPoul-Henning Kamp }
37524084f9bSBrian Somers
37624084f9bSBrian Somers while (running) {
37722c62477SPoul-Henning Kamp mip = LIST_FIRST(&root); /* XXX: simon */
378fb994b07SBrian Somers
37922c62477SPoul-Henning Kamp if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) {
380fb994b07SBrian Somers /*
381fb994b07SBrian Somers * When using only one socket, just call
382fb994b07SBrian Somers * DoAliasing repeatedly to process packets.
383fb994b07SBrian Somers */
38422c62477SPoul-Henning Kamp DoAliasing (mip->divertInOut, DONT_KNOW);
385fb994b07SBrian Somers continue;
386fb994b07SBrian Somers }
38724084f9bSBrian Somers /*
38824084f9bSBrian Somers * Build read mask from socket descriptors to select.
38924084f9bSBrian Somers */
39024084f9bSBrian Somers FD_ZERO (&readMask);
391fb994b07SBrian Somers /*
3923daff242SRuslan Ermilov * Check if new packets are available.
393fb994b07SBrian Somers */
39422c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) {
39522c62477SPoul-Henning Kamp if (mip->divertIn != -1)
39622c62477SPoul-Henning Kamp FD_SET (mip->divertIn, &readMask);
39724084f9bSBrian Somers
39822c62477SPoul-Henning Kamp if (mip->divertOut != -1)
39922c62477SPoul-Henning Kamp FD_SET (mip->divertOut, &readMask);
40024084f9bSBrian Somers
40122c62477SPoul-Henning Kamp if (mip->divertInOut != -1)
40222c62477SPoul-Henning Kamp FD_SET (mip->divertInOut, &readMask);
40322c62477SPoul-Henning Kamp }
404fb994b07SBrian Somers /*
405fb994b07SBrian Somers * Routing info is processed always.
406fb994b07SBrian Somers */
40724084f9bSBrian Somers if (routeSock != -1)
40824084f9bSBrian Somers FD_SET (routeSock, &readMask);
40924084f9bSBrian Somers
41022c62477SPoul-Henning Kamp if (divertGlobal != -1)
41122c62477SPoul-Henning Kamp FD_SET (divertGlobal, &readMask);
41222c62477SPoul-Henning Kamp
41324084f9bSBrian Somers if (select (fdMax + 1,
41424084f9bSBrian Somers &readMask,
4153daff242SRuslan Ermilov NULL,
41624084f9bSBrian Somers NULL,
41724084f9bSBrian Somers NULL) == -1) {
41824084f9bSBrian Somers
41924084f9bSBrian Somers if (errno == EINTR)
42024084f9bSBrian Somers continue;
42124084f9bSBrian Somers
42224084f9bSBrian Somers Quit ("Select failed.");
42324084f9bSBrian Somers }
42424084f9bSBrian Somers
42522c62477SPoul-Henning Kamp if (divertGlobal != -1)
42622c62477SPoul-Henning Kamp if (FD_ISSET (divertGlobal, &readMask))
42722c62477SPoul-Henning Kamp DoGlobal (divertGlobal);
42822c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) {
42922c62477SPoul-Henning Kamp mla = mip->la;
43022c62477SPoul-Henning Kamp if (mip->divertIn != -1)
43122c62477SPoul-Henning Kamp if (FD_ISSET (mip->divertIn, &readMask))
43222c62477SPoul-Henning Kamp DoAliasing (mip->divertIn, INPUT);
43324084f9bSBrian Somers
43422c62477SPoul-Henning Kamp if (mip->divertOut != -1)
43522c62477SPoul-Henning Kamp if (FD_ISSET (mip->divertOut, &readMask))
43622c62477SPoul-Henning Kamp DoAliasing (mip->divertOut, OUTPUT);
43724084f9bSBrian Somers
43822c62477SPoul-Henning Kamp if (mip->divertInOut != -1)
43922c62477SPoul-Henning Kamp if (FD_ISSET (mip->divertInOut, &readMask))
44022c62477SPoul-Henning Kamp DoAliasing (mip->divertInOut, DONT_KNOW);
44124084f9bSBrian Somers
44222c62477SPoul-Henning Kamp }
44324084f9bSBrian Somers if (routeSock != -1)
44424084f9bSBrian Somers if (FD_ISSET (routeSock, &readMask))
44524084f9bSBrian Somers HandleRoutingInfo (routeSock);
44624084f9bSBrian Somers }
44724084f9bSBrian Somers
44824084f9bSBrian Somers if (background)
449b79840a6SRuslan Ermilov unlink (pidName);
45024084f9bSBrian Somers
45124084f9bSBrian Somers return 0;
45224084f9bSBrian Somers }
45324084f9bSBrian Somers
DaemonMode(void)4547154ce64SEd Schouten static void DaemonMode(void)
45524084f9bSBrian Somers {
45624084f9bSBrian Somers FILE* pidFile;
45724084f9bSBrian Somers
45824084f9bSBrian Somers daemon (0, 0);
45924084f9bSBrian Somers background = 1;
46024084f9bSBrian Somers
461b79840a6SRuslan Ermilov pidFile = fopen (pidName, "w");
46224084f9bSBrian Somers if (pidFile) {
46324084f9bSBrian Somers
46424084f9bSBrian Somers fprintf (pidFile, "%d\n", getpid ());
46524084f9bSBrian Somers fclose (pidFile);
46624084f9bSBrian Somers }
46724084f9bSBrian Somers }
46824084f9bSBrian Somers
ParseArgs(int argc,char ** argv)46924084f9bSBrian Somers static void ParseArgs (int argc, char** argv)
47024084f9bSBrian Somers {
47124084f9bSBrian Somers int arg;
47224084f9bSBrian Somers char* opt;
47324084f9bSBrian Somers char parmBuf[256];
47430395bb5SJosef Karthauser int len; /* bounds checking */
47524084f9bSBrian Somers
47624084f9bSBrian Somers for (arg = 1; arg < argc; arg++) {
47724084f9bSBrian Somers
47824084f9bSBrian Somers opt = argv[arg];
47924084f9bSBrian Somers if (*opt != '-') {
48024084f9bSBrian Somers
4810fc81af1SPhilippe Charnier warnx ("invalid option %s", opt);
48224084f9bSBrian Somers Usage ();
48324084f9bSBrian Somers }
48424084f9bSBrian Somers
48524084f9bSBrian Somers parmBuf[0] = '\0';
48630395bb5SJosef Karthauser len = 0;
48724084f9bSBrian Somers
48824084f9bSBrian Somers while (arg < argc - 1) {
48924084f9bSBrian Somers
49024084f9bSBrian Somers if (argv[arg + 1][0] == '-')
49124084f9bSBrian Somers break;
49224084f9bSBrian Somers
49330395bb5SJosef Karthauser if (len) {
49430395bb5SJosef Karthauser strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
49530395bb5SJosef Karthauser len += strlen(parmBuf + len);
49624084f9bSBrian Somers }
49724084f9bSBrian Somers
49830395bb5SJosef Karthauser ++arg;
49930395bb5SJosef Karthauser strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
50030395bb5SJosef Karthauser len += strlen(parmBuf + len);
50130395bb5SJosef Karthauser
50230395bb5SJosef Karthauser }
50330395bb5SJosef Karthauser
504b0f55af6SRuslan Ermilov ParseOption (opt + 1, (len ? parmBuf : NULL));
50530395bb5SJosef Karthauser
50624084f9bSBrian Somers }
50724084f9bSBrian Somers }
50824084f9bSBrian Somers
DoGlobal(int fd)50922c62477SPoul-Henning Kamp static void DoGlobal (int fd)
51022c62477SPoul-Henning Kamp {
51122c62477SPoul-Henning Kamp int bytes;
51222c62477SPoul-Henning Kamp int origBytes;
51322c62477SPoul-Henning Kamp char buf[IP_MAXPACKET];
51422c62477SPoul-Henning Kamp struct sockaddr_in addr;
51522c62477SPoul-Henning Kamp int wrote;
51648ce8ca1SXin LI socklen_t addrSize;
51722c62477SPoul-Henning Kamp struct ip* ip;
51822c62477SPoul-Henning Kamp char msgBuf[80];
51922c62477SPoul-Henning Kamp
52022c62477SPoul-Henning Kamp /*
52122c62477SPoul-Henning Kamp * Get packet from socket.
52222c62477SPoul-Henning Kamp */
52322c62477SPoul-Henning Kamp addrSize = sizeof addr;
52422c62477SPoul-Henning Kamp origBytes = recvfrom (fd,
52522c62477SPoul-Henning Kamp buf,
52622c62477SPoul-Henning Kamp sizeof buf,
52722c62477SPoul-Henning Kamp 0,
52822c62477SPoul-Henning Kamp (struct sockaddr*) &addr,
52922c62477SPoul-Henning Kamp &addrSize);
53022c62477SPoul-Henning Kamp
53122c62477SPoul-Henning Kamp if (origBytes == -1) {
53222c62477SPoul-Henning Kamp
53322c62477SPoul-Henning Kamp if (errno != EINTR)
53422c62477SPoul-Henning Kamp Warn ("read from divert socket failed");
53522c62477SPoul-Henning Kamp
53622c62477SPoul-Henning Kamp return;
53722c62477SPoul-Henning Kamp }
53822c62477SPoul-Henning Kamp
53922c62477SPoul-Henning Kamp #if 0
54022c62477SPoul-Henning Kamp if (mip->assignAliasAddr) {
5410afb958bSMaxim Sobolev if (SetAliasAddressFromIfName (mip->ifName) != 0)
5420afb958bSMaxim Sobolev exit(1);
54322c62477SPoul-Henning Kamp mip->assignAliasAddr = 0;
54422c62477SPoul-Henning Kamp }
54522c62477SPoul-Henning Kamp #endif
54622c62477SPoul-Henning Kamp /*
54722c62477SPoul-Henning Kamp * This is an IP packet.
54822c62477SPoul-Henning Kamp */
54922c62477SPoul-Henning Kamp ip = (struct ip*) buf;
55022c62477SPoul-Henning Kamp
55122c62477SPoul-Henning Kamp if (verbose) {
55222c62477SPoul-Henning Kamp /*
55322c62477SPoul-Henning Kamp * Print packet direction and protocol type.
55422c62477SPoul-Henning Kamp */
55522c62477SPoul-Henning Kamp printf ("Glb ");
55622c62477SPoul-Henning Kamp
55722c62477SPoul-Henning Kamp switch (ip->ip_p) {
55822c62477SPoul-Henning Kamp case IPPROTO_TCP:
55922c62477SPoul-Henning Kamp printf ("[TCP] ");
56022c62477SPoul-Henning Kamp break;
56122c62477SPoul-Henning Kamp
56222c62477SPoul-Henning Kamp case IPPROTO_UDP:
56322c62477SPoul-Henning Kamp printf ("[UDP] ");
56422c62477SPoul-Henning Kamp break;
56522c62477SPoul-Henning Kamp
56622c62477SPoul-Henning Kamp case IPPROTO_ICMP:
56722c62477SPoul-Henning Kamp printf ("[ICMP] ");
56822c62477SPoul-Henning Kamp break;
56922c62477SPoul-Henning Kamp
57022c62477SPoul-Henning Kamp default:
57122c62477SPoul-Henning Kamp printf ("[%d] ", ip->ip_p);
57222c62477SPoul-Henning Kamp break;
57322c62477SPoul-Henning Kamp }
57422c62477SPoul-Henning Kamp /*
57522c62477SPoul-Henning Kamp * Print addresses.
57622c62477SPoul-Henning Kamp */
57722c62477SPoul-Henning Kamp PrintPacket (ip);
57822c62477SPoul-Henning Kamp }
57922c62477SPoul-Henning Kamp
58022c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) {
58122c62477SPoul-Henning Kamp mla = mip->la;
58222c62477SPoul-Henning Kamp if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED)
58322c62477SPoul-Henning Kamp break;
58422c62477SPoul-Henning Kamp }
58522c62477SPoul-Henning Kamp /*
58622c62477SPoul-Henning Kamp * Length might have changed during aliasing.
58722c62477SPoul-Henning Kamp */
58822c62477SPoul-Henning Kamp bytes = ntohs (ip->ip_len);
58922c62477SPoul-Henning Kamp /*
59022c62477SPoul-Henning Kamp * Update alias overhead size for outgoing packets.
59122c62477SPoul-Henning Kamp */
59222c62477SPoul-Henning Kamp if (mip != NULL && bytes - origBytes > mip->aliasOverhead)
59322c62477SPoul-Henning Kamp mip->aliasOverhead = bytes - origBytes;
59422c62477SPoul-Henning Kamp
59522c62477SPoul-Henning Kamp if (verbose) {
59622c62477SPoul-Henning Kamp
59722c62477SPoul-Henning Kamp /*
59822c62477SPoul-Henning Kamp * Print addresses after aliasing.
59922c62477SPoul-Henning Kamp */
60022c62477SPoul-Henning Kamp printf (" aliased to\n");
60122c62477SPoul-Henning Kamp printf (" ");
60222c62477SPoul-Henning Kamp PrintPacket (ip);
60322c62477SPoul-Henning Kamp printf ("\n");
60422c62477SPoul-Henning Kamp }
60522c62477SPoul-Henning Kamp
60622c62477SPoul-Henning Kamp /*
60722c62477SPoul-Henning Kamp * Put packet back for processing.
60822c62477SPoul-Henning Kamp */
60922c62477SPoul-Henning Kamp wrote = sendto (fd,
61022c62477SPoul-Henning Kamp buf,
61122c62477SPoul-Henning Kamp bytes,
61222c62477SPoul-Henning Kamp 0,
61322c62477SPoul-Henning Kamp (struct sockaddr*) &addr,
61422c62477SPoul-Henning Kamp sizeof addr);
61522c62477SPoul-Henning Kamp
61622c62477SPoul-Henning Kamp if (wrote != bytes) {
61722c62477SPoul-Henning Kamp
6186481f66bSPoul-Henning Kamp if (errno == EMSGSIZE && mip != NULL) {
61922c62477SPoul-Henning Kamp
62022c62477SPoul-Henning Kamp if (mip->ifMTU != -1)
62122c62477SPoul-Henning Kamp SendNeedFragIcmp (icmpSock,
62222c62477SPoul-Henning Kamp (struct ip*) buf,
62322c62477SPoul-Henning Kamp mip->ifMTU - mip->aliasOverhead);
62422c62477SPoul-Henning Kamp }
62522c62477SPoul-Henning Kamp else if (errno == EACCES && logIpfwDenied) {
62622c62477SPoul-Henning Kamp
62722c62477SPoul-Henning Kamp sprintf (msgBuf, "failed to write packet back");
62822c62477SPoul-Henning Kamp Warn (msgBuf);
62922c62477SPoul-Henning Kamp }
63022c62477SPoul-Henning Kamp }
63122c62477SPoul-Henning Kamp }
63222c62477SPoul-Henning Kamp
63322c62477SPoul-Henning Kamp
DoAliasing(int fd,int direction)63459a7c613SBrian Somers static void DoAliasing (int fd, int direction)
63524084f9bSBrian Somers {
63624084f9bSBrian Somers int bytes;
63724084f9bSBrian Somers int origBytes;
6383daff242SRuslan Ermilov char buf[IP_MAXPACKET];
6393daff242SRuslan Ermilov struct sockaddr_in addr;
6403daff242SRuslan Ermilov int wrote;
641f9b06d5cSBrian Somers int status;
64248ce8ca1SXin LI socklen_t addrSize;
64324084f9bSBrian Somers struct ip* ip;
6443daff242SRuslan Ermilov char msgBuf[80];
6450afb958bSMaxim Sobolev int rval;
64624084f9bSBrian Somers
64722c62477SPoul-Henning Kamp if (mip->assignAliasAddr) {
6480afb958bSMaxim Sobolev do {
6490afb958bSMaxim Sobolev rval = SetAliasAddressFromIfName (mip->ifName);
650dde269c9SMaxim Sobolev if (background == 0 || dynamicMode == 0)
651dde269c9SMaxim Sobolev break;
652dde269c9SMaxim Sobolev if (rval == EAGAIN)
6530afb958bSMaxim Sobolev sleep(1);
654dde269c9SMaxim Sobolev } while (rval == EAGAIN);
6550afb958bSMaxim Sobolev if (rval != 0)
6560afb958bSMaxim Sobolev exit(1);
65722c62477SPoul-Henning Kamp mip->assignAliasAddr = 0;
65824084f9bSBrian Somers }
65924084f9bSBrian Somers /*
66024084f9bSBrian Somers * Get packet from socket.
66124084f9bSBrian Somers */
6623daff242SRuslan Ermilov addrSize = sizeof addr;
66324084f9bSBrian Somers origBytes = recvfrom (fd,
6643daff242SRuslan Ermilov buf,
6653daff242SRuslan Ermilov sizeof buf,
66624084f9bSBrian Somers 0,
6673daff242SRuslan Ermilov (struct sockaddr*) &addr,
66824084f9bSBrian Somers &addrSize);
66924084f9bSBrian Somers
67024084f9bSBrian Somers if (origBytes == -1) {
67124084f9bSBrian Somers
67224084f9bSBrian Somers if (errno != EINTR)
6730fc81af1SPhilippe Charnier Warn ("read from divert socket failed");
67424084f9bSBrian Somers
67524084f9bSBrian Somers return;
67624084f9bSBrian Somers }
67724084f9bSBrian Somers /*
6789d5abbddSJens Schweikhardt * This is an IP packet.
67924084f9bSBrian Somers */
6803daff242SRuslan Ermilov ip = (struct ip*) buf;
681ebe70c8fSWarner Losh if (direction == DONT_KNOW) {
6823daff242SRuslan Ermilov if (addr.sin_addr.s_addr == INADDR_ANY)
68359a7c613SBrian Somers direction = OUTPUT;
68459a7c613SBrian Somers else
68559a7c613SBrian Somers direction = INPUT;
686ebe70c8fSWarner Losh }
68724084f9bSBrian Somers
68824084f9bSBrian Somers if (verbose) {
68924084f9bSBrian Somers /*
69024084f9bSBrian Somers * Print packet direction and protocol type.
69124084f9bSBrian Somers */
69259a7c613SBrian Somers printf (direction == OUTPUT ? "Out " : "In ");
69322c62477SPoul-Henning Kamp if (ninstance > 1)
69448ce8ca1SXin LI printf ("{%s}", mip->name);
69524084f9bSBrian Somers
69624084f9bSBrian Somers switch (ip->ip_p) {
69724084f9bSBrian Somers case IPPROTO_TCP:
69824084f9bSBrian Somers printf ("[TCP] ");
69924084f9bSBrian Somers break;
70024084f9bSBrian Somers
70124084f9bSBrian Somers case IPPROTO_UDP:
70224084f9bSBrian Somers printf ("[UDP] ");
70324084f9bSBrian Somers break;
70424084f9bSBrian Somers
70524084f9bSBrian Somers case IPPROTO_ICMP:
70624084f9bSBrian Somers printf ("[ICMP] ");
70724084f9bSBrian Somers break;
70824084f9bSBrian Somers
70924084f9bSBrian Somers default:
71059a7c613SBrian Somers printf ("[%d] ", ip->ip_p);
71124084f9bSBrian Somers break;
71224084f9bSBrian Somers }
71324084f9bSBrian Somers /*
71424084f9bSBrian Somers * Print addresses.
71524084f9bSBrian Somers */
71624084f9bSBrian Somers PrintPacket (ip);
71724084f9bSBrian Somers }
71824084f9bSBrian Somers
71959a7c613SBrian Somers if (direction == OUTPUT) {
72024084f9bSBrian Somers /*
72124084f9bSBrian Somers * Outgoing packets. Do aliasing.
72224084f9bSBrian Somers */
72322c62477SPoul-Henning Kamp LibAliasOut (mla, buf, IP_MAXPACKET);
72424084f9bSBrian Somers }
72524084f9bSBrian Somers else {
72659a7c613SBrian Somers
72724084f9bSBrian Somers /*
72824084f9bSBrian Somers * Do aliasing.
72924084f9bSBrian Somers */
73022c62477SPoul-Henning Kamp status = LibAliasIn (mla, buf, IP_MAXPACKET);
731f9b06d5cSBrian Somers if (status == PKT_ALIAS_IGNORED &&
73222c62477SPoul-Henning Kamp mip->dropIgnoredIncoming) {
733f9b06d5cSBrian Somers
73459a7c613SBrian Somers if (verbose)
735f9b06d5cSBrian Somers printf (" dropped.\n");
73659a7c613SBrian Somers
73722c62477SPoul-Henning Kamp if (mip->logDropped)
73859a7c613SBrian Somers SyslogPacket (ip, LOG_WARNING, "denied");
73959a7c613SBrian Somers
740f9b06d5cSBrian Somers return;
741f9b06d5cSBrian Somers }
74224084f9bSBrian Somers }
74324084f9bSBrian Somers /*
74424084f9bSBrian Somers * Length might have changed during aliasing.
74524084f9bSBrian Somers */
74624084f9bSBrian Somers bytes = ntohs (ip->ip_len);
74724084f9bSBrian Somers /*
74824084f9bSBrian Somers * Update alias overhead size for outgoing packets.
74924084f9bSBrian Somers */
75059a7c613SBrian Somers if (direction == OUTPUT &&
75122c62477SPoul-Henning Kamp bytes - origBytes > mip->aliasOverhead)
75222c62477SPoul-Henning Kamp mip->aliasOverhead = bytes - origBytes;
75324084f9bSBrian Somers
75424084f9bSBrian Somers if (verbose) {
75524084f9bSBrian Somers
75624084f9bSBrian Somers /*
75724084f9bSBrian Somers * Print addresses after aliasing.
75824084f9bSBrian Somers */
75924084f9bSBrian Somers printf (" aliased to\n");
76024084f9bSBrian Somers printf (" ");
76124084f9bSBrian Somers PrintPacket (ip);
76224084f9bSBrian Somers printf ("\n");
76324084f9bSBrian Somers }
764fb994b07SBrian Somers
76524084f9bSBrian Somers /*
76624084f9bSBrian Somers * Put packet back for processing.
76724084f9bSBrian Somers */
76824084f9bSBrian Somers wrote = sendto (fd,
7693daff242SRuslan Ermilov buf,
7703daff242SRuslan Ermilov bytes,
77124084f9bSBrian Somers 0,
7723daff242SRuslan Ermilov (struct sockaddr*) &addr,
7733daff242SRuslan Ermilov sizeof addr);
77424084f9bSBrian Somers
7753daff242SRuslan Ermilov if (wrote != bytes) {
77624084f9bSBrian Somers
77724084f9bSBrian Somers if (errno == EMSGSIZE) {
77824084f9bSBrian Somers
7793daff242SRuslan Ermilov if (direction == OUTPUT &&
78022c62477SPoul-Henning Kamp mip->ifMTU != -1)
78124084f9bSBrian Somers SendNeedFragIcmp (icmpSock,
7823daff242SRuslan Ermilov (struct ip*) buf,
78322c62477SPoul-Henning Kamp mip->ifMTU - mip->aliasOverhead);
78424084f9bSBrian Somers }
7853843533eSRuslan Ermilov else if (errno == EACCES && logIpfwDenied) {
78624084f9bSBrian Somers
787d782daf0SJosef Karthauser sprintf (msgBuf, "failed to write packet back");
78824084f9bSBrian Somers Warn (msgBuf);
78924084f9bSBrian Somers }
79024084f9bSBrian Somers }
79124084f9bSBrian Somers }
79224084f9bSBrian Somers
HandleRoutingInfo(int fd)79324084f9bSBrian Somers static void HandleRoutingInfo (int fd)
79424084f9bSBrian Somers {
79524084f9bSBrian Somers int bytes;
79624084f9bSBrian Somers struct if_msghdr ifMsg;
79724084f9bSBrian Somers /*
79824084f9bSBrian Somers * Get packet from socket.
79924084f9bSBrian Somers */
80024084f9bSBrian Somers bytes = read (fd, &ifMsg, sizeof ifMsg);
80124084f9bSBrian Somers if (bytes == -1) {
80224084f9bSBrian Somers
8030fc81af1SPhilippe Charnier Warn ("read from routing socket failed");
80424084f9bSBrian Somers return;
80524084f9bSBrian Somers }
80624084f9bSBrian Somers
80724084f9bSBrian Somers if (ifMsg.ifm_version != RTM_VERSION) {
80824084f9bSBrian Somers
8090fc81af1SPhilippe Charnier Warn ("unexpected packet read from routing socket");
81024084f9bSBrian Somers return;
81124084f9bSBrian Somers }
81224084f9bSBrian Somers
81324084f9bSBrian Somers if (verbose)
8146f3dbe5eSRuslan Ermilov printf ("Routing message %#x received.\n", ifMsg.ifm_type);
81524084f9bSBrian Somers
81622c62477SPoul-Henning Kamp if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) {
81722c62477SPoul-Henning Kamp LIST_FOREACH(mip, &root, list) {
81822c62477SPoul-Henning Kamp mla = mip->la;
81922c62477SPoul-Henning Kamp if (ifMsg.ifm_index == mip->ifIndex) {
8206f3dbe5eSRuslan Ermilov if (verbose)
8216f3dbe5eSRuslan Ermilov printf("Interface address/MTU has probably changed.\n");
82222c62477SPoul-Henning Kamp mip->assignAliasAddr = 1;
82322c62477SPoul-Henning Kamp }
82422c62477SPoul-Henning Kamp }
82524084f9bSBrian Somers }
8266f3dbe5eSRuslan Ermilov }
82724084f9bSBrian Somers
PrintPacket(struct ip * ip)82824084f9bSBrian Somers static void PrintPacket (struct ip* ip)
82924084f9bSBrian Somers {
83059a7c613SBrian Somers printf ("%s", FormatPacket (ip));
83159a7c613SBrian Somers }
83259a7c613SBrian Somers
SyslogPacket(struct ip * ip,int priority,const char * label)833902cb50aSBrian Somers static void SyslogPacket (struct ip* ip, int priority, const char *label)
83459a7c613SBrian Somers {
83559a7c613SBrian Somers syslog (priority, "%s %s", label, FormatPacket (ip));
83659a7c613SBrian Somers }
83759a7c613SBrian Somers
FormatPacket(struct ip * ip)83859a7c613SBrian Somers static char* FormatPacket (struct ip* ip)
83959a7c613SBrian Somers {
84059a7c613SBrian Somers static char buf[256];
84124084f9bSBrian Somers struct tcphdr* tcphdr;
84259a7c613SBrian Somers struct udphdr* udphdr;
84359a7c613SBrian Somers struct icmp* icmphdr;
84459a7c613SBrian Somers char src[20];
84559a7c613SBrian Somers char dst[20];
84624084f9bSBrian Somers
84759a7c613SBrian Somers strcpy (src, inet_ntoa (ip->ip_src));
84859a7c613SBrian Somers strcpy (dst, inet_ntoa (ip->ip_dst));
84959a7c613SBrian Somers
85059a7c613SBrian Somers switch (ip->ip_p) {
85159a7c613SBrian Somers case IPPROTO_TCP:
85224084f9bSBrian Somers tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
85359a7c613SBrian Somers sprintf (buf, "[TCP] %s:%d -> %s:%d",
85459a7c613SBrian Somers src,
85559a7c613SBrian Somers ntohs (tcphdr->th_sport),
85659a7c613SBrian Somers dst,
85759a7c613SBrian Somers ntohs (tcphdr->th_dport));
85859a7c613SBrian Somers break;
85924084f9bSBrian Somers
86059a7c613SBrian Somers case IPPROTO_UDP:
86159a7c613SBrian Somers udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
86259a7c613SBrian Somers sprintf (buf, "[UDP] %s:%d -> %s:%d",
86359a7c613SBrian Somers src,
86459a7c613SBrian Somers ntohs (udphdr->uh_sport),
86559a7c613SBrian Somers dst,
86659a7c613SBrian Somers ntohs (udphdr->uh_dport));
86759a7c613SBrian Somers break;
86824084f9bSBrian Somers
86959a7c613SBrian Somers case IPPROTO_ICMP:
87059a7c613SBrian Somers icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
871b71e869dSBrian Somers sprintf (buf, "[ICMP] %s -> %s %u(%u)",
87259a7c613SBrian Somers src,
87359a7c613SBrian Somers dst,
874b71e869dSBrian Somers icmphdr->icmp_type,
875b71e869dSBrian Somers icmphdr->icmp_code);
87659a7c613SBrian Somers break;
87759a7c613SBrian Somers
87859a7c613SBrian Somers default:
87959a7c613SBrian Somers sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
88059a7c613SBrian Somers break;
88159a7c613SBrian Somers }
88259a7c613SBrian Somers
88359a7c613SBrian Somers return buf;
88424084f9bSBrian Somers }
88524084f9bSBrian Somers
8860afb958bSMaxim Sobolev static int
SetAliasAddressFromIfName(const char * ifn)8874c04fa4cSRuslan Ermilov SetAliasAddressFromIfName(const char *ifn)
88824084f9bSBrian Somers {
8894c04fa4cSRuslan Ermilov size_t needed;
8904c04fa4cSRuslan Ermilov int mib[6];
8914c04fa4cSRuslan Ermilov char *buf, *lim, *next;
8924c04fa4cSRuslan Ermilov struct if_msghdr *ifm;
8934c04fa4cSRuslan Ermilov struct ifa_msghdr *ifam;
8944c04fa4cSRuslan Ermilov struct sockaddr_dl *sdl;
8954c04fa4cSRuslan Ermilov struct sockaddr_in *sin;
89624084f9bSBrian Somers
8974c04fa4cSRuslan Ermilov mib[0] = CTL_NET;
8984c04fa4cSRuslan Ermilov mib[1] = PF_ROUTE;
8994c04fa4cSRuslan Ermilov mib[2] = 0;
9004c04fa4cSRuslan Ermilov mib[3] = AF_INET; /* Only IP addresses please */
9014c04fa4cSRuslan Ermilov mib[4] = NET_RT_IFLIST;
9024c04fa4cSRuslan Ermilov mib[5] = 0; /* ifIndex??? */
90324084f9bSBrian Somers /*
90424084f9bSBrian Somers * Get interface data.
90524084f9bSBrian Somers */
9064c04fa4cSRuslan Ermilov if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
9074c04fa4cSRuslan Ermilov err(1, "iflist-sysctl-estimate");
9084c04fa4cSRuslan Ermilov if ((buf = malloc(needed)) == NULL)
9094c04fa4cSRuslan Ermilov errx(1, "malloc failed");
910ec95e4c2SBrian Somers if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1 && errno != ENOMEM)
9114c04fa4cSRuslan Ermilov err(1, "iflist-sysctl-get");
9124c04fa4cSRuslan Ermilov lim = buf + needed;
91324084f9bSBrian Somers /*
91424084f9bSBrian Somers * Loop through interfaces until one with
91524084f9bSBrian Somers * given name is found. This is done to
91624084f9bSBrian Somers * find correct interface index for routing
91724084f9bSBrian Somers * message processing.
91824084f9bSBrian Somers */
91922c62477SPoul-Henning Kamp mip->ifIndex = 0;
9204c04fa4cSRuslan Ermilov next = buf;
9214c04fa4cSRuslan Ermilov while (next < lim) {
9224c04fa4cSRuslan Ermilov ifm = (struct if_msghdr *)next;
9234c04fa4cSRuslan Ermilov next += ifm->ifm_msglen;
9244c04fa4cSRuslan Ermilov if (ifm->ifm_version != RTM_VERSION) {
9254c04fa4cSRuslan Ermilov if (verbose)
9264c04fa4cSRuslan Ermilov warnx("routing message version %d "
9274c04fa4cSRuslan Ermilov "not understood", ifm->ifm_version);
9284c04fa4cSRuslan Ermilov continue;
9294c04fa4cSRuslan Ermilov }
9304c04fa4cSRuslan Ermilov if (ifm->ifm_type == RTM_IFINFO) {
9314c04fa4cSRuslan Ermilov sdl = (struct sockaddr_dl *)(ifm + 1);
9324c04fa4cSRuslan Ermilov if (strlen(ifn) == sdl->sdl_nlen &&
9334c04fa4cSRuslan Ermilov strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
93422c62477SPoul-Henning Kamp mip->ifIndex = ifm->ifm_index;
93522c62477SPoul-Henning Kamp mip->ifMTU = ifm->ifm_data.ifi_mtu;
93624084f9bSBrian Somers break;
93724084f9bSBrian Somers }
93824084f9bSBrian Somers }
93924084f9bSBrian Somers }
94022c62477SPoul-Henning Kamp if (!mip->ifIndex)
9414c04fa4cSRuslan Ermilov errx(1, "unknown interface name %s", ifn);
94224084f9bSBrian Somers /*
94324084f9bSBrian Somers * Get interface address.
94424084f9bSBrian Somers */
9454c04fa4cSRuslan Ermilov sin = NULL;
9464c04fa4cSRuslan Ermilov while (next < lim) {
9474c04fa4cSRuslan Ermilov ifam = (struct ifa_msghdr *)next;
9484c04fa4cSRuslan Ermilov next += ifam->ifam_msglen;
9494c04fa4cSRuslan Ermilov if (ifam->ifam_version != RTM_VERSION) {
9504c04fa4cSRuslan Ermilov if (verbose)
9514c04fa4cSRuslan Ermilov warnx("routing message version %d "
9524c04fa4cSRuslan Ermilov "not understood", ifam->ifam_version);
9534c04fa4cSRuslan Ermilov continue;
9544c04fa4cSRuslan Ermilov }
9554c04fa4cSRuslan Ermilov if (ifam->ifam_type != RTM_NEWADDR)
9564c04fa4cSRuslan Ermilov break;
9574c04fa4cSRuslan Ermilov if (ifam->ifam_addrs & RTA_IFA) {
9584c04fa4cSRuslan Ermilov int i;
9594c04fa4cSRuslan Ermilov char *cp = (char *)(ifam + 1);
96024084f9bSBrian Somers
9614c04fa4cSRuslan Ermilov for (i = 1; i < RTA_IFA; i <<= 1)
9624c04fa4cSRuslan Ermilov if (ifam->ifam_addrs & i)
9630b46c085SLuigi Rizzo cp += SA_SIZE((struct sockaddr *)cp);
9644c04fa4cSRuslan Ermilov if (((struct sockaddr *)cp)->sa_family == AF_INET) {
9654c04fa4cSRuslan Ermilov sin = (struct sockaddr_in *)cp;
9664c04fa4cSRuslan Ermilov break;
9674c04fa4cSRuslan Ermilov }
9684c04fa4cSRuslan Ermilov }
9694c04fa4cSRuslan Ermilov }
9700afb958bSMaxim Sobolev if (sin == NULL) {
9710afb958bSMaxim Sobolev warnx("%s: cannot get interface address", ifn);
9720afb958bSMaxim Sobolev free(buf);
97374def44dSMaxim Sobolev return EAGAIN;
9740afb958bSMaxim Sobolev }
9754c04fa4cSRuslan Ermilov
97622c62477SPoul-Henning Kamp LibAliasSetAddress(mla, sin->sin_addr);
97724084f9bSBrian Somers syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
97822c62477SPoul-Henning Kamp inet_ntoa(sin->sin_addr), mip->ifMTU);
97924084f9bSBrian Somers
9804c04fa4cSRuslan Ermilov free(buf);
9810afb958bSMaxim Sobolev
9820afb958bSMaxim Sobolev return 0;
98324084f9bSBrian Somers }
98424084f9bSBrian Somers
Quit(const char * msg)985902cb50aSBrian Somers void Quit (const char* msg)
98624084f9bSBrian Somers {
98724084f9bSBrian Somers Warn (msg);
98824084f9bSBrian Somers exit (1);
98924084f9bSBrian Somers }
99024084f9bSBrian Somers
Warn(const char * msg)991902cb50aSBrian Somers void Warn (const char* msg)
99224084f9bSBrian Somers {
99324084f9bSBrian Somers if (background)
99424084f9bSBrian Somers syslog (LOG_ALERT, "%s (%m)", msg);
99524084f9bSBrian Somers else
99604d06bb6SKris Kennaway warn ("%s", msg);
99724084f9bSBrian Somers }
99824084f9bSBrian Somers
RefreshAddr(int sig __unused)99948ce8ca1SXin LI static void RefreshAddr (int sig __unused)
100024084f9bSBrian Somers {
1001be4f3cd0SPaolo Pisati LibAliasRefreshModules();
1002be4f3cd0SPaolo Pisati if (mip != NULL && mip->ifName != NULL)
100322c62477SPoul-Henning Kamp mip->assignAliasAddr = 1;
100424084f9bSBrian Somers }
100524084f9bSBrian Somers
InitiateShutdown(int sig __unused)100648ce8ca1SXin LI static void InitiateShutdown (int sig __unused)
100724084f9bSBrian Somers {
100824084f9bSBrian Somers /*
100924084f9bSBrian Somers * Start timer to allow kernel gracefully
101024084f9bSBrian Somers * shutdown existing connections when system
101124084f9bSBrian Somers * is shut down.
101224084f9bSBrian Somers */
1013cd45c931SRuslan Ermilov siginterrupt(SIGALRM, 1);
101424084f9bSBrian Somers signal (SIGALRM, Shutdown);
101572cbe4adSAlexander Motin ualarm(exitDelay*1000, 1000);
101624084f9bSBrian Somers }
101724084f9bSBrian Somers
Shutdown(int sig __unused)101848ce8ca1SXin LI static void Shutdown (int sig __unused)
101924084f9bSBrian Somers {
102024084f9bSBrian Somers running = 0;
102124084f9bSBrian Somers }
102224084f9bSBrian Somers
102324084f9bSBrian Somers /*
102424084f9bSBrian Somers * Different options recognized by this program.
102524084f9bSBrian Somers */
102624084f9bSBrian Somers
102724084f9bSBrian Somers enum Option {
102824084f9bSBrian Somers
102922c62477SPoul-Henning Kamp LibAliasOption,
103022c62477SPoul-Henning Kamp Instance,
103124084f9bSBrian Somers Verbose,
103224084f9bSBrian Somers InPort,
103324084f9bSBrian Somers OutPort,
103424084f9bSBrian Somers Port,
103522c62477SPoul-Henning Kamp GlobalPort,
103624084f9bSBrian Somers AliasAddress,
103711c2b3bfSRuslan Ermilov TargetAddress,
103824084f9bSBrian Somers InterfaceName,
103924084f9bSBrian Somers RedirectPort,
10404330006dSRuslan Ermilov RedirectProto,
104124084f9bSBrian Somers RedirectAddress,
104224084f9bSBrian Somers ConfigFile,
104359a7c613SBrian Somers DynamicMode,
104459a7c613SBrian Somers ProxyRule,
104559a7c613SBrian Somers LogDenied,
1046bc4ebb98SRuslan Ermilov LogFacility,
104784ef95bdSPoul-Henning Kamp PunchFW,
1048b07fbc17SJoe Marcus Clarke SkinnyPort,
1049b79840a6SRuslan Ermilov LogIpfwDenied,
105072cbe4adSAlexander Motin PidFile,
105172cbe4adSAlexander Motin ExitDelay
105224084f9bSBrian Somers };
105324084f9bSBrian Somers
105424084f9bSBrian Somers enum Param {
105524084f9bSBrian Somers
105624084f9bSBrian Somers YesNo,
105724084f9bSBrian Somers Numeric,
105824084f9bSBrian Somers String,
105924084f9bSBrian Somers None,
106024084f9bSBrian Somers Address,
106124084f9bSBrian Somers Service
106224084f9bSBrian Somers };
106324084f9bSBrian Somers
106424084f9bSBrian Somers /*
106524084f9bSBrian Somers * Option information structure (used by ParseOption).
106624084f9bSBrian Somers */
106724084f9bSBrian Somers
106824084f9bSBrian Somers struct OptionInfo {
106924084f9bSBrian Somers
107024084f9bSBrian Somers enum Option type;
107124084f9bSBrian Somers int packetAliasOpt;
107224084f9bSBrian Somers enum Param parm;
1073902cb50aSBrian Somers const char* parmDescription;
1074902cb50aSBrian Somers const char* description;
1075902cb50aSBrian Somers const char* name;
1076902cb50aSBrian Somers const char* shortName;
107724084f9bSBrian Somers };
107824084f9bSBrian Somers
107924084f9bSBrian Somers /*
108024084f9bSBrian Somers * Table of known options.
108124084f9bSBrian Somers */
108224084f9bSBrian Somers
108324084f9bSBrian Somers static struct OptionInfo optionTable[] = {
108424084f9bSBrian Somers
108522c62477SPoul-Henning Kamp { LibAliasOption,
108624084f9bSBrian Somers PKT_ALIAS_UNREGISTERED_ONLY,
108724084f9bSBrian Somers YesNo,
108824084f9bSBrian Somers "[yes|no]",
108924084f9bSBrian Somers "alias only unregistered addresses",
109024084f9bSBrian Somers "unregistered_only",
109124084f9bSBrian Somers "u" },
109224084f9bSBrian Somers
109322c62477SPoul-Henning Kamp { LibAliasOption,
109424084f9bSBrian Somers PKT_ALIAS_LOG,
109524084f9bSBrian Somers YesNo,
109624084f9bSBrian Somers "[yes|no]",
109724084f9bSBrian Somers "enable logging",
109824084f9bSBrian Somers "log",
109924084f9bSBrian Somers "l" },
110024084f9bSBrian Somers
110122c62477SPoul-Henning Kamp { LibAliasOption,
110259a7c613SBrian Somers PKT_ALIAS_PROXY_ONLY,
110359a7c613SBrian Somers YesNo,
110459a7c613SBrian Somers "[yes|no]",
110559a7c613SBrian Somers "proxy only",
110659a7c613SBrian Somers "proxy_only",
110759a7c613SBrian Somers NULL },
110859a7c613SBrian Somers
110922c62477SPoul-Henning Kamp { LibAliasOption,
111059a7c613SBrian Somers PKT_ALIAS_REVERSE,
111159a7c613SBrian Somers YesNo,
111259a7c613SBrian Somers "[yes|no]",
111359a7c613SBrian Somers "operate in reverse mode",
111459a7c613SBrian Somers "reverse",
111559a7c613SBrian Somers NULL },
111659a7c613SBrian Somers
111722c62477SPoul-Henning Kamp { LibAliasOption,
111824084f9bSBrian Somers PKT_ALIAS_DENY_INCOMING,
111924084f9bSBrian Somers YesNo,
112024084f9bSBrian Somers "[yes|no]",
112124084f9bSBrian Somers "allow incoming connections",
112224084f9bSBrian Somers "deny_incoming",
112324084f9bSBrian Somers "d" },
112424084f9bSBrian Somers
112522c62477SPoul-Henning Kamp { LibAliasOption,
112624084f9bSBrian Somers PKT_ALIAS_USE_SOCKETS,
112724084f9bSBrian Somers YesNo,
112824084f9bSBrian Somers "[yes|no]",
112924084f9bSBrian Somers "use sockets to inhibit port conflict",
113024084f9bSBrian Somers "use_sockets",
113124084f9bSBrian Somers "s" },
113224084f9bSBrian Somers
113322c62477SPoul-Henning Kamp { LibAliasOption,
113424084f9bSBrian Somers PKT_ALIAS_SAME_PORTS,
113524084f9bSBrian Somers YesNo,
113624084f9bSBrian Somers "[yes|no]",
113724084f9bSBrian Somers "try to keep original port numbers for connections",
113824084f9bSBrian Somers "same_ports",
113924084f9bSBrian Somers "m" },
114024084f9bSBrian Somers
1141*ef185949SDamjan Jovanovic { LibAliasOption,
1142*ef185949SDamjan Jovanovic PKT_ALIAS_UDP_EIM,
1143*ef185949SDamjan Jovanovic YesNo,
1144*ef185949SDamjan Jovanovic "[yes|no]",
1145*ef185949SDamjan Jovanovic "UDP traffic uses endpoint-independent mapping (\"full cone\" NAT)",
1146*ef185949SDamjan Jovanovic "udp_eim",
1147*ef185949SDamjan Jovanovic NULL },
1148*ef185949SDamjan Jovanovic
114924084f9bSBrian Somers { Verbose,
115024084f9bSBrian Somers 0,
115124084f9bSBrian Somers YesNo,
115224084f9bSBrian Somers "[yes|no]",
115324084f9bSBrian Somers "verbose mode, dump packet information",
115424084f9bSBrian Somers "verbose",
115524084f9bSBrian Somers "v" },
115624084f9bSBrian Somers
115724084f9bSBrian Somers { DynamicMode,
115824084f9bSBrian Somers 0,
115924084f9bSBrian Somers YesNo,
116024084f9bSBrian Somers "[yes|no]",
116124084f9bSBrian Somers "dynamic mode, automatically detect interface address changes",
116224084f9bSBrian Somers "dynamic",
116324084f9bSBrian Somers NULL },
116424084f9bSBrian Somers
116524084f9bSBrian Somers { InPort,
116624084f9bSBrian Somers 0,
116724084f9bSBrian Somers Service,
116824084f9bSBrian Somers "number|service_name",
116924084f9bSBrian Somers "set port for incoming packets",
117024084f9bSBrian Somers "in_port",
117124084f9bSBrian Somers "i" },
117224084f9bSBrian Somers
117324084f9bSBrian Somers { OutPort,
117424084f9bSBrian Somers 0,
117524084f9bSBrian Somers Service,
117624084f9bSBrian Somers "number|service_name",
117724084f9bSBrian Somers "set port for outgoing packets",
117824084f9bSBrian Somers "out_port",
117924084f9bSBrian Somers "o" },
118024084f9bSBrian Somers
118124084f9bSBrian Somers { Port,
118224084f9bSBrian Somers 0,
118324084f9bSBrian Somers Service,
118424084f9bSBrian Somers "number|service_name",
118524084f9bSBrian Somers "set port (defaults to natd/divert)",
118624084f9bSBrian Somers "port",
118724084f9bSBrian Somers "p" },
118824084f9bSBrian Somers
118922c62477SPoul-Henning Kamp { GlobalPort,
119022c62477SPoul-Henning Kamp 0,
119122c62477SPoul-Henning Kamp Service,
119222c62477SPoul-Henning Kamp "number|service_name",
119322c62477SPoul-Henning Kamp "set globalport",
119422c62477SPoul-Henning Kamp "globalport",
119522c62477SPoul-Henning Kamp NULL },
119622c62477SPoul-Henning Kamp
119724084f9bSBrian Somers { AliasAddress,
119824084f9bSBrian Somers 0,
119924084f9bSBrian Somers Address,
120024084f9bSBrian Somers "x.x.x.x",
120124084f9bSBrian Somers "address to use for aliasing",
120224084f9bSBrian Somers "alias_address",
120324084f9bSBrian Somers "a" },
120424084f9bSBrian Somers
120511c2b3bfSRuslan Ermilov { TargetAddress,
120611c2b3bfSRuslan Ermilov 0,
120711c2b3bfSRuslan Ermilov Address,
120811c2b3bfSRuslan Ermilov "x.x.x.x",
120911c2b3bfSRuslan Ermilov "address to use for incoming sessions",
121011c2b3bfSRuslan Ermilov "target_address",
121111c2b3bfSRuslan Ermilov "t" },
121211c2b3bfSRuslan Ermilov
121324084f9bSBrian Somers { InterfaceName,
121424084f9bSBrian Somers 0,
121524084f9bSBrian Somers String,
121624084f9bSBrian Somers "network_if_name",
121724084f9bSBrian Somers "take aliasing address from interface",
121824084f9bSBrian Somers "interface",
121924084f9bSBrian Somers "n" },
122024084f9bSBrian Somers
122159a7c613SBrian Somers { ProxyRule,
122224084f9bSBrian Somers 0,
122324084f9bSBrian Somers String,
122459a7c613SBrian Somers "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
122559a7c613SBrian Somers "a.b.c.d:yyyy",
122659a7c613SBrian Somers "add transparent proxying / destination NAT",
122759a7c613SBrian Somers "proxy_rule",
122824084f9bSBrian Somers NULL },
122924084f9bSBrian Somers
123024084f9bSBrian Somers { RedirectPort,
123124084f9bSBrian Somers 0,
123224084f9bSBrian Somers String,
1233bd690510SRuslan Ermilov "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
12345d8ee958SBrian Somers " [remote_addr[:remote_port_range]]",
12355d8ee958SBrian Somers "redirect a port (or ports) for incoming traffic",
123624084f9bSBrian Somers "redirect_port",
123724084f9bSBrian Somers NULL },
123824084f9bSBrian Somers
12394330006dSRuslan Ermilov { RedirectProto,
12404330006dSRuslan Ermilov 0,
12414330006dSRuslan Ermilov String,
12424330006dSRuslan Ermilov "proto local_addr [public_addr] [remote_addr]",
12434330006dSRuslan Ermilov "redirect packets of a given proto",
12444330006dSRuslan Ermilov "redirect_proto",
12454330006dSRuslan Ermilov NULL },
12464330006dSRuslan Ermilov
124724084f9bSBrian Somers { RedirectAddress,
124824084f9bSBrian Somers 0,
124924084f9bSBrian Somers String,
1250bd690510SRuslan Ermilov "local_addr[,...] public_addr",
125124084f9bSBrian Somers "define mapping between local and public addresses",
125224084f9bSBrian Somers "redirect_address",
125324084f9bSBrian Somers NULL },
125424084f9bSBrian Somers
125524084f9bSBrian Somers { ConfigFile,
125624084f9bSBrian Somers 0,
125724084f9bSBrian Somers String,
125824084f9bSBrian Somers "file_name",
125924084f9bSBrian Somers "read options from configuration file",
126024084f9bSBrian Somers "config",
126159a7c613SBrian Somers "f" },
126259a7c613SBrian Somers
126359a7c613SBrian Somers { LogDenied,
126459a7c613SBrian Somers 0,
126559a7c613SBrian Somers YesNo,
126659a7c613SBrian Somers "[yes|no]",
126759a7c613SBrian Somers "enable logging of denied incoming packets",
126859a7c613SBrian Somers "log_denied",
126959a7c613SBrian Somers NULL },
127059a7c613SBrian Somers
127159a7c613SBrian Somers { LogFacility,
127259a7c613SBrian Somers 0,
127359a7c613SBrian Somers String,
127459a7c613SBrian Somers "facility",
127559a7c613SBrian Somers "name of syslog facility to use for logging",
127659a7c613SBrian Somers "log_facility",
1277bc4ebb98SRuslan Ermilov NULL },
127859a7c613SBrian Somers
1279bc4ebb98SRuslan Ermilov { PunchFW,
1280bc4ebb98SRuslan Ermilov 0,
1281bc4ebb98SRuslan Ermilov String,
1282bc4ebb98SRuslan Ermilov "basenumber:count",
1283bc4ebb98SRuslan Ermilov "punch holes in the firewall for incoming FTP/IRC DCC connections",
1284bc4ebb98SRuslan Ermilov "punch_fw",
128584ef95bdSPoul-Henning Kamp NULL },
128684ef95bdSPoul-Henning Kamp
1287b07fbc17SJoe Marcus Clarke { SkinnyPort,
1288b07fbc17SJoe Marcus Clarke 0,
1289b07fbc17SJoe Marcus Clarke String,
1290b07fbc17SJoe Marcus Clarke "port",
1291b07fbc17SJoe Marcus Clarke "set the TCP port for use with the Skinny Station protocol",
1292b07fbc17SJoe Marcus Clarke "skinny_port",
1293b07fbc17SJoe Marcus Clarke NULL },
1294b07fbc17SJoe Marcus Clarke
129584ef95bdSPoul-Henning Kamp { LogIpfwDenied,
129684ef95bdSPoul-Henning Kamp 0,
129784ef95bdSPoul-Henning Kamp YesNo,
129884ef95bdSPoul-Henning Kamp "[yes|no]",
129984ef95bdSPoul-Henning Kamp "log packets converted by natd, but denied by ipfw",
130084ef95bdSPoul-Henning Kamp "log_ipfw_denied",
130184ef95bdSPoul-Henning Kamp NULL },
1302b79840a6SRuslan Ermilov
1303b79840a6SRuslan Ermilov { PidFile,
1304b79840a6SRuslan Ermilov 0,
1305b79840a6SRuslan Ermilov String,
1306b79840a6SRuslan Ermilov "file_name",
1307b79840a6SRuslan Ermilov "store PID in an alternate file",
1308b79840a6SRuslan Ermilov "pid_file",
1309b79840a6SRuslan Ermilov "P" },
131022c62477SPoul-Henning Kamp { Instance,
131122c62477SPoul-Henning Kamp 0,
131222c62477SPoul-Henning Kamp String,
131322c62477SPoul-Henning Kamp "instance name",
131422c62477SPoul-Henning Kamp "name of aliasing engine instance",
131522c62477SPoul-Henning Kamp "instance",
131622c62477SPoul-Henning Kamp NULL },
131772cbe4adSAlexander Motin { ExitDelay,
131872cbe4adSAlexander Motin 0,
131972cbe4adSAlexander Motin Numeric,
132072cbe4adSAlexander Motin "ms",
132172cbe4adSAlexander Motin "delay in ms before daemon exit after signal",
132272cbe4adSAlexander Motin "exit_delay",
132372cbe4adSAlexander Motin NULL },
132424084f9bSBrian Somers };
132524084f9bSBrian Somers
ParseOption(const char * option,const char * parms)1326b0f55af6SRuslan Ermilov static void ParseOption (const char* option, const char* parms)
132724084f9bSBrian Somers {
132824084f9bSBrian Somers int i;
132924084f9bSBrian Somers struct OptionInfo* info;
133024084f9bSBrian Somers int yesNoValue;
133124084f9bSBrian Somers int aliasValue;
133224084f9bSBrian Somers int numValue;
133367a886fbSBrian Somers u_short uNumValue;
1334902cb50aSBrian Somers const char* strValue;
133524084f9bSBrian Somers struct in_addr addrValue;
133624084f9bSBrian Somers int max;
133724084f9bSBrian Somers char* end;
133839893d56SEd Schouten const CODE* fac_record = NULL;
133924084f9bSBrian Somers /*
134024084f9bSBrian Somers * Find option from table.
134124084f9bSBrian Somers */
134224084f9bSBrian Somers max = sizeof (optionTable) / sizeof (struct OptionInfo);
134324084f9bSBrian Somers for (i = 0, info = optionTable; i < max; i++, info++) {
134424084f9bSBrian Somers
134524084f9bSBrian Somers if (!strcmp (info->name, option))
134624084f9bSBrian Somers break;
134724084f9bSBrian Somers
134824084f9bSBrian Somers if (info->shortName)
134924084f9bSBrian Somers if (!strcmp (info->shortName, option))
135024084f9bSBrian Somers break;
135124084f9bSBrian Somers }
135224084f9bSBrian Somers
135324084f9bSBrian Somers if (i >= max) {
135424084f9bSBrian Somers
13550fc81af1SPhilippe Charnier warnx ("unknown option %s", option);
135624084f9bSBrian Somers Usage ();
135724084f9bSBrian Somers }
135824084f9bSBrian Somers
135967a886fbSBrian Somers uNumValue = 0;
136024084f9bSBrian Somers yesNoValue = 0;
136124084f9bSBrian Somers numValue = 0;
136224084f9bSBrian Somers strValue = NULL;
136324084f9bSBrian Somers /*
136424084f9bSBrian Somers * Check parameters.
136524084f9bSBrian Somers */
136624084f9bSBrian Somers switch (info->parm) {
136724084f9bSBrian Somers case YesNo:
136824084f9bSBrian Somers if (!parms)
136924084f9bSBrian Somers parms = "yes";
137024084f9bSBrian Somers
137124084f9bSBrian Somers if (!strcmp (parms, "yes"))
137224084f9bSBrian Somers yesNoValue = 1;
137324084f9bSBrian Somers else
137424084f9bSBrian Somers if (!strcmp (parms, "no"))
137524084f9bSBrian Somers yesNoValue = 0;
13760fc81af1SPhilippe Charnier else
13770fc81af1SPhilippe Charnier errx (1, "%s needs yes/no parameter", option);
137824084f9bSBrian Somers break;
137924084f9bSBrian Somers
138024084f9bSBrian Somers case Service:
13810fc81af1SPhilippe Charnier if (!parms)
138267a886fbSBrian Somers errx (1, "%s needs service name or "
138367a886fbSBrian Somers "port number parameter",
138467a886fbSBrian Somers option);
138524084f9bSBrian Somers
138667a886fbSBrian Somers uNumValue = StrToPort (parms, "divert");
138724084f9bSBrian Somers break;
138824084f9bSBrian Somers
138924084f9bSBrian Somers case Numeric:
139024084f9bSBrian Somers if (parms)
139124084f9bSBrian Somers numValue = strtol (parms, &end, 10);
139224084f9bSBrian Somers else
1393902cb50aSBrian Somers end = NULL;
139424084f9bSBrian Somers
13950fc81af1SPhilippe Charnier if (end == parms)
13960fc81af1SPhilippe Charnier errx (1, "%s needs numeric parameter", option);
139724084f9bSBrian Somers break;
139824084f9bSBrian Somers
139924084f9bSBrian Somers case String:
140024084f9bSBrian Somers strValue = parms;
14010fc81af1SPhilippe Charnier if (!strValue)
14020fc81af1SPhilippe Charnier errx (1, "%s needs parameter", option);
140324084f9bSBrian Somers break;
140424084f9bSBrian Somers
140524084f9bSBrian Somers case None:
14060fc81af1SPhilippe Charnier if (parms)
14070fc81af1SPhilippe Charnier errx (1, "%s does not take parameters", option);
140824084f9bSBrian Somers break;
140924084f9bSBrian Somers
141024084f9bSBrian Somers case Address:
14110fc81af1SPhilippe Charnier if (!parms)
14120fc81af1SPhilippe Charnier errx (1, "%s needs address/host parameter", option);
141324084f9bSBrian Somers
141424084f9bSBrian Somers StrToAddr (parms, &addrValue);
141524084f9bSBrian Somers break;
141624084f9bSBrian Somers }
141724084f9bSBrian Somers
141824084f9bSBrian Somers switch (info->type) {
141922c62477SPoul-Henning Kamp case LibAliasOption:
142024084f9bSBrian Somers
142124084f9bSBrian Somers aliasValue = yesNoValue ? info->packetAliasOpt : 0;
142222c62477SPoul-Henning Kamp LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
142324084f9bSBrian Somers break;
142424084f9bSBrian Somers
142524084f9bSBrian Somers case Verbose:
142624084f9bSBrian Somers verbose = yesNoValue;
142724084f9bSBrian Somers break;
142824084f9bSBrian Somers
142924084f9bSBrian Somers case DynamicMode:
143024084f9bSBrian Somers dynamicMode = yesNoValue;
143124084f9bSBrian Somers break;
143224084f9bSBrian Somers
143324084f9bSBrian Somers case InPort:
143422c62477SPoul-Henning Kamp mip->inPort = uNumValue;
143524084f9bSBrian Somers break;
143624084f9bSBrian Somers
143724084f9bSBrian Somers case OutPort:
143822c62477SPoul-Henning Kamp mip->outPort = uNumValue;
143924084f9bSBrian Somers break;
144024084f9bSBrian Somers
144124084f9bSBrian Somers case Port:
144222c62477SPoul-Henning Kamp mip->inOutPort = uNumValue;
144322c62477SPoul-Henning Kamp break;
144422c62477SPoul-Henning Kamp
144522c62477SPoul-Henning Kamp case GlobalPort:
144622c62477SPoul-Henning Kamp globalPort = uNumValue;
144724084f9bSBrian Somers break;
144824084f9bSBrian Somers
144924084f9bSBrian Somers case AliasAddress:
145022c62477SPoul-Henning Kamp memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
145124084f9bSBrian Somers break;
145224084f9bSBrian Somers
145311c2b3bfSRuslan Ermilov case TargetAddress:
145422c62477SPoul-Henning Kamp LibAliasSetTarget(mla, addrValue);
145511c2b3bfSRuslan Ermilov break;
145611c2b3bfSRuslan Ermilov
145724084f9bSBrian Somers case RedirectPort:
145824084f9bSBrian Somers SetupPortRedirect (strValue);
145924084f9bSBrian Somers break;
146024084f9bSBrian Somers
14614330006dSRuslan Ermilov case RedirectProto:
14624330006dSRuslan Ermilov SetupProtoRedirect(strValue);
14634330006dSRuslan Ermilov break;
14644330006dSRuslan Ermilov
146524084f9bSBrian Somers case RedirectAddress:
146624084f9bSBrian Somers SetupAddressRedirect (strValue);
146724084f9bSBrian Somers break;
146824084f9bSBrian Somers
146959a7c613SBrian Somers case ProxyRule:
147022c62477SPoul-Henning Kamp LibAliasProxyRule (mla, strValue);
147159a7c613SBrian Somers break;
147259a7c613SBrian Somers
147324084f9bSBrian Somers case InterfaceName:
147422c62477SPoul-Henning Kamp if (mip->ifName)
147522c62477SPoul-Henning Kamp free (mip->ifName);
147624084f9bSBrian Somers
147722c62477SPoul-Henning Kamp mip->ifName = strdup (strValue);
147824084f9bSBrian Somers break;
147924084f9bSBrian Somers
148024084f9bSBrian Somers case ConfigFile:
148124084f9bSBrian Somers ReadConfigFile (strValue);
148224084f9bSBrian Somers break;
148359a7c613SBrian Somers
148459a7c613SBrian Somers case LogDenied:
148522c62477SPoul-Henning Kamp mip->logDropped = yesNoValue;
148659a7c613SBrian Somers break;
148759a7c613SBrian Somers
148859a7c613SBrian Somers case LogFacility:
148959a7c613SBrian Somers
149059a7c613SBrian Somers fac_record = facilitynames;
149159a7c613SBrian Somers while (fac_record->c_name != NULL) {
149259a7c613SBrian Somers
149359a7c613SBrian Somers if (!strcmp (fac_record->c_name, strValue)) {
149459a7c613SBrian Somers
149559a7c613SBrian Somers logFacility = fac_record->c_val;
149659a7c613SBrian Somers break;
149759a7c613SBrian Somers
149859a7c613SBrian Somers }
149959a7c613SBrian Somers else
150059a7c613SBrian Somers fac_record++;
150159a7c613SBrian Somers }
150259a7c613SBrian Somers
150359a7c613SBrian Somers if(fac_record->c_name == NULL)
150459a7c613SBrian Somers errx(1, "Unknown log facility name: %s", strValue);
150559a7c613SBrian Somers
150659a7c613SBrian Somers break;
1507bc4ebb98SRuslan Ermilov
1508bc4ebb98SRuslan Ermilov case PunchFW:
1509bc4ebb98SRuslan Ermilov SetupPunchFW(strValue);
1510bc4ebb98SRuslan Ermilov break;
15113843533eSRuslan Ermilov
1512b07fbc17SJoe Marcus Clarke case SkinnyPort:
1513b07fbc17SJoe Marcus Clarke SetupSkinnyPort(strValue);
1514b07fbc17SJoe Marcus Clarke break;
1515b07fbc17SJoe Marcus Clarke
151684ef95bdSPoul-Henning Kamp case LogIpfwDenied:
1517db702c59SEitan Adler logIpfwDenied = yesNoValue;
15183843533eSRuslan Ermilov break;
1519b79840a6SRuslan Ermilov
1520b79840a6SRuslan Ermilov case PidFile:
1521b79840a6SRuslan Ermilov pidName = strdup (strValue);
1522b79840a6SRuslan Ermilov break;
152322c62477SPoul-Henning Kamp case Instance:
152422c62477SPoul-Henning Kamp NewInstance(strValue);
152522c62477SPoul-Henning Kamp break;
152672cbe4adSAlexander Motin case ExitDelay:
152772cbe4adSAlexander Motin if (numValue < 0 || numValue > MAX_EXIT_DELAY)
152872cbe4adSAlexander Motin errx(1, "Incorrect exit delay: %d", numValue);
152972cbe4adSAlexander Motin exitDelay = numValue;
153072cbe4adSAlexander Motin break;
153124084f9bSBrian Somers }
153224084f9bSBrian Somers }
153324084f9bSBrian Somers
ReadConfigFile(const char * fileName)1534902cb50aSBrian Somers void ReadConfigFile (const char* fileName)
153524084f9bSBrian Somers {
153624084f9bSBrian Somers FILE* file;
1537d99cc1daSRuslan Ermilov char *buf;
1538d99cc1daSRuslan Ermilov size_t len;
15392e7e7c71SRuslan Ermilov char *ptr, *p;
154024084f9bSBrian Somers char* option;
154124084f9bSBrian Somers
154224084f9bSBrian Somers file = fopen (fileName, "r");
1543d99cc1daSRuslan Ermilov if (!file)
1544d99cc1daSRuslan Ermilov err(1, "cannot open config file %s", fileName);
154524084f9bSBrian Somers
1546d99cc1daSRuslan Ermilov while ((buf = fgetln(file, &len)) != NULL) {
1547d99cc1daSRuslan Ermilov if (buf[len - 1] == '\n')
1548d99cc1daSRuslan Ermilov buf[len - 1] = '\0';
1549d99cc1daSRuslan Ermilov else
1550d99cc1daSRuslan Ermilov errx(1, "config file format error: "
1551d99cc1daSRuslan Ermilov "last line should end with newline");
155224084f9bSBrian Somers
155324084f9bSBrian Somers /*
15542e7e7c71SRuslan Ermilov * Check for comments, strip off trailing spaces.
155524084f9bSBrian Somers */
15562e7e7c71SRuslan Ermilov if ((ptr = strchr(buf, '#')))
15572e7e7c71SRuslan Ermilov *ptr = '\0';
15582e7e7c71SRuslan Ermilov for (ptr = buf; isspace(*ptr); ++ptr)
15592e7e7c71SRuslan Ermilov continue;
156024084f9bSBrian Somers if (*ptr == '\0')
156124084f9bSBrian Somers continue;
15622e7e7c71SRuslan Ermilov for (p = strchr(buf, '\0'); isspace(*--p);)
15632e7e7c71SRuslan Ermilov continue;
15642e7e7c71SRuslan Ermilov *++p = '\0';
15652e7e7c71SRuslan Ermilov
156624084f9bSBrian Somers /*
156724084f9bSBrian Somers * Extract option name.
156824084f9bSBrian Somers */
156924084f9bSBrian Somers option = ptr;
157024084f9bSBrian Somers while (*ptr && !isspace (*ptr))
157124084f9bSBrian Somers ++ptr;
157224084f9bSBrian Somers
157324084f9bSBrian Somers if (*ptr != '\0') {
157424084f9bSBrian Somers
157524084f9bSBrian Somers *ptr = '\0';
157624084f9bSBrian Somers ++ptr;
157724084f9bSBrian Somers }
157824084f9bSBrian Somers /*
157924084f9bSBrian Somers * Skip white space between name and parms.
158024084f9bSBrian Somers */
158124084f9bSBrian Somers while (*ptr && isspace (*ptr))
158224084f9bSBrian Somers ++ptr;
158324084f9bSBrian Somers
1584b0f55af6SRuslan Ermilov ParseOption (option, *ptr ? ptr : NULL);
158524084f9bSBrian Somers }
158624084f9bSBrian Somers
158724084f9bSBrian Somers fclose (file);
158824084f9bSBrian Somers }
158924084f9bSBrian Somers
Usage(void)15907154ce64SEd Schouten static void Usage(void)
159124084f9bSBrian Somers {
159224084f9bSBrian Somers int i;
159324084f9bSBrian Somers int max;
159424084f9bSBrian Somers struct OptionInfo* info;
159524084f9bSBrian Somers
159624084f9bSBrian Somers fprintf (stderr, "Recognized options:\n\n");
159724084f9bSBrian Somers
159824084f9bSBrian Somers max = sizeof (optionTable) / sizeof (struct OptionInfo);
159924084f9bSBrian Somers for (i = 0, info = optionTable; i < max; i++, info++) {
160024084f9bSBrian Somers
160124084f9bSBrian Somers fprintf (stderr, "-%-20s %s\n", info->name,
160224084f9bSBrian Somers info->parmDescription);
160324084f9bSBrian Somers
160424084f9bSBrian Somers if (info->shortName)
160524084f9bSBrian Somers fprintf (stderr, "-%-20s %s\n", info->shortName,
160624084f9bSBrian Somers info->parmDescription);
160724084f9bSBrian Somers
160824084f9bSBrian Somers fprintf (stderr, " %s\n\n", info->description);
160924084f9bSBrian Somers }
161024084f9bSBrian Somers
161124084f9bSBrian Somers exit (1);
161224084f9bSBrian Somers }
161324084f9bSBrian Somers
SetupPortRedirect(const char * parms)1614902cb50aSBrian Somers void SetupPortRedirect (const char* parms)
161524084f9bSBrian Somers {
1616b6365f95SAlexander Motin char *buf;
161724084f9bSBrian Somers char* ptr;
1618bd690510SRuslan Ermilov char* serverPool;
161924084f9bSBrian Somers struct in_addr localAddr;
162024084f9bSBrian Somers struct in_addr publicAddr;
162124084f9bSBrian Somers struct in_addr remoteAddr;
16225d8ee958SBrian Somers port_range portRange;
16235d8ee958SBrian Somers u_short localPort = 0;
16245d8ee958SBrian Somers u_short publicPort = 0;
16255d8ee958SBrian Somers u_short remotePort = 0;
16265d8ee958SBrian Somers u_short numLocalPorts = 0;
16275d8ee958SBrian Somers u_short numPublicPorts = 0;
16285d8ee958SBrian Somers u_short numRemotePorts = 0;
162924084f9bSBrian Somers int proto;
163024084f9bSBrian Somers char* protoName;
163124084f9bSBrian Somers char* separator;
16325d8ee958SBrian Somers int i;
163348ce8ca1SXin LI struct alias_link *aliaslink = NULL;
163424084f9bSBrian Somers
1635b6365f95SAlexander Motin buf = strdup (parms);
1636b6365f95SAlexander Motin if (!buf)
1637b6365f95SAlexander Motin errx (1, "redirect_port: strdup() failed");
163824084f9bSBrian Somers /*
163924084f9bSBrian Somers * Extract protocol.
164024084f9bSBrian Somers */
164124084f9bSBrian Somers protoName = strtok (buf, " \t");
16420fc81af1SPhilippe Charnier if (!protoName)
16430fc81af1SPhilippe Charnier errx (1, "redirect_port: missing protocol");
164424084f9bSBrian Somers
164524084f9bSBrian Somers proto = StrToProto (protoName);
164624084f9bSBrian Somers /*
164724084f9bSBrian Somers * Extract local address.
164824084f9bSBrian Somers */
164924084f9bSBrian Somers ptr = strtok (NULL, " \t");
16500fc81af1SPhilippe Charnier if (!ptr)
16510fc81af1SPhilippe Charnier errx (1, "redirect_port: missing local address");
165224084f9bSBrian Somers
1653bd690510SRuslan Ermilov separator = strchr(ptr, ',');
1654bd690510SRuslan Ermilov if (separator) { /* LSNAT redirection syntax. */
1655bd690510SRuslan Ermilov localAddr.s_addr = INADDR_NONE;
1656bd690510SRuslan Ermilov localPort = ~0;
1657bd690510SRuslan Ermilov numLocalPorts = 1;
1658bd690510SRuslan Ermilov serverPool = ptr;
1659bd690510SRuslan Ermilov } else {
16605d8ee958SBrian Somers if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
16615d8ee958SBrian Somers errx (1, "redirect_port: invalid local port range");
16625d8ee958SBrian Somers
16635d8ee958SBrian Somers localPort = GETLOPORT(portRange);
16645d8ee958SBrian Somers numLocalPorts = GETNUMPORTS(portRange);
1665bd690510SRuslan Ermilov serverPool = NULL;
1666bd690510SRuslan Ermilov }
16675d8ee958SBrian Somers
166824084f9bSBrian Somers /*
16699c501140SBrian Somers * Extract public port and optionally address.
167024084f9bSBrian Somers */
167124084f9bSBrian Somers ptr = strtok (NULL, " \t");
16720fc81af1SPhilippe Charnier if (!ptr)
16730fc81af1SPhilippe Charnier errx (1, "redirect_port: missing public port");
167424084f9bSBrian Somers
167524084f9bSBrian Somers separator = strchr (ptr, ':');
16765d8ee958SBrian Somers if (separator) {
16775d8ee958SBrian Somers if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
16785d8ee958SBrian Somers errx (1, "redirect_port: invalid public port range");
167924084f9bSBrian Somers }
16805d8ee958SBrian Somers else {
16815d8ee958SBrian Somers publicAddr.s_addr = INADDR_ANY;
16825d8ee958SBrian Somers if (StrToPortRange (ptr, protoName, &portRange) != 0)
16835d8ee958SBrian Somers errx (1, "redirect_port: invalid public port range");
16845d8ee958SBrian Somers }
16855d8ee958SBrian Somers
16865d8ee958SBrian Somers publicPort = GETLOPORT(portRange);
16875d8ee958SBrian Somers numPublicPorts = GETNUMPORTS(portRange);
168824084f9bSBrian Somers
168924084f9bSBrian Somers /*
169024084f9bSBrian Somers * Extract remote address and optionally port.
169124084f9bSBrian Somers */
169224084f9bSBrian Somers ptr = strtok (NULL, " \t");
169324084f9bSBrian Somers if (ptr) {
169424084f9bSBrian Somers separator = strchr (ptr, ':');
1695ebe70c8fSWarner Losh if (separator) {
16965d8ee958SBrian Somers if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
16975d8ee958SBrian Somers errx (1, "redirect_port: invalid remote port range");
1698ebe70c8fSWarner Losh } else {
16995d8ee958SBrian Somers SETLOPORT(portRange, 0);
17005d8ee958SBrian Somers SETNUMPORTS(portRange, 1);
170124084f9bSBrian Somers StrToAddr (ptr, &remoteAddr);
170224084f9bSBrian Somers }
170324084f9bSBrian Somers }
170424084f9bSBrian Somers else {
17055d8ee958SBrian Somers SETLOPORT(portRange, 0);
17065d8ee958SBrian Somers SETNUMPORTS(portRange, 1);
170724084f9bSBrian Somers remoteAddr.s_addr = INADDR_ANY;
170824084f9bSBrian Somers }
170924084f9bSBrian Somers
17105d8ee958SBrian Somers remotePort = GETLOPORT(portRange);
17115d8ee958SBrian Somers numRemotePorts = GETNUMPORTS(portRange);
17125d8ee958SBrian Somers
17135d8ee958SBrian Somers /*
17145d8ee958SBrian Somers * Make sure port ranges match up, then add the redirect ports.
17155d8ee958SBrian Somers */
17165d8ee958SBrian Somers if (numLocalPorts != numPublicPorts)
17175d8ee958SBrian Somers errx (1, "redirect_port: port ranges must be equal in size");
17185d8ee958SBrian Somers
17195d8ee958SBrian Somers /* Remote port range is allowed to be '0' which means all ports. */
172029d97436SBrian Somers if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
17215d8ee958SBrian Somers errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
17225d8ee958SBrian Somers
17235d8ee958SBrian Somers for (i = 0 ; i < numPublicPorts ; ++i) {
17245d8ee958SBrian Somers /* If remotePort is all ports, set it to 0. */
17255d8ee958SBrian Somers u_short remotePortCopy = remotePort + i;
17265d8ee958SBrian Somers if (numRemotePorts == 1 && remotePort == 0)
17275d8ee958SBrian Somers remotePortCopy = 0;
17285d8ee958SBrian Somers
172948ce8ca1SXin LI aliaslink = LibAliasRedirectPort (mla, localAddr,
17305d8ee958SBrian Somers htons(localPort + i),
173124084f9bSBrian Somers remoteAddr,
17325d8ee958SBrian Somers htons(remotePortCopy),
173324084f9bSBrian Somers publicAddr,
17345d8ee958SBrian Somers htons(publicPort + i),
173524084f9bSBrian Somers proto);
173624084f9bSBrian Somers }
1737bd690510SRuslan Ermilov
1738bd690510SRuslan Ermilov /*
1739bd690510SRuslan Ermilov * Setup LSNAT server pool.
1740bd690510SRuslan Ermilov */
174148ce8ca1SXin LI if (serverPool != NULL && aliaslink != NULL) {
1742bd690510SRuslan Ermilov ptr = strtok(serverPool, ",");
1743bd690510SRuslan Ermilov while (ptr != NULL) {
1744bd690510SRuslan Ermilov if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1745bd690510SRuslan Ermilov errx(1, "redirect_port: invalid local port range");
1746bd690510SRuslan Ermilov
1747bd690510SRuslan Ermilov localPort = GETLOPORT(portRange);
1748bd690510SRuslan Ermilov if (GETNUMPORTS(portRange) != 1)
1749bd690510SRuslan Ermilov errx(1, "redirect_port: local port must be single in this context");
175048ce8ca1SXin LI LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
1751bd690510SRuslan Ermilov ptr = strtok(NULL, ",");
1752bd690510SRuslan Ermilov }
1753bd690510SRuslan Ermilov }
1754b6365f95SAlexander Motin
1755b6365f95SAlexander Motin free (buf);
17565d8ee958SBrian Somers }
175724084f9bSBrian Somers
17584330006dSRuslan Ermilov void
SetupProtoRedirect(const char * parms)17594330006dSRuslan Ermilov SetupProtoRedirect(const char* parms)
17604330006dSRuslan Ermilov {
1761b6365f95SAlexander Motin char *buf;
17624330006dSRuslan Ermilov char* ptr;
17634330006dSRuslan Ermilov struct in_addr localAddr;
17644330006dSRuslan Ermilov struct in_addr publicAddr;
17654330006dSRuslan Ermilov struct in_addr remoteAddr;
17664330006dSRuslan Ermilov int proto;
17674330006dSRuslan Ermilov char* protoName;
17684330006dSRuslan Ermilov struct protoent *protoent;
17694330006dSRuslan Ermilov
1770b6365f95SAlexander Motin buf = strdup (parms);
1771b6365f95SAlexander Motin if (!buf)
1772b6365f95SAlexander Motin errx (1, "redirect_port: strdup() failed");
17734330006dSRuslan Ermilov /*
17744330006dSRuslan Ermilov * Extract protocol.
17754330006dSRuslan Ermilov */
17764330006dSRuslan Ermilov protoName = strtok(buf, " \t");
17774330006dSRuslan Ermilov if (!protoName)
17784330006dSRuslan Ermilov errx(1, "redirect_proto: missing protocol");
17794330006dSRuslan Ermilov
17804330006dSRuslan Ermilov protoent = getprotobyname(protoName);
17814330006dSRuslan Ermilov if (protoent == NULL)
17824330006dSRuslan Ermilov errx(1, "redirect_proto: unknown protocol %s", protoName);
17834330006dSRuslan Ermilov else
17844330006dSRuslan Ermilov proto = protoent->p_proto;
17854330006dSRuslan Ermilov /*
17864330006dSRuslan Ermilov * Extract local address.
17874330006dSRuslan Ermilov */
17884330006dSRuslan Ermilov ptr = strtok(NULL, " \t");
17894330006dSRuslan Ermilov if (!ptr)
17904330006dSRuslan Ermilov errx(1, "redirect_proto: missing local address");
17914330006dSRuslan Ermilov else
17924330006dSRuslan Ermilov StrToAddr(ptr, &localAddr);
17934330006dSRuslan Ermilov /*
17944330006dSRuslan Ermilov * Extract optional public address.
17954330006dSRuslan Ermilov */
17964330006dSRuslan Ermilov ptr = strtok(NULL, " \t");
17974330006dSRuslan Ermilov if (ptr)
17984330006dSRuslan Ermilov StrToAddr(ptr, &publicAddr);
17994330006dSRuslan Ermilov else
18004330006dSRuslan Ermilov publicAddr.s_addr = INADDR_ANY;
18014330006dSRuslan Ermilov /*
18024330006dSRuslan Ermilov * Extract optional remote address.
18034330006dSRuslan Ermilov */
18044330006dSRuslan Ermilov ptr = strtok(NULL, " \t");
18054330006dSRuslan Ermilov if (ptr)
18064330006dSRuslan Ermilov StrToAddr(ptr, &remoteAddr);
18074330006dSRuslan Ermilov else
18084330006dSRuslan Ermilov remoteAddr.s_addr = INADDR_ANY;
18094330006dSRuslan Ermilov /*
18104330006dSRuslan Ermilov * Create aliasing link.
18114330006dSRuslan Ermilov */
181222c62477SPoul-Henning Kamp (void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
18134330006dSRuslan Ermilov proto);
1814b6365f95SAlexander Motin
1815b6365f95SAlexander Motin free (buf);
18164330006dSRuslan Ermilov }
18174330006dSRuslan Ermilov
SetupAddressRedirect(const char * parms)1818902cb50aSBrian Somers void SetupAddressRedirect (const char* parms)
181924084f9bSBrian Somers {
1820b6365f95SAlexander Motin char *buf;
182124084f9bSBrian Somers char* ptr;
1822bd690510SRuslan Ermilov char* separator;
182324084f9bSBrian Somers struct in_addr localAddr;
182424084f9bSBrian Somers struct in_addr publicAddr;
1825bd690510SRuslan Ermilov char* serverPool;
182648ce8ca1SXin LI struct alias_link *aliaslink;
182724084f9bSBrian Somers
1828b6365f95SAlexander Motin buf = strdup (parms);
1829b6365f95SAlexander Motin if (!buf)
1830b6365f95SAlexander Motin errx (1, "redirect_port: strdup() failed");
183124084f9bSBrian Somers /*
183224084f9bSBrian Somers * Extract local address.
183324084f9bSBrian Somers */
183424084f9bSBrian Somers ptr = strtok (buf, " \t");
18350fc81af1SPhilippe Charnier if (!ptr)
18360fc81af1SPhilippe Charnier errx (1, "redirect_address: missing local address");
183724084f9bSBrian Somers
1838bd690510SRuslan Ermilov separator = strchr(ptr, ',');
1839bd690510SRuslan Ermilov if (separator) { /* LSNAT redirection syntax. */
1840bd690510SRuslan Ermilov localAddr.s_addr = INADDR_NONE;
1841bd690510SRuslan Ermilov serverPool = ptr;
1842bd690510SRuslan Ermilov } else {
184324084f9bSBrian Somers StrToAddr (ptr, &localAddr);
1844bd690510SRuslan Ermilov serverPool = NULL;
1845bd690510SRuslan Ermilov }
184624084f9bSBrian Somers /*
184724084f9bSBrian Somers * Extract public address.
184824084f9bSBrian Somers */
184924084f9bSBrian Somers ptr = strtok (NULL, " \t");
18500fc81af1SPhilippe Charnier if (!ptr)
18510fc81af1SPhilippe Charnier errx (1, "redirect_address: missing public address");
185224084f9bSBrian Somers
185324084f9bSBrian Somers StrToAddr (ptr, &publicAddr);
185448ce8ca1SXin LI aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1855bd690510SRuslan Ermilov
1856bd690510SRuslan Ermilov /*
1857bd690510SRuslan Ermilov * Setup LSNAT server pool.
1858bd690510SRuslan Ermilov */
185948ce8ca1SXin LI if (serverPool != NULL && aliaslink != NULL) {
1860bd690510SRuslan Ermilov ptr = strtok(serverPool, ",");
1861bd690510SRuslan Ermilov while (ptr != NULL) {
1862bd690510SRuslan Ermilov StrToAddr(ptr, &localAddr);
186348ce8ca1SXin LI LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
1864bd690510SRuslan Ermilov ptr = strtok(NULL, ",");
1865bd690510SRuslan Ermilov }
1866bd690510SRuslan Ermilov }
1867b6365f95SAlexander Motin
1868b6365f95SAlexander Motin free (buf);
186924084f9bSBrian Somers }
187024084f9bSBrian Somers
StrToAddr(const char * str,struct in_addr * addr)1871902cb50aSBrian Somers void StrToAddr (const char* str, struct in_addr* addr)
187224084f9bSBrian Somers {
187324084f9bSBrian Somers struct hostent* hp;
187424084f9bSBrian Somers
187524084f9bSBrian Somers if (inet_aton (str, addr))
187624084f9bSBrian Somers return;
187724084f9bSBrian Somers
187824084f9bSBrian Somers hp = gethostbyname (str);
18790fc81af1SPhilippe Charnier if (!hp)
18800fc81af1SPhilippe Charnier errx (1, "unknown host %s", str);
188124084f9bSBrian Somers
188224084f9bSBrian Somers memcpy (addr, hp->h_addr, sizeof (struct in_addr));
188324084f9bSBrian Somers }
188424084f9bSBrian Somers
StrToPort(const char * str,const char * proto)1885902cb50aSBrian Somers u_short StrToPort (const char* str, const char* proto)
188624084f9bSBrian Somers {
188767a886fbSBrian Somers u_short port;
188824084f9bSBrian Somers struct servent* sp;
188924084f9bSBrian Somers char* end;
189024084f9bSBrian Somers
189124084f9bSBrian Somers port = strtol (str, &end, 10);
189224084f9bSBrian Somers if (end != str)
189327c20503SBrian Somers return htons (port);
189424084f9bSBrian Somers
189524084f9bSBrian Somers sp = getservbyname (str, proto);
18960fc81af1SPhilippe Charnier if (!sp)
189729e3edccSPhilippe Charnier errx (1, "%s/%s: unknown service", str, proto);
189824084f9bSBrian Somers
189924084f9bSBrian Somers return sp->s_port;
190024084f9bSBrian Somers }
190124084f9bSBrian Somers
StrToPortRange(const char * str,const char * proto,port_range * portRange)1902902cb50aSBrian Somers int StrToPortRange (const char* str, const char* proto, port_range *portRange)
19035d8ee958SBrian Somers {
1904ef02f85cSPoul-Henning Kamp const char* sep;
19055d8ee958SBrian Somers struct servent* sp;
19065d8ee958SBrian Somers char* end;
19075d8ee958SBrian Somers u_short loPort;
19085d8ee958SBrian Somers u_short hiPort;
19095d8ee958SBrian Somers
19105d8ee958SBrian Somers /* First see if this is a service, return corresponding port if so. */
19115d8ee958SBrian Somers sp = getservbyname (str,proto);
19125d8ee958SBrian Somers if (sp) {
19135d8ee958SBrian Somers SETLOPORT(*portRange, ntohs(sp->s_port));
19145d8ee958SBrian Somers SETNUMPORTS(*portRange, 1);
19155d8ee958SBrian Somers return 0;
19165d8ee958SBrian Somers }
19175d8ee958SBrian Somers
19185d8ee958SBrian Somers /* Not a service, see if it's a single port or port range. */
19195d8ee958SBrian Somers sep = strchr (str, '-');
19205d8ee958SBrian Somers if (sep == NULL) {
19215d8ee958SBrian Somers SETLOPORT(*portRange, strtol(str, &end, 10));
19225d8ee958SBrian Somers if (end != str) {
19235d8ee958SBrian Somers /* Single port. */
19245d8ee958SBrian Somers SETNUMPORTS(*portRange, 1);
19255d8ee958SBrian Somers return 0;
19265d8ee958SBrian Somers }
19275d8ee958SBrian Somers
19285d8ee958SBrian Somers /* Error in port range field. */
192929e3edccSPhilippe Charnier errx (1, "%s/%s: unknown service", str, proto);
19305d8ee958SBrian Somers }
19315d8ee958SBrian Somers
19325d8ee958SBrian Somers /* Port range, get the values and sanity check. */
19335d8ee958SBrian Somers sscanf (str, "%hu-%hu", &loPort, &hiPort);
19345d8ee958SBrian Somers SETLOPORT(*portRange, loPort);
19355d8ee958SBrian Somers SETNUMPORTS(*portRange, 0); /* Error by default */
19365d8ee958SBrian Somers if (loPort <= hiPort)
19375d8ee958SBrian Somers SETNUMPORTS(*portRange, hiPort - loPort + 1);
19385d8ee958SBrian Somers
19395d8ee958SBrian Somers if (GETNUMPORTS(*portRange) == 0)
19405d8ee958SBrian Somers errx (1, "invalid port range %s", str);
19415d8ee958SBrian Somers
19425d8ee958SBrian Somers return 0;
19435d8ee958SBrian Somers }
19445d8ee958SBrian Somers
19455d8ee958SBrian Somers
1946ef02f85cSPoul-Henning Kamp static int
StrToProto(const char * str)1947ef02f85cSPoul-Henning Kamp StrToProto (const char* str)
194824084f9bSBrian Somers {
194924084f9bSBrian Somers if (!strcmp (str, "tcp"))
195024084f9bSBrian Somers return IPPROTO_TCP;
195124084f9bSBrian Somers
195224084f9bSBrian Somers if (!strcmp (str, "udp"))
195324084f9bSBrian Somers return IPPROTO_UDP;
195424084f9bSBrian Somers
19550fc81af1SPhilippe Charnier errx (1, "unknown protocol %s. Expected tcp or udp", str);
195624084f9bSBrian Somers }
195724084f9bSBrian Somers
1958ef02f85cSPoul-Henning Kamp static int
StrToAddrAndPortRange(char * str,struct in_addr * addr,char * proto,port_range * portRange)1959ef02f85cSPoul-Henning Kamp StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange)
196024084f9bSBrian Somers {
196124084f9bSBrian Somers char* ptr;
196224084f9bSBrian Somers
196324084f9bSBrian Somers ptr = strchr (str, ':');
19640fc81af1SPhilippe Charnier if (!ptr)
19650fc81af1SPhilippe Charnier errx (1, "%s is missing port number", str);
196624084f9bSBrian Somers
196724084f9bSBrian Somers *ptr = '\0';
196824084f9bSBrian Somers ++ptr;
196924084f9bSBrian Somers
197024084f9bSBrian Somers StrToAddr (str, addr);
19715d8ee958SBrian Somers return StrToPortRange (ptr, proto, portRange);
197224084f9bSBrian Somers }
1973bc4ebb98SRuslan Ermilov
1974bc4ebb98SRuslan Ermilov static void
SetupPunchFW(const char * strValue)1975bc4ebb98SRuslan Ermilov SetupPunchFW(const char *strValue)
1976bc4ebb98SRuslan Ermilov {
1977bc4ebb98SRuslan Ermilov unsigned int base, num;
1978bc4ebb98SRuslan Ermilov
1979bc4ebb98SRuslan Ermilov if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1980bc4ebb98SRuslan Ermilov errx(1, "punch_fw: basenumber:count parameter required");
1981bc4ebb98SRuslan Ermilov
1982d53fe710SRoman Kurakin if (CheckIpfwRulenum(base + num - 1) == -1)
1983d53fe710SRoman Kurakin errx(1, "punch_fw: basenumber:count parameter should fit "
1984d53fe710SRoman Kurakin "the maximum allowed rule numbers");
1985d53fe710SRoman Kurakin
198622c62477SPoul-Henning Kamp LibAliasSetFWBase(mla, base, num);
198722c62477SPoul-Henning Kamp (void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1988bc4ebb98SRuslan Ermilov }
1989b07fbc17SJoe Marcus Clarke
1990b07fbc17SJoe Marcus Clarke static void
SetupSkinnyPort(const char * strValue)1991b07fbc17SJoe Marcus Clarke SetupSkinnyPort(const char *strValue)
1992b07fbc17SJoe Marcus Clarke {
1993b07fbc17SJoe Marcus Clarke unsigned int port;
1994b07fbc17SJoe Marcus Clarke
1995b07fbc17SJoe Marcus Clarke if (sscanf(strValue, "%u", &port) != 1)
1996b07fbc17SJoe Marcus Clarke errx(1, "skinny_port: port parameter required");
1997b07fbc17SJoe Marcus Clarke
199822c62477SPoul-Henning Kamp LibAliasSetSkinnyPort(mla, port);
199922c62477SPoul-Henning Kamp }
200022c62477SPoul-Henning Kamp
200122c62477SPoul-Henning Kamp static void
NewInstance(const char * name)200222c62477SPoul-Henning Kamp NewInstance(const char *name)
200322c62477SPoul-Henning Kamp {
200422c62477SPoul-Henning Kamp struct instance *ip;
200522c62477SPoul-Henning Kamp
200622c62477SPoul-Henning Kamp LIST_FOREACH(ip, &root, list) {
200722c62477SPoul-Henning Kamp if (!strcmp(ip->name, name)) {
200822c62477SPoul-Henning Kamp mla = ip->la;
200922c62477SPoul-Henning Kamp mip = ip;
201022c62477SPoul-Henning Kamp return;
201122c62477SPoul-Henning Kamp }
201222c62477SPoul-Henning Kamp }
201322c62477SPoul-Henning Kamp ninstance++;
2014f405b033SMarcelo Araujo ip = calloc(1, sizeof(*ip));
201522c62477SPoul-Henning Kamp ip->name = strdup(name);
201622c62477SPoul-Henning Kamp ip->la = LibAliasInit (ip->la);
201722c62477SPoul-Henning Kamp ip->assignAliasAddr = 0;
201822c62477SPoul-Henning Kamp ip->ifName = NULL;
201922c62477SPoul-Henning Kamp ip->logDropped = 0;
202022c62477SPoul-Henning Kamp ip->inPort = 0;
202122c62477SPoul-Henning Kamp ip->outPort = 0;
202222c62477SPoul-Henning Kamp ip->inOutPort = 0;
202322c62477SPoul-Henning Kamp ip->aliasAddr.s_addr = INADDR_NONE;
202422c62477SPoul-Henning Kamp ip->ifMTU = -1;
202522c62477SPoul-Henning Kamp ip->aliasOverhead = 12;
202622c62477SPoul-Henning Kamp LIST_INSERT_HEAD(&root, ip, list);
202722c62477SPoul-Henning Kamp mla = ip->la;
202822c62477SPoul-Henning Kamp mip = ip;
2029b07fbc17SJoe Marcus Clarke }
2030d53fe710SRoman Kurakin
2031d53fe710SRoman Kurakin static int
CheckIpfwRulenum(unsigned int rnum)2032d53fe710SRoman Kurakin CheckIpfwRulenum(unsigned int rnum)
2033d53fe710SRoman Kurakin {
2034d53fe710SRoman Kurakin unsigned int default_rule;
2035d53fe710SRoman Kurakin size_t len = sizeof(default_rule);
2036d53fe710SRoman Kurakin
2037d53fe710SRoman Kurakin if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len,
2038d53fe710SRoman Kurakin NULL, 0) == -1) {
2039d53fe710SRoman Kurakin warn("Failed to get the default ipfw rule number, using "
2040d53fe710SRoman Kurakin "default historical value 65535. The reason was");
2041d53fe710SRoman Kurakin default_rule = 65535;
2042d53fe710SRoman Kurakin }
2043d53fe710SRoman Kurakin if (rnum >= default_rule) {
2044d53fe710SRoman Kurakin return -1;
2045d53fe710SRoman Kurakin }
2046d53fe710SRoman Kurakin
2047d53fe710SRoman Kurakin return 0;
2048d53fe710SRoman Kurakin }
2049