xref: /freebsd/sbin/natd/natd.c (revision ef18594985c0d569650b44b0ba0171a6fd8703a5)
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