xref: /freebsd/sbin/natd/natd.c (revision 7154ce64ab67c6fc0f6373f597f1314822844e78)
124084f9bSBrian Somers /*
224084f9bSBrian Somers  * natd - Network Address Translation Daemon for FreeBSD.
324084f9bSBrian Somers  *
4f13f9fadSAlexander Langer  * This software is provided free of charge, with no
524084f9bSBrian Somers  * warranty of any kind, either expressed or implied.
624084f9bSBrian Somers  * Use at your own risk.
724084f9bSBrian Somers  *
824084f9bSBrian Somers  * You may copy, modify and distribute this software (natd.c) freely.
924084f9bSBrian Somers  *
10fb994b07SBrian Somers  * Ari Suutari <suutari@iki.fi>
1124084f9bSBrian Somers  */
1224084f9bSBrian Somers 
1329e3edccSPhilippe Charnier #include <sys/cdefs.h>
1429e3edccSPhilippe Charnier __FBSDID("$FreeBSD$");
1529e3edccSPhilippe Charnier 
1659a7c613SBrian Somers #define SYSLOG_NAMES
1759a7c613SBrian Somers 
1824084f9bSBrian Somers #include <sys/types.h>
1924084f9bSBrian Somers #include <sys/socket.h>
204c04fa4cSRuslan Ermilov #include <sys/sysctl.h>
2124084f9bSBrian Somers #include <sys/time.h>
2222c62477SPoul-Henning Kamp #include <sys/queue.h>
2324084f9bSBrian Somers 
2424084f9bSBrian Somers #include <netinet/in.h>
2524084f9bSBrian Somers #include <netinet/in_systm.h>
2624084f9bSBrian Somers #include <netinet/ip.h>
2724084f9bSBrian Somers #include <machine/in_cksum.h>
2824084f9bSBrian Somers #include <netinet/tcp.h>
2959a7c613SBrian Somers #include <netinet/udp.h>
3059a7c613SBrian Somers #include <netinet/ip_icmp.h>
3124084f9bSBrian Somers #include <net/if.h>
324c04fa4cSRuslan Ermilov #include <net/if_dl.h>
3324084f9bSBrian Somers #include <net/route.h>
3424084f9bSBrian Somers #include <arpa/inet.h>
3524084f9bSBrian Somers 
3624084f9bSBrian Somers #include <alias.h>
370fc81af1SPhilippe Charnier #include <ctype.h>
380fc81af1SPhilippe Charnier #include <err.h>
390fc81af1SPhilippe Charnier #include <errno.h>
400fc81af1SPhilippe Charnier #include <netdb.h>
410fc81af1SPhilippe Charnier #include <signal.h>
420fc81af1SPhilippe Charnier #include <stdio.h>
430fc81af1SPhilippe Charnier #include <stdlib.h>
440fc81af1SPhilippe Charnier #include <string.h>
450fc81af1SPhilippe Charnier #include <syslog.h>
460fc81af1SPhilippe Charnier #include <unistd.h>
4767a886fbSBrian Somers 
4824084f9bSBrian Somers #include "natd.h"
4924084f9bSBrian Somers 
5022c62477SPoul-Henning Kamp struct instance {
5122c62477SPoul-Henning Kamp 	const char		*name;
5222c62477SPoul-Henning Kamp 	struct libalias		*la;
5322c62477SPoul-Henning Kamp 	LIST_ENTRY(instance)	list;
5422c62477SPoul-Henning Kamp 
5522c62477SPoul-Henning Kamp 	int			ifIndex;
5622c62477SPoul-Henning Kamp 	int			assignAliasAddr;
5722c62477SPoul-Henning Kamp 	char*			ifName;
5822c62477SPoul-Henning Kamp 	int			logDropped;
5922c62477SPoul-Henning Kamp 	u_short			inPort;
6022c62477SPoul-Henning Kamp 	u_short			outPort;
6122c62477SPoul-Henning Kamp 	u_short			inOutPort;
6222c62477SPoul-Henning Kamp 	struct in_addr		aliasAddr;
6322c62477SPoul-Henning Kamp 	int			ifMTU;
6422c62477SPoul-Henning Kamp 	int			aliasOverhead;
6522c62477SPoul-Henning Kamp 	int			dropIgnoredIncoming;
6622c62477SPoul-Henning Kamp 	int			divertIn;
6722c62477SPoul-Henning Kamp 	int			divertOut;
6822c62477SPoul-Henning Kamp 	int			divertInOut;
6922c62477SPoul-Henning Kamp };
7022c62477SPoul-Henning Kamp 
7113e403fdSAntoine Brodin static LIST_HEAD(, instance) root = LIST_HEAD_INITIALIZER(root);
7222c62477SPoul-Henning Kamp 
7322c62477SPoul-Henning Kamp struct libalias *mla;
7422c62477SPoul-Henning Kamp struct instance *mip;
7522c62477SPoul-Henning Kamp int ninstance = 1;
7622c62477SPoul-Henning Kamp 
7724084f9bSBrian Somers /*
7824084f9bSBrian Somers  * Default values for input and output
7924084f9bSBrian Somers  * divert socket ports.
8024084f9bSBrian Somers  */
8124084f9bSBrian Somers 
8224084f9bSBrian Somers #define	DEFAULT_SERVICE	"natd"
8324084f9bSBrian Somers 
8424084f9bSBrian Somers /*
855d8ee958SBrian Somers  * Definition of a port range, and macros to deal with values.
865d8ee958SBrian Somers  * FORMAT:  HI 16-bits == first port in range, 0 == all ports.
875d8ee958SBrian Somers  *          LO 16-bits == number of ports in range
885d8ee958SBrian Somers  * NOTES:   - Port values are not stored in network byte order.
895d8ee958SBrian Somers  */
905d8ee958SBrian Somers 
915d8ee958SBrian Somers typedef u_long port_range;
925d8ee958SBrian Somers 
935d8ee958SBrian Somers #define GETLOPORT(x)     ((x) >> 0x10)
945d8ee958SBrian Somers #define GETNUMPORTS(x)   ((x) & 0x0000ffff)
955d8ee958SBrian Somers #define GETHIPORT(x)     (GETLOPORT((x)) + GETNUMPORTS((x)))
965d8ee958SBrian Somers 
975d8ee958SBrian Somers /* Set y to be the low-port value in port_range variable x. */
985d8ee958SBrian Somers #define SETLOPORT(x,y)   ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
995d8ee958SBrian Somers 
1005d8ee958SBrian Somers /* Set y to be the number of ports in port_range variable x. */
1015d8ee958SBrian Somers #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
1025d8ee958SBrian Somers 
1035d8ee958SBrian Somers /*
10424084f9bSBrian Somers  * Function prototypes.
10524084f9bSBrian Somers  */
10624084f9bSBrian Somers 
10759a7c613SBrian Somers static void	DoAliasing (int fd, int direction);
108902cb50aSBrian Somers static void	DaemonMode (void);
10924084f9bSBrian Somers static void	HandleRoutingInfo (int fd);
110902cb50aSBrian Somers static void	Usage (void);
11159a7c613SBrian Somers static char*	FormatPacket (struct ip*);
11224084f9bSBrian Somers static void	PrintPacket (struct ip*);
113902cb50aSBrian Somers static void	SyslogPacket (struct ip*, int priority, const char *label);
1144c04fa4cSRuslan Ermilov static void	SetAliasAddressFromIfName (const char *ifName);
115902cb50aSBrian Somers static void	InitiateShutdown (int);
116902cb50aSBrian Somers static void	Shutdown (int);
117902cb50aSBrian Somers static void	RefreshAddr (int);
118b0f55af6SRuslan Ermilov static void	ParseOption (const char* option, const char* parms);
119902cb50aSBrian Somers static void	ReadConfigFile (const char* fileName);
120902cb50aSBrian Somers static void	SetupPortRedirect (const char* parms);
1214330006dSRuslan Ermilov static void	SetupProtoRedirect(const char* parms);
122902cb50aSBrian Somers static void	SetupAddressRedirect (const char* parms);
123902cb50aSBrian Somers static void	StrToAddr (const char* str, struct in_addr* addr);
124902cb50aSBrian Somers static u_short  StrToPort (const char* str, const char* proto);
125902cb50aSBrian Somers static int      StrToPortRange (const char* str, const char* proto, port_range *portRange);
126902cb50aSBrian Somers static int 	StrToProto (const char* str);
127902cb50aSBrian Somers static int      StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange);
12824084f9bSBrian Somers static void	ParseArgs (int argc, char** argv);
129bc4ebb98SRuslan Ermilov static void	SetupPunchFW(const char *strValue);
130b07fbc17SJoe Marcus Clarke static void	SetupSkinnyPort(const char *strValue);
13122c62477SPoul-Henning Kamp static void	NewInstance(const char *name);
13222c62477SPoul-Henning Kamp static void	DoGlobal (int fd);
133d53fe710SRoman Kurakin static int	CheckIpfwRulenum(unsigned int rnum);
13424084f9bSBrian Somers 
13524084f9bSBrian Somers /*
13624084f9bSBrian Somers  * Globals.
13724084f9bSBrian Somers  */
13824084f9bSBrian Somers 
13924084f9bSBrian Somers static	int			verbose;
14024084f9bSBrian Somers static 	int			background;
14124084f9bSBrian Somers static	int			running;
14259a7c613SBrian Somers static	int			logFacility;
14322c62477SPoul-Henning Kamp 
14422c62477SPoul-Henning Kamp static 	int			dynamicMode;
14522c62477SPoul-Henning Kamp static 	int			icmpSock;
1463843533eSRuslan Ermilov static	int			logIpfwDenied;
14748ce8ca1SXin LI static	const char*		pidName;
14822c62477SPoul-Henning Kamp static	int			routeSock;
14922c62477SPoul-Henning Kamp static	int			globalPort;
15022c62477SPoul-Henning Kamp static	int			divertGlobal;
15172cbe4adSAlexander Motin static	int			exitDelay;
15272cbe4adSAlexander Motin 
15324084f9bSBrian Somers 
15424084f9bSBrian Somers int main (int argc, char** argv)
15524084f9bSBrian Somers {
15624084f9bSBrian Somers 	struct sockaddr_in	addr;
15724084f9bSBrian Somers 	fd_set			readMask;
15824084f9bSBrian Somers 	int			fdMax;
15924084f9bSBrian Somers /*
16024084f9bSBrian Somers  * Initialize packet aliasing software.
16124084f9bSBrian Somers  * Done already here to be able to alter option bits
16224084f9bSBrian Somers  * during command line and configuration file processing.
16324084f9bSBrian Somers  */
16422c62477SPoul-Henning Kamp 	NewInstance("default");
16522c62477SPoul-Henning Kamp 
16624084f9bSBrian Somers /*
16724084f9bSBrian Somers  * Parse options.
16824084f9bSBrian Somers  */
16924084f9bSBrian Somers 	verbose 		= 0;
17024084f9bSBrian Somers 	background		= 0;
17124084f9bSBrian Somers 	running			= 1;
17224084f9bSBrian Somers 	dynamicMode		= 0;
17359a7c613SBrian Somers  	logFacility		= LOG_DAEMON;
174c0956cf8SRuslan Ermilov 	logIpfwDenied		= -1;
175b79840a6SRuslan Ermilov 	pidName			= PIDFILE;
17622c62477SPoul-Henning Kamp 	routeSock 		= -1;
17722c62477SPoul-Henning Kamp 	icmpSock 		= -1;
17822c62477SPoul-Henning Kamp 	fdMax	 		= -1;
17922c62477SPoul-Henning Kamp 	divertGlobal		= -1;
18072cbe4adSAlexander Motin 	exitDelay		= EXIT_DELAY;
18124084f9bSBrian Somers 
18224084f9bSBrian Somers 	ParseArgs (argc, argv);
18324084f9bSBrian Somers /*
184c0956cf8SRuslan Ermilov  * Log ipfw(8) denied packets by default in verbose mode.
185c0956cf8SRuslan Ermilov  */
186c0956cf8SRuslan Ermilov 	if (logIpfwDenied == -1)
187c0956cf8SRuslan Ermilov 		logIpfwDenied = verbose;
188c0956cf8SRuslan Ermilov /*
18959a7c613SBrian Somers  * Open syslog channel.
19059a7c613SBrian Somers  */
1914c04fa4cSRuslan Ermilov 	openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
1924c04fa4cSRuslan Ermilov 		 logFacility);
19322c62477SPoul-Henning Kamp 
19422c62477SPoul-Henning Kamp 	LIST_FOREACH(mip, &root, list) {
19522c62477SPoul-Henning Kamp 		mla = mip->la;
19659a7c613SBrian Somers /*
1973d23e8b8SRuslan Ermilov  * If not doing the transparent proxying only,
1983d23e8b8SRuslan Ermilov  * check that valid aliasing address has been given.
19924084f9bSBrian Somers  */
20022c62477SPoul-Henning Kamp 		if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL &&
20122c62477SPoul-Henning Kamp 		    !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY))
20222c62477SPoul-Henning Kamp 			errx (1, "instance %s: aliasing address not given", mip->name);
20324084f9bSBrian Somers 
20422c62477SPoul-Henning Kamp 		if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL)
20567a886fbSBrian Somers 			errx (1, "both alias address and interface "
20667a886fbSBrian Somers 				 "name are not allowed");
20724084f9bSBrian Somers /*
20824084f9bSBrian Somers  * Check that valid port number is known.
20924084f9bSBrian Somers  */
21022c62477SPoul-Henning Kamp 		if (mip->inPort != 0 || mip->outPort != 0)
21122c62477SPoul-Henning Kamp 			if (mip->inPort == 0 || mip->outPort == 0)
2120fc81af1SPhilippe Charnier 				errx (1, "both input and output ports are required");
21324084f9bSBrian Somers 
21422c62477SPoul-Henning Kamp 		if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0)
215b0f55af6SRuslan Ermilov 			ParseOption ("port", DEFAULT_SERVICE);
21624084f9bSBrian Somers 
21724084f9bSBrian Somers /*
218f9b06d5cSBrian Somers  * Check if ignored packets should be dropped.
219f9b06d5cSBrian Somers  */
22022c62477SPoul-Henning Kamp 		mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0);
22122c62477SPoul-Henning Kamp 		mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
222f9b06d5cSBrian Somers /*
22324084f9bSBrian Somers  * Create divert sockets. Use only one socket if -p was specified
22424084f9bSBrian Somers  * on command line. Otherwise, create separate sockets for
22524084f9bSBrian Somers  * outgoing and incoming connnections.
22624084f9bSBrian Somers  */
22722c62477SPoul-Henning Kamp 		if (mip->inOutPort) {
22824084f9bSBrian Somers 
22922c62477SPoul-Henning Kamp 			mip->divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
23022c62477SPoul-Henning Kamp 			if (mip->divertInOut == -1)
23124084f9bSBrian Somers 				Quit ("Unable to create divert socket.");
23222c62477SPoul-Henning Kamp 			if (mip->divertInOut > fdMax)
23322c62477SPoul-Henning Kamp 				fdMax = mip->divertInOut;
23424084f9bSBrian Somers 
23522c62477SPoul-Henning Kamp 			mip->divertIn  = -1;
23622c62477SPoul-Henning Kamp 			mip->divertOut = -1;
23724084f9bSBrian Somers /*
23824084f9bSBrian Somers  * Bind socket.
23924084f9bSBrian Somers  */
24024084f9bSBrian Somers 
24124084f9bSBrian Somers 			addr.sin_family		= AF_INET;
24224084f9bSBrian Somers 			addr.sin_addr.s_addr	= INADDR_ANY;
24322c62477SPoul-Henning Kamp 			addr.sin_port		= mip->inOutPort;
24424084f9bSBrian Somers 
24522c62477SPoul-Henning Kamp 			if (bind (mip->divertInOut,
24624084f9bSBrian Somers 				  (struct sockaddr*) &addr,
24724084f9bSBrian Somers 				  sizeof addr) == -1)
24824084f9bSBrian Somers 				Quit ("Unable to bind divert socket.");
24924084f9bSBrian Somers 		}
25024084f9bSBrian Somers 		else {
25124084f9bSBrian Somers 
25222c62477SPoul-Henning Kamp 			mip->divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
25322c62477SPoul-Henning Kamp 			if (mip->divertIn == -1)
25424084f9bSBrian Somers 				Quit ("Unable to create incoming divert socket.");
25522c62477SPoul-Henning Kamp 			if (mip->divertIn > fdMax)
25622c62477SPoul-Henning Kamp 				fdMax = mip->divertIn;
25724084f9bSBrian Somers 
25822c62477SPoul-Henning Kamp 
25922c62477SPoul-Henning Kamp 			mip->divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
26022c62477SPoul-Henning Kamp 			if (mip->divertOut == -1)
26124084f9bSBrian Somers 				Quit ("Unable to create outgoing divert socket.");
26222c62477SPoul-Henning Kamp 			if (mip->divertOut > fdMax)
26322c62477SPoul-Henning Kamp 				fdMax = mip->divertOut;
26424084f9bSBrian Somers 
26522c62477SPoul-Henning Kamp 			mip->divertInOut = -1;
26624084f9bSBrian Somers 
26724084f9bSBrian Somers /*
26824084f9bSBrian Somers  * Bind divert sockets.
26924084f9bSBrian Somers  */
27024084f9bSBrian Somers 
27124084f9bSBrian Somers 			addr.sin_family		= AF_INET;
27224084f9bSBrian Somers 			addr.sin_addr.s_addr	= INADDR_ANY;
27322c62477SPoul-Henning Kamp 			addr.sin_port		= mip->inPort;
27424084f9bSBrian Somers 
27522c62477SPoul-Henning Kamp 			if (bind (mip->divertIn,
27624084f9bSBrian Somers 				  (struct sockaddr*) &addr,
27724084f9bSBrian Somers 				  sizeof addr) == -1)
27824084f9bSBrian Somers 				Quit ("Unable to bind incoming divert socket.");
27924084f9bSBrian Somers 
28024084f9bSBrian Somers 			addr.sin_family		= AF_INET;
28124084f9bSBrian Somers 			addr.sin_addr.s_addr	= INADDR_ANY;
28222c62477SPoul-Henning Kamp 			addr.sin_port		= mip->outPort;
28324084f9bSBrian Somers 
28422c62477SPoul-Henning Kamp 			if (bind (mip->divertOut,
28524084f9bSBrian Somers 				  (struct sockaddr*) &addr,
28624084f9bSBrian Somers 				  sizeof addr) == -1)
28724084f9bSBrian Somers 				Quit ("Unable to bind outgoing divert socket.");
28824084f9bSBrian Somers 		}
28924084f9bSBrian Somers /*
290f2da55a2SRuslan Ermilov  * Create routing socket if interface name specified and in dynamic mode.
29124084f9bSBrian Somers  */
29222c62477SPoul-Henning Kamp 		if (mip->ifName) {
293f2da55a2SRuslan Ermilov 			if (dynamicMode) {
29424084f9bSBrian Somers 
29522c62477SPoul-Henning Kamp 				if (routeSock == -1)
29624084f9bSBrian Somers 					routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
29724084f9bSBrian Somers 				if (routeSock == -1)
29824084f9bSBrian Somers 					Quit ("Unable to create routing info socket.");
29922c62477SPoul-Henning Kamp 				if (routeSock > fdMax)
30022c62477SPoul-Henning Kamp 					fdMax = routeSock;
301f2da55a2SRuslan Ermilov 
30222c62477SPoul-Henning Kamp 				mip->assignAliasAddr = 1;
30324084f9bSBrian Somers 			}
30424084f9bSBrian Somers 			else
30522c62477SPoul-Henning Kamp 				SetAliasAddressFromIfName (mip->ifName);
30622c62477SPoul-Henning Kamp 		}
30722c62477SPoul-Henning Kamp 
30822c62477SPoul-Henning Kamp 	}
30922c62477SPoul-Henning Kamp 	if (globalPort) {
31022c62477SPoul-Henning Kamp 
31122c62477SPoul-Henning Kamp 		divertGlobal = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
31222c62477SPoul-Henning Kamp 		if (divertGlobal == -1)
31322c62477SPoul-Henning Kamp 			Quit ("Unable to create divert socket.");
31422c62477SPoul-Henning Kamp 		if (divertGlobal > fdMax)
31522c62477SPoul-Henning Kamp 			fdMax = divertGlobal;
31622c62477SPoul-Henning Kamp 
31722c62477SPoul-Henning Kamp /*
31822c62477SPoul-Henning Kamp * Bind socket.
31922c62477SPoul-Henning Kamp */
32022c62477SPoul-Henning Kamp 
32122c62477SPoul-Henning Kamp 		addr.sin_family		= AF_INET;
32222c62477SPoul-Henning Kamp 		addr.sin_addr.s_addr	= INADDR_ANY;
32322c62477SPoul-Henning Kamp 		addr.sin_port		= globalPort;
32422c62477SPoul-Henning Kamp 
32522c62477SPoul-Henning Kamp 		if (bind (divertGlobal,
32622c62477SPoul-Henning Kamp 			  (struct sockaddr*) &addr,
32722c62477SPoul-Henning Kamp 			  sizeof addr) == -1)
32822c62477SPoul-Henning Kamp 			Quit ("Unable to bind global divert socket.");
329f2da55a2SRuslan Ermilov 	}
33024084f9bSBrian Somers /*
33124084f9bSBrian Somers  * Create socket for sending ICMP messages.
33224084f9bSBrian Somers  */
33324084f9bSBrian Somers 	icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
33424084f9bSBrian Somers 	if (icmpSock == -1)
33524084f9bSBrian Somers 		Quit ("Unable to create ICMP socket.");
336f3d64024SBrian Somers 
337f3d64024SBrian Somers /*
338f3d64024SBrian Somers  * And disable reads for the socket, otherwise it slowly fills
339f3d64024SBrian Somers  * up with received icmps which we do not use.
340f3d64024SBrian Somers  */
341f3d64024SBrian Somers 	shutdown(icmpSock, SHUT_RD);
342f3d64024SBrian Somers 
34324084f9bSBrian Somers /*
34424084f9bSBrian Somers  * Become a daemon unless verbose mode was requested.
34524084f9bSBrian Somers  */
34624084f9bSBrian Somers 	if (!verbose)
34724084f9bSBrian Somers 		DaemonMode ();
34824084f9bSBrian Somers /*
34924084f9bSBrian Somers  * Catch signals to manage shutdown and
35024084f9bSBrian Somers  * refresh of interface address.
35124084f9bSBrian Somers  */
352cd45c931SRuslan Ermilov 	siginterrupt(SIGTERM, 1);
353cd45c931SRuslan Ermilov 	siginterrupt(SIGHUP, 1);
35472cbe4adSAlexander Motin 	if (exitDelay)
35524084f9bSBrian Somers 		signal(SIGTERM, InitiateShutdown);
35672cbe4adSAlexander Motin 	else
35772cbe4adSAlexander Motin 		signal(SIGTERM, Shutdown);
35824084f9bSBrian Somers 	signal (SIGHUP, RefreshAddr);
35924084f9bSBrian Somers /*
36024084f9bSBrian Somers  * Set alias address if it has been given.
36124084f9bSBrian Somers  */
36222c62477SPoul-Henning Kamp 	mip = LIST_FIRST(&root);	/* XXX: simon */
36322c62477SPoul-Henning Kamp 	LIST_FOREACH(mip, &root, list) {
36422c62477SPoul-Henning Kamp 		mla = mip->la;
36522c62477SPoul-Henning Kamp 		if (mip->aliasAddr.s_addr != INADDR_NONE)
36622c62477SPoul-Henning Kamp 			LibAliasSetAddress (mla, mip->aliasAddr);
36722c62477SPoul-Henning Kamp 	}
36824084f9bSBrian Somers 
36924084f9bSBrian Somers 	while (running) {
37022c62477SPoul-Henning Kamp 		mip = LIST_FIRST(&root);	/* XXX: simon */
371fb994b07SBrian Somers 
37222c62477SPoul-Henning Kamp 		if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) {
373fb994b07SBrian Somers /*
374fb994b07SBrian Somers  * When using only one socket, just call
375fb994b07SBrian Somers  * DoAliasing repeatedly to process packets.
376fb994b07SBrian Somers  */
37722c62477SPoul-Henning Kamp 			DoAliasing (mip->divertInOut, DONT_KNOW);
378fb994b07SBrian Somers 			continue;
379fb994b07SBrian Somers 		}
38024084f9bSBrian Somers /*
38124084f9bSBrian Somers  * Build read mask from socket descriptors to select.
38224084f9bSBrian Somers  */
38324084f9bSBrian Somers 		FD_ZERO (&readMask);
384fb994b07SBrian Somers /*
3853daff242SRuslan Ermilov  * Check if new packets are available.
386fb994b07SBrian Somers  */
38722c62477SPoul-Henning Kamp 		LIST_FOREACH(mip, &root, list) {
38822c62477SPoul-Henning Kamp 			if (mip->divertIn != -1)
38922c62477SPoul-Henning Kamp 				FD_SET (mip->divertIn, &readMask);
39024084f9bSBrian Somers 
39122c62477SPoul-Henning Kamp 			if (mip->divertOut != -1)
39222c62477SPoul-Henning Kamp 				FD_SET (mip->divertOut, &readMask);
39324084f9bSBrian Somers 
39422c62477SPoul-Henning Kamp 			if (mip->divertInOut != -1)
39522c62477SPoul-Henning Kamp 				FD_SET (mip->divertInOut, &readMask);
39622c62477SPoul-Henning Kamp 		}
397fb994b07SBrian Somers /*
398fb994b07SBrian Somers  * Routing info is processed always.
399fb994b07SBrian Somers  */
40024084f9bSBrian Somers 		if (routeSock != -1)
40124084f9bSBrian Somers 			FD_SET (routeSock, &readMask);
40224084f9bSBrian Somers 
40322c62477SPoul-Henning Kamp 		if (divertGlobal != -1)
40422c62477SPoul-Henning Kamp 			FD_SET (divertGlobal, &readMask);
40522c62477SPoul-Henning Kamp 
40624084f9bSBrian Somers 		if (select (fdMax + 1,
40724084f9bSBrian Somers 			    &readMask,
4083daff242SRuslan Ermilov 			    NULL,
40924084f9bSBrian Somers 			    NULL,
41024084f9bSBrian Somers 			    NULL) == -1) {
41124084f9bSBrian Somers 
41224084f9bSBrian Somers 			if (errno == EINTR)
41324084f9bSBrian Somers 				continue;
41424084f9bSBrian Somers 
41524084f9bSBrian Somers 			Quit ("Select failed.");
41624084f9bSBrian Somers 		}
41724084f9bSBrian Somers 
41822c62477SPoul-Henning Kamp 		if (divertGlobal != -1)
41922c62477SPoul-Henning Kamp 			if (FD_ISSET (divertGlobal, &readMask))
42022c62477SPoul-Henning Kamp 				DoGlobal (divertGlobal);
42122c62477SPoul-Henning Kamp 		LIST_FOREACH(mip, &root, list) {
42222c62477SPoul-Henning Kamp 			mla = mip->la;
42322c62477SPoul-Henning Kamp 			if (mip->divertIn != -1)
42422c62477SPoul-Henning Kamp 				if (FD_ISSET (mip->divertIn, &readMask))
42522c62477SPoul-Henning Kamp 					DoAliasing (mip->divertIn, INPUT);
42624084f9bSBrian Somers 
42722c62477SPoul-Henning Kamp 			if (mip->divertOut != -1)
42822c62477SPoul-Henning Kamp 				if (FD_ISSET (mip->divertOut, &readMask))
42922c62477SPoul-Henning Kamp 					DoAliasing (mip->divertOut, OUTPUT);
43024084f9bSBrian Somers 
43122c62477SPoul-Henning Kamp 			if (mip->divertInOut != -1)
43222c62477SPoul-Henning Kamp 				if (FD_ISSET (mip->divertInOut, &readMask))
43322c62477SPoul-Henning Kamp 					DoAliasing (mip->divertInOut, DONT_KNOW);
43424084f9bSBrian Somers 
43522c62477SPoul-Henning Kamp 		}
43624084f9bSBrian Somers 		if (routeSock != -1)
43724084f9bSBrian Somers 			if (FD_ISSET (routeSock, &readMask))
43824084f9bSBrian Somers 				HandleRoutingInfo (routeSock);
43924084f9bSBrian Somers 	}
44024084f9bSBrian Somers 
44124084f9bSBrian Somers 	if (background)
442b79840a6SRuslan Ermilov 		unlink (pidName);
44324084f9bSBrian Somers 
44424084f9bSBrian Somers 	return 0;
44524084f9bSBrian Somers }
44624084f9bSBrian Somers 
4477154ce64SEd Schouten static void DaemonMode(void)
44824084f9bSBrian Somers {
44924084f9bSBrian Somers 	FILE*	pidFile;
45024084f9bSBrian Somers 
45124084f9bSBrian Somers 	daemon (0, 0);
45224084f9bSBrian Somers 	background = 1;
45324084f9bSBrian Somers 
454b79840a6SRuslan Ermilov 	pidFile = fopen (pidName, "w");
45524084f9bSBrian Somers 	if (pidFile) {
45624084f9bSBrian Somers 
45724084f9bSBrian Somers 		fprintf (pidFile, "%d\n", getpid ());
45824084f9bSBrian Somers 		fclose (pidFile);
45924084f9bSBrian Somers 	}
46024084f9bSBrian Somers }
46124084f9bSBrian Somers 
46224084f9bSBrian Somers static void ParseArgs (int argc, char** argv)
46324084f9bSBrian Somers {
46424084f9bSBrian Somers 	int		arg;
46524084f9bSBrian Somers 	char*		opt;
46624084f9bSBrian Somers 	char		parmBuf[256];
46730395bb5SJosef Karthauser 	int		len; /* bounds checking */
46824084f9bSBrian Somers 
46924084f9bSBrian Somers 	for (arg = 1; arg < argc; arg++) {
47024084f9bSBrian Somers 
47124084f9bSBrian Somers 		opt  = argv[arg];
47224084f9bSBrian Somers 		if (*opt != '-') {
47324084f9bSBrian Somers 
4740fc81af1SPhilippe Charnier 			warnx ("invalid option %s", opt);
47524084f9bSBrian Somers 			Usage ();
47624084f9bSBrian Somers 		}
47724084f9bSBrian Somers 
47824084f9bSBrian Somers 		parmBuf[0] = '\0';
47930395bb5SJosef Karthauser 		len = 0;
48024084f9bSBrian Somers 
48124084f9bSBrian Somers 		while (arg < argc - 1) {
48224084f9bSBrian Somers 
48324084f9bSBrian Somers 			if (argv[arg + 1][0] == '-')
48424084f9bSBrian Somers 				break;
48524084f9bSBrian Somers 
48630395bb5SJosef Karthauser 			if (len) {
48730395bb5SJosef Karthauser 				strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
48830395bb5SJosef Karthauser 				len += strlen(parmBuf + len);
48924084f9bSBrian Somers 			}
49024084f9bSBrian Somers 
49130395bb5SJosef Karthauser 			++arg;
49230395bb5SJosef Karthauser 			strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
49330395bb5SJosef Karthauser 			len += strlen(parmBuf + len);
49430395bb5SJosef Karthauser 
49530395bb5SJosef Karthauser 		}
49630395bb5SJosef Karthauser 
497b0f55af6SRuslan Ermilov 		ParseOption (opt + 1, (len ? parmBuf : NULL));
49830395bb5SJosef Karthauser 
49924084f9bSBrian Somers 	}
50024084f9bSBrian Somers }
50124084f9bSBrian Somers 
50222c62477SPoul-Henning Kamp static void DoGlobal (int fd)
50322c62477SPoul-Henning Kamp {
50422c62477SPoul-Henning Kamp 	int			bytes;
50522c62477SPoul-Henning Kamp 	int			origBytes;
50622c62477SPoul-Henning Kamp 	char			buf[IP_MAXPACKET];
50722c62477SPoul-Henning Kamp 	struct sockaddr_in	addr;
50822c62477SPoul-Henning Kamp 	int			wrote;
50948ce8ca1SXin LI 	socklen_t		addrSize;
51022c62477SPoul-Henning Kamp 	struct ip*		ip;
51122c62477SPoul-Henning Kamp 	char			msgBuf[80];
51222c62477SPoul-Henning Kamp 
51322c62477SPoul-Henning Kamp /*
51422c62477SPoul-Henning Kamp  * Get packet from socket.
51522c62477SPoul-Henning Kamp  */
51622c62477SPoul-Henning Kamp 	addrSize  = sizeof addr;
51722c62477SPoul-Henning Kamp 	origBytes = recvfrom (fd,
51822c62477SPoul-Henning Kamp 			      buf,
51922c62477SPoul-Henning Kamp 			      sizeof buf,
52022c62477SPoul-Henning Kamp 			      0,
52122c62477SPoul-Henning Kamp 			      (struct sockaddr*) &addr,
52222c62477SPoul-Henning Kamp 			      &addrSize);
52322c62477SPoul-Henning Kamp 
52422c62477SPoul-Henning Kamp 	if (origBytes == -1) {
52522c62477SPoul-Henning Kamp 
52622c62477SPoul-Henning Kamp 		if (errno != EINTR)
52722c62477SPoul-Henning Kamp 			Warn ("read from divert socket failed");
52822c62477SPoul-Henning Kamp 
52922c62477SPoul-Henning Kamp 		return;
53022c62477SPoul-Henning Kamp 	}
53122c62477SPoul-Henning Kamp 
53222c62477SPoul-Henning Kamp #if 0
53322c62477SPoul-Henning Kamp 	if (mip->assignAliasAddr) {
53422c62477SPoul-Henning Kamp 		SetAliasAddressFromIfName (mip->ifName);
53522c62477SPoul-Henning Kamp 		mip->assignAliasAddr = 0;
53622c62477SPoul-Henning Kamp 	}
53722c62477SPoul-Henning Kamp #endif
53822c62477SPoul-Henning Kamp /*
53922c62477SPoul-Henning Kamp  * This is an IP packet.
54022c62477SPoul-Henning Kamp  */
54122c62477SPoul-Henning Kamp 	ip = (struct ip*) buf;
54222c62477SPoul-Henning Kamp 
54322c62477SPoul-Henning Kamp 	if (verbose) {
54422c62477SPoul-Henning Kamp /*
54522c62477SPoul-Henning Kamp  * Print packet direction and protocol type.
54622c62477SPoul-Henning Kamp  */
54722c62477SPoul-Henning Kamp 		printf ("Glb ");
54822c62477SPoul-Henning Kamp 
54922c62477SPoul-Henning Kamp 		switch (ip->ip_p) {
55022c62477SPoul-Henning Kamp 		case IPPROTO_TCP:
55122c62477SPoul-Henning Kamp 			printf ("[TCP]  ");
55222c62477SPoul-Henning Kamp 			break;
55322c62477SPoul-Henning Kamp 
55422c62477SPoul-Henning Kamp 		case IPPROTO_UDP:
55522c62477SPoul-Henning Kamp 			printf ("[UDP]  ");
55622c62477SPoul-Henning Kamp 			break;
55722c62477SPoul-Henning Kamp 
55822c62477SPoul-Henning Kamp 		case IPPROTO_ICMP:
55922c62477SPoul-Henning Kamp 			printf ("[ICMP] ");
56022c62477SPoul-Henning Kamp 			break;
56122c62477SPoul-Henning Kamp 
56222c62477SPoul-Henning Kamp 		default:
56322c62477SPoul-Henning Kamp 			printf ("[%d]    ", ip->ip_p);
56422c62477SPoul-Henning Kamp 			break;
56522c62477SPoul-Henning Kamp 		}
56622c62477SPoul-Henning Kamp /*
56722c62477SPoul-Henning Kamp  * Print addresses.
56822c62477SPoul-Henning Kamp  */
56922c62477SPoul-Henning Kamp 		PrintPacket (ip);
57022c62477SPoul-Henning Kamp 	}
57122c62477SPoul-Henning Kamp 
57222c62477SPoul-Henning Kamp 	LIST_FOREACH(mip, &root, list) {
57322c62477SPoul-Henning Kamp 		mla = mip->la;
57422c62477SPoul-Henning Kamp 		if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED)
57522c62477SPoul-Henning Kamp 			break;
57622c62477SPoul-Henning Kamp 	}
57722c62477SPoul-Henning Kamp /*
57822c62477SPoul-Henning Kamp  * Length might have changed during aliasing.
57922c62477SPoul-Henning Kamp  */
58022c62477SPoul-Henning Kamp 	bytes = ntohs (ip->ip_len);
58122c62477SPoul-Henning Kamp /*
58222c62477SPoul-Henning Kamp  * Update alias overhead size for outgoing packets.
58322c62477SPoul-Henning Kamp  */
58422c62477SPoul-Henning Kamp 	if (mip != NULL && bytes - origBytes > mip->aliasOverhead)
58522c62477SPoul-Henning Kamp 		mip->aliasOverhead = bytes - origBytes;
58622c62477SPoul-Henning Kamp 
58722c62477SPoul-Henning Kamp 	if (verbose) {
58822c62477SPoul-Henning Kamp 
58922c62477SPoul-Henning Kamp /*
59022c62477SPoul-Henning Kamp  * Print addresses after aliasing.
59122c62477SPoul-Henning Kamp  */
59222c62477SPoul-Henning Kamp 		printf (" aliased to\n");
59322c62477SPoul-Henning Kamp 		printf ("           ");
59422c62477SPoul-Henning Kamp 		PrintPacket (ip);
59522c62477SPoul-Henning Kamp 		printf ("\n");
59622c62477SPoul-Henning Kamp 	}
59722c62477SPoul-Henning Kamp 
59822c62477SPoul-Henning Kamp /*
59922c62477SPoul-Henning Kamp  * Put packet back for processing.
60022c62477SPoul-Henning Kamp  */
60122c62477SPoul-Henning Kamp 	wrote = sendto (fd,
60222c62477SPoul-Henning Kamp 		        buf,
60322c62477SPoul-Henning Kamp 	    		bytes,
60422c62477SPoul-Henning Kamp 	    		0,
60522c62477SPoul-Henning Kamp 	    		(struct sockaddr*) &addr,
60622c62477SPoul-Henning Kamp 	    		sizeof addr);
60722c62477SPoul-Henning Kamp 
60822c62477SPoul-Henning Kamp 	if (wrote != bytes) {
60922c62477SPoul-Henning Kamp 
61022c62477SPoul-Henning Kamp 		if (errno == EMSGSIZE) {
61122c62477SPoul-Henning Kamp 
61222c62477SPoul-Henning Kamp 			if (mip->ifMTU != -1)
61322c62477SPoul-Henning Kamp 				SendNeedFragIcmp (icmpSock,
61422c62477SPoul-Henning Kamp 						  (struct ip*) buf,
61522c62477SPoul-Henning Kamp 						  mip->ifMTU - mip->aliasOverhead);
61622c62477SPoul-Henning Kamp 		}
61722c62477SPoul-Henning Kamp 		else if (errno == EACCES && logIpfwDenied) {
61822c62477SPoul-Henning Kamp 
61922c62477SPoul-Henning Kamp 			sprintf (msgBuf, "failed to write packet back");
62022c62477SPoul-Henning Kamp 			Warn (msgBuf);
62122c62477SPoul-Henning Kamp 		}
62222c62477SPoul-Henning Kamp 	}
62322c62477SPoul-Henning Kamp }
62422c62477SPoul-Henning Kamp 
62522c62477SPoul-Henning Kamp 
62659a7c613SBrian Somers static void DoAliasing (int fd, int direction)
62724084f9bSBrian Somers {
62824084f9bSBrian Somers 	int			bytes;
62924084f9bSBrian Somers 	int			origBytes;
6303daff242SRuslan Ermilov 	char			buf[IP_MAXPACKET];
6313daff242SRuslan Ermilov 	struct sockaddr_in	addr;
6323daff242SRuslan Ermilov 	int			wrote;
633f9b06d5cSBrian Somers 	int			status;
63448ce8ca1SXin LI 	socklen_t		addrSize;
63524084f9bSBrian Somers 	struct ip*		ip;
6363daff242SRuslan Ermilov 	char			msgBuf[80];
63724084f9bSBrian Somers 
63822c62477SPoul-Henning Kamp 	if (mip->assignAliasAddr) {
63924084f9bSBrian Somers 
64022c62477SPoul-Henning Kamp 		SetAliasAddressFromIfName (mip->ifName);
64122c62477SPoul-Henning Kamp 		mip->assignAliasAddr = 0;
64224084f9bSBrian Somers 	}
64324084f9bSBrian Somers /*
64424084f9bSBrian Somers  * Get packet from socket.
64524084f9bSBrian Somers  */
6463daff242SRuslan Ermilov 	addrSize  = sizeof addr;
64724084f9bSBrian Somers 	origBytes = recvfrom (fd,
6483daff242SRuslan Ermilov 			      buf,
6493daff242SRuslan Ermilov 			      sizeof buf,
65024084f9bSBrian Somers 			      0,
6513daff242SRuslan Ermilov 			      (struct sockaddr*) &addr,
65224084f9bSBrian Somers 			      &addrSize);
65324084f9bSBrian Somers 
65424084f9bSBrian Somers 	if (origBytes == -1) {
65524084f9bSBrian Somers 
65624084f9bSBrian Somers 		if (errno != EINTR)
6570fc81af1SPhilippe Charnier 			Warn ("read from divert socket failed");
65824084f9bSBrian Somers 
65924084f9bSBrian Somers 		return;
66024084f9bSBrian Somers 	}
66124084f9bSBrian Somers /*
6629d5abbddSJens Schweikhardt  * This is an IP packet.
66324084f9bSBrian Somers  */
6643daff242SRuslan Ermilov 	ip = (struct ip*) buf;
665ebe70c8fSWarner Losh 	if (direction == DONT_KNOW) {
6663daff242SRuslan Ermilov 		if (addr.sin_addr.s_addr == INADDR_ANY)
66759a7c613SBrian Somers 			direction = OUTPUT;
66859a7c613SBrian Somers 		else
66959a7c613SBrian Somers 			direction = INPUT;
670ebe70c8fSWarner Losh 	}
67124084f9bSBrian Somers 
67224084f9bSBrian Somers 	if (verbose) {
67324084f9bSBrian Somers /*
67424084f9bSBrian Somers  * Print packet direction and protocol type.
67524084f9bSBrian Somers  */
67659a7c613SBrian Somers 		printf (direction == OUTPUT ? "Out " : "In  ");
67722c62477SPoul-Henning Kamp 		if (ninstance > 1)
67848ce8ca1SXin LI 			printf ("{%s}", mip->name);
67924084f9bSBrian Somers 
68024084f9bSBrian Somers 		switch (ip->ip_p) {
68124084f9bSBrian Somers 		case IPPROTO_TCP:
68224084f9bSBrian Somers 			printf ("[TCP]  ");
68324084f9bSBrian Somers 			break;
68424084f9bSBrian Somers 
68524084f9bSBrian Somers 		case IPPROTO_UDP:
68624084f9bSBrian Somers 			printf ("[UDP]  ");
68724084f9bSBrian Somers 			break;
68824084f9bSBrian Somers 
68924084f9bSBrian Somers 		case IPPROTO_ICMP:
69024084f9bSBrian Somers 			printf ("[ICMP] ");
69124084f9bSBrian Somers 			break;
69224084f9bSBrian Somers 
69324084f9bSBrian Somers 		default:
69459a7c613SBrian Somers 			printf ("[%d]    ", ip->ip_p);
69524084f9bSBrian Somers 			break;
69624084f9bSBrian Somers 		}
69724084f9bSBrian Somers /*
69824084f9bSBrian Somers  * Print addresses.
69924084f9bSBrian Somers  */
70024084f9bSBrian Somers 		PrintPacket (ip);
70124084f9bSBrian Somers 	}
70224084f9bSBrian Somers 
70359a7c613SBrian Somers 	if (direction == OUTPUT) {
70424084f9bSBrian Somers /*
70524084f9bSBrian Somers  * Outgoing packets. Do aliasing.
70624084f9bSBrian Somers  */
70722c62477SPoul-Henning Kamp 		LibAliasOut (mla, buf, IP_MAXPACKET);
70824084f9bSBrian Somers 	}
70924084f9bSBrian Somers 	else {
71059a7c613SBrian Somers 
71124084f9bSBrian Somers /*
71224084f9bSBrian Somers  * Do aliasing.
71324084f9bSBrian Somers  */
71422c62477SPoul-Henning Kamp 		status = LibAliasIn (mla, buf, IP_MAXPACKET);
715f9b06d5cSBrian Somers 		if (status == PKT_ALIAS_IGNORED &&
71622c62477SPoul-Henning Kamp 		    mip->dropIgnoredIncoming) {
717f9b06d5cSBrian Somers 
71859a7c613SBrian Somers 			if (verbose)
719f9b06d5cSBrian Somers 				printf (" dropped.\n");
72059a7c613SBrian Somers 
72122c62477SPoul-Henning Kamp 			if (mip->logDropped)
72259a7c613SBrian Somers 				SyslogPacket (ip, LOG_WARNING, "denied");
72359a7c613SBrian Somers 
724f9b06d5cSBrian Somers 			return;
725f9b06d5cSBrian Somers 		}
72624084f9bSBrian Somers 	}
72724084f9bSBrian Somers /*
72824084f9bSBrian Somers  * Length might have changed during aliasing.
72924084f9bSBrian Somers  */
73024084f9bSBrian Somers 	bytes = ntohs (ip->ip_len);
73124084f9bSBrian Somers /*
73224084f9bSBrian Somers  * Update alias overhead size for outgoing packets.
73324084f9bSBrian Somers  */
73459a7c613SBrian Somers 	if (direction == OUTPUT &&
73522c62477SPoul-Henning Kamp 	    bytes - origBytes > mip->aliasOverhead)
73622c62477SPoul-Henning Kamp 		mip->aliasOverhead = bytes - origBytes;
73724084f9bSBrian Somers 
73824084f9bSBrian Somers 	if (verbose) {
73924084f9bSBrian Somers 
74024084f9bSBrian Somers /*
74124084f9bSBrian Somers  * Print addresses after aliasing.
74224084f9bSBrian Somers  */
74324084f9bSBrian Somers 		printf (" aliased to\n");
74424084f9bSBrian Somers 		printf ("           ");
74524084f9bSBrian Somers 		PrintPacket (ip);
74624084f9bSBrian Somers 		printf ("\n");
74724084f9bSBrian Somers 	}
748fb994b07SBrian Somers 
74924084f9bSBrian Somers /*
75024084f9bSBrian Somers  * Put packet back for processing.
75124084f9bSBrian Somers  */
75224084f9bSBrian Somers 	wrote = sendto (fd,
7533daff242SRuslan Ermilov 		        buf,
7543daff242SRuslan Ermilov 	    		bytes,
75524084f9bSBrian Somers 	    		0,
7563daff242SRuslan Ermilov 	    		(struct sockaddr*) &addr,
7573daff242SRuslan Ermilov 	    		sizeof addr);
75824084f9bSBrian Somers 
7593daff242SRuslan Ermilov 	if (wrote != bytes) {
76024084f9bSBrian Somers 
76124084f9bSBrian Somers 		if (errno == EMSGSIZE) {
76224084f9bSBrian Somers 
7633daff242SRuslan Ermilov 			if (direction == OUTPUT &&
76422c62477SPoul-Henning Kamp 			    mip->ifMTU != -1)
76524084f9bSBrian Somers 				SendNeedFragIcmp (icmpSock,
7663daff242SRuslan Ermilov 						  (struct ip*) buf,
76722c62477SPoul-Henning Kamp 						  mip->ifMTU - mip->aliasOverhead);
76824084f9bSBrian Somers 		}
7693843533eSRuslan Ermilov 		else if (errno == EACCES && logIpfwDenied) {
77024084f9bSBrian Somers 
771d782daf0SJosef Karthauser 			sprintf (msgBuf, "failed to write packet back");
77224084f9bSBrian Somers 			Warn (msgBuf);
77324084f9bSBrian Somers 		}
77424084f9bSBrian Somers 	}
77524084f9bSBrian Somers }
77624084f9bSBrian Somers 
77724084f9bSBrian Somers static void HandleRoutingInfo (int fd)
77824084f9bSBrian Somers {
77924084f9bSBrian Somers 	int			bytes;
78024084f9bSBrian Somers 	struct if_msghdr	ifMsg;
78124084f9bSBrian Somers /*
78224084f9bSBrian Somers  * Get packet from socket.
78324084f9bSBrian Somers  */
78424084f9bSBrian Somers 	bytes = read (fd, &ifMsg, sizeof ifMsg);
78524084f9bSBrian Somers 	if (bytes == -1) {
78624084f9bSBrian Somers 
7870fc81af1SPhilippe Charnier 		Warn ("read from routing socket failed");
78824084f9bSBrian Somers 		return;
78924084f9bSBrian Somers 	}
79024084f9bSBrian Somers 
79124084f9bSBrian Somers 	if (ifMsg.ifm_version != RTM_VERSION) {
79224084f9bSBrian Somers 
7930fc81af1SPhilippe Charnier 		Warn ("unexpected packet read from routing socket");
79424084f9bSBrian Somers 		return;
79524084f9bSBrian Somers 	}
79624084f9bSBrian Somers 
79724084f9bSBrian Somers 	if (verbose)
7986f3dbe5eSRuslan Ermilov 		printf ("Routing message %#x received.\n", ifMsg.ifm_type);
79924084f9bSBrian Somers 
80022c62477SPoul-Henning Kamp 	if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) {
80122c62477SPoul-Henning Kamp 		LIST_FOREACH(mip, &root, list) {
80222c62477SPoul-Henning Kamp 			mla = mip->la;
80322c62477SPoul-Henning Kamp 			if (ifMsg.ifm_index == mip->ifIndex) {
8046f3dbe5eSRuslan Ermilov 				if (verbose)
8056f3dbe5eSRuslan Ermilov 					printf("Interface address/MTU has probably changed.\n");
80622c62477SPoul-Henning Kamp 				mip->assignAliasAddr = 1;
80722c62477SPoul-Henning Kamp 			}
80822c62477SPoul-Henning Kamp 		}
80924084f9bSBrian Somers 	}
8106f3dbe5eSRuslan Ermilov }
81124084f9bSBrian Somers 
81224084f9bSBrian Somers static void PrintPacket (struct ip* ip)
81324084f9bSBrian Somers {
81459a7c613SBrian Somers 	printf ("%s", FormatPacket (ip));
81559a7c613SBrian Somers }
81659a7c613SBrian Somers 
817902cb50aSBrian Somers static void SyslogPacket (struct ip* ip, int priority, const char *label)
81859a7c613SBrian Somers {
81959a7c613SBrian Somers 	syslog (priority, "%s %s", label, FormatPacket (ip));
82059a7c613SBrian Somers }
82159a7c613SBrian Somers 
82259a7c613SBrian Somers static char* FormatPacket (struct ip* ip)
82359a7c613SBrian Somers {
82459a7c613SBrian Somers 	static char	buf[256];
82524084f9bSBrian Somers 	struct tcphdr*	tcphdr;
82659a7c613SBrian Somers 	struct udphdr*	udphdr;
82759a7c613SBrian Somers 	struct icmp*	icmphdr;
82859a7c613SBrian Somers 	char		src[20];
82959a7c613SBrian Somers 	char		dst[20];
83024084f9bSBrian Somers 
83159a7c613SBrian Somers 	strcpy (src, inet_ntoa (ip->ip_src));
83259a7c613SBrian Somers 	strcpy (dst, inet_ntoa (ip->ip_dst));
83359a7c613SBrian Somers 
83459a7c613SBrian Somers 	switch (ip->ip_p) {
83559a7c613SBrian Somers 	case IPPROTO_TCP:
83624084f9bSBrian Somers 		tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
83759a7c613SBrian Somers 		sprintf (buf, "[TCP] %s:%d -> %s:%d",
83859a7c613SBrian Somers 			      src,
83959a7c613SBrian Somers 			      ntohs (tcphdr->th_sport),
84059a7c613SBrian Somers 			      dst,
84159a7c613SBrian Somers 			      ntohs (tcphdr->th_dport));
84259a7c613SBrian Somers 		break;
84324084f9bSBrian Somers 
84459a7c613SBrian Somers 	case IPPROTO_UDP:
84559a7c613SBrian Somers 		udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
84659a7c613SBrian Somers 		sprintf (buf, "[UDP] %s:%d -> %s:%d",
84759a7c613SBrian Somers 			      src,
84859a7c613SBrian Somers 			      ntohs (udphdr->uh_sport),
84959a7c613SBrian Somers 			      dst,
85059a7c613SBrian Somers 			      ntohs (udphdr->uh_dport));
85159a7c613SBrian Somers 		break;
85224084f9bSBrian Somers 
85359a7c613SBrian Somers 	case IPPROTO_ICMP:
85459a7c613SBrian Somers 		icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
855b71e869dSBrian Somers 		sprintf (buf, "[ICMP] %s -> %s %u(%u)",
85659a7c613SBrian Somers 			      src,
85759a7c613SBrian Somers 			      dst,
858b71e869dSBrian Somers 			      icmphdr->icmp_type,
859b71e869dSBrian Somers 			      icmphdr->icmp_code);
86059a7c613SBrian Somers 		break;
86159a7c613SBrian Somers 
86259a7c613SBrian Somers 	default:
86359a7c613SBrian Somers 		sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
86459a7c613SBrian Somers 		break;
86559a7c613SBrian Somers 	}
86659a7c613SBrian Somers 
86759a7c613SBrian Somers 	return buf;
86824084f9bSBrian Somers }
86924084f9bSBrian Somers 
8704c04fa4cSRuslan Ermilov static void
8714c04fa4cSRuslan Ermilov SetAliasAddressFromIfName(const char *ifn)
87224084f9bSBrian Somers {
8734c04fa4cSRuslan Ermilov 	size_t needed;
8744c04fa4cSRuslan Ermilov 	int mib[6];
8754c04fa4cSRuslan Ermilov 	char *buf, *lim, *next;
8764c04fa4cSRuslan Ermilov 	struct if_msghdr *ifm;
8774c04fa4cSRuslan Ermilov 	struct ifa_msghdr *ifam;
8784c04fa4cSRuslan Ermilov 	struct sockaddr_dl *sdl;
8794c04fa4cSRuslan Ermilov 	struct sockaddr_in *sin;
88024084f9bSBrian Somers 
8814c04fa4cSRuslan Ermilov 	mib[0] = CTL_NET;
8824c04fa4cSRuslan Ermilov 	mib[1] = PF_ROUTE;
8834c04fa4cSRuslan Ermilov 	mib[2] = 0;
8844c04fa4cSRuslan Ermilov 	mib[3] = AF_INET;	/* Only IP addresses please */
8854c04fa4cSRuslan Ermilov 	mib[4] = NET_RT_IFLIST;
8864c04fa4cSRuslan Ermilov 	mib[5] = 0;		/* ifIndex??? */
88724084f9bSBrian Somers /*
88824084f9bSBrian Somers  * Get interface data.
88924084f9bSBrian Somers  */
8904c04fa4cSRuslan Ermilov 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
8914c04fa4cSRuslan Ermilov 		err(1, "iflist-sysctl-estimate");
8924c04fa4cSRuslan Ermilov 	if ((buf = malloc(needed)) == NULL)
8934c04fa4cSRuslan Ermilov 		errx(1, "malloc failed");
894ec95e4c2SBrian Somers 	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1 && errno != ENOMEM)
8954c04fa4cSRuslan Ermilov 		err(1, "iflist-sysctl-get");
8964c04fa4cSRuslan Ermilov 	lim = buf + needed;
89724084f9bSBrian Somers /*
89824084f9bSBrian Somers  * Loop through interfaces until one with
89924084f9bSBrian Somers  * given name is found. This is done to
90024084f9bSBrian Somers  * find correct interface index for routing
90124084f9bSBrian Somers  * message processing.
90224084f9bSBrian Somers  */
90322c62477SPoul-Henning Kamp 	mip->ifIndex	= 0;
9044c04fa4cSRuslan Ermilov 	next = buf;
9054c04fa4cSRuslan Ermilov 	while (next < lim) {
9064c04fa4cSRuslan Ermilov 		ifm = (struct if_msghdr *)next;
9074c04fa4cSRuslan Ermilov 		next += ifm->ifm_msglen;
9084c04fa4cSRuslan Ermilov 		if (ifm->ifm_version != RTM_VERSION) {
9094c04fa4cSRuslan Ermilov 			if (verbose)
9104c04fa4cSRuslan Ermilov 				warnx("routing message version %d "
9114c04fa4cSRuslan Ermilov 				      "not understood", ifm->ifm_version);
9124c04fa4cSRuslan Ermilov 			continue;
9134c04fa4cSRuslan Ermilov 		}
9144c04fa4cSRuslan Ermilov 		if (ifm->ifm_type == RTM_IFINFO) {
9154c04fa4cSRuslan Ermilov 			sdl = (struct sockaddr_dl *)(ifm + 1);
9164c04fa4cSRuslan Ermilov 			if (strlen(ifn) == sdl->sdl_nlen &&
9174c04fa4cSRuslan Ermilov 			    strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
91822c62477SPoul-Henning Kamp 				mip->ifIndex = ifm->ifm_index;
91922c62477SPoul-Henning Kamp 				mip->ifMTU = ifm->ifm_data.ifi_mtu;
92024084f9bSBrian Somers 				break;
92124084f9bSBrian Somers 			}
92224084f9bSBrian Somers 		}
92324084f9bSBrian Somers 	}
92422c62477SPoul-Henning Kamp 	if (!mip->ifIndex)
9254c04fa4cSRuslan Ermilov 		errx(1, "unknown interface name %s", ifn);
92624084f9bSBrian Somers /*
92724084f9bSBrian Somers  * Get interface address.
92824084f9bSBrian Somers  */
9294c04fa4cSRuslan Ermilov 	sin = NULL;
9304c04fa4cSRuslan Ermilov 	while (next < lim) {
9314c04fa4cSRuslan Ermilov 		ifam = (struct ifa_msghdr *)next;
9324c04fa4cSRuslan Ermilov 		next += ifam->ifam_msglen;
9334c04fa4cSRuslan Ermilov 		if (ifam->ifam_version != RTM_VERSION) {
9344c04fa4cSRuslan Ermilov 			if (verbose)
9354c04fa4cSRuslan Ermilov 				warnx("routing message version %d "
9364c04fa4cSRuslan Ermilov 				      "not understood", ifam->ifam_version);
9374c04fa4cSRuslan Ermilov 			continue;
9384c04fa4cSRuslan Ermilov 		}
9394c04fa4cSRuslan Ermilov 		if (ifam->ifam_type != RTM_NEWADDR)
9404c04fa4cSRuslan Ermilov 			break;
9414c04fa4cSRuslan Ermilov 		if (ifam->ifam_addrs & RTA_IFA) {
9424c04fa4cSRuslan Ermilov 			int i;
9434c04fa4cSRuslan Ermilov 			char *cp = (char *)(ifam + 1);
94424084f9bSBrian Somers 
9454c04fa4cSRuslan Ermilov 			for (i = 1; i < RTA_IFA; i <<= 1)
9464c04fa4cSRuslan Ermilov 				if (ifam->ifam_addrs & i)
9470b46c085SLuigi Rizzo 					cp += SA_SIZE((struct sockaddr *)cp);
9484c04fa4cSRuslan Ermilov 			if (((struct sockaddr *)cp)->sa_family == AF_INET) {
9494c04fa4cSRuslan Ermilov 				sin = (struct sockaddr_in *)cp;
9504c04fa4cSRuslan Ermilov 				break;
9514c04fa4cSRuslan Ermilov 			}
9524c04fa4cSRuslan Ermilov 		}
9534c04fa4cSRuslan Ermilov 	}
9544c04fa4cSRuslan Ermilov 	if (sin == NULL)
9554c04fa4cSRuslan Ermilov 		errx(1, "%s: cannot get interface address", ifn);
9564c04fa4cSRuslan Ermilov 
95722c62477SPoul-Henning Kamp 	LibAliasSetAddress(mla, sin->sin_addr);
95824084f9bSBrian Somers 	syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
95922c62477SPoul-Henning Kamp 	       inet_ntoa(sin->sin_addr), mip->ifMTU);
96024084f9bSBrian Somers 
9614c04fa4cSRuslan Ermilov 	free(buf);
96224084f9bSBrian Somers }
96324084f9bSBrian Somers 
964902cb50aSBrian Somers void Quit (const char* msg)
96524084f9bSBrian Somers {
96624084f9bSBrian Somers 	Warn (msg);
96724084f9bSBrian Somers 	exit (1);
96824084f9bSBrian Somers }
96924084f9bSBrian Somers 
970902cb50aSBrian Somers void Warn (const char* msg)
97124084f9bSBrian Somers {
97224084f9bSBrian Somers 	if (background)
97324084f9bSBrian Somers 		syslog (LOG_ALERT, "%s (%m)", msg);
97424084f9bSBrian Somers 	else
97504d06bb6SKris Kennaway 		warn ("%s", msg);
97624084f9bSBrian Somers }
97724084f9bSBrian Somers 
97848ce8ca1SXin LI static void RefreshAddr (int sig __unused)
97924084f9bSBrian Somers {
980be4f3cd0SPaolo Pisati 	LibAliasRefreshModules();
981be4f3cd0SPaolo Pisati 	if (mip != NULL && mip->ifName != NULL)
98222c62477SPoul-Henning Kamp 		mip->assignAliasAddr = 1;
98324084f9bSBrian Somers }
98424084f9bSBrian Somers 
98548ce8ca1SXin LI static void InitiateShutdown (int sig __unused)
98624084f9bSBrian Somers {
98724084f9bSBrian Somers /*
98824084f9bSBrian Somers  * Start timer to allow kernel gracefully
98924084f9bSBrian Somers  * shutdown existing connections when system
99024084f9bSBrian Somers  * is shut down.
99124084f9bSBrian Somers  */
992cd45c931SRuslan Ermilov 	siginterrupt(SIGALRM, 1);
99324084f9bSBrian Somers 	signal (SIGALRM, Shutdown);
99472cbe4adSAlexander Motin 	ualarm(exitDelay*1000, 1000);
99524084f9bSBrian Somers }
99624084f9bSBrian Somers 
99748ce8ca1SXin LI static void Shutdown (int sig __unused)
99824084f9bSBrian Somers {
99924084f9bSBrian Somers 	running = 0;
100024084f9bSBrian Somers }
100124084f9bSBrian Somers 
100224084f9bSBrian Somers /*
100324084f9bSBrian Somers  * Different options recognized by this program.
100424084f9bSBrian Somers  */
100524084f9bSBrian Somers 
100624084f9bSBrian Somers enum Option {
100724084f9bSBrian Somers 
100822c62477SPoul-Henning Kamp 	LibAliasOption,
100922c62477SPoul-Henning Kamp 	Instance,
101024084f9bSBrian Somers 	Verbose,
101124084f9bSBrian Somers 	InPort,
101224084f9bSBrian Somers 	OutPort,
101324084f9bSBrian Somers 	Port,
101422c62477SPoul-Henning Kamp 	GlobalPort,
101524084f9bSBrian Somers 	AliasAddress,
101611c2b3bfSRuslan Ermilov 	TargetAddress,
101724084f9bSBrian Somers 	InterfaceName,
101824084f9bSBrian Somers 	RedirectPort,
10194330006dSRuslan Ermilov 	RedirectProto,
102024084f9bSBrian Somers 	RedirectAddress,
102124084f9bSBrian Somers 	ConfigFile,
102259a7c613SBrian Somers 	DynamicMode,
102359a7c613SBrian Somers 	ProxyRule,
102459a7c613SBrian Somers  	LogDenied,
1025bc4ebb98SRuslan Ermilov  	LogFacility,
102684ef95bdSPoul-Henning Kamp 	PunchFW,
1027b07fbc17SJoe Marcus Clarke 	SkinnyPort,
1028b79840a6SRuslan Ermilov 	LogIpfwDenied,
102972cbe4adSAlexander Motin 	PidFile,
103072cbe4adSAlexander Motin 	ExitDelay
103124084f9bSBrian Somers };
103224084f9bSBrian Somers 
103324084f9bSBrian Somers enum Param {
103424084f9bSBrian Somers 
103524084f9bSBrian Somers 	YesNo,
103624084f9bSBrian Somers 	Numeric,
103724084f9bSBrian Somers 	String,
103824084f9bSBrian Somers 	None,
103924084f9bSBrian Somers 	Address,
104024084f9bSBrian Somers 	Service
104124084f9bSBrian Somers };
104224084f9bSBrian Somers 
104324084f9bSBrian Somers /*
104424084f9bSBrian Somers  * Option information structure (used by ParseOption).
104524084f9bSBrian Somers  */
104624084f9bSBrian Somers 
104724084f9bSBrian Somers struct OptionInfo {
104824084f9bSBrian Somers 
104924084f9bSBrian Somers 	enum Option		type;
105024084f9bSBrian Somers 	int			packetAliasOpt;
105124084f9bSBrian Somers 	enum Param		parm;
1052902cb50aSBrian Somers 	const char*		parmDescription;
1053902cb50aSBrian Somers 	const char*		description;
1054902cb50aSBrian Somers 	const char*		name;
1055902cb50aSBrian Somers 	const char*		shortName;
105624084f9bSBrian Somers };
105724084f9bSBrian Somers 
105824084f9bSBrian Somers /*
105924084f9bSBrian Somers  * Table of known options.
106024084f9bSBrian Somers  */
106124084f9bSBrian Somers 
106224084f9bSBrian Somers static struct OptionInfo optionTable[] = {
106324084f9bSBrian Somers 
106422c62477SPoul-Henning Kamp 	{ LibAliasOption,
106524084f9bSBrian Somers 		PKT_ALIAS_UNREGISTERED_ONLY,
106624084f9bSBrian Somers 		YesNo,
106724084f9bSBrian Somers 		"[yes|no]",
106824084f9bSBrian Somers 		"alias only unregistered addresses",
106924084f9bSBrian Somers 		"unregistered_only",
107024084f9bSBrian Somers 		"u" },
107124084f9bSBrian Somers 
107222c62477SPoul-Henning Kamp 	{ LibAliasOption,
107324084f9bSBrian Somers 		PKT_ALIAS_LOG,
107424084f9bSBrian Somers 		YesNo,
107524084f9bSBrian Somers 		"[yes|no]",
107624084f9bSBrian Somers 		"enable logging",
107724084f9bSBrian Somers 		"log",
107824084f9bSBrian Somers 		"l" },
107924084f9bSBrian Somers 
108022c62477SPoul-Henning Kamp 	{ LibAliasOption,
108159a7c613SBrian Somers 		PKT_ALIAS_PROXY_ONLY,
108259a7c613SBrian Somers 		YesNo,
108359a7c613SBrian Somers 		"[yes|no]",
108459a7c613SBrian Somers 		"proxy only",
108559a7c613SBrian Somers 		"proxy_only",
108659a7c613SBrian Somers 		NULL },
108759a7c613SBrian Somers 
108822c62477SPoul-Henning Kamp 	{ LibAliasOption,
108959a7c613SBrian Somers 		PKT_ALIAS_REVERSE,
109059a7c613SBrian Somers 		YesNo,
109159a7c613SBrian Somers 		"[yes|no]",
109259a7c613SBrian Somers 		"operate in reverse mode",
109359a7c613SBrian Somers 		"reverse",
109459a7c613SBrian Somers 		NULL },
109559a7c613SBrian Somers 
109622c62477SPoul-Henning Kamp 	{ LibAliasOption,
109724084f9bSBrian Somers 		PKT_ALIAS_DENY_INCOMING,
109824084f9bSBrian Somers 		YesNo,
109924084f9bSBrian Somers 		"[yes|no]",
110024084f9bSBrian Somers 		"allow incoming connections",
110124084f9bSBrian Somers 		"deny_incoming",
110224084f9bSBrian Somers 		"d" },
110324084f9bSBrian Somers 
110422c62477SPoul-Henning Kamp 	{ LibAliasOption,
110524084f9bSBrian Somers 		PKT_ALIAS_USE_SOCKETS,
110624084f9bSBrian Somers 		YesNo,
110724084f9bSBrian Somers 		"[yes|no]",
110824084f9bSBrian Somers 		"use sockets to inhibit port conflict",
110924084f9bSBrian Somers 		"use_sockets",
111024084f9bSBrian Somers 		"s" },
111124084f9bSBrian Somers 
111222c62477SPoul-Henning Kamp 	{ LibAliasOption,
111324084f9bSBrian Somers 		PKT_ALIAS_SAME_PORTS,
111424084f9bSBrian Somers 		YesNo,
111524084f9bSBrian Somers 		"[yes|no]",
111624084f9bSBrian Somers 		"try to keep original port numbers for connections",
111724084f9bSBrian Somers 		"same_ports",
111824084f9bSBrian Somers 		"m" },
111924084f9bSBrian Somers 
112024084f9bSBrian Somers 	{ Verbose,
112124084f9bSBrian Somers 		0,
112224084f9bSBrian Somers 		YesNo,
112324084f9bSBrian Somers 		"[yes|no]",
112424084f9bSBrian Somers 		"verbose mode, dump packet information",
112524084f9bSBrian Somers 		"verbose",
112624084f9bSBrian Somers 		"v" },
112724084f9bSBrian Somers 
112824084f9bSBrian Somers 	{ DynamicMode,
112924084f9bSBrian Somers 		0,
113024084f9bSBrian Somers 		YesNo,
113124084f9bSBrian Somers 		"[yes|no]",
113224084f9bSBrian Somers 		"dynamic mode, automatically detect interface address changes",
113324084f9bSBrian Somers 		"dynamic",
113424084f9bSBrian Somers 		NULL },
113524084f9bSBrian Somers 
113624084f9bSBrian Somers 	{ InPort,
113724084f9bSBrian Somers 		0,
113824084f9bSBrian Somers 		Service,
113924084f9bSBrian Somers 		"number|service_name",
114024084f9bSBrian Somers 		"set port for incoming packets",
114124084f9bSBrian Somers 		"in_port",
114224084f9bSBrian Somers 		"i" },
114324084f9bSBrian Somers 
114424084f9bSBrian Somers 	{ OutPort,
114524084f9bSBrian Somers 		0,
114624084f9bSBrian Somers 		Service,
114724084f9bSBrian Somers 		"number|service_name",
114824084f9bSBrian Somers 		"set port for outgoing packets",
114924084f9bSBrian Somers 		"out_port",
115024084f9bSBrian Somers 		"o" },
115124084f9bSBrian Somers 
115224084f9bSBrian Somers 	{ Port,
115324084f9bSBrian Somers 		0,
115424084f9bSBrian Somers 		Service,
115524084f9bSBrian Somers 		"number|service_name",
115624084f9bSBrian Somers 		"set port (defaults to natd/divert)",
115724084f9bSBrian Somers 		"port",
115824084f9bSBrian Somers 		"p" },
115924084f9bSBrian Somers 
116022c62477SPoul-Henning Kamp 	{ GlobalPort,
116122c62477SPoul-Henning Kamp 		0,
116222c62477SPoul-Henning Kamp 		Service,
116322c62477SPoul-Henning Kamp 		"number|service_name",
116422c62477SPoul-Henning Kamp 		"set globalport",
116522c62477SPoul-Henning Kamp 		"globalport",
116622c62477SPoul-Henning Kamp 		NULL },
116722c62477SPoul-Henning Kamp 
116824084f9bSBrian Somers 	{ AliasAddress,
116924084f9bSBrian Somers 		0,
117024084f9bSBrian Somers 		Address,
117124084f9bSBrian Somers 		"x.x.x.x",
117224084f9bSBrian Somers 		"address to use for aliasing",
117324084f9bSBrian Somers 		"alias_address",
117424084f9bSBrian Somers 		"a" },
117524084f9bSBrian Somers 
117611c2b3bfSRuslan Ermilov 	{ TargetAddress,
117711c2b3bfSRuslan Ermilov 		0,
117811c2b3bfSRuslan Ermilov 		Address,
117911c2b3bfSRuslan Ermilov 		"x.x.x.x",
118011c2b3bfSRuslan Ermilov 		"address to use for incoming sessions",
118111c2b3bfSRuslan Ermilov 		"target_address",
118211c2b3bfSRuslan Ermilov 		"t" },
118311c2b3bfSRuslan Ermilov 
118424084f9bSBrian Somers 	{ InterfaceName,
118524084f9bSBrian Somers 		0,
118624084f9bSBrian Somers 		String,
118724084f9bSBrian Somers 	        "network_if_name",
118824084f9bSBrian Somers 		"take aliasing address from interface",
118924084f9bSBrian Somers 		"interface",
119024084f9bSBrian Somers 		"n" },
119124084f9bSBrian Somers 
119259a7c613SBrian Somers 	{ ProxyRule,
119324084f9bSBrian Somers 		0,
119424084f9bSBrian Somers 		String,
119559a7c613SBrian Somers 	        "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
119659a7c613SBrian Somers 		"a.b.c.d:yyyy",
119759a7c613SBrian Somers 		"add transparent proxying / destination NAT",
119859a7c613SBrian Somers 		"proxy_rule",
119924084f9bSBrian Somers 		NULL },
120024084f9bSBrian Somers 
120124084f9bSBrian Somers 	{ RedirectPort,
120224084f9bSBrian Somers 		0,
120324084f9bSBrian Somers 		String,
1204bd690510SRuslan Ermilov 	        "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
12055d8ee958SBrian Somers 	 	" [remote_addr[:remote_port_range]]",
12065d8ee958SBrian Somers 		"redirect a port (or ports) for incoming traffic",
120724084f9bSBrian Somers 		"redirect_port",
120824084f9bSBrian Somers 		NULL },
120924084f9bSBrian Somers 
12104330006dSRuslan Ermilov 	{ RedirectProto,
12114330006dSRuslan Ermilov 		0,
12124330006dSRuslan Ermilov 		String,
12134330006dSRuslan Ermilov 	        "proto local_addr [public_addr] [remote_addr]",
12144330006dSRuslan Ermilov 		"redirect packets of a given proto",
12154330006dSRuslan Ermilov 		"redirect_proto",
12164330006dSRuslan Ermilov 		NULL },
12174330006dSRuslan Ermilov 
121824084f9bSBrian Somers 	{ RedirectAddress,
121924084f9bSBrian Somers 		0,
122024084f9bSBrian Somers 		String,
1221bd690510SRuslan Ermilov 	        "local_addr[,...] public_addr",
122224084f9bSBrian Somers 		"define mapping between local and public addresses",
122324084f9bSBrian Somers 		"redirect_address",
122424084f9bSBrian Somers 		NULL },
122524084f9bSBrian Somers 
122624084f9bSBrian Somers 	{ ConfigFile,
122724084f9bSBrian Somers 		0,
122824084f9bSBrian Somers 		String,
122924084f9bSBrian Somers 		"file_name",
123024084f9bSBrian Somers 		"read options from configuration file",
123124084f9bSBrian Somers 		"config",
123259a7c613SBrian Somers 		"f" },
123359a7c613SBrian Somers 
123459a7c613SBrian Somers 	{ LogDenied,
123559a7c613SBrian Somers 		0,
123659a7c613SBrian Somers 		YesNo,
123759a7c613SBrian Somers 	        "[yes|no]",
123859a7c613SBrian Somers 		"enable logging of denied incoming packets",
123959a7c613SBrian Somers 		"log_denied",
124059a7c613SBrian Somers 		NULL },
124159a7c613SBrian Somers 
124259a7c613SBrian Somers 	{ LogFacility,
124359a7c613SBrian Somers 		0,
124459a7c613SBrian Somers 		String,
124559a7c613SBrian Somers 	        "facility",
124659a7c613SBrian Somers 		"name of syslog facility to use for logging",
124759a7c613SBrian Somers 		"log_facility",
1248bc4ebb98SRuslan Ermilov 		NULL },
124959a7c613SBrian Somers 
1250bc4ebb98SRuslan Ermilov 	{ PunchFW,
1251bc4ebb98SRuslan Ermilov 		0,
1252bc4ebb98SRuslan Ermilov 		String,
1253bc4ebb98SRuslan Ermilov 	        "basenumber:count",
1254bc4ebb98SRuslan Ermilov 		"punch holes in the firewall for incoming FTP/IRC DCC connections",
1255bc4ebb98SRuslan Ermilov 		"punch_fw",
125684ef95bdSPoul-Henning Kamp 		NULL },
125784ef95bdSPoul-Henning Kamp 
1258b07fbc17SJoe Marcus Clarke 	{ SkinnyPort,
1259b07fbc17SJoe Marcus Clarke 		0,
1260b07fbc17SJoe Marcus Clarke 		String,
1261b07fbc17SJoe Marcus Clarke 		"port",
1262b07fbc17SJoe Marcus Clarke 		"set the TCP port for use with the Skinny Station protocol",
1263b07fbc17SJoe Marcus Clarke 		"skinny_port",
1264b07fbc17SJoe Marcus Clarke 		NULL },
1265b07fbc17SJoe Marcus Clarke 
126684ef95bdSPoul-Henning Kamp 	{ LogIpfwDenied,
126784ef95bdSPoul-Henning Kamp 		0,
126884ef95bdSPoul-Henning Kamp 		YesNo,
126984ef95bdSPoul-Henning Kamp 	        "[yes|no]",
127084ef95bdSPoul-Henning Kamp 		"log packets converted by natd, but denied by ipfw",
127184ef95bdSPoul-Henning Kamp 		"log_ipfw_denied",
127284ef95bdSPoul-Henning Kamp 		NULL },
1273b79840a6SRuslan Ermilov 
1274b79840a6SRuslan Ermilov 	{ PidFile,
1275b79840a6SRuslan Ermilov 		0,
1276b79840a6SRuslan Ermilov 		String,
1277b79840a6SRuslan Ermilov 		"file_name",
1278b79840a6SRuslan Ermilov 		"store PID in an alternate file",
1279b79840a6SRuslan Ermilov 		"pid_file",
1280b79840a6SRuslan Ermilov 		"P" },
128122c62477SPoul-Henning Kamp 	{ Instance,
128222c62477SPoul-Henning Kamp 		0,
128322c62477SPoul-Henning Kamp 		String,
128422c62477SPoul-Henning Kamp 		"instance name",
128522c62477SPoul-Henning Kamp 		"name of aliasing engine instance",
128622c62477SPoul-Henning Kamp 		"instance",
128722c62477SPoul-Henning Kamp 		NULL },
128872cbe4adSAlexander Motin 	{ ExitDelay,
128972cbe4adSAlexander Motin 		0,
129072cbe4adSAlexander Motin 		Numeric,
129172cbe4adSAlexander Motin 		"ms",
129272cbe4adSAlexander Motin 		"delay in ms before daemon exit after signal",
129372cbe4adSAlexander Motin 		"exit_delay",
129472cbe4adSAlexander Motin 		NULL },
129524084f9bSBrian Somers };
129624084f9bSBrian Somers 
1297b0f55af6SRuslan Ermilov static void ParseOption (const char* option, const char* parms)
129824084f9bSBrian Somers {
129924084f9bSBrian Somers 	int			i;
130024084f9bSBrian Somers 	struct OptionInfo*	info;
130124084f9bSBrian Somers 	int			yesNoValue;
130224084f9bSBrian Somers 	int			aliasValue;
130324084f9bSBrian Somers 	int			numValue;
130467a886fbSBrian Somers 	u_short			uNumValue;
1305902cb50aSBrian Somers 	const char*		strValue;
130624084f9bSBrian Somers 	struct in_addr		addrValue;
130724084f9bSBrian Somers 	int			max;
130824084f9bSBrian Somers 	char*			end;
130959a7c613SBrian Somers 	CODE* 			fac_record = NULL;
131024084f9bSBrian Somers /*
131124084f9bSBrian Somers  * Find option from table.
131224084f9bSBrian Somers  */
131324084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
131424084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
131524084f9bSBrian Somers 
131624084f9bSBrian Somers 		if (!strcmp (info->name, option))
131724084f9bSBrian Somers 			break;
131824084f9bSBrian Somers 
131924084f9bSBrian Somers 		if (info->shortName)
132024084f9bSBrian Somers 			if (!strcmp (info->shortName, option))
132124084f9bSBrian Somers 				break;
132224084f9bSBrian Somers 	}
132324084f9bSBrian Somers 
132424084f9bSBrian Somers 	if (i >= max) {
132524084f9bSBrian Somers 
13260fc81af1SPhilippe Charnier 		warnx ("unknown option %s", option);
132724084f9bSBrian Somers 		Usage ();
132824084f9bSBrian Somers 	}
132924084f9bSBrian Somers 
133067a886fbSBrian Somers 	uNumValue	= 0;
133124084f9bSBrian Somers 	yesNoValue	= 0;
133224084f9bSBrian Somers 	numValue	= 0;
133324084f9bSBrian Somers 	strValue	= NULL;
133424084f9bSBrian Somers /*
133524084f9bSBrian Somers  * Check parameters.
133624084f9bSBrian Somers  */
133724084f9bSBrian Somers 	switch (info->parm) {
133824084f9bSBrian Somers 	case YesNo:
133924084f9bSBrian Somers 		if (!parms)
134024084f9bSBrian Somers 			parms = "yes";
134124084f9bSBrian Somers 
134224084f9bSBrian Somers 		if (!strcmp (parms, "yes"))
134324084f9bSBrian Somers 			yesNoValue = 1;
134424084f9bSBrian Somers 		else
134524084f9bSBrian Somers 			if (!strcmp (parms, "no"))
134624084f9bSBrian Somers 				yesNoValue = 0;
13470fc81af1SPhilippe Charnier 			else
13480fc81af1SPhilippe Charnier 				errx (1, "%s needs yes/no parameter", option);
134924084f9bSBrian Somers 		break;
135024084f9bSBrian Somers 
135124084f9bSBrian Somers 	case Service:
13520fc81af1SPhilippe Charnier 		if (!parms)
135367a886fbSBrian Somers 			errx (1, "%s needs service name or "
135467a886fbSBrian Somers 				 "port number parameter",
135567a886fbSBrian Somers 				 option);
135624084f9bSBrian Somers 
135767a886fbSBrian Somers 		uNumValue = StrToPort (parms, "divert");
135824084f9bSBrian Somers 		break;
135924084f9bSBrian Somers 
136024084f9bSBrian Somers 	case Numeric:
136124084f9bSBrian Somers 		if (parms)
136224084f9bSBrian Somers 			numValue = strtol (parms, &end, 10);
136324084f9bSBrian Somers 		else
1364902cb50aSBrian Somers 			end = NULL;
136524084f9bSBrian Somers 
13660fc81af1SPhilippe Charnier 		if (end == parms)
13670fc81af1SPhilippe Charnier 			errx (1, "%s needs numeric parameter", option);
136824084f9bSBrian Somers 		break;
136924084f9bSBrian Somers 
137024084f9bSBrian Somers 	case String:
137124084f9bSBrian Somers 		strValue = parms;
13720fc81af1SPhilippe Charnier 		if (!strValue)
13730fc81af1SPhilippe Charnier 			errx (1, "%s needs parameter", option);
137424084f9bSBrian Somers 		break;
137524084f9bSBrian Somers 
137624084f9bSBrian Somers 	case None:
13770fc81af1SPhilippe Charnier 		if (parms)
13780fc81af1SPhilippe Charnier 			errx (1, "%s does not take parameters", option);
137924084f9bSBrian Somers 		break;
138024084f9bSBrian Somers 
138124084f9bSBrian Somers 	case Address:
13820fc81af1SPhilippe Charnier 		if (!parms)
13830fc81af1SPhilippe Charnier 			errx (1, "%s needs address/host parameter", option);
138424084f9bSBrian Somers 
138524084f9bSBrian Somers 		StrToAddr (parms, &addrValue);
138624084f9bSBrian Somers 		break;
138724084f9bSBrian Somers 	}
138824084f9bSBrian Somers 
138924084f9bSBrian Somers 	switch (info->type) {
139022c62477SPoul-Henning Kamp 	case LibAliasOption:
139124084f9bSBrian Somers 
139224084f9bSBrian Somers 		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
139322c62477SPoul-Henning Kamp 		LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
139424084f9bSBrian Somers 		break;
139524084f9bSBrian Somers 
139624084f9bSBrian Somers 	case Verbose:
139724084f9bSBrian Somers 		verbose = yesNoValue;
139824084f9bSBrian Somers 		break;
139924084f9bSBrian Somers 
140024084f9bSBrian Somers 	case DynamicMode:
140124084f9bSBrian Somers 		dynamicMode = yesNoValue;
140224084f9bSBrian Somers 		break;
140324084f9bSBrian Somers 
140424084f9bSBrian Somers 	case InPort:
140522c62477SPoul-Henning Kamp 		mip->inPort = uNumValue;
140624084f9bSBrian Somers 		break;
140724084f9bSBrian Somers 
140824084f9bSBrian Somers 	case OutPort:
140922c62477SPoul-Henning Kamp 		mip->outPort = uNumValue;
141024084f9bSBrian Somers 		break;
141124084f9bSBrian Somers 
141224084f9bSBrian Somers 	case Port:
141322c62477SPoul-Henning Kamp 		mip->inOutPort = uNumValue;
141422c62477SPoul-Henning Kamp 		break;
141522c62477SPoul-Henning Kamp 
141622c62477SPoul-Henning Kamp 	case GlobalPort:
141722c62477SPoul-Henning Kamp 		globalPort = uNumValue;
141824084f9bSBrian Somers 		break;
141924084f9bSBrian Somers 
142024084f9bSBrian Somers 	case AliasAddress:
142122c62477SPoul-Henning Kamp 		memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
142224084f9bSBrian Somers 		break;
142324084f9bSBrian Somers 
142411c2b3bfSRuslan Ermilov 	case TargetAddress:
142522c62477SPoul-Henning Kamp 		LibAliasSetTarget(mla, addrValue);
142611c2b3bfSRuslan Ermilov 		break;
142711c2b3bfSRuslan Ermilov 
142824084f9bSBrian Somers 	case RedirectPort:
142924084f9bSBrian Somers 		SetupPortRedirect (strValue);
143024084f9bSBrian Somers 		break;
143124084f9bSBrian Somers 
14324330006dSRuslan Ermilov 	case RedirectProto:
14334330006dSRuslan Ermilov 		SetupProtoRedirect(strValue);
14344330006dSRuslan Ermilov 		break;
14354330006dSRuslan Ermilov 
143624084f9bSBrian Somers 	case RedirectAddress:
143724084f9bSBrian Somers 		SetupAddressRedirect (strValue);
143824084f9bSBrian Somers 		break;
143924084f9bSBrian Somers 
144059a7c613SBrian Somers 	case ProxyRule:
144122c62477SPoul-Henning Kamp 		LibAliasProxyRule (mla, strValue);
144259a7c613SBrian Somers 		break;
144359a7c613SBrian Somers 
144424084f9bSBrian Somers 	case InterfaceName:
144522c62477SPoul-Henning Kamp 		if (mip->ifName)
144622c62477SPoul-Henning Kamp 			free (mip->ifName);
144724084f9bSBrian Somers 
144822c62477SPoul-Henning Kamp 		mip->ifName = strdup (strValue);
144924084f9bSBrian Somers 		break;
145024084f9bSBrian Somers 
145124084f9bSBrian Somers 	case ConfigFile:
145224084f9bSBrian Somers 		ReadConfigFile (strValue);
145324084f9bSBrian Somers 		break;
145459a7c613SBrian Somers 
145559a7c613SBrian Somers 	case LogDenied:
145622c62477SPoul-Henning Kamp 		mip->logDropped = yesNoValue;
145759a7c613SBrian Somers 		break;
145859a7c613SBrian Somers 
145959a7c613SBrian Somers 	case LogFacility:
146059a7c613SBrian Somers 
146159a7c613SBrian Somers 		fac_record = facilitynames;
146259a7c613SBrian Somers 		while (fac_record->c_name != NULL) {
146359a7c613SBrian Somers 
146459a7c613SBrian Somers 			if (!strcmp (fac_record->c_name, strValue)) {
146559a7c613SBrian Somers 
146659a7c613SBrian Somers 				logFacility = fac_record->c_val;
146759a7c613SBrian Somers 				break;
146859a7c613SBrian Somers 
146959a7c613SBrian Somers 			}
147059a7c613SBrian Somers 			else
147159a7c613SBrian Somers 				fac_record++;
147259a7c613SBrian Somers 		}
147359a7c613SBrian Somers 
147459a7c613SBrian Somers 		if(fac_record->c_name == NULL)
147559a7c613SBrian Somers 			errx(1, "Unknown log facility name: %s", strValue);
147659a7c613SBrian Somers 
147759a7c613SBrian Somers 		break;
1478bc4ebb98SRuslan Ermilov 
1479bc4ebb98SRuslan Ermilov 	case PunchFW:
1480bc4ebb98SRuslan Ermilov 		SetupPunchFW(strValue);
1481bc4ebb98SRuslan Ermilov 		break;
14823843533eSRuslan Ermilov 
1483b07fbc17SJoe Marcus Clarke 	case SkinnyPort:
1484b07fbc17SJoe Marcus Clarke 		SetupSkinnyPort(strValue);
1485b07fbc17SJoe Marcus Clarke 		break;
1486b07fbc17SJoe Marcus Clarke 
148784ef95bdSPoul-Henning Kamp 	case LogIpfwDenied:
14883843533eSRuslan Ermilov 		logIpfwDenied = yesNoValue;;
14893843533eSRuslan Ermilov 		break;
1490b79840a6SRuslan Ermilov 
1491b79840a6SRuslan Ermilov 	case PidFile:
1492b79840a6SRuslan Ermilov 		pidName = strdup (strValue);
1493b79840a6SRuslan Ermilov 		break;
149422c62477SPoul-Henning Kamp 	case Instance:
149522c62477SPoul-Henning Kamp 		NewInstance(strValue);
149622c62477SPoul-Henning Kamp 		break;
149772cbe4adSAlexander Motin 	case ExitDelay:
149872cbe4adSAlexander Motin 		if (numValue < 0 || numValue > MAX_EXIT_DELAY)
149972cbe4adSAlexander Motin 			errx(1, "Incorrect exit delay: %d", numValue);
150072cbe4adSAlexander Motin 		exitDelay = numValue;
150172cbe4adSAlexander Motin 		break;
150224084f9bSBrian Somers 	}
150324084f9bSBrian Somers }
150424084f9bSBrian Somers 
1505902cb50aSBrian Somers void ReadConfigFile (const char* fileName)
150624084f9bSBrian Somers {
150724084f9bSBrian Somers 	FILE*	file;
1508d99cc1daSRuslan Ermilov 	char	*buf;
1509d99cc1daSRuslan Ermilov 	size_t	len;
15102e7e7c71SRuslan Ermilov 	char	*ptr, *p;
151124084f9bSBrian Somers 	char*	option;
151224084f9bSBrian Somers 
151324084f9bSBrian Somers 	file = fopen (fileName, "r");
1514d99cc1daSRuslan Ermilov 	if (!file)
1515d99cc1daSRuslan Ermilov 		err(1, "cannot open config file %s", fileName);
151624084f9bSBrian Somers 
1517d99cc1daSRuslan Ermilov 	while ((buf = fgetln(file, &len)) != NULL) {
1518d99cc1daSRuslan Ermilov 		if (buf[len - 1] == '\n')
1519d99cc1daSRuslan Ermilov 			buf[len - 1] = '\0';
1520d99cc1daSRuslan Ermilov 		else
1521d99cc1daSRuslan Ermilov 			errx(1, "config file format error: "
1522d99cc1daSRuslan Ermilov 				"last line should end with newline");
152324084f9bSBrian Somers 
152424084f9bSBrian Somers /*
15252e7e7c71SRuslan Ermilov  * Check for comments, strip off trailing spaces.
152624084f9bSBrian Somers  */
15272e7e7c71SRuslan Ermilov 		if ((ptr = strchr(buf, '#')))
15282e7e7c71SRuslan Ermilov 			*ptr = '\0';
15292e7e7c71SRuslan Ermilov 		for (ptr = buf; isspace(*ptr); ++ptr)
15302e7e7c71SRuslan Ermilov 			continue;
153124084f9bSBrian Somers 		if (*ptr == '\0')
153224084f9bSBrian Somers 			continue;
15332e7e7c71SRuslan Ermilov 		for (p = strchr(buf, '\0'); isspace(*--p);)
15342e7e7c71SRuslan Ermilov 			continue;
15352e7e7c71SRuslan Ermilov 		*++p = '\0';
15362e7e7c71SRuslan Ermilov 
153724084f9bSBrian Somers /*
153824084f9bSBrian Somers  * Extract option name.
153924084f9bSBrian Somers  */
154024084f9bSBrian Somers 		option = ptr;
154124084f9bSBrian Somers 		while (*ptr && !isspace (*ptr))
154224084f9bSBrian Somers 			++ptr;
154324084f9bSBrian Somers 
154424084f9bSBrian Somers 		if (*ptr != '\0') {
154524084f9bSBrian Somers 
154624084f9bSBrian Somers 			*ptr = '\0';
154724084f9bSBrian Somers 			++ptr;
154824084f9bSBrian Somers 		}
154924084f9bSBrian Somers /*
155024084f9bSBrian Somers  * Skip white space between name and parms.
155124084f9bSBrian Somers  */
155224084f9bSBrian Somers 		while (*ptr && isspace (*ptr))
155324084f9bSBrian Somers 			++ptr;
155424084f9bSBrian Somers 
1555b0f55af6SRuslan Ermilov 		ParseOption (option, *ptr ? ptr : NULL);
155624084f9bSBrian Somers 	}
155724084f9bSBrian Somers 
155824084f9bSBrian Somers 	fclose (file);
155924084f9bSBrian Somers }
156024084f9bSBrian Somers 
15617154ce64SEd Schouten static void Usage(void)
156224084f9bSBrian Somers {
156324084f9bSBrian Somers 	int			i;
156424084f9bSBrian Somers 	int			max;
156524084f9bSBrian Somers 	struct OptionInfo*	info;
156624084f9bSBrian Somers 
156724084f9bSBrian Somers 	fprintf (stderr, "Recognized options:\n\n");
156824084f9bSBrian Somers 
156924084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
157024084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
157124084f9bSBrian Somers 
157224084f9bSBrian Somers 		fprintf (stderr, "-%-20s %s\n", info->name,
157324084f9bSBrian Somers 						info->parmDescription);
157424084f9bSBrian Somers 
157524084f9bSBrian Somers 		if (info->shortName)
157624084f9bSBrian Somers 			fprintf (stderr, "-%-20s %s\n", info->shortName,
157724084f9bSBrian Somers 							info->parmDescription);
157824084f9bSBrian Somers 
157924084f9bSBrian Somers 		fprintf (stderr, "      %s\n\n", info->description);
158024084f9bSBrian Somers 	}
158124084f9bSBrian Somers 
158224084f9bSBrian Somers 	exit (1);
158324084f9bSBrian Somers }
158424084f9bSBrian Somers 
1585902cb50aSBrian Somers void SetupPortRedirect (const char* parms)
158624084f9bSBrian Somers {
1587b6365f95SAlexander Motin 	char		*buf;
158824084f9bSBrian Somers 	char*		ptr;
1589bd690510SRuslan Ermilov 	char*		serverPool;
159024084f9bSBrian Somers 	struct in_addr	localAddr;
159124084f9bSBrian Somers 	struct in_addr	publicAddr;
159224084f9bSBrian Somers 	struct in_addr	remoteAddr;
15935d8ee958SBrian Somers 	port_range      portRange;
15945d8ee958SBrian Somers 	u_short         localPort      = 0;
15955d8ee958SBrian Somers 	u_short         publicPort     = 0;
15965d8ee958SBrian Somers 	u_short         remotePort     = 0;
15975d8ee958SBrian Somers 	u_short         numLocalPorts  = 0;
15985d8ee958SBrian Somers 	u_short         numPublicPorts = 0;
15995d8ee958SBrian Somers 	u_short         numRemotePorts = 0;
160024084f9bSBrian Somers 	int		proto;
160124084f9bSBrian Somers 	char*		protoName;
160224084f9bSBrian Somers 	char*		separator;
16035d8ee958SBrian Somers 	int             i;
160448ce8ca1SXin LI 	struct alias_link *aliaslink = NULL;
160524084f9bSBrian Somers 
1606b6365f95SAlexander Motin 	buf = strdup (parms);
1607b6365f95SAlexander Motin 	if (!buf)
1608b6365f95SAlexander Motin 		errx (1, "redirect_port: strdup() failed");
160924084f9bSBrian Somers /*
161024084f9bSBrian Somers  * Extract protocol.
161124084f9bSBrian Somers  */
161224084f9bSBrian Somers 	protoName = strtok (buf, " \t");
16130fc81af1SPhilippe Charnier 	if (!protoName)
16140fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing protocol");
161524084f9bSBrian Somers 
161624084f9bSBrian Somers 	proto = StrToProto (protoName);
161724084f9bSBrian Somers /*
161824084f9bSBrian Somers  * Extract local address.
161924084f9bSBrian Somers  */
162024084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
16210fc81af1SPhilippe Charnier 	if (!ptr)
16220fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing local address");
162324084f9bSBrian Somers 
1624bd690510SRuslan Ermilov 	separator = strchr(ptr, ',');
1625bd690510SRuslan Ermilov 	if (separator) {		/* LSNAT redirection syntax. */
1626bd690510SRuslan Ermilov 		localAddr.s_addr = INADDR_NONE;
1627bd690510SRuslan Ermilov 		localPort = ~0;
1628bd690510SRuslan Ermilov 		numLocalPorts = 1;
1629bd690510SRuslan Ermilov 		serverPool = ptr;
1630bd690510SRuslan Ermilov 	} else {
16315d8ee958SBrian Somers 		if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
16325d8ee958SBrian Somers 			errx (1, "redirect_port: invalid local port range");
16335d8ee958SBrian Somers 
16345d8ee958SBrian Somers 		localPort     = GETLOPORT(portRange);
16355d8ee958SBrian Somers 		numLocalPorts = GETNUMPORTS(portRange);
1636bd690510SRuslan Ermilov 		serverPool = NULL;
1637bd690510SRuslan Ermilov 	}
16385d8ee958SBrian Somers 
163924084f9bSBrian Somers /*
16409c501140SBrian Somers  * Extract public port and optionally address.
164124084f9bSBrian Somers  */
164224084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
16430fc81af1SPhilippe Charnier 	if (!ptr)
16440fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing public port");
164524084f9bSBrian Somers 
164624084f9bSBrian Somers 	separator = strchr (ptr, ':');
16475d8ee958SBrian Somers 	if (separator) {
16485d8ee958SBrian Somers 	        if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
16495d8ee958SBrian Somers 		        errx (1, "redirect_port: invalid public port range");
165024084f9bSBrian Somers 	}
16515d8ee958SBrian Somers 	else {
16525d8ee958SBrian Somers 		publicAddr.s_addr = INADDR_ANY;
16535d8ee958SBrian Somers 		if (StrToPortRange (ptr, protoName, &portRange) != 0)
16545d8ee958SBrian Somers 		        errx (1, "redirect_port: invalid public port range");
16555d8ee958SBrian Somers 	}
16565d8ee958SBrian Somers 
16575d8ee958SBrian Somers 	publicPort     = GETLOPORT(portRange);
16585d8ee958SBrian Somers 	numPublicPorts = GETNUMPORTS(portRange);
165924084f9bSBrian Somers 
166024084f9bSBrian Somers /*
166124084f9bSBrian Somers  * Extract remote address and optionally port.
166224084f9bSBrian Somers  */
166324084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
166424084f9bSBrian Somers 	if (ptr) {
166524084f9bSBrian Somers 		separator = strchr (ptr, ':');
1666ebe70c8fSWarner Losh 		if (separator) {
16675d8ee958SBrian Somers 		        if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
16685d8ee958SBrian Somers 			        errx (1, "redirect_port: invalid remote port range");
1669ebe70c8fSWarner Losh 		} else {
16705d8ee958SBrian Somers 		        SETLOPORT(portRange, 0);
16715d8ee958SBrian Somers 			SETNUMPORTS(portRange, 1);
167224084f9bSBrian Somers 			StrToAddr (ptr, &remoteAddr);
167324084f9bSBrian Somers 		}
167424084f9bSBrian Somers 	}
167524084f9bSBrian Somers 	else {
16765d8ee958SBrian Somers 	        SETLOPORT(portRange, 0);
16775d8ee958SBrian Somers 		SETNUMPORTS(portRange, 1);
167824084f9bSBrian Somers 		remoteAddr.s_addr = INADDR_ANY;
167924084f9bSBrian Somers 	}
168024084f9bSBrian Somers 
16815d8ee958SBrian Somers 	remotePort     = GETLOPORT(portRange);
16825d8ee958SBrian Somers 	numRemotePorts = GETNUMPORTS(portRange);
16835d8ee958SBrian Somers 
16845d8ee958SBrian Somers /*
16855d8ee958SBrian Somers  * Make sure port ranges match up, then add the redirect ports.
16865d8ee958SBrian Somers  */
16875d8ee958SBrian Somers 	if (numLocalPorts != numPublicPorts)
16885d8ee958SBrian Somers 	        errx (1, "redirect_port: port ranges must be equal in size");
16895d8ee958SBrian Somers 
16905d8ee958SBrian Somers 	/* Remote port range is allowed to be '0' which means all ports. */
169129d97436SBrian Somers 	if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
16925d8ee958SBrian Somers 	        errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
16935d8ee958SBrian Somers 
16945d8ee958SBrian Somers 	for (i = 0 ; i < numPublicPorts ; ++i) {
16955d8ee958SBrian Somers 	        /* If remotePort is all ports, set it to 0. */
16965d8ee958SBrian Somers 	        u_short remotePortCopy = remotePort + i;
16975d8ee958SBrian Somers 	        if (numRemotePorts == 1 && remotePort == 0)
16985d8ee958SBrian Somers 		        remotePortCopy = 0;
16995d8ee958SBrian Somers 
170048ce8ca1SXin LI 		aliaslink = LibAliasRedirectPort (mla, localAddr,
17015d8ee958SBrian Somers 						htons(localPort + i),
170224084f9bSBrian Somers 						remoteAddr,
17035d8ee958SBrian Somers 						htons(remotePortCopy),
170424084f9bSBrian Somers 						publicAddr,
17055d8ee958SBrian Somers 						htons(publicPort + i),
170624084f9bSBrian Somers 						proto);
170724084f9bSBrian Somers 	}
1708bd690510SRuslan Ermilov 
1709bd690510SRuslan Ermilov /*
1710bd690510SRuslan Ermilov  * Setup LSNAT server pool.
1711bd690510SRuslan Ermilov  */
171248ce8ca1SXin LI 	if (serverPool != NULL && aliaslink != NULL) {
1713bd690510SRuslan Ermilov 		ptr = strtok(serverPool, ",");
1714bd690510SRuslan Ermilov 		while (ptr != NULL) {
1715bd690510SRuslan Ermilov 			if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1716bd690510SRuslan Ermilov 				errx(1, "redirect_port: invalid local port range");
1717bd690510SRuslan Ermilov 
1718bd690510SRuslan Ermilov 			localPort = GETLOPORT(portRange);
1719bd690510SRuslan Ermilov 			if (GETNUMPORTS(portRange) != 1)
1720bd690510SRuslan Ermilov 				errx(1, "redirect_port: local port must be single in this context");
172148ce8ca1SXin LI 			LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
1722bd690510SRuslan Ermilov 			ptr = strtok(NULL, ",");
1723bd690510SRuslan Ermilov 		}
1724bd690510SRuslan Ermilov 	}
1725b6365f95SAlexander Motin 
1726b6365f95SAlexander Motin 	free (buf);
17275d8ee958SBrian Somers }
172824084f9bSBrian Somers 
17294330006dSRuslan Ermilov void
17304330006dSRuslan Ermilov SetupProtoRedirect(const char* parms)
17314330006dSRuslan Ermilov {
1732b6365f95SAlexander Motin 	char		*buf;
17334330006dSRuslan Ermilov 	char*		ptr;
17344330006dSRuslan Ermilov 	struct in_addr	localAddr;
17354330006dSRuslan Ermilov 	struct in_addr	publicAddr;
17364330006dSRuslan Ermilov 	struct in_addr	remoteAddr;
17374330006dSRuslan Ermilov 	int		proto;
17384330006dSRuslan Ermilov 	char*		protoName;
17394330006dSRuslan Ermilov 	struct protoent *protoent;
17404330006dSRuslan Ermilov 
1741b6365f95SAlexander Motin 	buf = strdup (parms);
1742b6365f95SAlexander Motin 	if (!buf)
1743b6365f95SAlexander Motin 		errx (1, "redirect_port: strdup() failed");
17444330006dSRuslan Ermilov /*
17454330006dSRuslan Ermilov  * Extract protocol.
17464330006dSRuslan Ermilov  */
17474330006dSRuslan Ermilov 	protoName = strtok(buf, " \t");
17484330006dSRuslan Ermilov 	if (!protoName)
17494330006dSRuslan Ermilov 		errx(1, "redirect_proto: missing protocol");
17504330006dSRuslan Ermilov 
17514330006dSRuslan Ermilov 	protoent = getprotobyname(protoName);
17524330006dSRuslan Ermilov 	if (protoent == NULL)
17534330006dSRuslan Ermilov 		errx(1, "redirect_proto: unknown protocol %s", protoName);
17544330006dSRuslan Ermilov 	else
17554330006dSRuslan Ermilov 		proto = protoent->p_proto;
17564330006dSRuslan Ermilov /*
17574330006dSRuslan Ermilov  * Extract local address.
17584330006dSRuslan Ermilov  */
17594330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
17604330006dSRuslan Ermilov 	if (!ptr)
17614330006dSRuslan Ermilov 		errx(1, "redirect_proto: missing local address");
17624330006dSRuslan Ermilov 	else
17634330006dSRuslan Ermilov 		StrToAddr(ptr, &localAddr);
17644330006dSRuslan Ermilov /*
17654330006dSRuslan Ermilov  * Extract optional public address.
17664330006dSRuslan Ermilov  */
17674330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
17684330006dSRuslan Ermilov 	if (ptr)
17694330006dSRuslan Ermilov 		StrToAddr(ptr, &publicAddr);
17704330006dSRuslan Ermilov 	else
17714330006dSRuslan Ermilov 		publicAddr.s_addr = INADDR_ANY;
17724330006dSRuslan Ermilov /*
17734330006dSRuslan Ermilov  * Extract optional remote address.
17744330006dSRuslan Ermilov  */
17754330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
17764330006dSRuslan Ermilov 	if (ptr)
17774330006dSRuslan Ermilov 		StrToAddr(ptr, &remoteAddr);
17784330006dSRuslan Ermilov 	else
17794330006dSRuslan Ermilov 		remoteAddr.s_addr = INADDR_ANY;
17804330006dSRuslan Ermilov /*
17814330006dSRuslan Ermilov  * Create aliasing link.
17824330006dSRuslan Ermilov  */
178322c62477SPoul-Henning Kamp 	(void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
17844330006dSRuslan Ermilov 				       proto);
1785b6365f95SAlexander Motin 
1786b6365f95SAlexander Motin 	free (buf);
17874330006dSRuslan Ermilov }
17884330006dSRuslan Ermilov 
1789902cb50aSBrian Somers void SetupAddressRedirect (const char* parms)
179024084f9bSBrian Somers {
1791b6365f95SAlexander Motin 	char		*buf;
179224084f9bSBrian Somers 	char*		ptr;
1793bd690510SRuslan Ermilov 	char*		separator;
179424084f9bSBrian Somers 	struct in_addr	localAddr;
179524084f9bSBrian Somers 	struct in_addr	publicAddr;
1796bd690510SRuslan Ermilov 	char*		serverPool;
179748ce8ca1SXin LI 	struct alias_link *aliaslink;
179824084f9bSBrian Somers 
1799b6365f95SAlexander Motin 	buf = strdup (parms);
1800b6365f95SAlexander Motin 	if (!buf)
1801b6365f95SAlexander Motin 		errx (1, "redirect_port: strdup() failed");
180224084f9bSBrian Somers /*
180324084f9bSBrian Somers  * Extract local address.
180424084f9bSBrian Somers  */
180524084f9bSBrian Somers 	ptr = strtok (buf, " \t");
18060fc81af1SPhilippe Charnier 	if (!ptr)
18070fc81af1SPhilippe Charnier 		errx (1, "redirect_address: missing local address");
180824084f9bSBrian Somers 
1809bd690510SRuslan Ermilov 	separator = strchr(ptr, ',');
1810bd690510SRuslan Ermilov 	if (separator) {		/* LSNAT redirection syntax. */
1811bd690510SRuslan Ermilov 		localAddr.s_addr = INADDR_NONE;
1812bd690510SRuslan Ermilov 		serverPool = ptr;
1813bd690510SRuslan Ermilov 	} else {
181424084f9bSBrian Somers 		StrToAddr (ptr, &localAddr);
1815bd690510SRuslan Ermilov 		serverPool = NULL;
1816bd690510SRuslan Ermilov 	}
181724084f9bSBrian Somers /*
181824084f9bSBrian Somers  * Extract public address.
181924084f9bSBrian Somers  */
182024084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
18210fc81af1SPhilippe Charnier 	if (!ptr)
18220fc81af1SPhilippe Charnier 		errx (1, "redirect_address: missing public address");
182324084f9bSBrian Somers 
182424084f9bSBrian Somers 	StrToAddr (ptr, &publicAddr);
182548ce8ca1SXin LI 	aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1826bd690510SRuslan Ermilov 
1827bd690510SRuslan Ermilov /*
1828bd690510SRuslan Ermilov  * Setup LSNAT server pool.
1829bd690510SRuslan Ermilov  */
183048ce8ca1SXin LI 	if (serverPool != NULL && aliaslink != NULL) {
1831bd690510SRuslan Ermilov 		ptr = strtok(serverPool, ",");
1832bd690510SRuslan Ermilov 		while (ptr != NULL) {
1833bd690510SRuslan Ermilov 			StrToAddr(ptr, &localAddr);
183448ce8ca1SXin LI 			LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
1835bd690510SRuslan Ermilov 			ptr = strtok(NULL, ",");
1836bd690510SRuslan Ermilov 		}
1837bd690510SRuslan Ermilov 	}
1838b6365f95SAlexander Motin 
1839b6365f95SAlexander Motin 	free (buf);
184024084f9bSBrian Somers }
184124084f9bSBrian Somers 
1842902cb50aSBrian Somers void StrToAddr (const char* str, struct in_addr* addr)
184324084f9bSBrian Somers {
184424084f9bSBrian Somers 	struct hostent* hp;
184524084f9bSBrian Somers 
184624084f9bSBrian Somers 	if (inet_aton (str, addr))
184724084f9bSBrian Somers 		return;
184824084f9bSBrian Somers 
184924084f9bSBrian Somers 	hp = gethostbyname (str);
18500fc81af1SPhilippe Charnier 	if (!hp)
18510fc81af1SPhilippe Charnier 		errx (1, "unknown host %s", str);
185224084f9bSBrian Somers 
185324084f9bSBrian Somers 	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
185424084f9bSBrian Somers }
185524084f9bSBrian Somers 
1856902cb50aSBrian Somers u_short StrToPort (const char* str, const char* proto)
185724084f9bSBrian Somers {
185867a886fbSBrian Somers 	u_short		port;
185924084f9bSBrian Somers 	struct servent*	sp;
186024084f9bSBrian Somers 	char*		end;
186124084f9bSBrian Somers 
186224084f9bSBrian Somers 	port = strtol (str, &end, 10);
186324084f9bSBrian Somers 	if (end != str)
186427c20503SBrian Somers 		return htons (port);
186524084f9bSBrian Somers 
186624084f9bSBrian Somers 	sp = getservbyname (str, proto);
18670fc81af1SPhilippe Charnier 	if (!sp)
186829e3edccSPhilippe Charnier 		errx (1, "%s/%s: unknown service", str, proto);
186924084f9bSBrian Somers 
187024084f9bSBrian Somers 	return sp->s_port;
187124084f9bSBrian Somers }
187224084f9bSBrian Somers 
1873902cb50aSBrian Somers int StrToPortRange (const char* str, const char* proto, port_range *portRange)
18745d8ee958SBrian Somers {
18755d8ee958SBrian Somers 	char*           sep;
18765d8ee958SBrian Somers 	struct servent*	sp;
18775d8ee958SBrian Somers 	char*		end;
18785d8ee958SBrian Somers 	u_short         loPort;
18795d8ee958SBrian Somers 	u_short         hiPort;
18805d8ee958SBrian Somers 
18815d8ee958SBrian Somers 	/* First see if this is a service, return corresponding port if so. */
18825d8ee958SBrian Somers 	sp = getservbyname (str,proto);
18835d8ee958SBrian Somers 	if (sp) {
18845d8ee958SBrian Somers 	        SETLOPORT(*portRange, ntohs(sp->s_port));
18855d8ee958SBrian Somers 		SETNUMPORTS(*portRange, 1);
18865d8ee958SBrian Somers 		return 0;
18875d8ee958SBrian Somers 	}
18885d8ee958SBrian Somers 
18895d8ee958SBrian Somers 	/* Not a service, see if it's a single port or port range. */
18905d8ee958SBrian Somers 	sep = strchr (str, '-');
18915d8ee958SBrian Somers 	if (sep == NULL) {
18925d8ee958SBrian Somers 	        SETLOPORT(*portRange, strtol(str, &end, 10));
18935d8ee958SBrian Somers 		if (end != str) {
18945d8ee958SBrian Somers 		        /* Single port. */
18955d8ee958SBrian Somers 		        SETNUMPORTS(*portRange, 1);
18965d8ee958SBrian Somers 			return 0;
18975d8ee958SBrian Somers 		}
18985d8ee958SBrian Somers 
18995d8ee958SBrian Somers 		/* Error in port range field. */
190029e3edccSPhilippe Charnier 		errx (1, "%s/%s: unknown service", str, proto);
19015d8ee958SBrian Somers 	}
19025d8ee958SBrian Somers 
19035d8ee958SBrian Somers 	/* Port range, get the values and sanity check. */
19045d8ee958SBrian Somers 	sscanf (str, "%hu-%hu", &loPort, &hiPort);
19055d8ee958SBrian Somers 	SETLOPORT(*portRange, loPort);
19065d8ee958SBrian Somers 	SETNUMPORTS(*portRange, 0);	/* Error by default */
19075d8ee958SBrian Somers 	if (loPort <= hiPort)
19085d8ee958SBrian Somers 	        SETNUMPORTS(*portRange, hiPort - loPort + 1);
19095d8ee958SBrian Somers 
19105d8ee958SBrian Somers 	if (GETNUMPORTS(*portRange) == 0)
19115d8ee958SBrian Somers 	        errx (1, "invalid port range %s", str);
19125d8ee958SBrian Somers 
19135d8ee958SBrian Somers 	return 0;
19145d8ee958SBrian Somers }
19155d8ee958SBrian Somers 
19165d8ee958SBrian Somers 
1917902cb50aSBrian Somers int StrToProto (const char* str)
191824084f9bSBrian Somers {
191924084f9bSBrian Somers 	if (!strcmp (str, "tcp"))
192024084f9bSBrian Somers 		return IPPROTO_TCP;
192124084f9bSBrian Somers 
192224084f9bSBrian Somers 	if (!strcmp (str, "udp"))
192324084f9bSBrian Somers 		return IPPROTO_UDP;
192424084f9bSBrian Somers 
19250fc81af1SPhilippe Charnier 	errx (1, "unknown protocol %s. Expected tcp or udp", str);
192624084f9bSBrian Somers }
192724084f9bSBrian Somers 
1928902cb50aSBrian Somers int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
192924084f9bSBrian Somers {
193024084f9bSBrian Somers 	char*	ptr;
193124084f9bSBrian Somers 
193224084f9bSBrian Somers 	ptr = strchr (str, ':');
19330fc81af1SPhilippe Charnier 	if (!ptr)
19340fc81af1SPhilippe Charnier 		errx (1, "%s is missing port number", str);
193524084f9bSBrian Somers 
193624084f9bSBrian Somers 	*ptr = '\0';
193724084f9bSBrian Somers 	++ptr;
193824084f9bSBrian Somers 
193924084f9bSBrian Somers 	StrToAddr (str, addr);
19405d8ee958SBrian Somers 	return StrToPortRange (ptr, proto, portRange);
194124084f9bSBrian Somers }
1942bc4ebb98SRuslan Ermilov 
1943bc4ebb98SRuslan Ermilov static void
1944bc4ebb98SRuslan Ermilov SetupPunchFW(const char *strValue)
1945bc4ebb98SRuslan Ermilov {
1946bc4ebb98SRuslan Ermilov 	unsigned int base, num;
1947bc4ebb98SRuslan Ermilov 
1948bc4ebb98SRuslan Ermilov 	if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1949bc4ebb98SRuslan Ermilov 		errx(1, "punch_fw: basenumber:count parameter required");
1950bc4ebb98SRuslan Ermilov 
1951d53fe710SRoman Kurakin 	if (CheckIpfwRulenum(base + num - 1) == -1)
1952d53fe710SRoman Kurakin 		errx(1, "punch_fw: basenumber:count parameter should fit "
1953d53fe710SRoman Kurakin 			"the maximum allowed rule numbers");
1954d53fe710SRoman Kurakin 
195522c62477SPoul-Henning Kamp 	LibAliasSetFWBase(mla, base, num);
195622c62477SPoul-Henning Kamp 	(void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1957bc4ebb98SRuslan Ermilov }
1958b07fbc17SJoe Marcus Clarke 
1959b07fbc17SJoe Marcus Clarke static void
1960b07fbc17SJoe Marcus Clarke SetupSkinnyPort(const char *strValue)
1961b07fbc17SJoe Marcus Clarke {
1962b07fbc17SJoe Marcus Clarke 	unsigned int port;
1963b07fbc17SJoe Marcus Clarke 
1964b07fbc17SJoe Marcus Clarke 	if (sscanf(strValue, "%u", &port) != 1)
1965b07fbc17SJoe Marcus Clarke 		errx(1, "skinny_port: port parameter required");
1966b07fbc17SJoe Marcus Clarke 
196722c62477SPoul-Henning Kamp 	LibAliasSetSkinnyPort(mla, port);
196822c62477SPoul-Henning Kamp }
196922c62477SPoul-Henning Kamp 
197022c62477SPoul-Henning Kamp static void
197122c62477SPoul-Henning Kamp NewInstance(const char *name)
197222c62477SPoul-Henning Kamp {
197322c62477SPoul-Henning Kamp 	struct instance *ip;
197422c62477SPoul-Henning Kamp 
197522c62477SPoul-Henning Kamp 	LIST_FOREACH(ip, &root, list) {
197622c62477SPoul-Henning Kamp 		if (!strcmp(ip->name, name)) {
197722c62477SPoul-Henning Kamp 			mla = ip->la;
197822c62477SPoul-Henning Kamp 			mip = ip;
197922c62477SPoul-Henning Kamp 			return;
198022c62477SPoul-Henning Kamp 		}
198122c62477SPoul-Henning Kamp 	}
198222c62477SPoul-Henning Kamp 	ninstance++;
198322c62477SPoul-Henning Kamp 	ip = calloc(sizeof *ip, 1);
198422c62477SPoul-Henning Kamp 	ip->name = strdup(name);
198522c62477SPoul-Henning Kamp 	ip->la = LibAliasInit (ip->la);
198622c62477SPoul-Henning Kamp 	ip->assignAliasAddr	= 0;
198722c62477SPoul-Henning Kamp 	ip->ifName		= NULL;
198822c62477SPoul-Henning Kamp  	ip->logDropped		= 0;
198922c62477SPoul-Henning Kamp 	ip->inPort		= 0;
199022c62477SPoul-Henning Kamp 	ip->outPort		= 0;
199122c62477SPoul-Henning Kamp 	ip->inOutPort		= 0;
199222c62477SPoul-Henning Kamp 	ip->aliasAddr.s_addr	= INADDR_NONE;
199322c62477SPoul-Henning Kamp 	ip->ifMTU		= -1;
199422c62477SPoul-Henning Kamp 	ip->aliasOverhead	= 12;
199522c62477SPoul-Henning Kamp 	LIST_INSERT_HEAD(&root, ip, list);
199622c62477SPoul-Henning Kamp 	mla = ip->la;
199722c62477SPoul-Henning Kamp 	mip = ip;
1998b07fbc17SJoe Marcus Clarke }
1999d53fe710SRoman Kurakin 
2000d53fe710SRoman Kurakin static int
2001d53fe710SRoman Kurakin CheckIpfwRulenum(unsigned int rnum)
2002d53fe710SRoman Kurakin {
2003d53fe710SRoman Kurakin 	unsigned int default_rule;
2004d53fe710SRoman Kurakin 	size_t len = sizeof(default_rule);
2005d53fe710SRoman Kurakin 
2006d53fe710SRoman Kurakin 	if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len,
2007d53fe710SRoman Kurakin 		NULL, 0) == -1) {
2008d53fe710SRoman Kurakin 		warn("Failed to get the default ipfw rule number, using "
2009d53fe710SRoman Kurakin 		     "default historical value 65535.  The reason was");
2010d53fe710SRoman Kurakin 		default_rule = 65535;
2011d53fe710SRoman Kurakin 	}
2012d53fe710SRoman Kurakin 	if (rnum >= default_rule) {
2013d53fe710SRoman Kurakin 		return -1;
2014d53fe710SRoman Kurakin 	}
2015d53fe710SRoman Kurakin 
2016d53fe710SRoman Kurakin 	return 0;
2017d53fe710SRoman Kurakin }
2018