xref: /freebsd/sbin/natd/natd.c (revision db702c59cf2577cd10e82ed61282fef3e840f877)
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;
741efe3c6bSEd Schouten static struct instance *mip;
751efe3c6bSEd Schouten static int ninstance = 1;
7622c62477SPoul-Henning Kamp 
7724084f9bSBrian Somers /*
7824084f9bSBrian Somers  * Default values for input and output
7924084f9bSBrian Somers  * divert socket ports.
8024084f9bSBrian Somers  */
8124084f9bSBrian Somers 
8224084f9bSBrian Somers #define	DEFAULT_SERVICE	"natd"
8324084f9bSBrian Somers 
8424084f9bSBrian Somers /*
855d8ee958SBrian Somers  * Definition of a port range, and macros to deal with values.
865d8ee958SBrian Somers  * FORMAT:  HI 16-bits == first port in range, 0 == all ports.
875d8ee958SBrian Somers  *          LO 16-bits == number of ports in range
885d8ee958SBrian Somers  * NOTES:   - Port values are not stored in network byte order.
895d8ee958SBrian Somers  */
905d8ee958SBrian Somers 
915d8ee958SBrian Somers typedef u_long port_range;
925d8ee958SBrian Somers 
935d8ee958SBrian Somers #define GETLOPORT(x)     ((x) >> 0x10)
945d8ee958SBrian Somers #define GETNUMPORTS(x)   ((x) & 0x0000ffff)
955d8ee958SBrian Somers #define GETHIPORT(x)     (GETLOPORT((x)) + GETNUMPORTS((x)))
965d8ee958SBrian Somers 
975d8ee958SBrian Somers /* Set y to be the low-port value in port_range variable x. */
985d8ee958SBrian Somers #define SETLOPORT(x,y)   ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
995d8ee958SBrian Somers 
1005d8ee958SBrian Somers /* Set y to be the number of ports in port_range variable x. */
1015d8ee958SBrian Somers #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
1025d8ee958SBrian Somers 
1035d8ee958SBrian Somers /*
10424084f9bSBrian Somers  * Function prototypes.
10524084f9bSBrian Somers  */
10624084f9bSBrian Somers 
10759a7c613SBrian Somers static void	DoAliasing (int fd, int direction);
108902cb50aSBrian Somers static void	DaemonMode (void);
10924084f9bSBrian Somers static void	HandleRoutingInfo (int fd);
110902cb50aSBrian Somers static void	Usage (void);
11159a7c613SBrian Somers static char*	FormatPacket (struct ip*);
11224084f9bSBrian Somers static void	PrintPacket (struct ip*);
113902cb50aSBrian Somers static void	SyslogPacket (struct ip*, int priority, const char *label);
1140afb958bSMaxim Sobolev static int	SetAliasAddressFromIfName (const char *ifName);
115902cb50aSBrian Somers static void	InitiateShutdown (int);
116902cb50aSBrian Somers static void	Shutdown (int);
117902cb50aSBrian Somers static void	RefreshAddr (int);
118b0f55af6SRuslan Ermilov static void	ParseOption (const char* option, const char* parms);
119902cb50aSBrian Somers static void	ReadConfigFile (const char* fileName);
120902cb50aSBrian Somers static void	SetupPortRedirect (const char* parms);
1214330006dSRuslan Ermilov static void	SetupProtoRedirect(const char* parms);
122902cb50aSBrian Somers static void	SetupAddressRedirect (const char* parms);
123902cb50aSBrian Somers static void	StrToAddr (const char* str, struct in_addr* addr);
124902cb50aSBrian Somers static u_short  StrToPort (const char* str, const char* proto);
125902cb50aSBrian Somers static int      StrToPortRange (const char* str, const char* proto, port_range *portRange);
126902cb50aSBrian Somers static int 	StrToProto (const char* str);
127902cb50aSBrian Somers static int      StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange);
12824084f9bSBrian Somers static void	ParseArgs (int argc, char** argv);
129bc4ebb98SRuslan Ermilov static void	SetupPunchFW(const char *strValue);
130b07fbc17SJoe Marcus Clarke static void	SetupSkinnyPort(const char *strValue);
13122c62477SPoul-Henning Kamp static void	NewInstance(const char *name);
13222c62477SPoul-Henning Kamp static void	DoGlobal (int fd);
133d53fe710SRoman Kurakin static int	CheckIpfwRulenum(unsigned int rnum);
13424084f9bSBrian Somers 
13524084f9bSBrian Somers /*
13624084f9bSBrian Somers  * Globals.
13724084f9bSBrian Somers  */
13824084f9bSBrian Somers 
13924084f9bSBrian Somers static	int			verbose;
14024084f9bSBrian Somers static 	int			background;
14124084f9bSBrian Somers static	int			running;
14259a7c613SBrian Somers static	int			logFacility;
14322c62477SPoul-Henning Kamp 
14422c62477SPoul-Henning Kamp static 	int			dynamicMode;
14522c62477SPoul-Henning Kamp static 	int			icmpSock;
1463843533eSRuslan Ermilov static	int			logIpfwDenied;
14748ce8ca1SXin LI static	const char*		pidName;
14822c62477SPoul-Henning Kamp static	int			routeSock;
14922c62477SPoul-Henning Kamp static	int			globalPort;
15022c62477SPoul-Henning Kamp static	int			divertGlobal;
15172cbe4adSAlexander Motin static	int			exitDelay;
15272cbe4adSAlexander Motin 
15324084f9bSBrian Somers 
15424084f9bSBrian Somers int main (int argc, char** argv)
15524084f9bSBrian Somers {
15624084f9bSBrian Somers 	struct sockaddr_in	addr;
15724084f9bSBrian Somers 	fd_set			readMask;
15824084f9bSBrian Somers 	int			fdMax;
1590afb958bSMaxim Sobolev 	int			rval;
16024084f9bSBrian Somers /*
16124084f9bSBrian Somers  * Initialize packet aliasing software.
16224084f9bSBrian Somers  * Done already here to be able to alter option bits
16324084f9bSBrian Somers  * during command line and configuration file processing.
16424084f9bSBrian Somers  */
16522c62477SPoul-Henning Kamp 	NewInstance("default");
16622c62477SPoul-Henning Kamp 
16724084f9bSBrian Somers /*
16824084f9bSBrian Somers  * Parse options.
16924084f9bSBrian Somers  */
17024084f9bSBrian Somers 	verbose 		= 0;
17124084f9bSBrian Somers 	background		= 0;
17224084f9bSBrian Somers 	running			= 1;
17324084f9bSBrian Somers 	dynamicMode		= 0;
17459a7c613SBrian Somers  	logFacility		= LOG_DAEMON;
175c0956cf8SRuslan Ermilov 	logIpfwDenied		= -1;
176b79840a6SRuslan Ermilov 	pidName			= PIDFILE;
17722c62477SPoul-Henning Kamp 	routeSock 		= -1;
17822c62477SPoul-Henning Kamp 	icmpSock 		= -1;
17922c62477SPoul-Henning Kamp 	fdMax	 		= -1;
18022c62477SPoul-Henning Kamp 	divertGlobal		= -1;
18172cbe4adSAlexander Motin 	exitDelay		= EXIT_DELAY;
18224084f9bSBrian Somers 
18324084f9bSBrian Somers 	ParseArgs (argc, argv);
18424084f9bSBrian Somers /*
185c0956cf8SRuslan Ermilov  * Log ipfw(8) denied packets by default in verbose mode.
186c0956cf8SRuslan Ermilov  */
187c0956cf8SRuslan Ermilov 	if (logIpfwDenied == -1)
188c0956cf8SRuslan Ermilov 		logIpfwDenied = verbose;
189c0956cf8SRuslan Ermilov /*
19059a7c613SBrian Somers  * Open syslog channel.
19159a7c613SBrian Somers  */
1924c04fa4cSRuslan Ermilov 	openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
1934c04fa4cSRuslan Ermilov 		 logFacility);
19422c62477SPoul-Henning Kamp 
19522c62477SPoul-Henning Kamp 	LIST_FOREACH(mip, &root, list) {
19622c62477SPoul-Henning Kamp 		mla = mip->la;
19759a7c613SBrian Somers /*
1983d23e8b8SRuslan Ermilov  * If not doing the transparent proxying only,
1993d23e8b8SRuslan Ermilov  * check that valid aliasing address has been given.
20024084f9bSBrian Somers  */
20122c62477SPoul-Henning Kamp 		if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL &&
20222c62477SPoul-Henning Kamp 		    !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY))
20322c62477SPoul-Henning Kamp 			errx (1, "instance %s: aliasing address not given", mip->name);
20424084f9bSBrian Somers 
20522c62477SPoul-Henning Kamp 		if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL)
20667a886fbSBrian Somers 			errx (1, "both alias address and interface "
20767a886fbSBrian Somers 				 "name are not allowed");
20824084f9bSBrian Somers /*
20924084f9bSBrian Somers  * Check that valid port number is known.
21024084f9bSBrian Somers  */
21122c62477SPoul-Henning Kamp 		if (mip->inPort != 0 || mip->outPort != 0)
21222c62477SPoul-Henning Kamp 			if (mip->inPort == 0 || mip->outPort == 0)
2130fc81af1SPhilippe Charnier 				errx (1, "both input and output ports are required");
21424084f9bSBrian Somers 
21522c62477SPoul-Henning Kamp 		if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0)
216b0f55af6SRuslan Ermilov 			ParseOption ("port", DEFAULT_SERVICE);
21724084f9bSBrian Somers 
21824084f9bSBrian Somers /*
219f9b06d5cSBrian Somers  * Check if ignored packets should be dropped.
220f9b06d5cSBrian Somers  */
22122c62477SPoul-Henning Kamp 		mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0);
22222c62477SPoul-Henning Kamp 		mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
223f9b06d5cSBrian Somers /*
22424084f9bSBrian Somers  * Create divert sockets. Use only one socket if -p was specified
22524084f9bSBrian Somers  * on command line. Otherwise, create separate sockets for
22624084f9bSBrian Somers  * outgoing and incoming connnections.
22724084f9bSBrian Somers  */
22822c62477SPoul-Henning Kamp 		if (mip->inOutPort) {
22924084f9bSBrian Somers 
23022c62477SPoul-Henning Kamp 			mip->divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
23122c62477SPoul-Henning Kamp 			if (mip->divertInOut == -1)
23224084f9bSBrian Somers 				Quit ("Unable to create divert socket.");
23322c62477SPoul-Henning Kamp 			if (mip->divertInOut > fdMax)
23422c62477SPoul-Henning Kamp 				fdMax = mip->divertInOut;
23524084f9bSBrian Somers 
23622c62477SPoul-Henning Kamp 			mip->divertIn  = -1;
23722c62477SPoul-Henning Kamp 			mip->divertOut = -1;
23824084f9bSBrian Somers /*
23924084f9bSBrian Somers  * Bind socket.
24024084f9bSBrian Somers  */
24124084f9bSBrian Somers 
24224084f9bSBrian Somers 			addr.sin_family		= AF_INET;
24324084f9bSBrian Somers 			addr.sin_addr.s_addr	= INADDR_ANY;
24422c62477SPoul-Henning Kamp 			addr.sin_port		= mip->inOutPort;
24524084f9bSBrian Somers 
24622c62477SPoul-Henning Kamp 			if (bind (mip->divertInOut,
24724084f9bSBrian Somers 				  (struct sockaddr*) &addr,
24824084f9bSBrian Somers 				  sizeof addr) == -1)
24924084f9bSBrian Somers 				Quit ("Unable to bind divert socket.");
25024084f9bSBrian Somers 		}
25124084f9bSBrian Somers 		else {
25224084f9bSBrian Somers 
25322c62477SPoul-Henning Kamp 			mip->divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
25422c62477SPoul-Henning Kamp 			if (mip->divertIn == -1)
25524084f9bSBrian Somers 				Quit ("Unable to create incoming divert socket.");
25622c62477SPoul-Henning Kamp 			if (mip->divertIn > fdMax)
25722c62477SPoul-Henning Kamp 				fdMax = mip->divertIn;
25824084f9bSBrian Somers 
25922c62477SPoul-Henning Kamp 
26022c62477SPoul-Henning Kamp 			mip->divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
26122c62477SPoul-Henning Kamp 			if (mip->divertOut == -1)
26224084f9bSBrian Somers 				Quit ("Unable to create outgoing divert socket.");
26322c62477SPoul-Henning Kamp 			if (mip->divertOut > fdMax)
26422c62477SPoul-Henning Kamp 				fdMax = mip->divertOut;
26524084f9bSBrian Somers 
26622c62477SPoul-Henning Kamp 			mip->divertInOut = -1;
26724084f9bSBrian Somers 
26824084f9bSBrian Somers /*
26924084f9bSBrian Somers  * Bind divert sockets.
27024084f9bSBrian Somers  */
27124084f9bSBrian Somers 
27224084f9bSBrian Somers 			addr.sin_family		= AF_INET;
27324084f9bSBrian Somers 			addr.sin_addr.s_addr	= INADDR_ANY;
27422c62477SPoul-Henning Kamp 			addr.sin_port		= mip->inPort;
27524084f9bSBrian Somers 
27622c62477SPoul-Henning Kamp 			if (bind (mip->divertIn,
27724084f9bSBrian Somers 				  (struct sockaddr*) &addr,
27824084f9bSBrian Somers 				  sizeof addr) == -1)
27924084f9bSBrian Somers 				Quit ("Unable to bind incoming divert socket.");
28024084f9bSBrian Somers 
28124084f9bSBrian Somers 			addr.sin_family		= AF_INET;
28224084f9bSBrian Somers 			addr.sin_addr.s_addr	= INADDR_ANY;
28322c62477SPoul-Henning Kamp 			addr.sin_port		= mip->outPort;
28424084f9bSBrian Somers 
28522c62477SPoul-Henning Kamp 			if (bind (mip->divertOut,
28624084f9bSBrian Somers 				  (struct sockaddr*) &addr,
28724084f9bSBrian Somers 				  sizeof addr) == -1)
28824084f9bSBrian Somers 				Quit ("Unable to bind outgoing divert socket.");
28924084f9bSBrian Somers 		}
29024084f9bSBrian Somers /*
291f2da55a2SRuslan Ermilov  * Create routing socket if interface name specified and in dynamic mode.
29224084f9bSBrian Somers  */
29322c62477SPoul-Henning Kamp 		if (mip->ifName) {
294f2da55a2SRuslan Ermilov 			if (dynamicMode) {
29524084f9bSBrian Somers 
29622c62477SPoul-Henning Kamp 				if (routeSock == -1)
29724084f9bSBrian Somers 					routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
29824084f9bSBrian Somers 				if (routeSock == -1)
29924084f9bSBrian Somers 					Quit ("Unable to create routing info socket.");
30022c62477SPoul-Henning Kamp 				if (routeSock > fdMax)
30122c62477SPoul-Henning Kamp 					fdMax = routeSock;
302f2da55a2SRuslan Ermilov 
30322c62477SPoul-Henning Kamp 				mip->assignAliasAddr = 1;
30424084f9bSBrian Somers 			}
3050afb958bSMaxim Sobolev 			else {
3060afb958bSMaxim Sobolev 				do {
3070afb958bSMaxim Sobolev 					rval = SetAliasAddressFromIfName (mip->ifName);
308dde269c9SMaxim Sobolev 					if (background == 0 || dynamicMode == 0)
309dde269c9SMaxim Sobolev 						break;
310dde269c9SMaxim Sobolev 					if (rval == EAGAIN)
3110afb958bSMaxim Sobolev 						sleep(1);
312dde269c9SMaxim Sobolev 				} while (rval == EAGAIN);
3130afb958bSMaxim Sobolev 				if (rval != 0)
3140afb958bSMaxim Sobolev 					exit(1);
3150afb958bSMaxim Sobolev 			}
31622c62477SPoul-Henning Kamp 		}
31722c62477SPoul-Henning Kamp 
31822c62477SPoul-Henning Kamp 	}
31922c62477SPoul-Henning Kamp 	if (globalPort) {
32022c62477SPoul-Henning Kamp 
32122c62477SPoul-Henning Kamp 		divertGlobal = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
32222c62477SPoul-Henning Kamp 		if (divertGlobal == -1)
32322c62477SPoul-Henning Kamp 			Quit ("Unable to create divert socket.");
32422c62477SPoul-Henning Kamp 		if (divertGlobal > fdMax)
32522c62477SPoul-Henning Kamp 			fdMax = divertGlobal;
32622c62477SPoul-Henning Kamp 
32722c62477SPoul-Henning Kamp /*
32822c62477SPoul-Henning Kamp * Bind socket.
32922c62477SPoul-Henning Kamp */
33022c62477SPoul-Henning Kamp 
33122c62477SPoul-Henning Kamp 		addr.sin_family		= AF_INET;
33222c62477SPoul-Henning Kamp 		addr.sin_addr.s_addr	= INADDR_ANY;
33322c62477SPoul-Henning Kamp 		addr.sin_port		= globalPort;
33422c62477SPoul-Henning Kamp 
33522c62477SPoul-Henning Kamp 		if (bind (divertGlobal,
33622c62477SPoul-Henning Kamp 			  (struct sockaddr*) &addr,
33722c62477SPoul-Henning Kamp 			  sizeof addr) == -1)
33822c62477SPoul-Henning Kamp 			Quit ("Unable to bind global divert socket.");
339f2da55a2SRuslan Ermilov 	}
34024084f9bSBrian Somers /*
34124084f9bSBrian Somers  * Create socket for sending ICMP messages.
34224084f9bSBrian Somers  */
34324084f9bSBrian Somers 	icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
34424084f9bSBrian Somers 	if (icmpSock == -1)
34524084f9bSBrian Somers 		Quit ("Unable to create ICMP socket.");
346f3d64024SBrian Somers 
347f3d64024SBrian Somers /*
348f3d64024SBrian Somers  * And disable reads for the socket, otherwise it slowly fills
349f3d64024SBrian Somers  * up with received icmps which we do not use.
350f3d64024SBrian Somers  */
351f3d64024SBrian Somers 	shutdown(icmpSock, SHUT_RD);
352f3d64024SBrian Somers 
35324084f9bSBrian Somers /*
35424084f9bSBrian Somers  * Become a daemon unless verbose mode was requested.
35524084f9bSBrian Somers  */
35624084f9bSBrian Somers 	if (!verbose)
35724084f9bSBrian Somers 		DaemonMode ();
35824084f9bSBrian Somers /*
35924084f9bSBrian Somers  * Catch signals to manage shutdown and
36024084f9bSBrian Somers  * refresh of interface address.
36124084f9bSBrian Somers  */
362cd45c931SRuslan Ermilov 	siginterrupt(SIGTERM, 1);
363cd45c931SRuslan Ermilov 	siginterrupt(SIGHUP, 1);
36472cbe4adSAlexander Motin 	if (exitDelay)
36524084f9bSBrian Somers 		signal(SIGTERM, InitiateShutdown);
36672cbe4adSAlexander Motin 	else
36772cbe4adSAlexander Motin 		signal(SIGTERM, Shutdown);
36824084f9bSBrian Somers 	signal (SIGHUP, RefreshAddr);
36924084f9bSBrian Somers /*
37024084f9bSBrian Somers  * Set alias address if it has been given.
37124084f9bSBrian Somers  */
37222c62477SPoul-Henning Kamp 	mip = LIST_FIRST(&root);	/* XXX: simon */
37322c62477SPoul-Henning Kamp 	LIST_FOREACH(mip, &root, list) {
37422c62477SPoul-Henning Kamp 		mla = mip->la;
37522c62477SPoul-Henning Kamp 		if (mip->aliasAddr.s_addr != INADDR_NONE)
37622c62477SPoul-Henning Kamp 			LibAliasSetAddress (mla, mip->aliasAddr);
37722c62477SPoul-Henning Kamp 	}
37824084f9bSBrian Somers 
37924084f9bSBrian Somers 	while (running) {
38022c62477SPoul-Henning Kamp 		mip = LIST_FIRST(&root);	/* XXX: simon */
381fb994b07SBrian Somers 
38222c62477SPoul-Henning Kamp 		if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) {
383fb994b07SBrian Somers /*
384fb994b07SBrian Somers  * When using only one socket, just call
385fb994b07SBrian Somers  * DoAliasing repeatedly to process packets.
386fb994b07SBrian Somers  */
38722c62477SPoul-Henning Kamp 			DoAliasing (mip->divertInOut, DONT_KNOW);
388fb994b07SBrian Somers 			continue;
389fb994b07SBrian Somers 		}
39024084f9bSBrian Somers /*
39124084f9bSBrian Somers  * Build read mask from socket descriptors to select.
39224084f9bSBrian Somers  */
39324084f9bSBrian Somers 		FD_ZERO (&readMask);
394fb994b07SBrian Somers /*
3953daff242SRuslan Ermilov  * Check if new packets are available.
396fb994b07SBrian Somers  */
39722c62477SPoul-Henning Kamp 		LIST_FOREACH(mip, &root, list) {
39822c62477SPoul-Henning Kamp 			if (mip->divertIn != -1)
39922c62477SPoul-Henning Kamp 				FD_SET (mip->divertIn, &readMask);
40024084f9bSBrian Somers 
40122c62477SPoul-Henning Kamp 			if (mip->divertOut != -1)
40222c62477SPoul-Henning Kamp 				FD_SET (mip->divertOut, &readMask);
40324084f9bSBrian Somers 
40422c62477SPoul-Henning Kamp 			if (mip->divertInOut != -1)
40522c62477SPoul-Henning Kamp 				FD_SET (mip->divertInOut, &readMask);
40622c62477SPoul-Henning Kamp 		}
407fb994b07SBrian Somers /*
408fb994b07SBrian Somers  * Routing info is processed always.
409fb994b07SBrian Somers  */
41024084f9bSBrian Somers 		if (routeSock != -1)
41124084f9bSBrian Somers 			FD_SET (routeSock, &readMask);
41224084f9bSBrian Somers 
41322c62477SPoul-Henning Kamp 		if (divertGlobal != -1)
41422c62477SPoul-Henning Kamp 			FD_SET (divertGlobal, &readMask);
41522c62477SPoul-Henning Kamp 
41624084f9bSBrian Somers 		if (select (fdMax + 1,
41724084f9bSBrian Somers 			    &readMask,
4183daff242SRuslan Ermilov 			    NULL,
41924084f9bSBrian Somers 			    NULL,
42024084f9bSBrian Somers 			    NULL) == -1) {
42124084f9bSBrian Somers 
42224084f9bSBrian Somers 			if (errno == EINTR)
42324084f9bSBrian Somers 				continue;
42424084f9bSBrian Somers 
42524084f9bSBrian Somers 			Quit ("Select failed.");
42624084f9bSBrian Somers 		}
42724084f9bSBrian Somers 
42822c62477SPoul-Henning Kamp 		if (divertGlobal != -1)
42922c62477SPoul-Henning Kamp 			if (FD_ISSET (divertGlobal, &readMask))
43022c62477SPoul-Henning Kamp 				DoGlobal (divertGlobal);
43122c62477SPoul-Henning Kamp 		LIST_FOREACH(mip, &root, list) {
43222c62477SPoul-Henning Kamp 			mla = mip->la;
43322c62477SPoul-Henning Kamp 			if (mip->divertIn != -1)
43422c62477SPoul-Henning Kamp 				if (FD_ISSET (mip->divertIn, &readMask))
43522c62477SPoul-Henning Kamp 					DoAliasing (mip->divertIn, INPUT);
43624084f9bSBrian Somers 
43722c62477SPoul-Henning Kamp 			if (mip->divertOut != -1)
43822c62477SPoul-Henning Kamp 				if (FD_ISSET (mip->divertOut, &readMask))
43922c62477SPoul-Henning Kamp 					DoAliasing (mip->divertOut, OUTPUT);
44024084f9bSBrian Somers 
44122c62477SPoul-Henning Kamp 			if (mip->divertInOut != -1)
44222c62477SPoul-Henning Kamp 				if (FD_ISSET (mip->divertInOut, &readMask))
44322c62477SPoul-Henning Kamp 					DoAliasing (mip->divertInOut, DONT_KNOW);
44424084f9bSBrian Somers 
44522c62477SPoul-Henning Kamp 		}
44624084f9bSBrian Somers 		if (routeSock != -1)
44724084f9bSBrian Somers 			if (FD_ISSET (routeSock, &readMask))
44824084f9bSBrian Somers 				HandleRoutingInfo (routeSock);
44924084f9bSBrian Somers 	}
45024084f9bSBrian Somers 
45124084f9bSBrian Somers 	if (background)
452b79840a6SRuslan Ermilov 		unlink (pidName);
45324084f9bSBrian Somers 
45424084f9bSBrian Somers 	return 0;
45524084f9bSBrian Somers }
45624084f9bSBrian Somers 
4577154ce64SEd Schouten static void DaemonMode(void)
45824084f9bSBrian Somers {
45924084f9bSBrian Somers 	FILE*	pidFile;
46024084f9bSBrian Somers 
46124084f9bSBrian Somers 	daemon (0, 0);
46224084f9bSBrian Somers 	background = 1;
46324084f9bSBrian Somers 
464b79840a6SRuslan Ermilov 	pidFile = fopen (pidName, "w");
46524084f9bSBrian Somers 	if (pidFile) {
46624084f9bSBrian Somers 
46724084f9bSBrian Somers 		fprintf (pidFile, "%d\n", getpid ());
46824084f9bSBrian Somers 		fclose (pidFile);
46924084f9bSBrian Somers 	}
47024084f9bSBrian Somers }
47124084f9bSBrian Somers 
47224084f9bSBrian Somers static void ParseArgs (int argc, char** argv)
47324084f9bSBrian Somers {
47424084f9bSBrian Somers 	int		arg;
47524084f9bSBrian Somers 	char*		opt;
47624084f9bSBrian Somers 	char		parmBuf[256];
47730395bb5SJosef Karthauser 	int		len; /* bounds checking */
47824084f9bSBrian Somers 
47924084f9bSBrian Somers 	for (arg = 1; arg < argc; arg++) {
48024084f9bSBrian Somers 
48124084f9bSBrian Somers 		opt  = argv[arg];
48224084f9bSBrian Somers 		if (*opt != '-') {
48324084f9bSBrian Somers 
4840fc81af1SPhilippe Charnier 			warnx ("invalid option %s", opt);
48524084f9bSBrian Somers 			Usage ();
48624084f9bSBrian Somers 		}
48724084f9bSBrian Somers 
48824084f9bSBrian Somers 		parmBuf[0] = '\0';
48930395bb5SJosef Karthauser 		len = 0;
49024084f9bSBrian Somers 
49124084f9bSBrian Somers 		while (arg < argc - 1) {
49224084f9bSBrian Somers 
49324084f9bSBrian Somers 			if (argv[arg + 1][0] == '-')
49424084f9bSBrian Somers 				break;
49524084f9bSBrian Somers 
49630395bb5SJosef Karthauser 			if (len) {
49730395bb5SJosef Karthauser 				strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
49830395bb5SJosef Karthauser 				len += strlen(parmBuf + len);
49924084f9bSBrian Somers 			}
50024084f9bSBrian Somers 
50130395bb5SJosef Karthauser 			++arg;
50230395bb5SJosef Karthauser 			strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
50330395bb5SJosef Karthauser 			len += strlen(parmBuf + len);
50430395bb5SJosef Karthauser 
50530395bb5SJosef Karthauser 		}
50630395bb5SJosef Karthauser 
507b0f55af6SRuslan Ermilov 		ParseOption (opt + 1, (len ? parmBuf : NULL));
50830395bb5SJosef Karthauser 
50924084f9bSBrian Somers 	}
51024084f9bSBrian Somers }
51124084f9bSBrian Somers 
51222c62477SPoul-Henning Kamp static void DoGlobal (int fd)
51322c62477SPoul-Henning Kamp {
51422c62477SPoul-Henning Kamp 	int			bytes;
51522c62477SPoul-Henning Kamp 	int			origBytes;
51622c62477SPoul-Henning Kamp 	char			buf[IP_MAXPACKET];
51722c62477SPoul-Henning Kamp 	struct sockaddr_in	addr;
51822c62477SPoul-Henning Kamp 	int			wrote;
51948ce8ca1SXin LI 	socklen_t		addrSize;
52022c62477SPoul-Henning Kamp 	struct ip*		ip;
52122c62477SPoul-Henning Kamp 	char			msgBuf[80];
52222c62477SPoul-Henning Kamp 
52322c62477SPoul-Henning Kamp /*
52422c62477SPoul-Henning Kamp  * Get packet from socket.
52522c62477SPoul-Henning Kamp  */
52622c62477SPoul-Henning Kamp 	addrSize  = sizeof addr;
52722c62477SPoul-Henning Kamp 	origBytes = recvfrom (fd,
52822c62477SPoul-Henning Kamp 			      buf,
52922c62477SPoul-Henning Kamp 			      sizeof buf,
53022c62477SPoul-Henning Kamp 			      0,
53122c62477SPoul-Henning Kamp 			      (struct sockaddr*) &addr,
53222c62477SPoul-Henning Kamp 			      &addrSize);
53322c62477SPoul-Henning Kamp 
53422c62477SPoul-Henning Kamp 	if (origBytes == -1) {
53522c62477SPoul-Henning Kamp 
53622c62477SPoul-Henning Kamp 		if (errno != EINTR)
53722c62477SPoul-Henning Kamp 			Warn ("read from divert socket failed");
53822c62477SPoul-Henning Kamp 
53922c62477SPoul-Henning Kamp 		return;
54022c62477SPoul-Henning Kamp 	}
54122c62477SPoul-Henning Kamp 
54222c62477SPoul-Henning Kamp #if 0
54322c62477SPoul-Henning Kamp 	if (mip->assignAliasAddr) {
5440afb958bSMaxim Sobolev 		if (SetAliasAddressFromIfName (mip->ifName) != 0)
5450afb958bSMaxim Sobolev 			exit(1);
54622c62477SPoul-Henning Kamp 		mip->assignAliasAddr = 0;
54722c62477SPoul-Henning Kamp 	}
54822c62477SPoul-Henning Kamp #endif
54922c62477SPoul-Henning Kamp /*
55022c62477SPoul-Henning Kamp  * This is an IP packet.
55122c62477SPoul-Henning Kamp  */
55222c62477SPoul-Henning Kamp 	ip = (struct ip*) buf;
55322c62477SPoul-Henning Kamp 
55422c62477SPoul-Henning Kamp 	if (verbose) {
55522c62477SPoul-Henning Kamp /*
55622c62477SPoul-Henning Kamp  * Print packet direction and protocol type.
55722c62477SPoul-Henning Kamp  */
55822c62477SPoul-Henning Kamp 		printf ("Glb ");
55922c62477SPoul-Henning Kamp 
56022c62477SPoul-Henning Kamp 		switch (ip->ip_p) {
56122c62477SPoul-Henning Kamp 		case IPPROTO_TCP:
56222c62477SPoul-Henning Kamp 			printf ("[TCP]  ");
56322c62477SPoul-Henning Kamp 			break;
56422c62477SPoul-Henning Kamp 
56522c62477SPoul-Henning Kamp 		case IPPROTO_UDP:
56622c62477SPoul-Henning Kamp 			printf ("[UDP]  ");
56722c62477SPoul-Henning Kamp 			break;
56822c62477SPoul-Henning Kamp 
56922c62477SPoul-Henning Kamp 		case IPPROTO_ICMP:
57022c62477SPoul-Henning Kamp 			printf ("[ICMP] ");
57122c62477SPoul-Henning Kamp 			break;
57222c62477SPoul-Henning Kamp 
57322c62477SPoul-Henning Kamp 		default:
57422c62477SPoul-Henning Kamp 			printf ("[%d]    ", ip->ip_p);
57522c62477SPoul-Henning Kamp 			break;
57622c62477SPoul-Henning Kamp 		}
57722c62477SPoul-Henning Kamp /*
57822c62477SPoul-Henning Kamp  * Print addresses.
57922c62477SPoul-Henning Kamp  */
58022c62477SPoul-Henning Kamp 		PrintPacket (ip);
58122c62477SPoul-Henning Kamp 	}
58222c62477SPoul-Henning Kamp 
58322c62477SPoul-Henning Kamp 	LIST_FOREACH(mip, &root, list) {
58422c62477SPoul-Henning Kamp 		mla = mip->la;
58522c62477SPoul-Henning Kamp 		if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED)
58622c62477SPoul-Henning Kamp 			break;
58722c62477SPoul-Henning Kamp 	}
58822c62477SPoul-Henning Kamp /*
58922c62477SPoul-Henning Kamp  * Length might have changed during aliasing.
59022c62477SPoul-Henning Kamp  */
59122c62477SPoul-Henning Kamp 	bytes = ntohs (ip->ip_len);
59222c62477SPoul-Henning Kamp /*
59322c62477SPoul-Henning Kamp  * Update alias overhead size for outgoing packets.
59422c62477SPoul-Henning Kamp  */
59522c62477SPoul-Henning Kamp 	if (mip != NULL && bytes - origBytes > mip->aliasOverhead)
59622c62477SPoul-Henning Kamp 		mip->aliasOverhead = bytes - origBytes;
59722c62477SPoul-Henning Kamp 
59822c62477SPoul-Henning Kamp 	if (verbose) {
59922c62477SPoul-Henning Kamp 
60022c62477SPoul-Henning Kamp /*
60122c62477SPoul-Henning Kamp  * Print addresses after aliasing.
60222c62477SPoul-Henning Kamp  */
60322c62477SPoul-Henning Kamp 		printf (" aliased to\n");
60422c62477SPoul-Henning Kamp 		printf ("           ");
60522c62477SPoul-Henning Kamp 		PrintPacket (ip);
60622c62477SPoul-Henning Kamp 		printf ("\n");
60722c62477SPoul-Henning Kamp 	}
60822c62477SPoul-Henning Kamp 
60922c62477SPoul-Henning Kamp /*
61022c62477SPoul-Henning Kamp  * Put packet back for processing.
61122c62477SPoul-Henning Kamp  */
61222c62477SPoul-Henning Kamp 	wrote = sendto (fd,
61322c62477SPoul-Henning Kamp 		        buf,
61422c62477SPoul-Henning Kamp 	    		bytes,
61522c62477SPoul-Henning Kamp 	    		0,
61622c62477SPoul-Henning Kamp 	    		(struct sockaddr*) &addr,
61722c62477SPoul-Henning Kamp 	    		sizeof addr);
61822c62477SPoul-Henning Kamp 
61922c62477SPoul-Henning Kamp 	if (wrote != bytes) {
62022c62477SPoul-Henning Kamp 
62122c62477SPoul-Henning Kamp 		if (errno == EMSGSIZE) {
62222c62477SPoul-Henning Kamp 
62322c62477SPoul-Henning Kamp 			if (mip->ifMTU != -1)
62422c62477SPoul-Henning Kamp 				SendNeedFragIcmp (icmpSock,
62522c62477SPoul-Henning Kamp 						  (struct ip*) buf,
62622c62477SPoul-Henning Kamp 						  mip->ifMTU - mip->aliasOverhead);
62722c62477SPoul-Henning Kamp 		}
62822c62477SPoul-Henning Kamp 		else if (errno == EACCES && logIpfwDenied) {
62922c62477SPoul-Henning Kamp 
63022c62477SPoul-Henning Kamp 			sprintf (msgBuf, "failed to write packet back");
63122c62477SPoul-Henning Kamp 			Warn (msgBuf);
63222c62477SPoul-Henning Kamp 		}
63322c62477SPoul-Henning Kamp 	}
63422c62477SPoul-Henning Kamp }
63522c62477SPoul-Henning Kamp 
63622c62477SPoul-Henning Kamp 
63759a7c613SBrian Somers static void DoAliasing (int fd, int direction)
63824084f9bSBrian Somers {
63924084f9bSBrian Somers 	int			bytes;
64024084f9bSBrian Somers 	int			origBytes;
6413daff242SRuslan Ermilov 	char			buf[IP_MAXPACKET];
6423daff242SRuslan Ermilov 	struct sockaddr_in	addr;
6433daff242SRuslan Ermilov 	int			wrote;
644f9b06d5cSBrian Somers 	int			status;
64548ce8ca1SXin LI 	socklen_t		addrSize;
64624084f9bSBrian Somers 	struct ip*		ip;
6473daff242SRuslan Ermilov 	char			msgBuf[80];
6480afb958bSMaxim Sobolev 	int			rval;
64924084f9bSBrian Somers 
65022c62477SPoul-Henning Kamp 	if (mip->assignAliasAddr) {
6510afb958bSMaxim Sobolev 		do {
6520afb958bSMaxim Sobolev 			rval = SetAliasAddressFromIfName (mip->ifName);
653dde269c9SMaxim Sobolev 			if (background == 0 || dynamicMode == 0)
654dde269c9SMaxim Sobolev 				break;
655dde269c9SMaxim Sobolev 			if (rval == EAGAIN)
6560afb958bSMaxim Sobolev 				sleep(1);
657dde269c9SMaxim Sobolev 		} while (rval == EAGAIN);
6580afb958bSMaxim Sobolev 		if (rval != 0)
6590afb958bSMaxim Sobolev 			exit(1);
66022c62477SPoul-Henning Kamp 		mip->assignAliasAddr = 0;
66124084f9bSBrian Somers 	}
66224084f9bSBrian Somers /*
66324084f9bSBrian Somers  * Get packet from socket.
66424084f9bSBrian Somers  */
6653daff242SRuslan Ermilov 	addrSize  = sizeof addr;
66624084f9bSBrian Somers 	origBytes = recvfrom (fd,
6673daff242SRuslan Ermilov 			      buf,
6683daff242SRuslan Ermilov 			      sizeof buf,
66924084f9bSBrian Somers 			      0,
6703daff242SRuslan Ermilov 			      (struct sockaddr*) &addr,
67124084f9bSBrian Somers 			      &addrSize);
67224084f9bSBrian Somers 
67324084f9bSBrian Somers 	if (origBytes == -1) {
67424084f9bSBrian Somers 
67524084f9bSBrian Somers 		if (errno != EINTR)
6760fc81af1SPhilippe Charnier 			Warn ("read from divert socket failed");
67724084f9bSBrian Somers 
67824084f9bSBrian Somers 		return;
67924084f9bSBrian Somers 	}
68024084f9bSBrian Somers /*
6819d5abbddSJens Schweikhardt  * This is an IP packet.
68224084f9bSBrian Somers  */
6833daff242SRuslan Ermilov 	ip = (struct ip*) buf;
684ebe70c8fSWarner Losh 	if (direction == DONT_KNOW) {
6853daff242SRuslan Ermilov 		if (addr.sin_addr.s_addr == INADDR_ANY)
68659a7c613SBrian Somers 			direction = OUTPUT;
68759a7c613SBrian Somers 		else
68859a7c613SBrian Somers 			direction = INPUT;
689ebe70c8fSWarner Losh 	}
69024084f9bSBrian Somers 
69124084f9bSBrian Somers 	if (verbose) {
69224084f9bSBrian Somers /*
69324084f9bSBrian Somers  * Print packet direction and protocol type.
69424084f9bSBrian Somers  */
69559a7c613SBrian Somers 		printf (direction == OUTPUT ? "Out " : "In  ");
69622c62477SPoul-Henning Kamp 		if (ninstance > 1)
69748ce8ca1SXin LI 			printf ("{%s}", mip->name);
69824084f9bSBrian Somers 
69924084f9bSBrian Somers 		switch (ip->ip_p) {
70024084f9bSBrian Somers 		case IPPROTO_TCP:
70124084f9bSBrian Somers 			printf ("[TCP]  ");
70224084f9bSBrian Somers 			break;
70324084f9bSBrian Somers 
70424084f9bSBrian Somers 		case IPPROTO_UDP:
70524084f9bSBrian Somers 			printf ("[UDP]  ");
70624084f9bSBrian Somers 			break;
70724084f9bSBrian Somers 
70824084f9bSBrian Somers 		case IPPROTO_ICMP:
70924084f9bSBrian Somers 			printf ("[ICMP] ");
71024084f9bSBrian Somers 			break;
71124084f9bSBrian Somers 
71224084f9bSBrian Somers 		default:
71359a7c613SBrian Somers 			printf ("[%d]    ", ip->ip_p);
71424084f9bSBrian Somers 			break;
71524084f9bSBrian Somers 		}
71624084f9bSBrian Somers /*
71724084f9bSBrian Somers  * Print addresses.
71824084f9bSBrian Somers  */
71924084f9bSBrian Somers 		PrintPacket (ip);
72024084f9bSBrian Somers 	}
72124084f9bSBrian Somers 
72259a7c613SBrian Somers 	if (direction == OUTPUT) {
72324084f9bSBrian Somers /*
72424084f9bSBrian Somers  * Outgoing packets. Do aliasing.
72524084f9bSBrian Somers  */
72622c62477SPoul-Henning Kamp 		LibAliasOut (mla, buf, IP_MAXPACKET);
72724084f9bSBrian Somers 	}
72824084f9bSBrian Somers 	else {
72959a7c613SBrian Somers 
73024084f9bSBrian Somers /*
73124084f9bSBrian Somers  * Do aliasing.
73224084f9bSBrian Somers  */
73322c62477SPoul-Henning Kamp 		status = LibAliasIn (mla, buf, IP_MAXPACKET);
734f9b06d5cSBrian Somers 		if (status == PKT_ALIAS_IGNORED &&
73522c62477SPoul-Henning Kamp 		    mip->dropIgnoredIncoming) {
736f9b06d5cSBrian Somers 
73759a7c613SBrian Somers 			if (verbose)
738f9b06d5cSBrian Somers 				printf (" dropped.\n");
73959a7c613SBrian Somers 
74022c62477SPoul-Henning Kamp 			if (mip->logDropped)
74159a7c613SBrian Somers 				SyslogPacket (ip, LOG_WARNING, "denied");
74259a7c613SBrian Somers 
743f9b06d5cSBrian Somers 			return;
744f9b06d5cSBrian Somers 		}
74524084f9bSBrian Somers 	}
74624084f9bSBrian Somers /*
74724084f9bSBrian Somers  * Length might have changed during aliasing.
74824084f9bSBrian Somers  */
74924084f9bSBrian Somers 	bytes = ntohs (ip->ip_len);
75024084f9bSBrian Somers /*
75124084f9bSBrian Somers  * Update alias overhead size for outgoing packets.
75224084f9bSBrian Somers  */
75359a7c613SBrian Somers 	if (direction == OUTPUT &&
75422c62477SPoul-Henning Kamp 	    bytes - origBytes > mip->aliasOverhead)
75522c62477SPoul-Henning Kamp 		mip->aliasOverhead = bytes - origBytes;
75624084f9bSBrian Somers 
75724084f9bSBrian Somers 	if (verbose) {
75824084f9bSBrian Somers 
75924084f9bSBrian Somers /*
76024084f9bSBrian Somers  * Print addresses after aliasing.
76124084f9bSBrian Somers  */
76224084f9bSBrian Somers 		printf (" aliased to\n");
76324084f9bSBrian Somers 		printf ("           ");
76424084f9bSBrian Somers 		PrintPacket (ip);
76524084f9bSBrian Somers 		printf ("\n");
76624084f9bSBrian Somers 	}
767fb994b07SBrian Somers 
76824084f9bSBrian Somers /*
76924084f9bSBrian Somers  * Put packet back for processing.
77024084f9bSBrian Somers  */
77124084f9bSBrian Somers 	wrote = sendto (fd,
7723daff242SRuslan Ermilov 		        buf,
7733daff242SRuslan Ermilov 	    		bytes,
77424084f9bSBrian Somers 	    		0,
7753daff242SRuslan Ermilov 	    		(struct sockaddr*) &addr,
7763daff242SRuslan Ermilov 	    		sizeof addr);
77724084f9bSBrian Somers 
7783daff242SRuslan Ermilov 	if (wrote != bytes) {
77924084f9bSBrian Somers 
78024084f9bSBrian Somers 		if (errno == EMSGSIZE) {
78124084f9bSBrian Somers 
7823daff242SRuslan Ermilov 			if (direction == OUTPUT &&
78322c62477SPoul-Henning Kamp 			    mip->ifMTU != -1)
78424084f9bSBrian Somers 				SendNeedFragIcmp (icmpSock,
7853daff242SRuslan Ermilov 						  (struct ip*) buf,
78622c62477SPoul-Henning Kamp 						  mip->ifMTU - mip->aliasOverhead);
78724084f9bSBrian Somers 		}
7883843533eSRuslan Ermilov 		else if (errno == EACCES && logIpfwDenied) {
78924084f9bSBrian Somers 
790d782daf0SJosef Karthauser 			sprintf (msgBuf, "failed to write packet back");
79124084f9bSBrian Somers 			Warn (msgBuf);
79224084f9bSBrian Somers 		}
79324084f9bSBrian Somers 	}
79424084f9bSBrian Somers }
79524084f9bSBrian Somers 
79624084f9bSBrian Somers static void HandleRoutingInfo (int fd)
79724084f9bSBrian Somers {
79824084f9bSBrian Somers 	int			bytes;
79924084f9bSBrian Somers 	struct if_msghdr	ifMsg;
80024084f9bSBrian Somers /*
80124084f9bSBrian Somers  * Get packet from socket.
80224084f9bSBrian Somers  */
80324084f9bSBrian Somers 	bytes = read (fd, &ifMsg, sizeof ifMsg);
80424084f9bSBrian Somers 	if (bytes == -1) {
80524084f9bSBrian Somers 
8060fc81af1SPhilippe Charnier 		Warn ("read from routing socket failed");
80724084f9bSBrian Somers 		return;
80824084f9bSBrian Somers 	}
80924084f9bSBrian Somers 
81024084f9bSBrian Somers 	if (ifMsg.ifm_version != RTM_VERSION) {
81124084f9bSBrian Somers 
8120fc81af1SPhilippe Charnier 		Warn ("unexpected packet read from routing socket");
81324084f9bSBrian Somers 		return;
81424084f9bSBrian Somers 	}
81524084f9bSBrian Somers 
81624084f9bSBrian Somers 	if (verbose)
8176f3dbe5eSRuslan Ermilov 		printf ("Routing message %#x received.\n", ifMsg.ifm_type);
81824084f9bSBrian Somers 
81922c62477SPoul-Henning Kamp 	if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) {
82022c62477SPoul-Henning Kamp 		LIST_FOREACH(mip, &root, list) {
82122c62477SPoul-Henning Kamp 			mla = mip->la;
82222c62477SPoul-Henning Kamp 			if (ifMsg.ifm_index == mip->ifIndex) {
8236f3dbe5eSRuslan Ermilov 				if (verbose)
8246f3dbe5eSRuslan Ermilov 					printf("Interface address/MTU has probably changed.\n");
82522c62477SPoul-Henning Kamp 				mip->assignAliasAddr = 1;
82622c62477SPoul-Henning Kamp 			}
82722c62477SPoul-Henning Kamp 		}
82824084f9bSBrian Somers 	}
8296f3dbe5eSRuslan Ermilov }
83024084f9bSBrian Somers 
83124084f9bSBrian Somers static void PrintPacket (struct ip* ip)
83224084f9bSBrian Somers {
83359a7c613SBrian Somers 	printf ("%s", FormatPacket (ip));
83459a7c613SBrian Somers }
83559a7c613SBrian Somers 
836902cb50aSBrian Somers static void SyslogPacket (struct ip* ip, int priority, const char *label)
83759a7c613SBrian Somers {
83859a7c613SBrian Somers 	syslog (priority, "%s %s", label, FormatPacket (ip));
83959a7c613SBrian Somers }
84059a7c613SBrian Somers 
84159a7c613SBrian Somers static char* FormatPacket (struct ip* ip)
84259a7c613SBrian Somers {
84359a7c613SBrian Somers 	static char	buf[256];
84424084f9bSBrian Somers 	struct tcphdr*	tcphdr;
84559a7c613SBrian Somers 	struct udphdr*	udphdr;
84659a7c613SBrian Somers 	struct icmp*	icmphdr;
84759a7c613SBrian Somers 	char		src[20];
84859a7c613SBrian Somers 	char		dst[20];
84924084f9bSBrian Somers 
85059a7c613SBrian Somers 	strcpy (src, inet_ntoa (ip->ip_src));
85159a7c613SBrian Somers 	strcpy (dst, inet_ntoa (ip->ip_dst));
85259a7c613SBrian Somers 
85359a7c613SBrian Somers 	switch (ip->ip_p) {
85459a7c613SBrian Somers 	case IPPROTO_TCP:
85524084f9bSBrian Somers 		tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
85659a7c613SBrian Somers 		sprintf (buf, "[TCP] %s:%d -> %s:%d",
85759a7c613SBrian Somers 			      src,
85859a7c613SBrian Somers 			      ntohs (tcphdr->th_sport),
85959a7c613SBrian Somers 			      dst,
86059a7c613SBrian Somers 			      ntohs (tcphdr->th_dport));
86159a7c613SBrian Somers 		break;
86224084f9bSBrian Somers 
86359a7c613SBrian Somers 	case IPPROTO_UDP:
86459a7c613SBrian Somers 		udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
86559a7c613SBrian Somers 		sprintf (buf, "[UDP] %s:%d -> %s:%d",
86659a7c613SBrian Somers 			      src,
86759a7c613SBrian Somers 			      ntohs (udphdr->uh_sport),
86859a7c613SBrian Somers 			      dst,
86959a7c613SBrian Somers 			      ntohs (udphdr->uh_dport));
87059a7c613SBrian Somers 		break;
87124084f9bSBrian Somers 
87259a7c613SBrian Somers 	case IPPROTO_ICMP:
87359a7c613SBrian Somers 		icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
874b71e869dSBrian Somers 		sprintf (buf, "[ICMP] %s -> %s %u(%u)",
87559a7c613SBrian Somers 			      src,
87659a7c613SBrian Somers 			      dst,
877b71e869dSBrian Somers 			      icmphdr->icmp_type,
878b71e869dSBrian Somers 			      icmphdr->icmp_code);
87959a7c613SBrian Somers 		break;
88059a7c613SBrian Somers 
88159a7c613SBrian Somers 	default:
88259a7c613SBrian Somers 		sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
88359a7c613SBrian Somers 		break;
88459a7c613SBrian Somers 	}
88559a7c613SBrian Somers 
88659a7c613SBrian Somers 	return buf;
88724084f9bSBrian Somers }
88824084f9bSBrian Somers 
8890afb958bSMaxim Sobolev static int
8904c04fa4cSRuslan Ermilov SetAliasAddressFromIfName(const char *ifn)
89124084f9bSBrian Somers {
8924c04fa4cSRuslan Ermilov 	size_t needed;
8934c04fa4cSRuslan Ermilov 	int mib[6];
8944c04fa4cSRuslan Ermilov 	char *buf, *lim, *next;
8954c04fa4cSRuslan Ermilov 	struct if_msghdr *ifm;
8964c04fa4cSRuslan Ermilov 	struct ifa_msghdr *ifam;
8974c04fa4cSRuslan Ermilov 	struct sockaddr_dl *sdl;
8984c04fa4cSRuslan Ermilov 	struct sockaddr_in *sin;
89924084f9bSBrian Somers 
9004c04fa4cSRuslan Ermilov 	mib[0] = CTL_NET;
9014c04fa4cSRuslan Ermilov 	mib[1] = PF_ROUTE;
9024c04fa4cSRuslan Ermilov 	mib[2] = 0;
9034c04fa4cSRuslan Ermilov 	mib[3] = AF_INET;	/* Only IP addresses please */
9044c04fa4cSRuslan Ermilov 	mib[4] = NET_RT_IFLIST;
9054c04fa4cSRuslan Ermilov 	mib[5] = 0;		/* ifIndex??? */
90624084f9bSBrian Somers /*
90724084f9bSBrian Somers  * Get interface data.
90824084f9bSBrian Somers  */
9094c04fa4cSRuslan Ermilov 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
9104c04fa4cSRuslan Ermilov 		err(1, "iflist-sysctl-estimate");
9114c04fa4cSRuslan Ermilov 	if ((buf = malloc(needed)) == NULL)
9124c04fa4cSRuslan Ermilov 		errx(1, "malloc failed");
913ec95e4c2SBrian Somers 	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1 && errno != ENOMEM)
9144c04fa4cSRuslan Ermilov 		err(1, "iflist-sysctl-get");
9154c04fa4cSRuslan Ermilov 	lim = buf + needed;
91624084f9bSBrian Somers /*
91724084f9bSBrian Somers  * Loop through interfaces until one with
91824084f9bSBrian Somers  * given name is found. This is done to
91924084f9bSBrian Somers  * find correct interface index for routing
92024084f9bSBrian Somers  * message processing.
92124084f9bSBrian Somers  */
92222c62477SPoul-Henning Kamp 	mip->ifIndex	= 0;
9234c04fa4cSRuslan Ermilov 	next = buf;
9244c04fa4cSRuslan Ermilov 	while (next < lim) {
9254c04fa4cSRuslan Ermilov 		ifm = (struct if_msghdr *)next;
9264c04fa4cSRuslan Ermilov 		next += ifm->ifm_msglen;
9274c04fa4cSRuslan Ermilov 		if (ifm->ifm_version != RTM_VERSION) {
9284c04fa4cSRuslan Ermilov 			if (verbose)
9294c04fa4cSRuslan Ermilov 				warnx("routing message version %d "
9304c04fa4cSRuslan Ermilov 				      "not understood", ifm->ifm_version);
9314c04fa4cSRuslan Ermilov 			continue;
9324c04fa4cSRuslan Ermilov 		}
9334c04fa4cSRuslan Ermilov 		if (ifm->ifm_type == RTM_IFINFO) {
9344c04fa4cSRuslan Ermilov 			sdl = (struct sockaddr_dl *)(ifm + 1);
9354c04fa4cSRuslan Ermilov 			if (strlen(ifn) == sdl->sdl_nlen &&
9364c04fa4cSRuslan Ermilov 			    strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
93722c62477SPoul-Henning Kamp 				mip->ifIndex = ifm->ifm_index;
93822c62477SPoul-Henning Kamp 				mip->ifMTU = ifm->ifm_data.ifi_mtu;
93924084f9bSBrian Somers 				break;
94024084f9bSBrian Somers 			}
94124084f9bSBrian Somers 		}
94224084f9bSBrian Somers 	}
94322c62477SPoul-Henning Kamp 	if (!mip->ifIndex)
9444c04fa4cSRuslan Ermilov 		errx(1, "unknown interface name %s", ifn);
94524084f9bSBrian Somers /*
94624084f9bSBrian Somers  * Get interface address.
94724084f9bSBrian Somers  */
9484c04fa4cSRuslan Ermilov 	sin = NULL;
9494c04fa4cSRuslan Ermilov 	while (next < lim) {
9504c04fa4cSRuslan Ermilov 		ifam = (struct ifa_msghdr *)next;
9514c04fa4cSRuslan Ermilov 		next += ifam->ifam_msglen;
9524c04fa4cSRuslan Ermilov 		if (ifam->ifam_version != RTM_VERSION) {
9534c04fa4cSRuslan Ermilov 			if (verbose)
9544c04fa4cSRuslan Ermilov 				warnx("routing message version %d "
9554c04fa4cSRuslan Ermilov 				      "not understood", ifam->ifam_version);
9564c04fa4cSRuslan Ermilov 			continue;
9574c04fa4cSRuslan Ermilov 		}
9584c04fa4cSRuslan Ermilov 		if (ifam->ifam_type != RTM_NEWADDR)
9594c04fa4cSRuslan Ermilov 			break;
9604c04fa4cSRuslan Ermilov 		if (ifam->ifam_addrs & RTA_IFA) {
9614c04fa4cSRuslan Ermilov 			int i;
9624c04fa4cSRuslan Ermilov 			char *cp = (char *)(ifam + 1);
96324084f9bSBrian Somers 
9644c04fa4cSRuslan Ermilov 			for (i = 1; i < RTA_IFA; i <<= 1)
9654c04fa4cSRuslan Ermilov 				if (ifam->ifam_addrs & i)
9660b46c085SLuigi Rizzo 					cp += SA_SIZE((struct sockaddr *)cp);
9674c04fa4cSRuslan Ermilov 			if (((struct sockaddr *)cp)->sa_family == AF_INET) {
9684c04fa4cSRuslan Ermilov 				sin = (struct sockaddr_in *)cp;
9694c04fa4cSRuslan Ermilov 				break;
9704c04fa4cSRuslan Ermilov 			}
9714c04fa4cSRuslan Ermilov 		}
9724c04fa4cSRuslan Ermilov 	}
9730afb958bSMaxim Sobolev 	if (sin == NULL) {
9740afb958bSMaxim Sobolev 		warnx("%s: cannot get interface address", ifn);
9750afb958bSMaxim Sobolev 		free(buf);
97674def44dSMaxim Sobolev 		return EAGAIN;
9770afb958bSMaxim Sobolev 	}
9784c04fa4cSRuslan Ermilov 
97922c62477SPoul-Henning Kamp 	LibAliasSetAddress(mla, sin->sin_addr);
98024084f9bSBrian Somers 	syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
98122c62477SPoul-Henning Kamp 	       inet_ntoa(sin->sin_addr), mip->ifMTU);
98224084f9bSBrian Somers 
9834c04fa4cSRuslan Ermilov 	free(buf);
9840afb958bSMaxim Sobolev 
9850afb958bSMaxim Sobolev 	return 0;
98624084f9bSBrian Somers }
98724084f9bSBrian Somers 
988902cb50aSBrian Somers void Quit (const char* msg)
98924084f9bSBrian Somers {
99024084f9bSBrian Somers 	Warn (msg);
99124084f9bSBrian Somers 	exit (1);
99224084f9bSBrian Somers }
99324084f9bSBrian Somers 
994902cb50aSBrian Somers void Warn (const char* msg)
99524084f9bSBrian Somers {
99624084f9bSBrian Somers 	if (background)
99724084f9bSBrian Somers 		syslog (LOG_ALERT, "%s (%m)", msg);
99824084f9bSBrian Somers 	else
99904d06bb6SKris Kennaway 		warn ("%s", msg);
100024084f9bSBrian Somers }
100124084f9bSBrian Somers 
100248ce8ca1SXin LI static void RefreshAddr (int sig __unused)
100324084f9bSBrian Somers {
1004be4f3cd0SPaolo Pisati 	LibAliasRefreshModules();
1005be4f3cd0SPaolo Pisati 	if (mip != NULL && mip->ifName != NULL)
100622c62477SPoul-Henning Kamp 		mip->assignAliasAddr = 1;
100724084f9bSBrian Somers }
100824084f9bSBrian Somers 
100948ce8ca1SXin LI static void InitiateShutdown (int sig __unused)
101024084f9bSBrian Somers {
101124084f9bSBrian Somers /*
101224084f9bSBrian Somers  * Start timer to allow kernel gracefully
101324084f9bSBrian Somers  * shutdown existing connections when system
101424084f9bSBrian Somers  * is shut down.
101524084f9bSBrian Somers  */
1016cd45c931SRuslan Ermilov 	siginterrupt(SIGALRM, 1);
101724084f9bSBrian Somers 	signal (SIGALRM, Shutdown);
101872cbe4adSAlexander Motin 	ualarm(exitDelay*1000, 1000);
101924084f9bSBrian Somers }
102024084f9bSBrian Somers 
102148ce8ca1SXin LI static void Shutdown (int sig __unused)
102224084f9bSBrian Somers {
102324084f9bSBrian Somers 	running = 0;
102424084f9bSBrian Somers }
102524084f9bSBrian Somers 
102624084f9bSBrian Somers /*
102724084f9bSBrian Somers  * Different options recognized by this program.
102824084f9bSBrian Somers  */
102924084f9bSBrian Somers 
103024084f9bSBrian Somers enum Option {
103124084f9bSBrian Somers 
103222c62477SPoul-Henning Kamp 	LibAliasOption,
103322c62477SPoul-Henning Kamp 	Instance,
103424084f9bSBrian Somers 	Verbose,
103524084f9bSBrian Somers 	InPort,
103624084f9bSBrian Somers 	OutPort,
103724084f9bSBrian Somers 	Port,
103822c62477SPoul-Henning Kamp 	GlobalPort,
103924084f9bSBrian Somers 	AliasAddress,
104011c2b3bfSRuslan Ermilov 	TargetAddress,
104124084f9bSBrian Somers 	InterfaceName,
104224084f9bSBrian Somers 	RedirectPort,
10434330006dSRuslan Ermilov 	RedirectProto,
104424084f9bSBrian Somers 	RedirectAddress,
104524084f9bSBrian Somers 	ConfigFile,
104659a7c613SBrian Somers 	DynamicMode,
104759a7c613SBrian Somers 	ProxyRule,
104859a7c613SBrian Somers  	LogDenied,
1049bc4ebb98SRuslan Ermilov  	LogFacility,
105084ef95bdSPoul-Henning Kamp 	PunchFW,
1051b07fbc17SJoe Marcus Clarke 	SkinnyPort,
1052b79840a6SRuslan Ermilov 	LogIpfwDenied,
105372cbe4adSAlexander Motin 	PidFile,
105472cbe4adSAlexander Motin 	ExitDelay
105524084f9bSBrian Somers };
105624084f9bSBrian Somers 
105724084f9bSBrian Somers enum Param {
105824084f9bSBrian Somers 
105924084f9bSBrian Somers 	YesNo,
106024084f9bSBrian Somers 	Numeric,
106124084f9bSBrian Somers 	String,
106224084f9bSBrian Somers 	None,
106324084f9bSBrian Somers 	Address,
106424084f9bSBrian Somers 	Service
106524084f9bSBrian Somers };
106624084f9bSBrian Somers 
106724084f9bSBrian Somers /*
106824084f9bSBrian Somers  * Option information structure (used by ParseOption).
106924084f9bSBrian Somers  */
107024084f9bSBrian Somers 
107124084f9bSBrian Somers struct OptionInfo {
107224084f9bSBrian Somers 
107324084f9bSBrian Somers 	enum Option		type;
107424084f9bSBrian Somers 	int			packetAliasOpt;
107524084f9bSBrian Somers 	enum Param		parm;
1076902cb50aSBrian Somers 	const char*		parmDescription;
1077902cb50aSBrian Somers 	const char*		description;
1078902cb50aSBrian Somers 	const char*		name;
1079902cb50aSBrian Somers 	const char*		shortName;
108024084f9bSBrian Somers };
108124084f9bSBrian Somers 
108224084f9bSBrian Somers /*
108324084f9bSBrian Somers  * Table of known options.
108424084f9bSBrian Somers  */
108524084f9bSBrian Somers 
108624084f9bSBrian Somers static struct OptionInfo optionTable[] = {
108724084f9bSBrian Somers 
108822c62477SPoul-Henning Kamp 	{ LibAliasOption,
108924084f9bSBrian Somers 		PKT_ALIAS_UNREGISTERED_ONLY,
109024084f9bSBrian Somers 		YesNo,
109124084f9bSBrian Somers 		"[yes|no]",
109224084f9bSBrian Somers 		"alias only unregistered addresses",
109324084f9bSBrian Somers 		"unregistered_only",
109424084f9bSBrian Somers 		"u" },
109524084f9bSBrian Somers 
109622c62477SPoul-Henning Kamp 	{ LibAliasOption,
109724084f9bSBrian Somers 		PKT_ALIAS_LOG,
109824084f9bSBrian Somers 		YesNo,
109924084f9bSBrian Somers 		"[yes|no]",
110024084f9bSBrian Somers 		"enable logging",
110124084f9bSBrian Somers 		"log",
110224084f9bSBrian Somers 		"l" },
110324084f9bSBrian Somers 
110422c62477SPoul-Henning Kamp 	{ LibAliasOption,
110559a7c613SBrian Somers 		PKT_ALIAS_PROXY_ONLY,
110659a7c613SBrian Somers 		YesNo,
110759a7c613SBrian Somers 		"[yes|no]",
110859a7c613SBrian Somers 		"proxy only",
110959a7c613SBrian Somers 		"proxy_only",
111059a7c613SBrian Somers 		NULL },
111159a7c613SBrian Somers 
111222c62477SPoul-Henning Kamp 	{ LibAliasOption,
111359a7c613SBrian Somers 		PKT_ALIAS_REVERSE,
111459a7c613SBrian Somers 		YesNo,
111559a7c613SBrian Somers 		"[yes|no]",
111659a7c613SBrian Somers 		"operate in reverse mode",
111759a7c613SBrian Somers 		"reverse",
111859a7c613SBrian Somers 		NULL },
111959a7c613SBrian Somers 
112022c62477SPoul-Henning Kamp 	{ LibAliasOption,
112124084f9bSBrian Somers 		PKT_ALIAS_DENY_INCOMING,
112224084f9bSBrian Somers 		YesNo,
112324084f9bSBrian Somers 		"[yes|no]",
112424084f9bSBrian Somers 		"allow incoming connections",
112524084f9bSBrian Somers 		"deny_incoming",
112624084f9bSBrian Somers 		"d" },
112724084f9bSBrian Somers 
112822c62477SPoul-Henning Kamp 	{ LibAliasOption,
112924084f9bSBrian Somers 		PKT_ALIAS_USE_SOCKETS,
113024084f9bSBrian Somers 		YesNo,
113124084f9bSBrian Somers 		"[yes|no]",
113224084f9bSBrian Somers 		"use sockets to inhibit port conflict",
113324084f9bSBrian Somers 		"use_sockets",
113424084f9bSBrian Somers 		"s" },
113524084f9bSBrian Somers 
113622c62477SPoul-Henning Kamp 	{ LibAliasOption,
113724084f9bSBrian Somers 		PKT_ALIAS_SAME_PORTS,
113824084f9bSBrian Somers 		YesNo,
113924084f9bSBrian Somers 		"[yes|no]",
114024084f9bSBrian Somers 		"try to keep original port numbers for connections",
114124084f9bSBrian Somers 		"same_ports",
114224084f9bSBrian Somers 		"m" },
114324084f9bSBrian Somers 
114424084f9bSBrian Somers 	{ Verbose,
114524084f9bSBrian Somers 		0,
114624084f9bSBrian Somers 		YesNo,
114724084f9bSBrian Somers 		"[yes|no]",
114824084f9bSBrian Somers 		"verbose mode, dump packet information",
114924084f9bSBrian Somers 		"verbose",
115024084f9bSBrian Somers 		"v" },
115124084f9bSBrian Somers 
115224084f9bSBrian Somers 	{ DynamicMode,
115324084f9bSBrian Somers 		0,
115424084f9bSBrian Somers 		YesNo,
115524084f9bSBrian Somers 		"[yes|no]",
115624084f9bSBrian Somers 		"dynamic mode, automatically detect interface address changes",
115724084f9bSBrian Somers 		"dynamic",
115824084f9bSBrian Somers 		NULL },
115924084f9bSBrian Somers 
116024084f9bSBrian Somers 	{ InPort,
116124084f9bSBrian Somers 		0,
116224084f9bSBrian Somers 		Service,
116324084f9bSBrian Somers 		"number|service_name",
116424084f9bSBrian Somers 		"set port for incoming packets",
116524084f9bSBrian Somers 		"in_port",
116624084f9bSBrian Somers 		"i" },
116724084f9bSBrian Somers 
116824084f9bSBrian Somers 	{ OutPort,
116924084f9bSBrian Somers 		0,
117024084f9bSBrian Somers 		Service,
117124084f9bSBrian Somers 		"number|service_name",
117224084f9bSBrian Somers 		"set port for outgoing packets",
117324084f9bSBrian Somers 		"out_port",
117424084f9bSBrian Somers 		"o" },
117524084f9bSBrian Somers 
117624084f9bSBrian Somers 	{ Port,
117724084f9bSBrian Somers 		0,
117824084f9bSBrian Somers 		Service,
117924084f9bSBrian Somers 		"number|service_name",
118024084f9bSBrian Somers 		"set port (defaults to natd/divert)",
118124084f9bSBrian Somers 		"port",
118224084f9bSBrian Somers 		"p" },
118324084f9bSBrian Somers 
118422c62477SPoul-Henning Kamp 	{ GlobalPort,
118522c62477SPoul-Henning Kamp 		0,
118622c62477SPoul-Henning Kamp 		Service,
118722c62477SPoul-Henning Kamp 		"number|service_name",
118822c62477SPoul-Henning Kamp 		"set globalport",
118922c62477SPoul-Henning Kamp 		"globalport",
119022c62477SPoul-Henning Kamp 		NULL },
119122c62477SPoul-Henning Kamp 
119224084f9bSBrian Somers 	{ AliasAddress,
119324084f9bSBrian Somers 		0,
119424084f9bSBrian Somers 		Address,
119524084f9bSBrian Somers 		"x.x.x.x",
119624084f9bSBrian Somers 		"address to use for aliasing",
119724084f9bSBrian Somers 		"alias_address",
119824084f9bSBrian Somers 		"a" },
119924084f9bSBrian Somers 
120011c2b3bfSRuslan Ermilov 	{ TargetAddress,
120111c2b3bfSRuslan Ermilov 		0,
120211c2b3bfSRuslan Ermilov 		Address,
120311c2b3bfSRuslan Ermilov 		"x.x.x.x",
120411c2b3bfSRuslan Ermilov 		"address to use for incoming sessions",
120511c2b3bfSRuslan Ermilov 		"target_address",
120611c2b3bfSRuslan Ermilov 		"t" },
120711c2b3bfSRuslan Ermilov 
120824084f9bSBrian Somers 	{ InterfaceName,
120924084f9bSBrian Somers 		0,
121024084f9bSBrian Somers 		String,
121124084f9bSBrian Somers 	        "network_if_name",
121224084f9bSBrian Somers 		"take aliasing address from interface",
121324084f9bSBrian Somers 		"interface",
121424084f9bSBrian Somers 		"n" },
121524084f9bSBrian Somers 
121659a7c613SBrian Somers 	{ ProxyRule,
121724084f9bSBrian Somers 		0,
121824084f9bSBrian Somers 		String,
121959a7c613SBrian Somers 	        "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
122059a7c613SBrian Somers 		"a.b.c.d:yyyy",
122159a7c613SBrian Somers 		"add transparent proxying / destination NAT",
122259a7c613SBrian Somers 		"proxy_rule",
122324084f9bSBrian Somers 		NULL },
122424084f9bSBrian Somers 
122524084f9bSBrian Somers 	{ RedirectPort,
122624084f9bSBrian Somers 		0,
122724084f9bSBrian Somers 		String,
1228bd690510SRuslan Ermilov 	        "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
12295d8ee958SBrian Somers 	 	" [remote_addr[:remote_port_range]]",
12305d8ee958SBrian Somers 		"redirect a port (or ports) for incoming traffic",
123124084f9bSBrian Somers 		"redirect_port",
123224084f9bSBrian Somers 		NULL },
123324084f9bSBrian Somers 
12344330006dSRuslan Ermilov 	{ RedirectProto,
12354330006dSRuslan Ermilov 		0,
12364330006dSRuslan Ermilov 		String,
12374330006dSRuslan Ermilov 	        "proto local_addr [public_addr] [remote_addr]",
12384330006dSRuslan Ermilov 		"redirect packets of a given proto",
12394330006dSRuslan Ermilov 		"redirect_proto",
12404330006dSRuslan Ermilov 		NULL },
12414330006dSRuslan Ermilov 
124224084f9bSBrian Somers 	{ RedirectAddress,
124324084f9bSBrian Somers 		0,
124424084f9bSBrian Somers 		String,
1245bd690510SRuslan Ermilov 	        "local_addr[,...] public_addr",
124624084f9bSBrian Somers 		"define mapping between local and public addresses",
124724084f9bSBrian Somers 		"redirect_address",
124824084f9bSBrian Somers 		NULL },
124924084f9bSBrian Somers 
125024084f9bSBrian Somers 	{ ConfigFile,
125124084f9bSBrian Somers 		0,
125224084f9bSBrian Somers 		String,
125324084f9bSBrian Somers 		"file_name",
125424084f9bSBrian Somers 		"read options from configuration file",
125524084f9bSBrian Somers 		"config",
125659a7c613SBrian Somers 		"f" },
125759a7c613SBrian Somers 
125859a7c613SBrian Somers 	{ LogDenied,
125959a7c613SBrian Somers 		0,
126059a7c613SBrian Somers 		YesNo,
126159a7c613SBrian Somers 	        "[yes|no]",
126259a7c613SBrian Somers 		"enable logging of denied incoming packets",
126359a7c613SBrian Somers 		"log_denied",
126459a7c613SBrian Somers 		NULL },
126559a7c613SBrian Somers 
126659a7c613SBrian Somers 	{ LogFacility,
126759a7c613SBrian Somers 		0,
126859a7c613SBrian Somers 		String,
126959a7c613SBrian Somers 	        "facility",
127059a7c613SBrian Somers 		"name of syslog facility to use for logging",
127159a7c613SBrian Somers 		"log_facility",
1272bc4ebb98SRuslan Ermilov 		NULL },
127359a7c613SBrian Somers 
1274bc4ebb98SRuslan Ermilov 	{ PunchFW,
1275bc4ebb98SRuslan Ermilov 		0,
1276bc4ebb98SRuslan Ermilov 		String,
1277bc4ebb98SRuslan Ermilov 	        "basenumber:count",
1278bc4ebb98SRuslan Ermilov 		"punch holes in the firewall for incoming FTP/IRC DCC connections",
1279bc4ebb98SRuslan Ermilov 		"punch_fw",
128084ef95bdSPoul-Henning Kamp 		NULL },
128184ef95bdSPoul-Henning Kamp 
1282b07fbc17SJoe Marcus Clarke 	{ SkinnyPort,
1283b07fbc17SJoe Marcus Clarke 		0,
1284b07fbc17SJoe Marcus Clarke 		String,
1285b07fbc17SJoe Marcus Clarke 		"port",
1286b07fbc17SJoe Marcus Clarke 		"set the TCP port for use with the Skinny Station protocol",
1287b07fbc17SJoe Marcus Clarke 		"skinny_port",
1288b07fbc17SJoe Marcus Clarke 		NULL },
1289b07fbc17SJoe Marcus Clarke 
129084ef95bdSPoul-Henning Kamp 	{ LogIpfwDenied,
129184ef95bdSPoul-Henning Kamp 		0,
129284ef95bdSPoul-Henning Kamp 		YesNo,
129384ef95bdSPoul-Henning Kamp 	        "[yes|no]",
129484ef95bdSPoul-Henning Kamp 		"log packets converted by natd, but denied by ipfw",
129584ef95bdSPoul-Henning Kamp 		"log_ipfw_denied",
129684ef95bdSPoul-Henning Kamp 		NULL },
1297b79840a6SRuslan Ermilov 
1298b79840a6SRuslan Ermilov 	{ PidFile,
1299b79840a6SRuslan Ermilov 		0,
1300b79840a6SRuslan Ermilov 		String,
1301b79840a6SRuslan Ermilov 		"file_name",
1302b79840a6SRuslan Ermilov 		"store PID in an alternate file",
1303b79840a6SRuslan Ermilov 		"pid_file",
1304b79840a6SRuslan Ermilov 		"P" },
130522c62477SPoul-Henning Kamp 	{ Instance,
130622c62477SPoul-Henning Kamp 		0,
130722c62477SPoul-Henning Kamp 		String,
130822c62477SPoul-Henning Kamp 		"instance name",
130922c62477SPoul-Henning Kamp 		"name of aliasing engine instance",
131022c62477SPoul-Henning Kamp 		"instance",
131122c62477SPoul-Henning Kamp 		NULL },
131272cbe4adSAlexander Motin 	{ ExitDelay,
131372cbe4adSAlexander Motin 		0,
131472cbe4adSAlexander Motin 		Numeric,
131572cbe4adSAlexander Motin 		"ms",
131672cbe4adSAlexander Motin 		"delay in ms before daemon exit after signal",
131772cbe4adSAlexander Motin 		"exit_delay",
131872cbe4adSAlexander Motin 		NULL },
131924084f9bSBrian Somers };
132024084f9bSBrian Somers 
1321b0f55af6SRuslan Ermilov static void ParseOption (const char* option, const char* parms)
132224084f9bSBrian Somers {
132324084f9bSBrian Somers 	int			i;
132424084f9bSBrian Somers 	struct OptionInfo*	info;
132524084f9bSBrian Somers 	int			yesNoValue;
132624084f9bSBrian Somers 	int			aliasValue;
132724084f9bSBrian Somers 	int			numValue;
132867a886fbSBrian Somers 	u_short			uNumValue;
1329902cb50aSBrian Somers 	const char*		strValue;
133024084f9bSBrian Somers 	struct in_addr		addrValue;
133124084f9bSBrian Somers 	int			max;
133224084f9bSBrian Somers 	char*			end;
133339893d56SEd Schouten 	const CODE* 		fac_record = NULL;
133424084f9bSBrian Somers /*
133524084f9bSBrian Somers  * Find option from table.
133624084f9bSBrian Somers  */
133724084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
133824084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
133924084f9bSBrian Somers 
134024084f9bSBrian Somers 		if (!strcmp (info->name, option))
134124084f9bSBrian Somers 			break;
134224084f9bSBrian Somers 
134324084f9bSBrian Somers 		if (info->shortName)
134424084f9bSBrian Somers 			if (!strcmp (info->shortName, option))
134524084f9bSBrian Somers 				break;
134624084f9bSBrian Somers 	}
134724084f9bSBrian Somers 
134824084f9bSBrian Somers 	if (i >= max) {
134924084f9bSBrian Somers 
13500fc81af1SPhilippe Charnier 		warnx ("unknown option %s", option);
135124084f9bSBrian Somers 		Usage ();
135224084f9bSBrian Somers 	}
135324084f9bSBrian Somers 
135467a886fbSBrian Somers 	uNumValue	= 0;
135524084f9bSBrian Somers 	yesNoValue	= 0;
135624084f9bSBrian Somers 	numValue	= 0;
135724084f9bSBrian Somers 	strValue	= NULL;
135824084f9bSBrian Somers /*
135924084f9bSBrian Somers  * Check parameters.
136024084f9bSBrian Somers  */
136124084f9bSBrian Somers 	switch (info->parm) {
136224084f9bSBrian Somers 	case YesNo:
136324084f9bSBrian Somers 		if (!parms)
136424084f9bSBrian Somers 			parms = "yes";
136524084f9bSBrian Somers 
136624084f9bSBrian Somers 		if (!strcmp (parms, "yes"))
136724084f9bSBrian Somers 			yesNoValue = 1;
136824084f9bSBrian Somers 		else
136924084f9bSBrian Somers 			if (!strcmp (parms, "no"))
137024084f9bSBrian Somers 				yesNoValue = 0;
13710fc81af1SPhilippe Charnier 			else
13720fc81af1SPhilippe Charnier 				errx (1, "%s needs yes/no parameter", option);
137324084f9bSBrian Somers 		break;
137424084f9bSBrian Somers 
137524084f9bSBrian Somers 	case Service:
13760fc81af1SPhilippe Charnier 		if (!parms)
137767a886fbSBrian Somers 			errx (1, "%s needs service name or "
137867a886fbSBrian Somers 				 "port number parameter",
137967a886fbSBrian Somers 				 option);
138024084f9bSBrian Somers 
138167a886fbSBrian Somers 		uNumValue = StrToPort (parms, "divert");
138224084f9bSBrian Somers 		break;
138324084f9bSBrian Somers 
138424084f9bSBrian Somers 	case Numeric:
138524084f9bSBrian Somers 		if (parms)
138624084f9bSBrian Somers 			numValue = strtol (parms, &end, 10);
138724084f9bSBrian Somers 		else
1388902cb50aSBrian Somers 			end = NULL;
138924084f9bSBrian Somers 
13900fc81af1SPhilippe Charnier 		if (end == parms)
13910fc81af1SPhilippe Charnier 			errx (1, "%s needs numeric parameter", option);
139224084f9bSBrian Somers 		break;
139324084f9bSBrian Somers 
139424084f9bSBrian Somers 	case String:
139524084f9bSBrian Somers 		strValue = parms;
13960fc81af1SPhilippe Charnier 		if (!strValue)
13970fc81af1SPhilippe Charnier 			errx (1, "%s needs parameter", option);
139824084f9bSBrian Somers 		break;
139924084f9bSBrian Somers 
140024084f9bSBrian Somers 	case None:
14010fc81af1SPhilippe Charnier 		if (parms)
14020fc81af1SPhilippe Charnier 			errx (1, "%s does not take parameters", option);
140324084f9bSBrian Somers 		break;
140424084f9bSBrian Somers 
140524084f9bSBrian Somers 	case Address:
14060fc81af1SPhilippe Charnier 		if (!parms)
14070fc81af1SPhilippe Charnier 			errx (1, "%s needs address/host parameter", option);
140824084f9bSBrian Somers 
140924084f9bSBrian Somers 		StrToAddr (parms, &addrValue);
141024084f9bSBrian Somers 		break;
141124084f9bSBrian Somers 	}
141224084f9bSBrian Somers 
141324084f9bSBrian Somers 	switch (info->type) {
141422c62477SPoul-Henning Kamp 	case LibAliasOption:
141524084f9bSBrian Somers 
141624084f9bSBrian Somers 		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
141722c62477SPoul-Henning Kamp 		LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
141824084f9bSBrian Somers 		break;
141924084f9bSBrian Somers 
142024084f9bSBrian Somers 	case Verbose:
142124084f9bSBrian Somers 		verbose = yesNoValue;
142224084f9bSBrian Somers 		break;
142324084f9bSBrian Somers 
142424084f9bSBrian Somers 	case DynamicMode:
142524084f9bSBrian Somers 		dynamicMode = yesNoValue;
142624084f9bSBrian Somers 		break;
142724084f9bSBrian Somers 
142824084f9bSBrian Somers 	case InPort:
142922c62477SPoul-Henning Kamp 		mip->inPort = uNumValue;
143024084f9bSBrian Somers 		break;
143124084f9bSBrian Somers 
143224084f9bSBrian Somers 	case OutPort:
143322c62477SPoul-Henning Kamp 		mip->outPort = uNumValue;
143424084f9bSBrian Somers 		break;
143524084f9bSBrian Somers 
143624084f9bSBrian Somers 	case Port:
143722c62477SPoul-Henning Kamp 		mip->inOutPort = uNumValue;
143822c62477SPoul-Henning Kamp 		break;
143922c62477SPoul-Henning Kamp 
144022c62477SPoul-Henning Kamp 	case GlobalPort:
144122c62477SPoul-Henning Kamp 		globalPort = uNumValue;
144224084f9bSBrian Somers 		break;
144324084f9bSBrian Somers 
144424084f9bSBrian Somers 	case AliasAddress:
144522c62477SPoul-Henning Kamp 		memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
144624084f9bSBrian Somers 		break;
144724084f9bSBrian Somers 
144811c2b3bfSRuslan Ermilov 	case TargetAddress:
144922c62477SPoul-Henning Kamp 		LibAliasSetTarget(mla, addrValue);
145011c2b3bfSRuslan Ermilov 		break;
145111c2b3bfSRuslan Ermilov 
145224084f9bSBrian Somers 	case RedirectPort:
145324084f9bSBrian Somers 		SetupPortRedirect (strValue);
145424084f9bSBrian Somers 		break;
145524084f9bSBrian Somers 
14564330006dSRuslan Ermilov 	case RedirectProto:
14574330006dSRuslan Ermilov 		SetupProtoRedirect(strValue);
14584330006dSRuslan Ermilov 		break;
14594330006dSRuslan Ermilov 
146024084f9bSBrian Somers 	case RedirectAddress:
146124084f9bSBrian Somers 		SetupAddressRedirect (strValue);
146224084f9bSBrian Somers 		break;
146324084f9bSBrian Somers 
146459a7c613SBrian Somers 	case ProxyRule:
146522c62477SPoul-Henning Kamp 		LibAliasProxyRule (mla, strValue);
146659a7c613SBrian Somers 		break;
146759a7c613SBrian Somers 
146824084f9bSBrian Somers 	case InterfaceName:
146922c62477SPoul-Henning Kamp 		if (mip->ifName)
147022c62477SPoul-Henning Kamp 			free (mip->ifName);
147124084f9bSBrian Somers 
147222c62477SPoul-Henning Kamp 		mip->ifName = strdup (strValue);
147324084f9bSBrian Somers 		break;
147424084f9bSBrian Somers 
147524084f9bSBrian Somers 	case ConfigFile:
147624084f9bSBrian Somers 		ReadConfigFile (strValue);
147724084f9bSBrian Somers 		break;
147859a7c613SBrian Somers 
147959a7c613SBrian Somers 	case LogDenied:
148022c62477SPoul-Henning Kamp 		mip->logDropped = yesNoValue;
148159a7c613SBrian Somers 		break;
148259a7c613SBrian Somers 
148359a7c613SBrian Somers 	case LogFacility:
148459a7c613SBrian Somers 
148559a7c613SBrian Somers 		fac_record = facilitynames;
148659a7c613SBrian Somers 		while (fac_record->c_name != NULL) {
148759a7c613SBrian Somers 
148859a7c613SBrian Somers 			if (!strcmp (fac_record->c_name, strValue)) {
148959a7c613SBrian Somers 
149059a7c613SBrian Somers 				logFacility = fac_record->c_val;
149159a7c613SBrian Somers 				break;
149259a7c613SBrian Somers 
149359a7c613SBrian Somers 			}
149459a7c613SBrian Somers 			else
149559a7c613SBrian Somers 				fac_record++;
149659a7c613SBrian Somers 		}
149759a7c613SBrian Somers 
149859a7c613SBrian Somers 		if(fac_record->c_name == NULL)
149959a7c613SBrian Somers 			errx(1, "Unknown log facility name: %s", strValue);
150059a7c613SBrian Somers 
150159a7c613SBrian Somers 		break;
1502bc4ebb98SRuslan Ermilov 
1503bc4ebb98SRuslan Ermilov 	case PunchFW:
1504bc4ebb98SRuslan Ermilov 		SetupPunchFW(strValue);
1505bc4ebb98SRuslan Ermilov 		break;
15063843533eSRuslan Ermilov 
1507b07fbc17SJoe Marcus Clarke 	case SkinnyPort:
1508b07fbc17SJoe Marcus Clarke 		SetupSkinnyPort(strValue);
1509b07fbc17SJoe Marcus Clarke 		break;
1510b07fbc17SJoe Marcus Clarke 
151184ef95bdSPoul-Henning Kamp 	case LogIpfwDenied:
1512*db702c59SEitan Adler 		logIpfwDenied = yesNoValue;
15133843533eSRuslan Ermilov 		break;
1514b79840a6SRuslan Ermilov 
1515b79840a6SRuslan Ermilov 	case PidFile:
1516b79840a6SRuslan Ermilov 		pidName = strdup (strValue);
1517b79840a6SRuslan Ermilov 		break;
151822c62477SPoul-Henning Kamp 	case Instance:
151922c62477SPoul-Henning Kamp 		NewInstance(strValue);
152022c62477SPoul-Henning Kamp 		break;
152172cbe4adSAlexander Motin 	case ExitDelay:
152272cbe4adSAlexander Motin 		if (numValue < 0 || numValue > MAX_EXIT_DELAY)
152372cbe4adSAlexander Motin 			errx(1, "Incorrect exit delay: %d", numValue);
152472cbe4adSAlexander Motin 		exitDelay = numValue;
152572cbe4adSAlexander Motin 		break;
152624084f9bSBrian Somers 	}
152724084f9bSBrian Somers }
152824084f9bSBrian Somers 
1529902cb50aSBrian Somers void ReadConfigFile (const char* fileName)
153024084f9bSBrian Somers {
153124084f9bSBrian Somers 	FILE*	file;
1532d99cc1daSRuslan Ermilov 	char	*buf;
1533d99cc1daSRuslan Ermilov 	size_t	len;
15342e7e7c71SRuslan Ermilov 	char	*ptr, *p;
153524084f9bSBrian Somers 	char*	option;
153624084f9bSBrian Somers 
153724084f9bSBrian Somers 	file = fopen (fileName, "r");
1538d99cc1daSRuslan Ermilov 	if (!file)
1539d99cc1daSRuslan Ermilov 		err(1, "cannot open config file %s", fileName);
154024084f9bSBrian Somers 
1541d99cc1daSRuslan Ermilov 	while ((buf = fgetln(file, &len)) != NULL) {
1542d99cc1daSRuslan Ermilov 		if (buf[len - 1] == '\n')
1543d99cc1daSRuslan Ermilov 			buf[len - 1] = '\0';
1544d99cc1daSRuslan Ermilov 		else
1545d99cc1daSRuslan Ermilov 			errx(1, "config file format error: "
1546d99cc1daSRuslan Ermilov 				"last line should end with newline");
154724084f9bSBrian Somers 
154824084f9bSBrian Somers /*
15492e7e7c71SRuslan Ermilov  * Check for comments, strip off trailing spaces.
155024084f9bSBrian Somers  */
15512e7e7c71SRuslan Ermilov 		if ((ptr = strchr(buf, '#')))
15522e7e7c71SRuslan Ermilov 			*ptr = '\0';
15532e7e7c71SRuslan Ermilov 		for (ptr = buf; isspace(*ptr); ++ptr)
15542e7e7c71SRuslan Ermilov 			continue;
155524084f9bSBrian Somers 		if (*ptr == '\0')
155624084f9bSBrian Somers 			continue;
15572e7e7c71SRuslan Ermilov 		for (p = strchr(buf, '\0'); isspace(*--p);)
15582e7e7c71SRuslan Ermilov 			continue;
15592e7e7c71SRuslan Ermilov 		*++p = '\0';
15602e7e7c71SRuslan Ermilov 
156124084f9bSBrian Somers /*
156224084f9bSBrian Somers  * Extract option name.
156324084f9bSBrian Somers  */
156424084f9bSBrian Somers 		option = ptr;
156524084f9bSBrian Somers 		while (*ptr && !isspace (*ptr))
156624084f9bSBrian Somers 			++ptr;
156724084f9bSBrian Somers 
156824084f9bSBrian Somers 		if (*ptr != '\0') {
156924084f9bSBrian Somers 
157024084f9bSBrian Somers 			*ptr = '\0';
157124084f9bSBrian Somers 			++ptr;
157224084f9bSBrian Somers 		}
157324084f9bSBrian Somers /*
157424084f9bSBrian Somers  * Skip white space between name and parms.
157524084f9bSBrian Somers  */
157624084f9bSBrian Somers 		while (*ptr && isspace (*ptr))
157724084f9bSBrian Somers 			++ptr;
157824084f9bSBrian Somers 
1579b0f55af6SRuslan Ermilov 		ParseOption (option, *ptr ? ptr : NULL);
158024084f9bSBrian Somers 	}
158124084f9bSBrian Somers 
158224084f9bSBrian Somers 	fclose (file);
158324084f9bSBrian Somers }
158424084f9bSBrian Somers 
15857154ce64SEd Schouten static void Usage(void)
158624084f9bSBrian Somers {
158724084f9bSBrian Somers 	int			i;
158824084f9bSBrian Somers 	int			max;
158924084f9bSBrian Somers 	struct OptionInfo*	info;
159024084f9bSBrian Somers 
159124084f9bSBrian Somers 	fprintf (stderr, "Recognized options:\n\n");
159224084f9bSBrian Somers 
159324084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
159424084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
159524084f9bSBrian Somers 
159624084f9bSBrian Somers 		fprintf (stderr, "-%-20s %s\n", info->name,
159724084f9bSBrian Somers 						info->parmDescription);
159824084f9bSBrian Somers 
159924084f9bSBrian Somers 		if (info->shortName)
160024084f9bSBrian Somers 			fprintf (stderr, "-%-20s %s\n", info->shortName,
160124084f9bSBrian Somers 							info->parmDescription);
160224084f9bSBrian Somers 
160324084f9bSBrian Somers 		fprintf (stderr, "      %s\n\n", info->description);
160424084f9bSBrian Somers 	}
160524084f9bSBrian Somers 
160624084f9bSBrian Somers 	exit (1);
160724084f9bSBrian Somers }
160824084f9bSBrian Somers 
1609902cb50aSBrian Somers void SetupPortRedirect (const char* parms)
161024084f9bSBrian Somers {
1611b6365f95SAlexander Motin 	char		*buf;
161224084f9bSBrian Somers 	char*		ptr;
1613bd690510SRuslan Ermilov 	char*		serverPool;
161424084f9bSBrian Somers 	struct in_addr	localAddr;
161524084f9bSBrian Somers 	struct in_addr	publicAddr;
161624084f9bSBrian Somers 	struct in_addr	remoteAddr;
16175d8ee958SBrian Somers 	port_range      portRange;
16185d8ee958SBrian Somers 	u_short         localPort      = 0;
16195d8ee958SBrian Somers 	u_short         publicPort     = 0;
16205d8ee958SBrian Somers 	u_short         remotePort     = 0;
16215d8ee958SBrian Somers 	u_short         numLocalPorts  = 0;
16225d8ee958SBrian Somers 	u_short         numPublicPorts = 0;
16235d8ee958SBrian Somers 	u_short         numRemotePorts = 0;
162424084f9bSBrian Somers 	int		proto;
162524084f9bSBrian Somers 	char*		protoName;
162624084f9bSBrian Somers 	char*		separator;
16275d8ee958SBrian Somers 	int             i;
162848ce8ca1SXin LI 	struct alias_link *aliaslink = NULL;
162924084f9bSBrian Somers 
1630b6365f95SAlexander Motin 	buf = strdup (parms);
1631b6365f95SAlexander Motin 	if (!buf)
1632b6365f95SAlexander Motin 		errx (1, "redirect_port: strdup() failed");
163324084f9bSBrian Somers /*
163424084f9bSBrian Somers  * Extract protocol.
163524084f9bSBrian Somers  */
163624084f9bSBrian Somers 	protoName = strtok (buf, " \t");
16370fc81af1SPhilippe Charnier 	if (!protoName)
16380fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing protocol");
163924084f9bSBrian Somers 
164024084f9bSBrian Somers 	proto = StrToProto (protoName);
164124084f9bSBrian Somers /*
164224084f9bSBrian Somers  * Extract local address.
164324084f9bSBrian Somers  */
164424084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
16450fc81af1SPhilippe Charnier 	if (!ptr)
16460fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing local address");
164724084f9bSBrian Somers 
1648bd690510SRuslan Ermilov 	separator = strchr(ptr, ',');
1649bd690510SRuslan Ermilov 	if (separator) {		/* LSNAT redirection syntax. */
1650bd690510SRuslan Ermilov 		localAddr.s_addr = INADDR_NONE;
1651bd690510SRuslan Ermilov 		localPort = ~0;
1652bd690510SRuslan Ermilov 		numLocalPorts = 1;
1653bd690510SRuslan Ermilov 		serverPool = ptr;
1654bd690510SRuslan Ermilov 	} else {
16555d8ee958SBrian Somers 		if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
16565d8ee958SBrian Somers 			errx (1, "redirect_port: invalid local port range");
16575d8ee958SBrian Somers 
16585d8ee958SBrian Somers 		localPort     = GETLOPORT(portRange);
16595d8ee958SBrian Somers 		numLocalPorts = GETNUMPORTS(portRange);
1660bd690510SRuslan Ermilov 		serverPool = NULL;
1661bd690510SRuslan Ermilov 	}
16625d8ee958SBrian Somers 
166324084f9bSBrian Somers /*
16649c501140SBrian Somers  * Extract public port and optionally address.
166524084f9bSBrian Somers  */
166624084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
16670fc81af1SPhilippe Charnier 	if (!ptr)
16680fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing public port");
166924084f9bSBrian Somers 
167024084f9bSBrian Somers 	separator = strchr (ptr, ':');
16715d8ee958SBrian Somers 	if (separator) {
16725d8ee958SBrian Somers 	        if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
16735d8ee958SBrian Somers 		        errx (1, "redirect_port: invalid public port range");
167424084f9bSBrian Somers 	}
16755d8ee958SBrian Somers 	else {
16765d8ee958SBrian Somers 		publicAddr.s_addr = INADDR_ANY;
16775d8ee958SBrian Somers 		if (StrToPortRange (ptr, protoName, &portRange) != 0)
16785d8ee958SBrian Somers 		        errx (1, "redirect_port: invalid public port range");
16795d8ee958SBrian Somers 	}
16805d8ee958SBrian Somers 
16815d8ee958SBrian Somers 	publicPort     = GETLOPORT(portRange);
16825d8ee958SBrian Somers 	numPublicPorts = GETNUMPORTS(portRange);
168324084f9bSBrian Somers 
168424084f9bSBrian Somers /*
168524084f9bSBrian Somers  * Extract remote address and optionally port.
168624084f9bSBrian Somers  */
168724084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
168824084f9bSBrian Somers 	if (ptr) {
168924084f9bSBrian Somers 		separator = strchr (ptr, ':');
1690ebe70c8fSWarner Losh 		if (separator) {
16915d8ee958SBrian Somers 		        if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
16925d8ee958SBrian Somers 			        errx (1, "redirect_port: invalid remote port range");
1693ebe70c8fSWarner Losh 		} else {
16945d8ee958SBrian Somers 		        SETLOPORT(portRange, 0);
16955d8ee958SBrian Somers 			SETNUMPORTS(portRange, 1);
169624084f9bSBrian Somers 			StrToAddr (ptr, &remoteAddr);
169724084f9bSBrian Somers 		}
169824084f9bSBrian Somers 	}
169924084f9bSBrian Somers 	else {
17005d8ee958SBrian Somers 	        SETLOPORT(portRange, 0);
17015d8ee958SBrian Somers 		SETNUMPORTS(portRange, 1);
170224084f9bSBrian Somers 		remoteAddr.s_addr = INADDR_ANY;
170324084f9bSBrian Somers 	}
170424084f9bSBrian Somers 
17055d8ee958SBrian Somers 	remotePort     = GETLOPORT(portRange);
17065d8ee958SBrian Somers 	numRemotePorts = GETNUMPORTS(portRange);
17075d8ee958SBrian Somers 
17085d8ee958SBrian Somers /*
17095d8ee958SBrian Somers  * Make sure port ranges match up, then add the redirect ports.
17105d8ee958SBrian Somers  */
17115d8ee958SBrian Somers 	if (numLocalPorts != numPublicPorts)
17125d8ee958SBrian Somers 	        errx (1, "redirect_port: port ranges must be equal in size");
17135d8ee958SBrian Somers 
17145d8ee958SBrian Somers 	/* Remote port range is allowed to be '0' which means all ports. */
171529d97436SBrian Somers 	if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
17165d8ee958SBrian Somers 	        errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
17175d8ee958SBrian Somers 
17185d8ee958SBrian Somers 	for (i = 0 ; i < numPublicPorts ; ++i) {
17195d8ee958SBrian Somers 	        /* If remotePort is all ports, set it to 0. */
17205d8ee958SBrian Somers 	        u_short remotePortCopy = remotePort + i;
17215d8ee958SBrian Somers 	        if (numRemotePorts == 1 && remotePort == 0)
17225d8ee958SBrian Somers 		        remotePortCopy = 0;
17235d8ee958SBrian Somers 
172448ce8ca1SXin LI 		aliaslink = LibAliasRedirectPort (mla, localAddr,
17255d8ee958SBrian Somers 						htons(localPort + i),
172624084f9bSBrian Somers 						remoteAddr,
17275d8ee958SBrian Somers 						htons(remotePortCopy),
172824084f9bSBrian Somers 						publicAddr,
17295d8ee958SBrian Somers 						htons(publicPort + i),
173024084f9bSBrian Somers 						proto);
173124084f9bSBrian Somers 	}
1732bd690510SRuslan Ermilov 
1733bd690510SRuslan Ermilov /*
1734bd690510SRuslan Ermilov  * Setup LSNAT server pool.
1735bd690510SRuslan Ermilov  */
173648ce8ca1SXin LI 	if (serverPool != NULL && aliaslink != NULL) {
1737bd690510SRuslan Ermilov 		ptr = strtok(serverPool, ",");
1738bd690510SRuslan Ermilov 		while (ptr != NULL) {
1739bd690510SRuslan Ermilov 			if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1740bd690510SRuslan Ermilov 				errx(1, "redirect_port: invalid local port range");
1741bd690510SRuslan Ermilov 
1742bd690510SRuslan Ermilov 			localPort = GETLOPORT(portRange);
1743bd690510SRuslan Ermilov 			if (GETNUMPORTS(portRange) != 1)
1744bd690510SRuslan Ermilov 				errx(1, "redirect_port: local port must be single in this context");
174548ce8ca1SXin LI 			LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
1746bd690510SRuslan Ermilov 			ptr = strtok(NULL, ",");
1747bd690510SRuslan Ermilov 		}
1748bd690510SRuslan Ermilov 	}
1749b6365f95SAlexander Motin 
1750b6365f95SAlexander Motin 	free (buf);
17515d8ee958SBrian Somers }
175224084f9bSBrian Somers 
17534330006dSRuslan Ermilov void
17544330006dSRuslan Ermilov SetupProtoRedirect(const char* parms)
17554330006dSRuslan Ermilov {
1756b6365f95SAlexander Motin 	char		*buf;
17574330006dSRuslan Ermilov 	char*		ptr;
17584330006dSRuslan Ermilov 	struct in_addr	localAddr;
17594330006dSRuslan Ermilov 	struct in_addr	publicAddr;
17604330006dSRuslan Ermilov 	struct in_addr	remoteAddr;
17614330006dSRuslan Ermilov 	int		proto;
17624330006dSRuslan Ermilov 	char*		protoName;
17634330006dSRuslan Ermilov 	struct protoent *protoent;
17644330006dSRuslan Ermilov 
1765b6365f95SAlexander Motin 	buf = strdup (parms);
1766b6365f95SAlexander Motin 	if (!buf)
1767b6365f95SAlexander Motin 		errx (1, "redirect_port: strdup() failed");
17684330006dSRuslan Ermilov /*
17694330006dSRuslan Ermilov  * Extract protocol.
17704330006dSRuslan Ermilov  */
17714330006dSRuslan Ermilov 	protoName = strtok(buf, " \t");
17724330006dSRuslan Ermilov 	if (!protoName)
17734330006dSRuslan Ermilov 		errx(1, "redirect_proto: missing protocol");
17744330006dSRuslan Ermilov 
17754330006dSRuslan Ermilov 	protoent = getprotobyname(protoName);
17764330006dSRuslan Ermilov 	if (protoent == NULL)
17774330006dSRuslan Ermilov 		errx(1, "redirect_proto: unknown protocol %s", protoName);
17784330006dSRuslan Ermilov 	else
17794330006dSRuslan Ermilov 		proto = protoent->p_proto;
17804330006dSRuslan Ermilov /*
17814330006dSRuslan Ermilov  * Extract local address.
17824330006dSRuslan Ermilov  */
17834330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
17844330006dSRuslan Ermilov 	if (!ptr)
17854330006dSRuslan Ermilov 		errx(1, "redirect_proto: missing local address");
17864330006dSRuslan Ermilov 	else
17874330006dSRuslan Ermilov 		StrToAddr(ptr, &localAddr);
17884330006dSRuslan Ermilov /*
17894330006dSRuslan Ermilov  * Extract optional public address.
17904330006dSRuslan Ermilov  */
17914330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
17924330006dSRuslan Ermilov 	if (ptr)
17934330006dSRuslan Ermilov 		StrToAddr(ptr, &publicAddr);
17944330006dSRuslan Ermilov 	else
17954330006dSRuslan Ermilov 		publicAddr.s_addr = INADDR_ANY;
17964330006dSRuslan Ermilov /*
17974330006dSRuslan Ermilov  * Extract optional remote address.
17984330006dSRuslan Ermilov  */
17994330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
18004330006dSRuslan Ermilov 	if (ptr)
18014330006dSRuslan Ermilov 		StrToAddr(ptr, &remoteAddr);
18024330006dSRuslan Ermilov 	else
18034330006dSRuslan Ermilov 		remoteAddr.s_addr = INADDR_ANY;
18044330006dSRuslan Ermilov /*
18054330006dSRuslan Ermilov  * Create aliasing link.
18064330006dSRuslan Ermilov  */
180722c62477SPoul-Henning Kamp 	(void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
18084330006dSRuslan Ermilov 				       proto);
1809b6365f95SAlexander Motin 
1810b6365f95SAlexander Motin 	free (buf);
18114330006dSRuslan Ermilov }
18124330006dSRuslan Ermilov 
1813902cb50aSBrian Somers void SetupAddressRedirect (const char* parms)
181424084f9bSBrian Somers {
1815b6365f95SAlexander Motin 	char		*buf;
181624084f9bSBrian Somers 	char*		ptr;
1817bd690510SRuslan Ermilov 	char*		separator;
181824084f9bSBrian Somers 	struct in_addr	localAddr;
181924084f9bSBrian Somers 	struct in_addr	publicAddr;
1820bd690510SRuslan Ermilov 	char*		serverPool;
182148ce8ca1SXin LI 	struct alias_link *aliaslink;
182224084f9bSBrian Somers 
1823b6365f95SAlexander Motin 	buf = strdup (parms);
1824b6365f95SAlexander Motin 	if (!buf)
1825b6365f95SAlexander Motin 		errx (1, "redirect_port: strdup() failed");
182624084f9bSBrian Somers /*
182724084f9bSBrian Somers  * Extract local address.
182824084f9bSBrian Somers  */
182924084f9bSBrian Somers 	ptr = strtok (buf, " \t");
18300fc81af1SPhilippe Charnier 	if (!ptr)
18310fc81af1SPhilippe Charnier 		errx (1, "redirect_address: missing local address");
183224084f9bSBrian Somers 
1833bd690510SRuslan Ermilov 	separator = strchr(ptr, ',');
1834bd690510SRuslan Ermilov 	if (separator) {		/* LSNAT redirection syntax. */
1835bd690510SRuslan Ermilov 		localAddr.s_addr = INADDR_NONE;
1836bd690510SRuslan Ermilov 		serverPool = ptr;
1837bd690510SRuslan Ermilov 	} else {
183824084f9bSBrian Somers 		StrToAddr (ptr, &localAddr);
1839bd690510SRuslan Ermilov 		serverPool = NULL;
1840bd690510SRuslan Ermilov 	}
184124084f9bSBrian Somers /*
184224084f9bSBrian Somers  * Extract public address.
184324084f9bSBrian Somers  */
184424084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
18450fc81af1SPhilippe Charnier 	if (!ptr)
18460fc81af1SPhilippe Charnier 		errx (1, "redirect_address: missing public address");
184724084f9bSBrian Somers 
184824084f9bSBrian Somers 	StrToAddr (ptr, &publicAddr);
184948ce8ca1SXin LI 	aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1850bd690510SRuslan Ermilov 
1851bd690510SRuslan Ermilov /*
1852bd690510SRuslan Ermilov  * Setup LSNAT server pool.
1853bd690510SRuslan Ermilov  */
185448ce8ca1SXin LI 	if (serverPool != NULL && aliaslink != NULL) {
1855bd690510SRuslan Ermilov 		ptr = strtok(serverPool, ",");
1856bd690510SRuslan Ermilov 		while (ptr != NULL) {
1857bd690510SRuslan Ermilov 			StrToAddr(ptr, &localAddr);
185848ce8ca1SXin LI 			LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
1859bd690510SRuslan Ermilov 			ptr = strtok(NULL, ",");
1860bd690510SRuslan Ermilov 		}
1861bd690510SRuslan Ermilov 	}
1862b6365f95SAlexander Motin 
1863b6365f95SAlexander Motin 	free (buf);
186424084f9bSBrian Somers }
186524084f9bSBrian Somers 
1866902cb50aSBrian Somers void StrToAddr (const char* str, struct in_addr* addr)
186724084f9bSBrian Somers {
186824084f9bSBrian Somers 	struct hostent* hp;
186924084f9bSBrian Somers 
187024084f9bSBrian Somers 	if (inet_aton (str, addr))
187124084f9bSBrian Somers 		return;
187224084f9bSBrian Somers 
187324084f9bSBrian Somers 	hp = gethostbyname (str);
18740fc81af1SPhilippe Charnier 	if (!hp)
18750fc81af1SPhilippe Charnier 		errx (1, "unknown host %s", str);
187624084f9bSBrian Somers 
187724084f9bSBrian Somers 	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
187824084f9bSBrian Somers }
187924084f9bSBrian Somers 
1880902cb50aSBrian Somers u_short StrToPort (const char* str, const char* proto)
188124084f9bSBrian Somers {
188267a886fbSBrian Somers 	u_short		port;
188324084f9bSBrian Somers 	struct servent*	sp;
188424084f9bSBrian Somers 	char*		end;
188524084f9bSBrian Somers 
188624084f9bSBrian Somers 	port = strtol (str, &end, 10);
188724084f9bSBrian Somers 	if (end != str)
188827c20503SBrian Somers 		return htons (port);
188924084f9bSBrian Somers 
189024084f9bSBrian Somers 	sp = getservbyname (str, proto);
18910fc81af1SPhilippe Charnier 	if (!sp)
189229e3edccSPhilippe Charnier 		errx (1, "%s/%s: unknown service", str, proto);
189324084f9bSBrian Somers 
189424084f9bSBrian Somers 	return sp->s_port;
189524084f9bSBrian Somers }
189624084f9bSBrian Somers 
1897902cb50aSBrian Somers int StrToPortRange (const char* str, const char* proto, port_range *portRange)
18985d8ee958SBrian Somers {
18995d8ee958SBrian Somers 	char*           sep;
19005d8ee958SBrian Somers 	struct servent*	sp;
19015d8ee958SBrian Somers 	char*		end;
19025d8ee958SBrian Somers 	u_short         loPort;
19035d8ee958SBrian Somers 	u_short         hiPort;
19045d8ee958SBrian Somers 
19055d8ee958SBrian Somers 	/* First see if this is a service, return corresponding port if so. */
19065d8ee958SBrian Somers 	sp = getservbyname (str,proto);
19075d8ee958SBrian Somers 	if (sp) {
19085d8ee958SBrian Somers 	        SETLOPORT(*portRange, ntohs(sp->s_port));
19095d8ee958SBrian Somers 		SETNUMPORTS(*portRange, 1);
19105d8ee958SBrian Somers 		return 0;
19115d8ee958SBrian Somers 	}
19125d8ee958SBrian Somers 
19135d8ee958SBrian Somers 	/* Not a service, see if it's a single port or port range. */
19145d8ee958SBrian Somers 	sep = strchr (str, '-');
19155d8ee958SBrian Somers 	if (sep == NULL) {
19165d8ee958SBrian Somers 	        SETLOPORT(*portRange, strtol(str, &end, 10));
19175d8ee958SBrian Somers 		if (end != str) {
19185d8ee958SBrian Somers 		        /* Single port. */
19195d8ee958SBrian Somers 		        SETNUMPORTS(*portRange, 1);
19205d8ee958SBrian Somers 			return 0;
19215d8ee958SBrian Somers 		}
19225d8ee958SBrian Somers 
19235d8ee958SBrian Somers 		/* Error in port range field. */
192429e3edccSPhilippe Charnier 		errx (1, "%s/%s: unknown service", str, proto);
19255d8ee958SBrian Somers 	}
19265d8ee958SBrian Somers 
19275d8ee958SBrian Somers 	/* Port range, get the values and sanity check. */
19285d8ee958SBrian Somers 	sscanf (str, "%hu-%hu", &loPort, &hiPort);
19295d8ee958SBrian Somers 	SETLOPORT(*portRange, loPort);
19305d8ee958SBrian Somers 	SETNUMPORTS(*portRange, 0);	/* Error by default */
19315d8ee958SBrian Somers 	if (loPort <= hiPort)
19325d8ee958SBrian Somers 	        SETNUMPORTS(*portRange, hiPort - loPort + 1);
19335d8ee958SBrian Somers 
19345d8ee958SBrian Somers 	if (GETNUMPORTS(*portRange) == 0)
19355d8ee958SBrian Somers 	        errx (1, "invalid port range %s", str);
19365d8ee958SBrian Somers 
19375d8ee958SBrian Somers 	return 0;
19385d8ee958SBrian Somers }
19395d8ee958SBrian Somers 
19405d8ee958SBrian Somers 
1941902cb50aSBrian Somers int StrToProto (const char* str)
194224084f9bSBrian Somers {
194324084f9bSBrian Somers 	if (!strcmp (str, "tcp"))
194424084f9bSBrian Somers 		return IPPROTO_TCP;
194524084f9bSBrian Somers 
194624084f9bSBrian Somers 	if (!strcmp (str, "udp"))
194724084f9bSBrian Somers 		return IPPROTO_UDP;
194824084f9bSBrian Somers 
19490fc81af1SPhilippe Charnier 	errx (1, "unknown protocol %s. Expected tcp or udp", str);
195024084f9bSBrian Somers }
195124084f9bSBrian Somers 
1952902cb50aSBrian Somers int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
195324084f9bSBrian Somers {
195424084f9bSBrian Somers 	char*	ptr;
195524084f9bSBrian Somers 
195624084f9bSBrian Somers 	ptr = strchr (str, ':');
19570fc81af1SPhilippe Charnier 	if (!ptr)
19580fc81af1SPhilippe Charnier 		errx (1, "%s is missing port number", str);
195924084f9bSBrian Somers 
196024084f9bSBrian Somers 	*ptr = '\0';
196124084f9bSBrian Somers 	++ptr;
196224084f9bSBrian Somers 
196324084f9bSBrian Somers 	StrToAddr (str, addr);
19645d8ee958SBrian Somers 	return StrToPortRange (ptr, proto, portRange);
196524084f9bSBrian Somers }
1966bc4ebb98SRuslan Ermilov 
1967bc4ebb98SRuslan Ermilov static void
1968bc4ebb98SRuslan Ermilov SetupPunchFW(const char *strValue)
1969bc4ebb98SRuslan Ermilov {
1970bc4ebb98SRuslan Ermilov 	unsigned int base, num;
1971bc4ebb98SRuslan Ermilov 
1972bc4ebb98SRuslan Ermilov 	if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1973bc4ebb98SRuslan Ermilov 		errx(1, "punch_fw: basenumber:count parameter required");
1974bc4ebb98SRuslan Ermilov 
1975d53fe710SRoman Kurakin 	if (CheckIpfwRulenum(base + num - 1) == -1)
1976d53fe710SRoman Kurakin 		errx(1, "punch_fw: basenumber:count parameter should fit "
1977d53fe710SRoman Kurakin 			"the maximum allowed rule numbers");
1978d53fe710SRoman Kurakin 
197922c62477SPoul-Henning Kamp 	LibAliasSetFWBase(mla, base, num);
198022c62477SPoul-Henning Kamp 	(void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1981bc4ebb98SRuslan Ermilov }
1982b07fbc17SJoe Marcus Clarke 
1983b07fbc17SJoe Marcus Clarke static void
1984b07fbc17SJoe Marcus Clarke SetupSkinnyPort(const char *strValue)
1985b07fbc17SJoe Marcus Clarke {
1986b07fbc17SJoe Marcus Clarke 	unsigned int port;
1987b07fbc17SJoe Marcus Clarke 
1988b07fbc17SJoe Marcus Clarke 	if (sscanf(strValue, "%u", &port) != 1)
1989b07fbc17SJoe Marcus Clarke 		errx(1, "skinny_port: port parameter required");
1990b07fbc17SJoe Marcus Clarke 
199122c62477SPoul-Henning Kamp 	LibAliasSetSkinnyPort(mla, port);
199222c62477SPoul-Henning Kamp }
199322c62477SPoul-Henning Kamp 
199422c62477SPoul-Henning Kamp static void
199522c62477SPoul-Henning Kamp NewInstance(const char *name)
199622c62477SPoul-Henning Kamp {
199722c62477SPoul-Henning Kamp 	struct instance *ip;
199822c62477SPoul-Henning Kamp 
199922c62477SPoul-Henning Kamp 	LIST_FOREACH(ip, &root, list) {
200022c62477SPoul-Henning Kamp 		if (!strcmp(ip->name, name)) {
200122c62477SPoul-Henning Kamp 			mla = ip->la;
200222c62477SPoul-Henning Kamp 			mip = ip;
200322c62477SPoul-Henning Kamp 			return;
200422c62477SPoul-Henning Kamp 		}
200522c62477SPoul-Henning Kamp 	}
200622c62477SPoul-Henning Kamp 	ninstance++;
200722c62477SPoul-Henning Kamp 	ip = calloc(sizeof *ip, 1);
200822c62477SPoul-Henning Kamp 	ip->name = strdup(name);
200922c62477SPoul-Henning Kamp 	ip->la = LibAliasInit (ip->la);
201022c62477SPoul-Henning Kamp 	ip->assignAliasAddr	= 0;
201122c62477SPoul-Henning Kamp 	ip->ifName		= NULL;
201222c62477SPoul-Henning Kamp  	ip->logDropped		= 0;
201322c62477SPoul-Henning Kamp 	ip->inPort		= 0;
201422c62477SPoul-Henning Kamp 	ip->outPort		= 0;
201522c62477SPoul-Henning Kamp 	ip->inOutPort		= 0;
201622c62477SPoul-Henning Kamp 	ip->aliasAddr.s_addr	= INADDR_NONE;
201722c62477SPoul-Henning Kamp 	ip->ifMTU		= -1;
201822c62477SPoul-Henning Kamp 	ip->aliasOverhead	= 12;
201922c62477SPoul-Henning Kamp 	LIST_INSERT_HEAD(&root, ip, list);
202022c62477SPoul-Henning Kamp 	mla = ip->la;
202122c62477SPoul-Henning Kamp 	mip = ip;
2022b07fbc17SJoe Marcus Clarke }
2023d53fe710SRoman Kurakin 
2024d53fe710SRoman Kurakin static int
2025d53fe710SRoman Kurakin CheckIpfwRulenum(unsigned int rnum)
2026d53fe710SRoman Kurakin {
2027d53fe710SRoman Kurakin 	unsigned int default_rule;
2028d53fe710SRoman Kurakin 	size_t len = sizeof(default_rule);
2029d53fe710SRoman Kurakin 
2030d53fe710SRoman Kurakin 	if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len,
2031d53fe710SRoman Kurakin 		NULL, 0) == -1) {
2032d53fe710SRoman Kurakin 		warn("Failed to get the default ipfw rule number, using "
2033d53fe710SRoman Kurakin 		     "default historical value 65535.  The reason was");
2034d53fe710SRoman Kurakin 		default_rule = 65535;
2035d53fe710SRoman Kurakin 	}
2036d53fe710SRoman Kurakin 	if (rnum >= default_rule) {
2037d53fe710SRoman Kurakin 		return -1;
2038d53fe710SRoman Kurakin 	}
2039d53fe710SRoman Kurakin 
2040d53fe710SRoman Kurakin 	return 0;
2041d53fe710SRoman Kurakin }
2042