xref: /freebsd/sbin/natd/natd.c (revision be4f3cd0d9c4f0d7755b1bf24c59ca26c336dccf)
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 
7122c62477SPoul-Henning Kamp static LIST_HEAD(, instance) root = LIST_HEAD_INITIALIZER(&root);
7222c62477SPoul-Henning Kamp 
7322c62477SPoul-Henning Kamp struct libalias *mla;
7422c62477SPoul-Henning Kamp struct instance *mip;
7522c62477SPoul-Henning Kamp int ninstance = 1;
7622c62477SPoul-Henning Kamp 
7724084f9bSBrian Somers /*
7824084f9bSBrian Somers  * Default values for input and output
7924084f9bSBrian Somers  * divert socket ports.
8024084f9bSBrian Somers  */
8124084f9bSBrian Somers 
8224084f9bSBrian Somers #define	DEFAULT_SERVICE	"natd"
8324084f9bSBrian Somers 
8424084f9bSBrian Somers /*
855d8ee958SBrian Somers  * Definition of a port range, and macros to deal with values.
865d8ee958SBrian Somers  * FORMAT:  HI 16-bits == first port in range, 0 == all ports.
875d8ee958SBrian Somers  *          LO 16-bits == number of ports in range
885d8ee958SBrian Somers  * NOTES:   - Port values are not stored in network byte order.
895d8ee958SBrian Somers  */
905d8ee958SBrian Somers 
915d8ee958SBrian Somers typedef u_long port_range;
925d8ee958SBrian Somers 
935d8ee958SBrian Somers #define GETLOPORT(x)     ((x) >> 0x10)
945d8ee958SBrian Somers #define GETNUMPORTS(x)   ((x) & 0x0000ffff)
955d8ee958SBrian Somers #define GETHIPORT(x)     (GETLOPORT((x)) + GETNUMPORTS((x)))
965d8ee958SBrian Somers 
975d8ee958SBrian Somers /* Set y to be the low-port value in port_range variable x. */
985d8ee958SBrian Somers #define SETLOPORT(x,y)   ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
995d8ee958SBrian Somers 
1005d8ee958SBrian Somers /* Set y to be the number of ports in port_range variable x. */
1015d8ee958SBrian Somers #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
1025d8ee958SBrian Somers 
1035d8ee958SBrian Somers /*
10424084f9bSBrian Somers  * Function prototypes.
10524084f9bSBrian Somers  */
10624084f9bSBrian Somers 
10759a7c613SBrian Somers static void	DoAliasing (int fd, int direction);
108902cb50aSBrian Somers static void	DaemonMode (void);
10924084f9bSBrian Somers static void	HandleRoutingInfo (int fd);
110902cb50aSBrian Somers static void	Usage (void);
11159a7c613SBrian Somers static char*	FormatPacket (struct ip*);
11224084f9bSBrian Somers static void	PrintPacket (struct ip*);
113902cb50aSBrian Somers static void	SyslogPacket (struct ip*, int priority, const char *label);
1144c04fa4cSRuslan Ermilov static void	SetAliasAddressFromIfName (const char *ifName);
115902cb50aSBrian Somers static void	InitiateShutdown (int);
116902cb50aSBrian Somers static void	Shutdown (int);
117902cb50aSBrian Somers static void	RefreshAddr (int);
118b0f55af6SRuslan Ermilov static void	ParseOption (const char* option, const char* parms);
119902cb50aSBrian Somers static void	ReadConfigFile (const char* fileName);
120902cb50aSBrian Somers static void	SetupPortRedirect (const char* parms);
1214330006dSRuslan Ermilov static void	SetupProtoRedirect(const char* parms);
122902cb50aSBrian Somers static void	SetupAddressRedirect (const char* parms);
123902cb50aSBrian Somers static void	StrToAddr (const char* str, struct in_addr* addr);
124902cb50aSBrian Somers static u_short  StrToPort (const char* str, const char* proto);
125902cb50aSBrian Somers static int      StrToPortRange (const char* str, const char* proto, port_range *portRange);
126902cb50aSBrian Somers static int 	StrToProto (const char* str);
127902cb50aSBrian Somers static int      StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange);
12824084f9bSBrian Somers static void	ParseArgs (int argc, char** argv);
129bc4ebb98SRuslan Ermilov static void	SetupPunchFW(const char *strValue);
130b07fbc17SJoe Marcus Clarke static void	SetupSkinnyPort(const char *strValue);
13122c62477SPoul-Henning Kamp static void	NewInstance(const char *name);
13222c62477SPoul-Henning Kamp static void	DoGlobal (int fd);
13324084f9bSBrian Somers 
13424084f9bSBrian Somers /*
13524084f9bSBrian Somers  * Globals.
13624084f9bSBrian Somers  */
13724084f9bSBrian Somers 
13824084f9bSBrian Somers static	int			verbose;
13924084f9bSBrian Somers static 	int			background;
14024084f9bSBrian Somers static	int			running;
14159a7c613SBrian Somers static	int			logFacility;
14222c62477SPoul-Henning Kamp 
14322c62477SPoul-Henning Kamp static 	int			dynamicMode;
14422c62477SPoul-Henning Kamp static 	int			icmpSock;
1453843533eSRuslan Ermilov static	int			logIpfwDenied;
14648ce8ca1SXin LI static	const char*		pidName;
14722c62477SPoul-Henning Kamp static	int			routeSock;
14822c62477SPoul-Henning Kamp static	int			globalPort;
14922c62477SPoul-Henning Kamp static	int			divertGlobal;
15024084f9bSBrian Somers 
15124084f9bSBrian Somers int main (int argc, char** argv)
15224084f9bSBrian Somers {
15324084f9bSBrian Somers 	struct sockaddr_in	addr;
15424084f9bSBrian Somers 	fd_set			readMask;
15524084f9bSBrian Somers 	int			fdMax;
15624084f9bSBrian Somers /*
15724084f9bSBrian Somers  * Initialize packet aliasing software.
15824084f9bSBrian Somers  * Done already here to be able to alter option bits
15924084f9bSBrian Somers  * during command line and configuration file processing.
16024084f9bSBrian Somers  */
16122c62477SPoul-Henning Kamp 	NewInstance("default");
16222c62477SPoul-Henning Kamp 
16324084f9bSBrian Somers /*
16424084f9bSBrian Somers  * Parse options.
16524084f9bSBrian Somers  */
16624084f9bSBrian Somers 	verbose 		= 0;
16724084f9bSBrian Somers 	background		= 0;
16824084f9bSBrian Somers 	running			= 1;
16924084f9bSBrian Somers 	dynamicMode		= 0;
17059a7c613SBrian Somers  	logFacility		= LOG_DAEMON;
171c0956cf8SRuslan Ermilov 	logIpfwDenied		= -1;
172b79840a6SRuslan Ermilov 	pidName			= PIDFILE;
17322c62477SPoul-Henning Kamp 	routeSock 		= -1;
17422c62477SPoul-Henning Kamp 	icmpSock 		= -1;
17522c62477SPoul-Henning Kamp 	fdMax	 		= -1;
17622c62477SPoul-Henning Kamp 	divertGlobal		= -1;
17724084f9bSBrian Somers 
17824084f9bSBrian Somers 	ParseArgs (argc, argv);
17924084f9bSBrian Somers /*
180c0956cf8SRuslan Ermilov  * Log ipfw(8) denied packets by default in verbose mode.
181c0956cf8SRuslan Ermilov  */
182c0956cf8SRuslan Ermilov 	if (logIpfwDenied == -1)
183c0956cf8SRuslan Ermilov 		logIpfwDenied = verbose;
184c0956cf8SRuslan Ermilov /*
18559a7c613SBrian Somers  * Open syslog channel.
18659a7c613SBrian Somers  */
1874c04fa4cSRuslan Ermilov 	openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
1884c04fa4cSRuslan Ermilov 		 logFacility);
18922c62477SPoul-Henning Kamp 
19022c62477SPoul-Henning Kamp 	LIST_FOREACH(mip, &root, list) {
19122c62477SPoul-Henning Kamp 		mla = mip->la;
19259a7c613SBrian Somers /*
1933d23e8b8SRuslan Ermilov  * If not doing the transparent proxying only,
1943d23e8b8SRuslan Ermilov  * check that valid aliasing address has been given.
19524084f9bSBrian Somers  */
19622c62477SPoul-Henning Kamp 		if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL &&
19722c62477SPoul-Henning Kamp 		    !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY))
19822c62477SPoul-Henning Kamp 			errx (1, "instance %s: aliasing address not given", mip->name);
19924084f9bSBrian Somers 
20022c62477SPoul-Henning Kamp 		if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL)
20167a886fbSBrian Somers 			errx (1, "both alias address and interface "
20267a886fbSBrian Somers 				 "name are not allowed");
20324084f9bSBrian Somers /*
20424084f9bSBrian Somers  * Check that valid port number is known.
20524084f9bSBrian Somers  */
20622c62477SPoul-Henning Kamp 		if (mip->inPort != 0 || mip->outPort != 0)
20722c62477SPoul-Henning Kamp 			if (mip->inPort == 0 || mip->outPort == 0)
2080fc81af1SPhilippe Charnier 				errx (1, "both input and output ports are required");
20924084f9bSBrian Somers 
21022c62477SPoul-Henning Kamp 		if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0)
211b0f55af6SRuslan Ermilov 			ParseOption ("port", DEFAULT_SERVICE);
21224084f9bSBrian Somers 
21324084f9bSBrian Somers /*
214f9b06d5cSBrian Somers  * Check if ignored packets should be dropped.
215f9b06d5cSBrian Somers  */
21622c62477SPoul-Henning Kamp 		mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0);
21722c62477SPoul-Henning Kamp 		mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
218f9b06d5cSBrian Somers /*
21924084f9bSBrian Somers  * Create divert sockets. Use only one socket if -p was specified
22024084f9bSBrian Somers  * on command line. Otherwise, create separate sockets for
22124084f9bSBrian Somers  * outgoing and incoming connnections.
22224084f9bSBrian Somers  */
22322c62477SPoul-Henning Kamp 		if (mip->inOutPort) {
22424084f9bSBrian Somers 
22522c62477SPoul-Henning Kamp 			mip->divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
22622c62477SPoul-Henning Kamp 			if (mip->divertInOut == -1)
22724084f9bSBrian Somers 				Quit ("Unable to create divert socket.");
22822c62477SPoul-Henning Kamp 			if (mip->divertInOut > fdMax)
22922c62477SPoul-Henning Kamp 				fdMax = mip->divertInOut;
23024084f9bSBrian Somers 
23122c62477SPoul-Henning Kamp 			mip->divertIn  = -1;
23222c62477SPoul-Henning Kamp 			mip->divertOut = -1;
23324084f9bSBrian Somers /*
23424084f9bSBrian Somers  * Bind socket.
23524084f9bSBrian Somers  */
23624084f9bSBrian Somers 
23724084f9bSBrian Somers 			addr.sin_family		= AF_INET;
23824084f9bSBrian Somers 			addr.sin_addr.s_addr	= INADDR_ANY;
23922c62477SPoul-Henning Kamp 			addr.sin_port		= mip->inOutPort;
24024084f9bSBrian Somers 
24122c62477SPoul-Henning Kamp 			if (bind (mip->divertInOut,
24224084f9bSBrian Somers 				  (struct sockaddr*) &addr,
24324084f9bSBrian Somers 				  sizeof addr) == -1)
24424084f9bSBrian Somers 				Quit ("Unable to bind divert socket.");
24524084f9bSBrian Somers 		}
24624084f9bSBrian Somers 		else {
24724084f9bSBrian Somers 
24822c62477SPoul-Henning Kamp 			mip->divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
24922c62477SPoul-Henning Kamp 			if (mip->divertIn == -1)
25024084f9bSBrian Somers 				Quit ("Unable to create incoming divert socket.");
25122c62477SPoul-Henning Kamp 			if (mip->divertIn > fdMax)
25222c62477SPoul-Henning Kamp 				fdMax = mip->divertIn;
25324084f9bSBrian Somers 
25422c62477SPoul-Henning Kamp 
25522c62477SPoul-Henning Kamp 			mip->divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
25622c62477SPoul-Henning Kamp 			if (mip->divertOut == -1)
25724084f9bSBrian Somers 				Quit ("Unable to create outgoing divert socket.");
25822c62477SPoul-Henning Kamp 			if (mip->divertOut > fdMax)
25922c62477SPoul-Henning Kamp 				fdMax = mip->divertOut;
26024084f9bSBrian Somers 
26122c62477SPoul-Henning Kamp 			mip->divertInOut = -1;
26224084f9bSBrian Somers 
26324084f9bSBrian Somers /*
26424084f9bSBrian Somers  * Bind divert sockets.
26524084f9bSBrian Somers  */
26624084f9bSBrian Somers 
26724084f9bSBrian Somers 			addr.sin_family		= AF_INET;
26824084f9bSBrian Somers 			addr.sin_addr.s_addr	= INADDR_ANY;
26922c62477SPoul-Henning Kamp 			addr.sin_port		= mip->inPort;
27024084f9bSBrian Somers 
27122c62477SPoul-Henning Kamp 			if (bind (mip->divertIn,
27224084f9bSBrian Somers 				  (struct sockaddr*) &addr,
27324084f9bSBrian Somers 				  sizeof addr) == -1)
27424084f9bSBrian Somers 				Quit ("Unable to bind incoming divert socket.");
27524084f9bSBrian Somers 
27624084f9bSBrian Somers 			addr.sin_family		= AF_INET;
27724084f9bSBrian Somers 			addr.sin_addr.s_addr	= INADDR_ANY;
27822c62477SPoul-Henning Kamp 			addr.sin_port		= mip->outPort;
27924084f9bSBrian Somers 
28022c62477SPoul-Henning Kamp 			if (bind (mip->divertOut,
28124084f9bSBrian Somers 				  (struct sockaddr*) &addr,
28224084f9bSBrian Somers 				  sizeof addr) == -1)
28324084f9bSBrian Somers 				Quit ("Unable to bind outgoing divert socket.");
28424084f9bSBrian Somers 		}
28524084f9bSBrian Somers /*
286f2da55a2SRuslan Ermilov  * Create routing socket if interface name specified and in dynamic mode.
28724084f9bSBrian Somers  */
28822c62477SPoul-Henning Kamp 		if (mip->ifName) {
289f2da55a2SRuslan Ermilov 			if (dynamicMode) {
29024084f9bSBrian Somers 
29122c62477SPoul-Henning Kamp 				if (routeSock == -1)
29224084f9bSBrian Somers 					routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
29324084f9bSBrian Somers 				if (routeSock == -1)
29424084f9bSBrian Somers 					Quit ("Unable to create routing info socket.");
29522c62477SPoul-Henning Kamp 				if (routeSock > fdMax)
29622c62477SPoul-Henning Kamp 					fdMax = routeSock;
297f2da55a2SRuslan Ermilov 
29822c62477SPoul-Henning Kamp 				mip->assignAliasAddr = 1;
29924084f9bSBrian Somers 			}
30024084f9bSBrian Somers 			else
30122c62477SPoul-Henning Kamp 				SetAliasAddressFromIfName (mip->ifName);
30222c62477SPoul-Henning Kamp 		}
30322c62477SPoul-Henning Kamp 
30422c62477SPoul-Henning Kamp 	}
30522c62477SPoul-Henning Kamp 	if (globalPort) {
30622c62477SPoul-Henning Kamp 
30722c62477SPoul-Henning Kamp 		divertGlobal = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
30822c62477SPoul-Henning Kamp 		if (divertGlobal == -1)
30922c62477SPoul-Henning Kamp 			Quit ("Unable to create divert socket.");
31022c62477SPoul-Henning Kamp 		if (divertGlobal > fdMax)
31122c62477SPoul-Henning Kamp 			fdMax = divertGlobal;
31222c62477SPoul-Henning Kamp 
31322c62477SPoul-Henning Kamp /*
31422c62477SPoul-Henning Kamp * Bind socket.
31522c62477SPoul-Henning Kamp */
31622c62477SPoul-Henning Kamp 
31722c62477SPoul-Henning Kamp 		addr.sin_family		= AF_INET;
31822c62477SPoul-Henning Kamp 		addr.sin_addr.s_addr	= INADDR_ANY;
31922c62477SPoul-Henning Kamp 		addr.sin_port		= globalPort;
32022c62477SPoul-Henning Kamp 
32122c62477SPoul-Henning Kamp 		if (bind (divertGlobal,
32222c62477SPoul-Henning Kamp 			  (struct sockaddr*) &addr,
32322c62477SPoul-Henning Kamp 			  sizeof addr) == -1)
32422c62477SPoul-Henning Kamp 			Quit ("Unable to bind global divert socket.");
325f2da55a2SRuslan Ermilov 	}
32624084f9bSBrian Somers /*
32724084f9bSBrian Somers  * Create socket for sending ICMP messages.
32824084f9bSBrian Somers  */
32924084f9bSBrian Somers 	icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
33024084f9bSBrian Somers 	if (icmpSock == -1)
33124084f9bSBrian Somers 		Quit ("Unable to create ICMP socket.");
332f3d64024SBrian Somers 
333f3d64024SBrian Somers /*
334f3d64024SBrian Somers  * And disable reads for the socket, otherwise it slowly fills
335f3d64024SBrian Somers  * up with received icmps which we do not use.
336f3d64024SBrian Somers  */
337f3d64024SBrian Somers 	shutdown(icmpSock, SHUT_RD);
338f3d64024SBrian Somers 
33924084f9bSBrian Somers /*
34024084f9bSBrian Somers  * Become a daemon unless verbose mode was requested.
34124084f9bSBrian Somers  */
34224084f9bSBrian Somers 	if (!verbose)
34324084f9bSBrian Somers 		DaemonMode ();
34424084f9bSBrian Somers /*
34524084f9bSBrian Somers  * Catch signals to manage shutdown and
34624084f9bSBrian Somers  * refresh of interface address.
34724084f9bSBrian Somers  */
348cd45c931SRuslan Ermilov 	siginterrupt(SIGTERM, 1);
349cd45c931SRuslan Ermilov 	siginterrupt(SIGHUP, 1);
35024084f9bSBrian Somers 	signal (SIGTERM, InitiateShutdown);
35124084f9bSBrian Somers 	signal (SIGHUP, RefreshAddr);
35224084f9bSBrian Somers /*
35324084f9bSBrian Somers  * Set alias address if it has been given.
35424084f9bSBrian Somers  */
35522c62477SPoul-Henning Kamp 	mip = LIST_FIRST(&root);	/* XXX: simon */
35622c62477SPoul-Henning Kamp 	LIST_FOREACH(mip, &root, list) {
35722c62477SPoul-Henning Kamp 		mla = mip->la;
35822c62477SPoul-Henning Kamp 		if (mip->aliasAddr.s_addr != INADDR_NONE)
35922c62477SPoul-Henning Kamp 			LibAliasSetAddress (mla, mip->aliasAddr);
36022c62477SPoul-Henning Kamp 	}
36124084f9bSBrian Somers 
36224084f9bSBrian Somers 	while (running) {
36322c62477SPoul-Henning Kamp 		mip = LIST_FIRST(&root);	/* XXX: simon */
364fb994b07SBrian Somers 
36522c62477SPoul-Henning Kamp 		if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) {
366fb994b07SBrian Somers /*
367fb994b07SBrian Somers  * When using only one socket, just call
368fb994b07SBrian Somers  * DoAliasing repeatedly to process packets.
369fb994b07SBrian Somers  */
37022c62477SPoul-Henning Kamp 			DoAliasing (mip->divertInOut, DONT_KNOW);
371fb994b07SBrian Somers 			continue;
372fb994b07SBrian Somers 		}
37324084f9bSBrian Somers /*
37424084f9bSBrian Somers  * Build read mask from socket descriptors to select.
37524084f9bSBrian Somers  */
37624084f9bSBrian Somers 		FD_ZERO (&readMask);
377fb994b07SBrian Somers /*
3783daff242SRuslan Ermilov  * Check if new packets are available.
379fb994b07SBrian Somers  */
38022c62477SPoul-Henning Kamp 		LIST_FOREACH(mip, &root, list) {
38122c62477SPoul-Henning Kamp 			if (mip->divertIn != -1)
38222c62477SPoul-Henning Kamp 				FD_SET (mip->divertIn, &readMask);
38324084f9bSBrian Somers 
38422c62477SPoul-Henning Kamp 			if (mip->divertOut != -1)
38522c62477SPoul-Henning Kamp 				FD_SET (mip->divertOut, &readMask);
38624084f9bSBrian Somers 
38722c62477SPoul-Henning Kamp 			if (mip->divertInOut != -1)
38822c62477SPoul-Henning Kamp 				FD_SET (mip->divertInOut, &readMask);
38922c62477SPoul-Henning Kamp 		}
390fb994b07SBrian Somers /*
391fb994b07SBrian Somers  * Routing info is processed always.
392fb994b07SBrian Somers  */
39324084f9bSBrian Somers 		if (routeSock != -1)
39424084f9bSBrian Somers 			FD_SET (routeSock, &readMask);
39524084f9bSBrian Somers 
39622c62477SPoul-Henning Kamp 		if (divertGlobal != -1)
39722c62477SPoul-Henning Kamp 			FD_SET (divertGlobal, &readMask);
39822c62477SPoul-Henning Kamp 
39924084f9bSBrian Somers 		if (select (fdMax + 1,
40024084f9bSBrian Somers 			    &readMask,
4013daff242SRuslan Ermilov 			    NULL,
40224084f9bSBrian Somers 			    NULL,
40324084f9bSBrian Somers 			    NULL) == -1) {
40424084f9bSBrian Somers 
40524084f9bSBrian Somers 			if (errno == EINTR)
40624084f9bSBrian Somers 				continue;
40724084f9bSBrian Somers 
40824084f9bSBrian Somers 			Quit ("Select failed.");
40924084f9bSBrian Somers 		}
41024084f9bSBrian Somers 
41122c62477SPoul-Henning Kamp 		if (divertGlobal != -1)
41222c62477SPoul-Henning Kamp 			if (FD_ISSET (divertGlobal, &readMask))
41322c62477SPoul-Henning Kamp 				DoGlobal (divertGlobal);
41422c62477SPoul-Henning Kamp 		LIST_FOREACH(mip, &root, list) {
41522c62477SPoul-Henning Kamp 			mla = mip->la;
41622c62477SPoul-Henning Kamp 			if (mip->divertIn != -1)
41722c62477SPoul-Henning Kamp 				if (FD_ISSET (mip->divertIn, &readMask))
41822c62477SPoul-Henning Kamp 					DoAliasing (mip->divertIn, INPUT);
41924084f9bSBrian Somers 
42022c62477SPoul-Henning Kamp 			if (mip->divertOut != -1)
42122c62477SPoul-Henning Kamp 				if (FD_ISSET (mip->divertOut, &readMask))
42222c62477SPoul-Henning Kamp 					DoAliasing (mip->divertOut, OUTPUT);
42324084f9bSBrian Somers 
42422c62477SPoul-Henning Kamp 			if (mip->divertInOut != -1)
42522c62477SPoul-Henning Kamp 				if (FD_ISSET (mip->divertInOut, &readMask))
42622c62477SPoul-Henning Kamp 					DoAliasing (mip->divertInOut, DONT_KNOW);
42724084f9bSBrian Somers 
42822c62477SPoul-Henning Kamp 		}
42924084f9bSBrian Somers 		if (routeSock != -1)
43024084f9bSBrian Somers 			if (FD_ISSET (routeSock, &readMask))
43124084f9bSBrian Somers 				HandleRoutingInfo (routeSock);
43224084f9bSBrian Somers 	}
43324084f9bSBrian Somers 
43424084f9bSBrian Somers 	if (background)
435b79840a6SRuslan Ermilov 		unlink (pidName);
43624084f9bSBrian Somers 
43724084f9bSBrian Somers 	return 0;
43824084f9bSBrian Somers }
43924084f9bSBrian Somers 
44024084f9bSBrian Somers static void DaemonMode ()
44124084f9bSBrian Somers {
44224084f9bSBrian Somers 	FILE*	pidFile;
44324084f9bSBrian Somers 
44424084f9bSBrian Somers 	daemon (0, 0);
44524084f9bSBrian Somers 	background = 1;
44624084f9bSBrian Somers 
447b79840a6SRuslan Ermilov 	pidFile = fopen (pidName, "w");
44824084f9bSBrian Somers 	if (pidFile) {
44924084f9bSBrian Somers 
45024084f9bSBrian Somers 		fprintf (pidFile, "%d\n", getpid ());
45124084f9bSBrian Somers 		fclose (pidFile);
45224084f9bSBrian Somers 	}
45324084f9bSBrian Somers }
45424084f9bSBrian Somers 
45524084f9bSBrian Somers static void ParseArgs (int argc, char** argv)
45624084f9bSBrian Somers {
45724084f9bSBrian Somers 	int		arg;
45824084f9bSBrian Somers 	char*		opt;
45924084f9bSBrian Somers 	char		parmBuf[256];
46030395bb5SJosef Karthauser 	int		len; /* bounds checking */
46124084f9bSBrian Somers 
46224084f9bSBrian Somers 	for (arg = 1; arg < argc; arg++) {
46324084f9bSBrian Somers 
46424084f9bSBrian Somers 		opt  = argv[arg];
46524084f9bSBrian Somers 		if (*opt != '-') {
46624084f9bSBrian Somers 
4670fc81af1SPhilippe Charnier 			warnx ("invalid option %s", opt);
46824084f9bSBrian Somers 			Usage ();
46924084f9bSBrian Somers 		}
47024084f9bSBrian Somers 
47124084f9bSBrian Somers 		parmBuf[0] = '\0';
47230395bb5SJosef Karthauser 		len = 0;
47324084f9bSBrian Somers 
47424084f9bSBrian Somers 		while (arg < argc - 1) {
47524084f9bSBrian Somers 
47624084f9bSBrian Somers 			if (argv[arg + 1][0] == '-')
47724084f9bSBrian Somers 				break;
47824084f9bSBrian Somers 
47930395bb5SJosef Karthauser 			if (len) {
48030395bb5SJosef Karthauser 				strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
48130395bb5SJosef Karthauser 				len += strlen(parmBuf + len);
48224084f9bSBrian Somers 			}
48324084f9bSBrian Somers 
48430395bb5SJosef Karthauser 			++arg;
48530395bb5SJosef Karthauser 			strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
48630395bb5SJosef Karthauser 			len += strlen(parmBuf + len);
48730395bb5SJosef Karthauser 
48830395bb5SJosef Karthauser 		}
48930395bb5SJosef Karthauser 
490b0f55af6SRuslan Ermilov 		ParseOption (opt + 1, (len ? parmBuf : NULL));
49130395bb5SJosef Karthauser 
49224084f9bSBrian Somers 	}
49324084f9bSBrian Somers }
49424084f9bSBrian Somers 
49522c62477SPoul-Henning Kamp static void DoGlobal (int fd)
49622c62477SPoul-Henning Kamp {
49722c62477SPoul-Henning Kamp 	int			bytes;
49822c62477SPoul-Henning Kamp 	int			origBytes;
49922c62477SPoul-Henning Kamp 	char			buf[IP_MAXPACKET];
50022c62477SPoul-Henning Kamp 	struct sockaddr_in	addr;
50122c62477SPoul-Henning Kamp 	int			wrote;
50248ce8ca1SXin LI 	socklen_t		addrSize;
50322c62477SPoul-Henning Kamp 	struct ip*		ip;
50422c62477SPoul-Henning Kamp 	char			msgBuf[80];
50522c62477SPoul-Henning Kamp 
50622c62477SPoul-Henning Kamp /*
50722c62477SPoul-Henning Kamp  * Get packet from socket.
50822c62477SPoul-Henning Kamp  */
50922c62477SPoul-Henning Kamp 	addrSize  = sizeof addr;
51022c62477SPoul-Henning Kamp 	origBytes = recvfrom (fd,
51122c62477SPoul-Henning Kamp 			      buf,
51222c62477SPoul-Henning Kamp 			      sizeof buf,
51322c62477SPoul-Henning Kamp 			      0,
51422c62477SPoul-Henning Kamp 			      (struct sockaddr*) &addr,
51522c62477SPoul-Henning Kamp 			      &addrSize);
51622c62477SPoul-Henning Kamp 
51722c62477SPoul-Henning Kamp 	if (origBytes == -1) {
51822c62477SPoul-Henning Kamp 
51922c62477SPoul-Henning Kamp 		if (errno != EINTR)
52022c62477SPoul-Henning Kamp 			Warn ("read from divert socket failed");
52122c62477SPoul-Henning Kamp 
52222c62477SPoul-Henning Kamp 		return;
52322c62477SPoul-Henning Kamp 	}
52422c62477SPoul-Henning Kamp 
52522c62477SPoul-Henning Kamp #if 0
52622c62477SPoul-Henning Kamp 	if (mip->assignAliasAddr) {
52722c62477SPoul-Henning Kamp 		SetAliasAddressFromIfName (mip->ifName);
52822c62477SPoul-Henning Kamp 		mip->assignAliasAddr = 0;
52922c62477SPoul-Henning Kamp 	}
53022c62477SPoul-Henning Kamp #endif
53122c62477SPoul-Henning Kamp /*
53222c62477SPoul-Henning Kamp  * This is an IP packet.
53322c62477SPoul-Henning Kamp  */
53422c62477SPoul-Henning Kamp 	ip = (struct ip*) buf;
53522c62477SPoul-Henning Kamp 
53622c62477SPoul-Henning Kamp 	if (verbose) {
53722c62477SPoul-Henning Kamp /*
53822c62477SPoul-Henning Kamp  * Print packet direction and protocol type.
53922c62477SPoul-Henning Kamp  */
54022c62477SPoul-Henning Kamp 		printf ("Glb ");
54122c62477SPoul-Henning Kamp 
54222c62477SPoul-Henning Kamp 		switch (ip->ip_p) {
54322c62477SPoul-Henning Kamp 		case IPPROTO_TCP:
54422c62477SPoul-Henning Kamp 			printf ("[TCP]  ");
54522c62477SPoul-Henning Kamp 			break;
54622c62477SPoul-Henning Kamp 
54722c62477SPoul-Henning Kamp 		case IPPROTO_UDP:
54822c62477SPoul-Henning Kamp 			printf ("[UDP]  ");
54922c62477SPoul-Henning Kamp 			break;
55022c62477SPoul-Henning Kamp 
55122c62477SPoul-Henning Kamp 		case IPPROTO_ICMP:
55222c62477SPoul-Henning Kamp 			printf ("[ICMP] ");
55322c62477SPoul-Henning Kamp 			break;
55422c62477SPoul-Henning Kamp 
55522c62477SPoul-Henning Kamp 		default:
55622c62477SPoul-Henning Kamp 			printf ("[%d]    ", ip->ip_p);
55722c62477SPoul-Henning Kamp 			break;
55822c62477SPoul-Henning Kamp 		}
55922c62477SPoul-Henning Kamp /*
56022c62477SPoul-Henning Kamp  * Print addresses.
56122c62477SPoul-Henning Kamp  */
56222c62477SPoul-Henning Kamp 		PrintPacket (ip);
56322c62477SPoul-Henning Kamp 	}
56422c62477SPoul-Henning Kamp 
56522c62477SPoul-Henning Kamp 	LIST_FOREACH(mip, &root, list) {
56622c62477SPoul-Henning Kamp 		mla = mip->la;
56722c62477SPoul-Henning Kamp 		if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED)
56822c62477SPoul-Henning Kamp 			break;
56922c62477SPoul-Henning Kamp 	}
57022c62477SPoul-Henning Kamp /*
57122c62477SPoul-Henning Kamp  * Length might have changed during aliasing.
57222c62477SPoul-Henning Kamp  */
57322c62477SPoul-Henning Kamp 	bytes = ntohs (ip->ip_len);
57422c62477SPoul-Henning Kamp /*
57522c62477SPoul-Henning Kamp  * Update alias overhead size for outgoing packets.
57622c62477SPoul-Henning Kamp  */
57722c62477SPoul-Henning Kamp 	if (mip != NULL && bytes - origBytes > mip->aliasOverhead)
57822c62477SPoul-Henning Kamp 		mip->aliasOverhead = bytes - origBytes;
57922c62477SPoul-Henning Kamp 
58022c62477SPoul-Henning Kamp 	if (verbose) {
58122c62477SPoul-Henning Kamp 
58222c62477SPoul-Henning Kamp /*
58322c62477SPoul-Henning Kamp  * Print addresses after aliasing.
58422c62477SPoul-Henning Kamp  */
58522c62477SPoul-Henning Kamp 		printf (" aliased to\n");
58622c62477SPoul-Henning Kamp 		printf ("           ");
58722c62477SPoul-Henning Kamp 		PrintPacket (ip);
58822c62477SPoul-Henning Kamp 		printf ("\n");
58922c62477SPoul-Henning Kamp 	}
59022c62477SPoul-Henning Kamp 
59122c62477SPoul-Henning Kamp /*
59222c62477SPoul-Henning Kamp  * Put packet back for processing.
59322c62477SPoul-Henning Kamp  */
59422c62477SPoul-Henning Kamp 	wrote = sendto (fd,
59522c62477SPoul-Henning Kamp 		        buf,
59622c62477SPoul-Henning Kamp 	    		bytes,
59722c62477SPoul-Henning Kamp 	    		0,
59822c62477SPoul-Henning Kamp 	    		(struct sockaddr*) &addr,
59922c62477SPoul-Henning Kamp 	    		sizeof addr);
60022c62477SPoul-Henning Kamp 
60122c62477SPoul-Henning Kamp 	if (wrote != bytes) {
60222c62477SPoul-Henning Kamp 
60322c62477SPoul-Henning Kamp 		if (errno == EMSGSIZE) {
60422c62477SPoul-Henning Kamp 
60522c62477SPoul-Henning Kamp 			if (mip->ifMTU != -1)
60622c62477SPoul-Henning Kamp 				SendNeedFragIcmp (icmpSock,
60722c62477SPoul-Henning Kamp 						  (struct ip*) buf,
60822c62477SPoul-Henning Kamp 						  mip->ifMTU - mip->aliasOverhead);
60922c62477SPoul-Henning Kamp 		}
61022c62477SPoul-Henning Kamp 		else if (errno == EACCES && logIpfwDenied) {
61122c62477SPoul-Henning Kamp 
61222c62477SPoul-Henning Kamp 			sprintf (msgBuf, "failed to write packet back");
61322c62477SPoul-Henning Kamp 			Warn (msgBuf);
61422c62477SPoul-Henning Kamp 		}
61522c62477SPoul-Henning Kamp 	}
61622c62477SPoul-Henning Kamp }
61722c62477SPoul-Henning Kamp 
61822c62477SPoul-Henning Kamp 
61959a7c613SBrian Somers static void DoAliasing (int fd, int direction)
62024084f9bSBrian Somers {
62124084f9bSBrian Somers 	int			bytes;
62224084f9bSBrian Somers 	int			origBytes;
6233daff242SRuslan Ermilov 	char			buf[IP_MAXPACKET];
6243daff242SRuslan Ermilov 	struct sockaddr_in	addr;
6253daff242SRuslan Ermilov 	int			wrote;
626f9b06d5cSBrian Somers 	int			status;
62748ce8ca1SXin LI 	socklen_t		addrSize;
62824084f9bSBrian Somers 	struct ip*		ip;
6293daff242SRuslan Ermilov 	char			msgBuf[80];
63024084f9bSBrian Somers 
63122c62477SPoul-Henning Kamp 	if (mip->assignAliasAddr) {
63224084f9bSBrian Somers 
63322c62477SPoul-Henning Kamp 		SetAliasAddressFromIfName (mip->ifName);
63422c62477SPoul-Henning Kamp 		mip->assignAliasAddr = 0;
63524084f9bSBrian Somers 	}
63624084f9bSBrian Somers /*
63724084f9bSBrian Somers  * Get packet from socket.
63824084f9bSBrian Somers  */
6393daff242SRuslan Ermilov 	addrSize  = sizeof addr;
64024084f9bSBrian Somers 	origBytes = recvfrom (fd,
6413daff242SRuslan Ermilov 			      buf,
6423daff242SRuslan Ermilov 			      sizeof buf,
64324084f9bSBrian Somers 			      0,
6443daff242SRuslan Ermilov 			      (struct sockaddr*) &addr,
64524084f9bSBrian Somers 			      &addrSize);
64624084f9bSBrian Somers 
64724084f9bSBrian Somers 	if (origBytes == -1) {
64824084f9bSBrian Somers 
64924084f9bSBrian Somers 		if (errno != EINTR)
6500fc81af1SPhilippe Charnier 			Warn ("read from divert socket failed");
65124084f9bSBrian Somers 
65224084f9bSBrian Somers 		return;
65324084f9bSBrian Somers 	}
65424084f9bSBrian Somers /*
6559d5abbddSJens Schweikhardt  * This is an IP packet.
65624084f9bSBrian Somers  */
6573daff242SRuslan Ermilov 	ip = (struct ip*) buf;
658ebe70c8fSWarner Losh 	if (direction == DONT_KNOW) {
6593daff242SRuslan Ermilov 		if (addr.sin_addr.s_addr == INADDR_ANY)
66059a7c613SBrian Somers 			direction = OUTPUT;
66159a7c613SBrian Somers 		else
66259a7c613SBrian Somers 			direction = INPUT;
663ebe70c8fSWarner Losh 	}
66424084f9bSBrian Somers 
66524084f9bSBrian Somers 	if (verbose) {
66624084f9bSBrian Somers /*
66724084f9bSBrian Somers  * Print packet direction and protocol type.
66824084f9bSBrian Somers  */
66959a7c613SBrian Somers 		printf (direction == OUTPUT ? "Out " : "In  ");
67022c62477SPoul-Henning Kamp 		if (ninstance > 1)
67148ce8ca1SXin LI 			printf ("{%s}", mip->name);
67224084f9bSBrian Somers 
67324084f9bSBrian Somers 		switch (ip->ip_p) {
67424084f9bSBrian Somers 		case IPPROTO_TCP:
67524084f9bSBrian Somers 			printf ("[TCP]  ");
67624084f9bSBrian Somers 			break;
67724084f9bSBrian Somers 
67824084f9bSBrian Somers 		case IPPROTO_UDP:
67924084f9bSBrian Somers 			printf ("[UDP]  ");
68024084f9bSBrian Somers 			break;
68124084f9bSBrian Somers 
68224084f9bSBrian Somers 		case IPPROTO_ICMP:
68324084f9bSBrian Somers 			printf ("[ICMP] ");
68424084f9bSBrian Somers 			break;
68524084f9bSBrian Somers 
68624084f9bSBrian Somers 		default:
68759a7c613SBrian Somers 			printf ("[%d]    ", ip->ip_p);
68824084f9bSBrian Somers 			break;
68924084f9bSBrian Somers 		}
69024084f9bSBrian Somers /*
69124084f9bSBrian Somers  * Print addresses.
69224084f9bSBrian Somers  */
69324084f9bSBrian Somers 		PrintPacket (ip);
69424084f9bSBrian Somers 	}
69524084f9bSBrian Somers 
69659a7c613SBrian Somers 	if (direction == OUTPUT) {
69724084f9bSBrian Somers /*
69824084f9bSBrian Somers  * Outgoing packets. Do aliasing.
69924084f9bSBrian Somers  */
70022c62477SPoul-Henning Kamp 		LibAliasOut (mla, buf, IP_MAXPACKET);
70124084f9bSBrian Somers 	}
70224084f9bSBrian Somers 	else {
70359a7c613SBrian Somers 
70424084f9bSBrian Somers /*
70524084f9bSBrian Somers  * Do aliasing.
70624084f9bSBrian Somers  */
70722c62477SPoul-Henning Kamp 		status = LibAliasIn (mla, buf, IP_MAXPACKET);
708f9b06d5cSBrian Somers 		if (status == PKT_ALIAS_IGNORED &&
70922c62477SPoul-Henning Kamp 		    mip->dropIgnoredIncoming) {
710f9b06d5cSBrian Somers 
71159a7c613SBrian Somers 			if (verbose)
712f9b06d5cSBrian Somers 				printf (" dropped.\n");
71359a7c613SBrian Somers 
71422c62477SPoul-Henning Kamp 			if (mip->logDropped)
71559a7c613SBrian Somers 				SyslogPacket (ip, LOG_WARNING, "denied");
71659a7c613SBrian Somers 
717f9b06d5cSBrian Somers 			return;
718f9b06d5cSBrian Somers 		}
71924084f9bSBrian Somers 	}
72024084f9bSBrian Somers /*
72124084f9bSBrian Somers  * Length might have changed during aliasing.
72224084f9bSBrian Somers  */
72324084f9bSBrian Somers 	bytes = ntohs (ip->ip_len);
72424084f9bSBrian Somers /*
72524084f9bSBrian Somers  * Update alias overhead size for outgoing packets.
72624084f9bSBrian Somers  */
72759a7c613SBrian Somers 	if (direction == OUTPUT &&
72822c62477SPoul-Henning Kamp 	    bytes - origBytes > mip->aliasOverhead)
72922c62477SPoul-Henning Kamp 		mip->aliasOverhead = bytes - origBytes;
73024084f9bSBrian Somers 
73124084f9bSBrian Somers 	if (verbose) {
73224084f9bSBrian Somers 
73324084f9bSBrian Somers /*
73424084f9bSBrian Somers  * Print addresses after aliasing.
73524084f9bSBrian Somers  */
73624084f9bSBrian Somers 		printf (" aliased to\n");
73724084f9bSBrian Somers 		printf ("           ");
73824084f9bSBrian Somers 		PrintPacket (ip);
73924084f9bSBrian Somers 		printf ("\n");
74024084f9bSBrian Somers 	}
741fb994b07SBrian Somers 
74224084f9bSBrian Somers /*
74324084f9bSBrian Somers  * Put packet back for processing.
74424084f9bSBrian Somers  */
74524084f9bSBrian Somers 	wrote = sendto (fd,
7463daff242SRuslan Ermilov 		        buf,
7473daff242SRuslan Ermilov 	    		bytes,
74824084f9bSBrian Somers 	    		0,
7493daff242SRuslan Ermilov 	    		(struct sockaddr*) &addr,
7503daff242SRuslan Ermilov 	    		sizeof addr);
75124084f9bSBrian Somers 
7523daff242SRuslan Ermilov 	if (wrote != bytes) {
75324084f9bSBrian Somers 
75424084f9bSBrian Somers 		if (errno == EMSGSIZE) {
75524084f9bSBrian Somers 
7563daff242SRuslan Ermilov 			if (direction == OUTPUT &&
75722c62477SPoul-Henning Kamp 			    mip->ifMTU != -1)
75824084f9bSBrian Somers 				SendNeedFragIcmp (icmpSock,
7593daff242SRuslan Ermilov 						  (struct ip*) buf,
76022c62477SPoul-Henning Kamp 						  mip->ifMTU - mip->aliasOverhead);
76124084f9bSBrian Somers 		}
7623843533eSRuslan Ermilov 		else if (errno == EACCES && logIpfwDenied) {
76324084f9bSBrian Somers 
764d782daf0SJosef Karthauser 			sprintf (msgBuf, "failed to write packet back");
76524084f9bSBrian Somers 			Warn (msgBuf);
76624084f9bSBrian Somers 		}
76724084f9bSBrian Somers 	}
76824084f9bSBrian Somers }
76924084f9bSBrian Somers 
77024084f9bSBrian Somers static void HandleRoutingInfo (int fd)
77124084f9bSBrian Somers {
77224084f9bSBrian Somers 	int			bytes;
77324084f9bSBrian Somers 	struct if_msghdr	ifMsg;
77424084f9bSBrian Somers /*
77524084f9bSBrian Somers  * Get packet from socket.
77624084f9bSBrian Somers  */
77724084f9bSBrian Somers 	bytes = read (fd, &ifMsg, sizeof ifMsg);
77824084f9bSBrian Somers 	if (bytes == -1) {
77924084f9bSBrian Somers 
7800fc81af1SPhilippe Charnier 		Warn ("read from routing socket failed");
78124084f9bSBrian Somers 		return;
78224084f9bSBrian Somers 	}
78324084f9bSBrian Somers 
78424084f9bSBrian Somers 	if (ifMsg.ifm_version != RTM_VERSION) {
78524084f9bSBrian Somers 
7860fc81af1SPhilippe Charnier 		Warn ("unexpected packet read from routing socket");
78724084f9bSBrian Somers 		return;
78824084f9bSBrian Somers 	}
78924084f9bSBrian Somers 
79024084f9bSBrian Somers 	if (verbose)
7916f3dbe5eSRuslan Ermilov 		printf ("Routing message %#x received.\n", ifMsg.ifm_type);
79224084f9bSBrian Somers 
79322c62477SPoul-Henning Kamp 	if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) {
79422c62477SPoul-Henning Kamp 		LIST_FOREACH(mip, &root, list) {
79522c62477SPoul-Henning Kamp 			mla = mip->la;
79622c62477SPoul-Henning Kamp 			if (ifMsg.ifm_index == mip->ifIndex) {
7976f3dbe5eSRuslan Ermilov 				if (verbose)
7986f3dbe5eSRuslan Ermilov 					printf("Interface address/MTU has probably changed.\n");
79922c62477SPoul-Henning Kamp 				mip->assignAliasAddr = 1;
80022c62477SPoul-Henning Kamp 			}
80122c62477SPoul-Henning Kamp 		}
80224084f9bSBrian Somers 	}
8036f3dbe5eSRuslan Ermilov }
80424084f9bSBrian Somers 
80524084f9bSBrian Somers static void PrintPacket (struct ip* ip)
80624084f9bSBrian Somers {
80759a7c613SBrian Somers 	printf ("%s", FormatPacket (ip));
80859a7c613SBrian Somers }
80959a7c613SBrian Somers 
810902cb50aSBrian Somers static void SyslogPacket (struct ip* ip, int priority, const char *label)
81159a7c613SBrian Somers {
81259a7c613SBrian Somers 	syslog (priority, "%s %s", label, FormatPacket (ip));
81359a7c613SBrian Somers }
81459a7c613SBrian Somers 
81559a7c613SBrian Somers static char* FormatPacket (struct ip* ip)
81659a7c613SBrian Somers {
81759a7c613SBrian Somers 	static char	buf[256];
81824084f9bSBrian Somers 	struct tcphdr*	tcphdr;
81959a7c613SBrian Somers 	struct udphdr*	udphdr;
82059a7c613SBrian Somers 	struct icmp*	icmphdr;
82159a7c613SBrian Somers 	char		src[20];
82259a7c613SBrian Somers 	char		dst[20];
82324084f9bSBrian Somers 
82459a7c613SBrian Somers 	strcpy (src, inet_ntoa (ip->ip_src));
82559a7c613SBrian Somers 	strcpy (dst, inet_ntoa (ip->ip_dst));
82659a7c613SBrian Somers 
82759a7c613SBrian Somers 	switch (ip->ip_p) {
82859a7c613SBrian Somers 	case IPPROTO_TCP:
82924084f9bSBrian Somers 		tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
83059a7c613SBrian Somers 		sprintf (buf, "[TCP] %s:%d -> %s:%d",
83159a7c613SBrian Somers 			      src,
83259a7c613SBrian Somers 			      ntohs (tcphdr->th_sport),
83359a7c613SBrian Somers 			      dst,
83459a7c613SBrian Somers 			      ntohs (tcphdr->th_dport));
83559a7c613SBrian Somers 		break;
83624084f9bSBrian Somers 
83759a7c613SBrian Somers 	case IPPROTO_UDP:
83859a7c613SBrian Somers 		udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
83959a7c613SBrian Somers 		sprintf (buf, "[UDP] %s:%d -> %s:%d",
84059a7c613SBrian Somers 			      src,
84159a7c613SBrian Somers 			      ntohs (udphdr->uh_sport),
84259a7c613SBrian Somers 			      dst,
84359a7c613SBrian Somers 			      ntohs (udphdr->uh_dport));
84459a7c613SBrian Somers 		break;
84524084f9bSBrian Somers 
84659a7c613SBrian Somers 	case IPPROTO_ICMP:
84759a7c613SBrian Somers 		icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
848b71e869dSBrian Somers 		sprintf (buf, "[ICMP] %s -> %s %u(%u)",
84959a7c613SBrian Somers 			      src,
85059a7c613SBrian Somers 			      dst,
851b71e869dSBrian Somers 			      icmphdr->icmp_type,
852b71e869dSBrian Somers 			      icmphdr->icmp_code);
85359a7c613SBrian Somers 		break;
85459a7c613SBrian Somers 
85559a7c613SBrian Somers 	default:
85659a7c613SBrian Somers 		sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
85759a7c613SBrian Somers 		break;
85859a7c613SBrian Somers 	}
85959a7c613SBrian Somers 
86059a7c613SBrian Somers 	return buf;
86124084f9bSBrian Somers }
86224084f9bSBrian Somers 
8634c04fa4cSRuslan Ermilov static void
8644c04fa4cSRuslan Ermilov SetAliasAddressFromIfName(const char *ifn)
86524084f9bSBrian Somers {
8664c04fa4cSRuslan Ermilov 	size_t needed;
8674c04fa4cSRuslan Ermilov 	int mib[6];
8684c04fa4cSRuslan Ermilov 	char *buf, *lim, *next;
8694c04fa4cSRuslan Ermilov 	struct if_msghdr *ifm;
8704c04fa4cSRuslan Ermilov 	struct ifa_msghdr *ifam;
8714c04fa4cSRuslan Ermilov 	struct sockaddr_dl *sdl;
8724c04fa4cSRuslan Ermilov 	struct sockaddr_in *sin;
87324084f9bSBrian Somers 
8744c04fa4cSRuslan Ermilov 	mib[0] = CTL_NET;
8754c04fa4cSRuslan Ermilov 	mib[1] = PF_ROUTE;
8764c04fa4cSRuslan Ermilov 	mib[2] = 0;
8774c04fa4cSRuslan Ermilov 	mib[3] = AF_INET;	/* Only IP addresses please */
8784c04fa4cSRuslan Ermilov 	mib[4] = NET_RT_IFLIST;
8794c04fa4cSRuslan Ermilov 	mib[5] = 0;		/* ifIndex??? */
88024084f9bSBrian Somers /*
88124084f9bSBrian Somers  * Get interface data.
88224084f9bSBrian Somers  */
8834c04fa4cSRuslan Ermilov 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
8844c04fa4cSRuslan Ermilov 		err(1, "iflist-sysctl-estimate");
8854c04fa4cSRuslan Ermilov 	if ((buf = malloc(needed)) == NULL)
8864c04fa4cSRuslan Ermilov 		errx(1, "malloc failed");
8874c04fa4cSRuslan Ermilov 	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
8884c04fa4cSRuslan Ermilov 		err(1, "iflist-sysctl-get");
8894c04fa4cSRuslan Ermilov 	lim = buf + needed;
89024084f9bSBrian Somers /*
89124084f9bSBrian Somers  * Loop through interfaces until one with
89224084f9bSBrian Somers  * given name is found. This is done to
89324084f9bSBrian Somers  * find correct interface index for routing
89424084f9bSBrian Somers  * message processing.
89524084f9bSBrian Somers  */
89622c62477SPoul-Henning Kamp 	mip->ifIndex	= 0;
8974c04fa4cSRuslan Ermilov 	next = buf;
8984c04fa4cSRuslan Ermilov 	while (next < lim) {
8994c04fa4cSRuslan Ermilov 		ifm = (struct if_msghdr *)next;
9004c04fa4cSRuslan Ermilov 		next += ifm->ifm_msglen;
9014c04fa4cSRuslan Ermilov 		if (ifm->ifm_version != RTM_VERSION) {
9024c04fa4cSRuslan Ermilov 			if (verbose)
9034c04fa4cSRuslan Ermilov 				warnx("routing message version %d "
9044c04fa4cSRuslan Ermilov 				      "not understood", ifm->ifm_version);
9054c04fa4cSRuslan Ermilov 			continue;
9064c04fa4cSRuslan Ermilov 		}
9074c04fa4cSRuslan Ermilov 		if (ifm->ifm_type == RTM_IFINFO) {
9084c04fa4cSRuslan Ermilov 			sdl = (struct sockaddr_dl *)(ifm + 1);
9094c04fa4cSRuslan Ermilov 			if (strlen(ifn) == sdl->sdl_nlen &&
9104c04fa4cSRuslan Ermilov 			    strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
91122c62477SPoul-Henning Kamp 				mip->ifIndex = ifm->ifm_index;
91222c62477SPoul-Henning Kamp 				mip->ifMTU = ifm->ifm_data.ifi_mtu;
91324084f9bSBrian Somers 				break;
91424084f9bSBrian Somers 			}
91524084f9bSBrian Somers 		}
91624084f9bSBrian Somers 	}
91722c62477SPoul-Henning Kamp 	if (!mip->ifIndex)
9184c04fa4cSRuslan Ermilov 		errx(1, "unknown interface name %s", ifn);
91924084f9bSBrian Somers /*
92024084f9bSBrian Somers  * Get interface address.
92124084f9bSBrian Somers  */
9224c04fa4cSRuslan Ermilov 	sin = NULL;
9234c04fa4cSRuslan Ermilov 	while (next < lim) {
9244c04fa4cSRuslan Ermilov 		ifam = (struct ifa_msghdr *)next;
9254c04fa4cSRuslan Ermilov 		next += ifam->ifam_msglen;
9264c04fa4cSRuslan Ermilov 		if (ifam->ifam_version != RTM_VERSION) {
9274c04fa4cSRuslan Ermilov 			if (verbose)
9284c04fa4cSRuslan Ermilov 				warnx("routing message version %d "
9294c04fa4cSRuslan Ermilov 				      "not understood", ifam->ifam_version);
9304c04fa4cSRuslan Ermilov 			continue;
9314c04fa4cSRuslan Ermilov 		}
9324c04fa4cSRuslan Ermilov 		if (ifam->ifam_type != RTM_NEWADDR)
9334c04fa4cSRuslan Ermilov 			break;
9344c04fa4cSRuslan Ermilov 		if (ifam->ifam_addrs & RTA_IFA) {
9354c04fa4cSRuslan Ermilov 			int i;
9364c04fa4cSRuslan Ermilov 			char *cp = (char *)(ifam + 1);
93724084f9bSBrian Somers 
9384c04fa4cSRuslan Ermilov 			for (i = 1; i < RTA_IFA; i <<= 1)
9394c04fa4cSRuslan Ermilov 				if (ifam->ifam_addrs & i)
9400b46c085SLuigi Rizzo 					cp += SA_SIZE((struct sockaddr *)cp);
9414c04fa4cSRuslan Ermilov 			if (((struct sockaddr *)cp)->sa_family == AF_INET) {
9424c04fa4cSRuslan Ermilov 				sin = (struct sockaddr_in *)cp;
9434c04fa4cSRuslan Ermilov 				break;
9444c04fa4cSRuslan Ermilov 			}
9454c04fa4cSRuslan Ermilov 		}
9464c04fa4cSRuslan Ermilov 	}
9474c04fa4cSRuslan Ermilov 	if (sin == NULL)
9484c04fa4cSRuslan Ermilov 		errx(1, "%s: cannot get interface address", ifn);
9494c04fa4cSRuslan Ermilov 
95022c62477SPoul-Henning Kamp 	LibAliasSetAddress(mla, sin->sin_addr);
95124084f9bSBrian Somers 	syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
95222c62477SPoul-Henning Kamp 	       inet_ntoa(sin->sin_addr), mip->ifMTU);
95324084f9bSBrian Somers 
9544c04fa4cSRuslan Ermilov 	free(buf);
95524084f9bSBrian Somers }
95624084f9bSBrian Somers 
957902cb50aSBrian Somers void Quit (const char* msg)
95824084f9bSBrian Somers {
95924084f9bSBrian Somers 	Warn (msg);
96024084f9bSBrian Somers 	exit (1);
96124084f9bSBrian Somers }
96224084f9bSBrian Somers 
963902cb50aSBrian Somers void Warn (const char* msg)
96424084f9bSBrian Somers {
96524084f9bSBrian Somers 	if (background)
96624084f9bSBrian Somers 		syslog (LOG_ALERT, "%s (%m)", msg);
96724084f9bSBrian Somers 	else
96804d06bb6SKris Kennaway 		warn ("%s", msg);
96924084f9bSBrian Somers }
97024084f9bSBrian Somers 
97148ce8ca1SXin LI static void RefreshAddr (int sig __unused)
97224084f9bSBrian Somers {
973be4f3cd0SPaolo Pisati 	LibAliasRefreshModules();
974be4f3cd0SPaolo Pisati 	if (mip != NULL && mip->ifName != NULL)
97522c62477SPoul-Henning Kamp 		mip->assignAliasAddr = 1;
97624084f9bSBrian Somers }
97724084f9bSBrian Somers 
97848ce8ca1SXin LI static void InitiateShutdown (int sig __unused)
97924084f9bSBrian Somers {
98024084f9bSBrian Somers /*
98124084f9bSBrian Somers  * Start timer to allow kernel gracefully
98224084f9bSBrian Somers  * shutdown existing connections when system
98324084f9bSBrian Somers  * is shut down.
98424084f9bSBrian Somers  */
985cd45c931SRuslan Ermilov 	siginterrupt(SIGALRM, 1);
98624084f9bSBrian Somers 	signal (SIGALRM, Shutdown);
98724084f9bSBrian Somers 	alarm (10);
98824084f9bSBrian Somers }
98924084f9bSBrian Somers 
99048ce8ca1SXin LI static void Shutdown (int sig __unused)
99124084f9bSBrian Somers {
99224084f9bSBrian Somers 	running = 0;
99324084f9bSBrian Somers }
99424084f9bSBrian Somers 
99524084f9bSBrian Somers /*
99624084f9bSBrian Somers  * Different options recognized by this program.
99724084f9bSBrian Somers  */
99824084f9bSBrian Somers 
99924084f9bSBrian Somers enum Option {
100024084f9bSBrian Somers 
100122c62477SPoul-Henning Kamp 	LibAliasOption,
100222c62477SPoul-Henning Kamp 	Instance,
100324084f9bSBrian Somers 	Verbose,
100424084f9bSBrian Somers 	InPort,
100524084f9bSBrian Somers 	OutPort,
100624084f9bSBrian Somers 	Port,
100722c62477SPoul-Henning Kamp 	GlobalPort,
100824084f9bSBrian Somers 	AliasAddress,
100911c2b3bfSRuslan Ermilov 	TargetAddress,
101024084f9bSBrian Somers 	InterfaceName,
101124084f9bSBrian Somers 	RedirectPort,
10124330006dSRuslan Ermilov 	RedirectProto,
101324084f9bSBrian Somers 	RedirectAddress,
101424084f9bSBrian Somers 	ConfigFile,
101559a7c613SBrian Somers 	DynamicMode,
101659a7c613SBrian Somers 	ProxyRule,
101759a7c613SBrian Somers  	LogDenied,
1018bc4ebb98SRuslan Ermilov  	LogFacility,
101984ef95bdSPoul-Henning Kamp 	PunchFW,
1020b07fbc17SJoe Marcus Clarke 	SkinnyPort,
1021b79840a6SRuslan Ermilov 	LogIpfwDenied,
1022b79840a6SRuslan Ermilov 	PidFile
102324084f9bSBrian Somers };
102424084f9bSBrian Somers 
102524084f9bSBrian Somers enum Param {
102624084f9bSBrian Somers 
102724084f9bSBrian Somers 	YesNo,
102824084f9bSBrian Somers 	Numeric,
102924084f9bSBrian Somers 	String,
103024084f9bSBrian Somers 	None,
103124084f9bSBrian Somers 	Address,
103224084f9bSBrian Somers 	Service
103324084f9bSBrian Somers };
103424084f9bSBrian Somers 
103524084f9bSBrian Somers /*
103624084f9bSBrian Somers  * Option information structure (used by ParseOption).
103724084f9bSBrian Somers  */
103824084f9bSBrian Somers 
103924084f9bSBrian Somers struct OptionInfo {
104024084f9bSBrian Somers 
104124084f9bSBrian Somers 	enum Option		type;
104224084f9bSBrian Somers 	int			packetAliasOpt;
104324084f9bSBrian Somers 	enum Param		parm;
1044902cb50aSBrian Somers 	const char*		parmDescription;
1045902cb50aSBrian Somers 	const char*		description;
1046902cb50aSBrian Somers 	const char*		name;
1047902cb50aSBrian Somers 	const char*		shortName;
104824084f9bSBrian Somers };
104924084f9bSBrian Somers 
105024084f9bSBrian Somers /*
105124084f9bSBrian Somers  * Table of known options.
105224084f9bSBrian Somers  */
105324084f9bSBrian Somers 
105424084f9bSBrian Somers static struct OptionInfo optionTable[] = {
105524084f9bSBrian Somers 
105622c62477SPoul-Henning Kamp 	{ LibAliasOption,
105724084f9bSBrian Somers 		PKT_ALIAS_UNREGISTERED_ONLY,
105824084f9bSBrian Somers 		YesNo,
105924084f9bSBrian Somers 		"[yes|no]",
106024084f9bSBrian Somers 		"alias only unregistered addresses",
106124084f9bSBrian Somers 		"unregistered_only",
106224084f9bSBrian Somers 		"u" },
106324084f9bSBrian Somers 
106422c62477SPoul-Henning Kamp 	{ LibAliasOption,
106524084f9bSBrian Somers 		PKT_ALIAS_LOG,
106624084f9bSBrian Somers 		YesNo,
106724084f9bSBrian Somers 		"[yes|no]",
106824084f9bSBrian Somers 		"enable logging",
106924084f9bSBrian Somers 		"log",
107024084f9bSBrian Somers 		"l" },
107124084f9bSBrian Somers 
107222c62477SPoul-Henning Kamp 	{ LibAliasOption,
107359a7c613SBrian Somers 		PKT_ALIAS_PROXY_ONLY,
107459a7c613SBrian Somers 		YesNo,
107559a7c613SBrian Somers 		"[yes|no]",
107659a7c613SBrian Somers 		"proxy only",
107759a7c613SBrian Somers 		"proxy_only",
107859a7c613SBrian Somers 		NULL },
107959a7c613SBrian Somers 
108022c62477SPoul-Henning Kamp 	{ LibAliasOption,
108159a7c613SBrian Somers 		PKT_ALIAS_REVERSE,
108259a7c613SBrian Somers 		YesNo,
108359a7c613SBrian Somers 		"[yes|no]",
108459a7c613SBrian Somers 		"operate in reverse mode",
108559a7c613SBrian Somers 		"reverse",
108659a7c613SBrian Somers 		NULL },
108759a7c613SBrian Somers 
108822c62477SPoul-Henning Kamp 	{ LibAliasOption,
108924084f9bSBrian Somers 		PKT_ALIAS_DENY_INCOMING,
109024084f9bSBrian Somers 		YesNo,
109124084f9bSBrian Somers 		"[yes|no]",
109224084f9bSBrian Somers 		"allow incoming connections",
109324084f9bSBrian Somers 		"deny_incoming",
109424084f9bSBrian Somers 		"d" },
109524084f9bSBrian Somers 
109622c62477SPoul-Henning Kamp 	{ LibAliasOption,
109724084f9bSBrian Somers 		PKT_ALIAS_USE_SOCKETS,
109824084f9bSBrian Somers 		YesNo,
109924084f9bSBrian Somers 		"[yes|no]",
110024084f9bSBrian Somers 		"use sockets to inhibit port conflict",
110124084f9bSBrian Somers 		"use_sockets",
110224084f9bSBrian Somers 		"s" },
110324084f9bSBrian Somers 
110422c62477SPoul-Henning Kamp 	{ LibAliasOption,
110524084f9bSBrian Somers 		PKT_ALIAS_SAME_PORTS,
110624084f9bSBrian Somers 		YesNo,
110724084f9bSBrian Somers 		"[yes|no]",
110824084f9bSBrian Somers 		"try to keep original port numbers for connections",
110924084f9bSBrian Somers 		"same_ports",
111024084f9bSBrian Somers 		"m" },
111124084f9bSBrian Somers 
111224084f9bSBrian Somers 	{ Verbose,
111324084f9bSBrian Somers 		0,
111424084f9bSBrian Somers 		YesNo,
111524084f9bSBrian Somers 		"[yes|no]",
111624084f9bSBrian Somers 		"verbose mode, dump packet information",
111724084f9bSBrian Somers 		"verbose",
111824084f9bSBrian Somers 		"v" },
111924084f9bSBrian Somers 
112024084f9bSBrian Somers 	{ DynamicMode,
112124084f9bSBrian Somers 		0,
112224084f9bSBrian Somers 		YesNo,
112324084f9bSBrian Somers 		"[yes|no]",
112424084f9bSBrian Somers 		"dynamic mode, automatically detect interface address changes",
112524084f9bSBrian Somers 		"dynamic",
112624084f9bSBrian Somers 		NULL },
112724084f9bSBrian Somers 
112824084f9bSBrian Somers 	{ InPort,
112924084f9bSBrian Somers 		0,
113024084f9bSBrian Somers 		Service,
113124084f9bSBrian Somers 		"number|service_name",
113224084f9bSBrian Somers 		"set port for incoming packets",
113324084f9bSBrian Somers 		"in_port",
113424084f9bSBrian Somers 		"i" },
113524084f9bSBrian Somers 
113624084f9bSBrian Somers 	{ OutPort,
113724084f9bSBrian Somers 		0,
113824084f9bSBrian Somers 		Service,
113924084f9bSBrian Somers 		"number|service_name",
114024084f9bSBrian Somers 		"set port for outgoing packets",
114124084f9bSBrian Somers 		"out_port",
114224084f9bSBrian Somers 		"o" },
114324084f9bSBrian Somers 
114424084f9bSBrian Somers 	{ Port,
114524084f9bSBrian Somers 		0,
114624084f9bSBrian Somers 		Service,
114724084f9bSBrian Somers 		"number|service_name",
114824084f9bSBrian Somers 		"set port (defaults to natd/divert)",
114924084f9bSBrian Somers 		"port",
115024084f9bSBrian Somers 		"p" },
115124084f9bSBrian Somers 
115222c62477SPoul-Henning Kamp 	{ GlobalPort,
115322c62477SPoul-Henning Kamp 		0,
115422c62477SPoul-Henning Kamp 		Service,
115522c62477SPoul-Henning Kamp 		"number|service_name",
115622c62477SPoul-Henning Kamp 		"set globalport",
115722c62477SPoul-Henning Kamp 		"globalport",
115822c62477SPoul-Henning Kamp 		NULL },
115922c62477SPoul-Henning Kamp 
116024084f9bSBrian Somers 	{ AliasAddress,
116124084f9bSBrian Somers 		0,
116224084f9bSBrian Somers 		Address,
116324084f9bSBrian Somers 		"x.x.x.x",
116424084f9bSBrian Somers 		"address to use for aliasing",
116524084f9bSBrian Somers 		"alias_address",
116624084f9bSBrian Somers 		"a" },
116724084f9bSBrian Somers 
116811c2b3bfSRuslan Ermilov 	{ TargetAddress,
116911c2b3bfSRuslan Ermilov 		0,
117011c2b3bfSRuslan Ermilov 		Address,
117111c2b3bfSRuslan Ermilov 		"x.x.x.x",
117211c2b3bfSRuslan Ermilov 		"address to use for incoming sessions",
117311c2b3bfSRuslan Ermilov 		"target_address",
117411c2b3bfSRuslan Ermilov 		"t" },
117511c2b3bfSRuslan Ermilov 
117624084f9bSBrian Somers 	{ InterfaceName,
117724084f9bSBrian Somers 		0,
117824084f9bSBrian Somers 		String,
117924084f9bSBrian Somers 	        "network_if_name",
118024084f9bSBrian Somers 		"take aliasing address from interface",
118124084f9bSBrian Somers 		"interface",
118224084f9bSBrian Somers 		"n" },
118324084f9bSBrian Somers 
118459a7c613SBrian Somers 	{ ProxyRule,
118524084f9bSBrian Somers 		0,
118624084f9bSBrian Somers 		String,
118759a7c613SBrian Somers 	        "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
118859a7c613SBrian Somers 		"a.b.c.d:yyyy",
118959a7c613SBrian Somers 		"add transparent proxying / destination NAT",
119059a7c613SBrian Somers 		"proxy_rule",
119124084f9bSBrian Somers 		NULL },
119224084f9bSBrian Somers 
119324084f9bSBrian Somers 	{ RedirectPort,
119424084f9bSBrian Somers 		0,
119524084f9bSBrian Somers 		String,
1196bd690510SRuslan Ermilov 	        "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
11975d8ee958SBrian Somers 	 	" [remote_addr[:remote_port_range]]",
11985d8ee958SBrian Somers 		"redirect a port (or ports) for incoming traffic",
119924084f9bSBrian Somers 		"redirect_port",
120024084f9bSBrian Somers 		NULL },
120124084f9bSBrian Somers 
12024330006dSRuslan Ermilov 	{ RedirectProto,
12034330006dSRuslan Ermilov 		0,
12044330006dSRuslan Ermilov 		String,
12054330006dSRuslan Ermilov 	        "proto local_addr [public_addr] [remote_addr]",
12064330006dSRuslan Ermilov 		"redirect packets of a given proto",
12074330006dSRuslan Ermilov 		"redirect_proto",
12084330006dSRuslan Ermilov 		NULL },
12094330006dSRuslan Ermilov 
121024084f9bSBrian Somers 	{ RedirectAddress,
121124084f9bSBrian Somers 		0,
121224084f9bSBrian Somers 		String,
1213bd690510SRuslan Ermilov 	        "local_addr[,...] public_addr",
121424084f9bSBrian Somers 		"define mapping between local and public addresses",
121524084f9bSBrian Somers 		"redirect_address",
121624084f9bSBrian Somers 		NULL },
121724084f9bSBrian Somers 
121824084f9bSBrian Somers 	{ ConfigFile,
121924084f9bSBrian Somers 		0,
122024084f9bSBrian Somers 		String,
122124084f9bSBrian Somers 		"file_name",
122224084f9bSBrian Somers 		"read options from configuration file",
122324084f9bSBrian Somers 		"config",
122459a7c613SBrian Somers 		"f" },
122559a7c613SBrian Somers 
122659a7c613SBrian Somers 	{ LogDenied,
122759a7c613SBrian Somers 		0,
122859a7c613SBrian Somers 		YesNo,
122959a7c613SBrian Somers 	        "[yes|no]",
123059a7c613SBrian Somers 		"enable logging of denied incoming packets",
123159a7c613SBrian Somers 		"log_denied",
123259a7c613SBrian Somers 		NULL },
123359a7c613SBrian Somers 
123459a7c613SBrian Somers 	{ LogFacility,
123559a7c613SBrian Somers 		0,
123659a7c613SBrian Somers 		String,
123759a7c613SBrian Somers 	        "facility",
123859a7c613SBrian Somers 		"name of syslog facility to use for logging",
123959a7c613SBrian Somers 		"log_facility",
1240bc4ebb98SRuslan Ermilov 		NULL },
124159a7c613SBrian Somers 
1242bc4ebb98SRuslan Ermilov 	{ PunchFW,
1243bc4ebb98SRuslan Ermilov 		0,
1244bc4ebb98SRuslan Ermilov 		String,
1245bc4ebb98SRuslan Ermilov 	        "basenumber:count",
1246bc4ebb98SRuslan Ermilov 		"punch holes in the firewall for incoming FTP/IRC DCC connections",
1247bc4ebb98SRuslan Ermilov 		"punch_fw",
124884ef95bdSPoul-Henning Kamp 		NULL },
124984ef95bdSPoul-Henning Kamp 
1250b07fbc17SJoe Marcus Clarke 	{ SkinnyPort,
1251b07fbc17SJoe Marcus Clarke 		0,
1252b07fbc17SJoe Marcus Clarke 		String,
1253b07fbc17SJoe Marcus Clarke 		"port",
1254b07fbc17SJoe Marcus Clarke 		"set the TCP port for use with the Skinny Station protocol",
1255b07fbc17SJoe Marcus Clarke 		"skinny_port",
1256b07fbc17SJoe Marcus Clarke 		NULL },
1257b07fbc17SJoe Marcus Clarke 
125884ef95bdSPoul-Henning Kamp 	{ LogIpfwDenied,
125984ef95bdSPoul-Henning Kamp 		0,
126084ef95bdSPoul-Henning Kamp 		YesNo,
126184ef95bdSPoul-Henning Kamp 	        "[yes|no]",
126284ef95bdSPoul-Henning Kamp 		"log packets converted by natd, but denied by ipfw",
126384ef95bdSPoul-Henning Kamp 		"log_ipfw_denied",
126484ef95bdSPoul-Henning Kamp 		NULL },
1265b79840a6SRuslan Ermilov 
1266b79840a6SRuslan Ermilov 	{ PidFile,
1267b79840a6SRuslan Ermilov 		0,
1268b79840a6SRuslan Ermilov 		String,
1269b79840a6SRuslan Ermilov 		"file_name",
1270b79840a6SRuslan Ermilov 		"store PID in an alternate file",
1271b79840a6SRuslan Ermilov 		"pid_file",
1272b79840a6SRuslan Ermilov 		"P" },
127322c62477SPoul-Henning Kamp 	{ Instance,
127422c62477SPoul-Henning Kamp 		0,
127522c62477SPoul-Henning Kamp 		String,
127622c62477SPoul-Henning Kamp 		"instance name",
127722c62477SPoul-Henning Kamp 		"name of aliasing engine instance",
127822c62477SPoul-Henning Kamp 		"instance",
127922c62477SPoul-Henning Kamp 		NULL },
128024084f9bSBrian Somers };
128124084f9bSBrian Somers 
1282b0f55af6SRuslan Ermilov static void ParseOption (const char* option, const char* parms)
128324084f9bSBrian Somers {
128424084f9bSBrian Somers 	int			i;
128524084f9bSBrian Somers 	struct OptionInfo*	info;
128624084f9bSBrian Somers 	int			yesNoValue;
128724084f9bSBrian Somers 	int			aliasValue;
128824084f9bSBrian Somers 	int			numValue;
128967a886fbSBrian Somers 	u_short			uNumValue;
1290902cb50aSBrian Somers 	const char*		strValue;
129124084f9bSBrian Somers 	struct in_addr		addrValue;
129224084f9bSBrian Somers 	int			max;
129324084f9bSBrian Somers 	char*			end;
129459a7c613SBrian Somers 	CODE* 			fac_record = NULL;
129524084f9bSBrian Somers /*
129624084f9bSBrian Somers  * Find option from table.
129724084f9bSBrian Somers  */
129824084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
129924084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
130024084f9bSBrian Somers 
130124084f9bSBrian Somers 		if (!strcmp (info->name, option))
130224084f9bSBrian Somers 			break;
130324084f9bSBrian Somers 
130424084f9bSBrian Somers 		if (info->shortName)
130524084f9bSBrian Somers 			if (!strcmp (info->shortName, option))
130624084f9bSBrian Somers 				break;
130724084f9bSBrian Somers 	}
130824084f9bSBrian Somers 
130924084f9bSBrian Somers 	if (i >= max) {
131024084f9bSBrian Somers 
13110fc81af1SPhilippe Charnier 		warnx ("unknown option %s", option);
131224084f9bSBrian Somers 		Usage ();
131324084f9bSBrian Somers 	}
131424084f9bSBrian Somers 
131567a886fbSBrian Somers 	uNumValue	= 0;
131624084f9bSBrian Somers 	yesNoValue	= 0;
131724084f9bSBrian Somers 	numValue	= 0;
131824084f9bSBrian Somers 	strValue	= NULL;
131924084f9bSBrian Somers /*
132024084f9bSBrian Somers  * Check parameters.
132124084f9bSBrian Somers  */
132224084f9bSBrian Somers 	switch (info->parm) {
132324084f9bSBrian Somers 	case YesNo:
132424084f9bSBrian Somers 		if (!parms)
132524084f9bSBrian Somers 			parms = "yes";
132624084f9bSBrian Somers 
132724084f9bSBrian Somers 		if (!strcmp (parms, "yes"))
132824084f9bSBrian Somers 			yesNoValue = 1;
132924084f9bSBrian Somers 		else
133024084f9bSBrian Somers 			if (!strcmp (parms, "no"))
133124084f9bSBrian Somers 				yesNoValue = 0;
13320fc81af1SPhilippe Charnier 			else
13330fc81af1SPhilippe Charnier 				errx (1, "%s needs yes/no parameter", option);
133424084f9bSBrian Somers 		break;
133524084f9bSBrian Somers 
133624084f9bSBrian Somers 	case Service:
13370fc81af1SPhilippe Charnier 		if (!parms)
133867a886fbSBrian Somers 			errx (1, "%s needs service name or "
133967a886fbSBrian Somers 				 "port number parameter",
134067a886fbSBrian Somers 				 option);
134124084f9bSBrian Somers 
134267a886fbSBrian Somers 		uNumValue = StrToPort (parms, "divert");
134324084f9bSBrian Somers 		break;
134424084f9bSBrian Somers 
134524084f9bSBrian Somers 	case Numeric:
134624084f9bSBrian Somers 		if (parms)
134724084f9bSBrian Somers 			numValue = strtol (parms, &end, 10);
134824084f9bSBrian Somers 		else
1349902cb50aSBrian Somers 			end = NULL;
135024084f9bSBrian Somers 
13510fc81af1SPhilippe Charnier 		if (end == parms)
13520fc81af1SPhilippe Charnier 			errx (1, "%s needs numeric parameter", option);
135324084f9bSBrian Somers 		break;
135424084f9bSBrian Somers 
135524084f9bSBrian Somers 	case String:
135624084f9bSBrian Somers 		strValue = parms;
13570fc81af1SPhilippe Charnier 		if (!strValue)
13580fc81af1SPhilippe Charnier 			errx (1, "%s needs parameter", option);
135924084f9bSBrian Somers 		break;
136024084f9bSBrian Somers 
136124084f9bSBrian Somers 	case None:
13620fc81af1SPhilippe Charnier 		if (parms)
13630fc81af1SPhilippe Charnier 			errx (1, "%s does not take parameters", option);
136424084f9bSBrian Somers 		break;
136524084f9bSBrian Somers 
136624084f9bSBrian Somers 	case Address:
13670fc81af1SPhilippe Charnier 		if (!parms)
13680fc81af1SPhilippe Charnier 			errx (1, "%s needs address/host parameter", option);
136924084f9bSBrian Somers 
137024084f9bSBrian Somers 		StrToAddr (parms, &addrValue);
137124084f9bSBrian Somers 		break;
137224084f9bSBrian Somers 	}
137324084f9bSBrian Somers 
137424084f9bSBrian Somers 	switch (info->type) {
137522c62477SPoul-Henning Kamp 	case LibAliasOption:
137624084f9bSBrian Somers 
137724084f9bSBrian Somers 		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
137822c62477SPoul-Henning Kamp 		LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
137924084f9bSBrian Somers 		break;
138024084f9bSBrian Somers 
138124084f9bSBrian Somers 	case Verbose:
138224084f9bSBrian Somers 		verbose = yesNoValue;
138324084f9bSBrian Somers 		break;
138424084f9bSBrian Somers 
138524084f9bSBrian Somers 	case DynamicMode:
138624084f9bSBrian Somers 		dynamicMode = yesNoValue;
138724084f9bSBrian Somers 		break;
138824084f9bSBrian Somers 
138924084f9bSBrian Somers 	case InPort:
139022c62477SPoul-Henning Kamp 		mip->inPort = uNumValue;
139124084f9bSBrian Somers 		break;
139224084f9bSBrian Somers 
139324084f9bSBrian Somers 	case OutPort:
139422c62477SPoul-Henning Kamp 		mip->outPort = uNumValue;
139524084f9bSBrian Somers 		break;
139624084f9bSBrian Somers 
139724084f9bSBrian Somers 	case Port:
139822c62477SPoul-Henning Kamp 		mip->inOutPort = uNumValue;
139922c62477SPoul-Henning Kamp 		break;
140022c62477SPoul-Henning Kamp 
140122c62477SPoul-Henning Kamp 	case GlobalPort:
140222c62477SPoul-Henning Kamp 		globalPort = uNumValue;
140324084f9bSBrian Somers 		break;
140424084f9bSBrian Somers 
140524084f9bSBrian Somers 	case AliasAddress:
140622c62477SPoul-Henning Kamp 		memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
140724084f9bSBrian Somers 		break;
140824084f9bSBrian Somers 
140911c2b3bfSRuslan Ermilov 	case TargetAddress:
141022c62477SPoul-Henning Kamp 		LibAliasSetTarget(mla, addrValue);
141111c2b3bfSRuslan Ermilov 		break;
141211c2b3bfSRuslan Ermilov 
141324084f9bSBrian Somers 	case RedirectPort:
141424084f9bSBrian Somers 		SetupPortRedirect (strValue);
141524084f9bSBrian Somers 		break;
141624084f9bSBrian Somers 
14174330006dSRuslan Ermilov 	case RedirectProto:
14184330006dSRuslan Ermilov 		SetupProtoRedirect(strValue);
14194330006dSRuslan Ermilov 		break;
14204330006dSRuslan Ermilov 
142124084f9bSBrian Somers 	case RedirectAddress:
142224084f9bSBrian Somers 		SetupAddressRedirect (strValue);
142324084f9bSBrian Somers 		break;
142424084f9bSBrian Somers 
142559a7c613SBrian Somers 	case ProxyRule:
142622c62477SPoul-Henning Kamp 		LibAliasProxyRule (mla, strValue);
142759a7c613SBrian Somers 		break;
142859a7c613SBrian Somers 
142924084f9bSBrian Somers 	case InterfaceName:
143022c62477SPoul-Henning Kamp 		if (mip->ifName)
143122c62477SPoul-Henning Kamp 			free (mip->ifName);
143224084f9bSBrian Somers 
143322c62477SPoul-Henning Kamp 		mip->ifName = strdup (strValue);
143424084f9bSBrian Somers 		break;
143524084f9bSBrian Somers 
143624084f9bSBrian Somers 	case ConfigFile:
143724084f9bSBrian Somers 		ReadConfigFile (strValue);
143824084f9bSBrian Somers 		break;
143959a7c613SBrian Somers 
144059a7c613SBrian Somers 	case LogDenied:
144122c62477SPoul-Henning Kamp 		mip->logDropped = yesNoValue;
144259a7c613SBrian Somers 		break;
144359a7c613SBrian Somers 
144459a7c613SBrian Somers 	case LogFacility:
144559a7c613SBrian Somers 
144659a7c613SBrian Somers 		fac_record = facilitynames;
144759a7c613SBrian Somers 		while (fac_record->c_name != NULL) {
144859a7c613SBrian Somers 
144959a7c613SBrian Somers 			if (!strcmp (fac_record->c_name, strValue)) {
145059a7c613SBrian Somers 
145159a7c613SBrian Somers 				logFacility = fac_record->c_val;
145259a7c613SBrian Somers 				break;
145359a7c613SBrian Somers 
145459a7c613SBrian Somers 			}
145559a7c613SBrian Somers 			else
145659a7c613SBrian Somers 				fac_record++;
145759a7c613SBrian Somers 		}
145859a7c613SBrian Somers 
145959a7c613SBrian Somers 		if(fac_record->c_name == NULL)
146059a7c613SBrian Somers 			errx(1, "Unknown log facility name: %s", strValue);
146159a7c613SBrian Somers 
146259a7c613SBrian Somers 		break;
1463bc4ebb98SRuslan Ermilov 
1464bc4ebb98SRuslan Ermilov 	case PunchFW:
1465bc4ebb98SRuslan Ermilov 		SetupPunchFW(strValue);
1466bc4ebb98SRuslan Ermilov 		break;
14673843533eSRuslan Ermilov 
1468b07fbc17SJoe Marcus Clarke 	case SkinnyPort:
1469b07fbc17SJoe Marcus Clarke 		SetupSkinnyPort(strValue);
1470b07fbc17SJoe Marcus Clarke 		break;
1471b07fbc17SJoe Marcus Clarke 
147284ef95bdSPoul-Henning Kamp 	case LogIpfwDenied:
14733843533eSRuslan Ermilov 		logIpfwDenied = yesNoValue;;
14743843533eSRuslan Ermilov 		break;
1475b79840a6SRuslan Ermilov 
1476b79840a6SRuslan Ermilov 	case PidFile:
1477b79840a6SRuslan Ermilov 		pidName = strdup (strValue);
1478b79840a6SRuslan Ermilov 		break;
147922c62477SPoul-Henning Kamp 	case Instance:
148022c62477SPoul-Henning Kamp 		NewInstance(strValue);
148122c62477SPoul-Henning Kamp 		break;
148224084f9bSBrian Somers 	}
148324084f9bSBrian Somers }
148424084f9bSBrian Somers 
1485902cb50aSBrian Somers void ReadConfigFile (const char* fileName)
148624084f9bSBrian Somers {
148724084f9bSBrian Somers 	FILE*	file;
1488d99cc1daSRuslan Ermilov 	char	*buf;
1489d99cc1daSRuslan Ermilov 	size_t	len;
14902e7e7c71SRuslan Ermilov 	char	*ptr, *p;
149124084f9bSBrian Somers 	char*	option;
149224084f9bSBrian Somers 
149324084f9bSBrian Somers 	file = fopen (fileName, "r");
1494d99cc1daSRuslan Ermilov 	if (!file)
1495d99cc1daSRuslan Ermilov 		err(1, "cannot open config file %s", fileName);
149624084f9bSBrian Somers 
1497d99cc1daSRuslan Ermilov 	while ((buf = fgetln(file, &len)) != NULL) {
1498d99cc1daSRuslan Ermilov 		if (buf[len - 1] == '\n')
1499d99cc1daSRuslan Ermilov 			buf[len - 1] = '\0';
1500d99cc1daSRuslan Ermilov 		else
1501d99cc1daSRuslan Ermilov 			errx(1, "config file format error: "
1502d99cc1daSRuslan Ermilov 				"last line should end with newline");
150324084f9bSBrian Somers 
150424084f9bSBrian Somers /*
15052e7e7c71SRuslan Ermilov  * Check for comments, strip off trailing spaces.
150624084f9bSBrian Somers  */
15072e7e7c71SRuslan Ermilov 		if ((ptr = strchr(buf, '#')))
15082e7e7c71SRuslan Ermilov 			*ptr = '\0';
15092e7e7c71SRuslan Ermilov 		for (ptr = buf; isspace(*ptr); ++ptr)
15102e7e7c71SRuslan Ermilov 			continue;
151124084f9bSBrian Somers 		if (*ptr == '\0')
151224084f9bSBrian Somers 			continue;
15132e7e7c71SRuslan Ermilov 		for (p = strchr(buf, '\0'); isspace(*--p);)
15142e7e7c71SRuslan Ermilov 			continue;
15152e7e7c71SRuslan Ermilov 		*++p = '\0';
15162e7e7c71SRuslan Ermilov 
151724084f9bSBrian Somers /*
151824084f9bSBrian Somers  * Extract option name.
151924084f9bSBrian Somers  */
152024084f9bSBrian Somers 		option = ptr;
152124084f9bSBrian Somers 		while (*ptr && !isspace (*ptr))
152224084f9bSBrian Somers 			++ptr;
152324084f9bSBrian Somers 
152424084f9bSBrian Somers 		if (*ptr != '\0') {
152524084f9bSBrian Somers 
152624084f9bSBrian Somers 			*ptr = '\0';
152724084f9bSBrian Somers 			++ptr;
152824084f9bSBrian Somers 		}
152924084f9bSBrian Somers /*
153024084f9bSBrian Somers  * Skip white space between name and parms.
153124084f9bSBrian Somers  */
153224084f9bSBrian Somers 		while (*ptr && isspace (*ptr))
153324084f9bSBrian Somers 			++ptr;
153424084f9bSBrian Somers 
1535b0f55af6SRuslan Ermilov 		ParseOption (option, *ptr ? ptr : NULL);
153624084f9bSBrian Somers 	}
153724084f9bSBrian Somers 
153824084f9bSBrian Somers 	fclose (file);
153924084f9bSBrian Somers }
154024084f9bSBrian Somers 
154124084f9bSBrian Somers static void Usage ()
154224084f9bSBrian Somers {
154324084f9bSBrian Somers 	int			i;
154424084f9bSBrian Somers 	int			max;
154524084f9bSBrian Somers 	struct OptionInfo*	info;
154624084f9bSBrian Somers 
154724084f9bSBrian Somers 	fprintf (stderr, "Recognized options:\n\n");
154824084f9bSBrian Somers 
154924084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
155024084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
155124084f9bSBrian Somers 
155224084f9bSBrian Somers 		fprintf (stderr, "-%-20s %s\n", info->name,
155324084f9bSBrian Somers 						info->parmDescription);
155424084f9bSBrian Somers 
155524084f9bSBrian Somers 		if (info->shortName)
155624084f9bSBrian Somers 			fprintf (stderr, "-%-20s %s\n", info->shortName,
155724084f9bSBrian Somers 							info->parmDescription);
155824084f9bSBrian Somers 
155924084f9bSBrian Somers 		fprintf (stderr, "      %s\n\n", info->description);
156024084f9bSBrian Somers 	}
156124084f9bSBrian Somers 
156224084f9bSBrian Somers 	exit (1);
156324084f9bSBrian Somers }
156424084f9bSBrian Somers 
1565902cb50aSBrian Somers void SetupPortRedirect (const char* parms)
156624084f9bSBrian Somers {
156724084f9bSBrian Somers 	char		buf[128];
156824084f9bSBrian Somers 	char*		ptr;
1569bd690510SRuslan Ermilov 	char*		serverPool;
157024084f9bSBrian Somers 	struct in_addr	localAddr;
157124084f9bSBrian Somers 	struct in_addr	publicAddr;
157224084f9bSBrian Somers 	struct in_addr	remoteAddr;
15735d8ee958SBrian Somers 	port_range      portRange;
15745d8ee958SBrian Somers 	u_short         localPort      = 0;
15755d8ee958SBrian Somers 	u_short         publicPort     = 0;
15765d8ee958SBrian Somers 	u_short         remotePort     = 0;
15775d8ee958SBrian Somers 	u_short         numLocalPorts  = 0;
15785d8ee958SBrian Somers 	u_short         numPublicPorts = 0;
15795d8ee958SBrian Somers 	u_short         numRemotePorts = 0;
158024084f9bSBrian Somers 	int		proto;
158124084f9bSBrian Somers 	char*		protoName;
158224084f9bSBrian Somers 	char*		separator;
15835d8ee958SBrian Somers 	int             i;
158448ce8ca1SXin LI 	struct alias_link *aliaslink = NULL;
158524084f9bSBrian Somers 
1586e53f7998SHiten Pandya 	strlcpy (buf, parms, sizeof(buf));
158724084f9bSBrian Somers /*
158824084f9bSBrian Somers  * Extract protocol.
158924084f9bSBrian Somers  */
159024084f9bSBrian Somers 	protoName = strtok (buf, " \t");
15910fc81af1SPhilippe Charnier 	if (!protoName)
15920fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing protocol");
159324084f9bSBrian Somers 
159424084f9bSBrian Somers 	proto = StrToProto (protoName);
159524084f9bSBrian Somers /*
159624084f9bSBrian Somers  * Extract local address.
159724084f9bSBrian Somers  */
159824084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
15990fc81af1SPhilippe Charnier 	if (!ptr)
16000fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing local address");
160124084f9bSBrian Somers 
1602bd690510SRuslan Ermilov 	separator = strchr(ptr, ',');
1603bd690510SRuslan Ermilov 	if (separator) {		/* LSNAT redirection syntax. */
1604bd690510SRuslan Ermilov 		localAddr.s_addr = INADDR_NONE;
1605bd690510SRuslan Ermilov 		localPort = ~0;
1606bd690510SRuslan Ermilov 		numLocalPorts = 1;
1607bd690510SRuslan Ermilov 		serverPool = ptr;
1608bd690510SRuslan Ermilov 	} else {
16095d8ee958SBrian Somers 		if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
16105d8ee958SBrian Somers 			errx (1, "redirect_port: invalid local port range");
16115d8ee958SBrian Somers 
16125d8ee958SBrian Somers 		localPort     = GETLOPORT(portRange);
16135d8ee958SBrian Somers 		numLocalPorts = GETNUMPORTS(portRange);
1614bd690510SRuslan Ermilov 		serverPool = NULL;
1615bd690510SRuslan Ermilov 	}
16165d8ee958SBrian Somers 
161724084f9bSBrian Somers /*
16189c501140SBrian Somers  * Extract public port and optionally address.
161924084f9bSBrian Somers  */
162024084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
16210fc81af1SPhilippe Charnier 	if (!ptr)
16220fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing public port");
162324084f9bSBrian Somers 
162424084f9bSBrian Somers 	separator = strchr (ptr, ':');
16255d8ee958SBrian Somers 	if (separator) {
16265d8ee958SBrian Somers 	        if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
16275d8ee958SBrian Somers 		        errx (1, "redirect_port: invalid public port range");
162824084f9bSBrian Somers 	}
16295d8ee958SBrian Somers 	else {
16305d8ee958SBrian Somers 		publicAddr.s_addr = INADDR_ANY;
16315d8ee958SBrian Somers 		if (StrToPortRange (ptr, protoName, &portRange) != 0)
16325d8ee958SBrian Somers 		        errx (1, "redirect_port: invalid public port range");
16335d8ee958SBrian Somers 	}
16345d8ee958SBrian Somers 
16355d8ee958SBrian Somers 	publicPort     = GETLOPORT(portRange);
16365d8ee958SBrian Somers 	numPublicPorts = GETNUMPORTS(portRange);
163724084f9bSBrian Somers 
163824084f9bSBrian Somers /*
163924084f9bSBrian Somers  * Extract remote address and optionally port.
164024084f9bSBrian Somers  */
164124084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
164224084f9bSBrian Somers 	if (ptr) {
164324084f9bSBrian Somers 		separator = strchr (ptr, ':');
1644ebe70c8fSWarner Losh 		if (separator) {
16455d8ee958SBrian Somers 		        if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
16465d8ee958SBrian Somers 			        errx (1, "redirect_port: invalid remote port range");
1647ebe70c8fSWarner Losh 		} else {
16485d8ee958SBrian Somers 		        SETLOPORT(portRange, 0);
16495d8ee958SBrian Somers 			SETNUMPORTS(portRange, 1);
165024084f9bSBrian Somers 			StrToAddr (ptr, &remoteAddr);
165124084f9bSBrian Somers 		}
165224084f9bSBrian Somers 	}
165324084f9bSBrian Somers 	else {
16545d8ee958SBrian Somers 	        SETLOPORT(portRange, 0);
16555d8ee958SBrian Somers 		SETNUMPORTS(portRange, 1);
165624084f9bSBrian Somers 		remoteAddr.s_addr = INADDR_ANY;
165724084f9bSBrian Somers 	}
165824084f9bSBrian Somers 
16595d8ee958SBrian Somers 	remotePort     = GETLOPORT(portRange);
16605d8ee958SBrian Somers 	numRemotePorts = GETNUMPORTS(portRange);
16615d8ee958SBrian Somers 
16625d8ee958SBrian Somers /*
16635d8ee958SBrian Somers  * Make sure port ranges match up, then add the redirect ports.
16645d8ee958SBrian Somers  */
16655d8ee958SBrian Somers 	if (numLocalPorts != numPublicPorts)
16665d8ee958SBrian Somers 	        errx (1, "redirect_port: port ranges must be equal in size");
16675d8ee958SBrian Somers 
16685d8ee958SBrian Somers 	/* Remote port range is allowed to be '0' which means all ports. */
166929d97436SBrian Somers 	if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
16705d8ee958SBrian Somers 	        errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
16715d8ee958SBrian Somers 
16725d8ee958SBrian Somers 	for (i = 0 ; i < numPublicPorts ; ++i) {
16735d8ee958SBrian Somers 	        /* If remotePort is all ports, set it to 0. */
16745d8ee958SBrian Somers 	        u_short remotePortCopy = remotePort + i;
16755d8ee958SBrian Somers 	        if (numRemotePorts == 1 && remotePort == 0)
16765d8ee958SBrian Somers 		        remotePortCopy = 0;
16775d8ee958SBrian Somers 
167848ce8ca1SXin LI 		aliaslink = LibAliasRedirectPort (mla, localAddr,
16795d8ee958SBrian Somers 						htons(localPort + i),
168024084f9bSBrian Somers 						remoteAddr,
16815d8ee958SBrian Somers 						htons(remotePortCopy),
168224084f9bSBrian Somers 						publicAddr,
16835d8ee958SBrian Somers 						htons(publicPort + i),
168424084f9bSBrian Somers 						proto);
168524084f9bSBrian Somers 	}
1686bd690510SRuslan Ermilov 
1687bd690510SRuslan Ermilov /*
1688bd690510SRuslan Ermilov  * Setup LSNAT server pool.
1689bd690510SRuslan Ermilov  */
169048ce8ca1SXin LI 	if (serverPool != NULL && aliaslink != NULL) {
1691bd690510SRuslan Ermilov 		ptr = strtok(serverPool, ",");
1692bd690510SRuslan Ermilov 		while (ptr != NULL) {
1693bd690510SRuslan Ermilov 			if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1694bd690510SRuslan Ermilov 				errx(1, "redirect_port: invalid local port range");
1695bd690510SRuslan Ermilov 
1696bd690510SRuslan Ermilov 			localPort = GETLOPORT(portRange);
1697bd690510SRuslan Ermilov 			if (GETNUMPORTS(portRange) != 1)
1698bd690510SRuslan Ermilov 				errx(1, "redirect_port: local port must be single in this context");
169948ce8ca1SXin LI 			LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
1700bd690510SRuslan Ermilov 			ptr = strtok(NULL, ",");
1701bd690510SRuslan Ermilov 		}
1702bd690510SRuslan Ermilov 	}
17035d8ee958SBrian Somers }
170424084f9bSBrian Somers 
17054330006dSRuslan Ermilov void
17064330006dSRuslan Ermilov SetupProtoRedirect(const char* parms)
17074330006dSRuslan Ermilov {
17084330006dSRuslan Ermilov 	char		buf[128];
17094330006dSRuslan Ermilov 	char*		ptr;
17104330006dSRuslan Ermilov 	struct in_addr	localAddr;
17114330006dSRuslan Ermilov 	struct in_addr	publicAddr;
17124330006dSRuslan Ermilov 	struct in_addr	remoteAddr;
17134330006dSRuslan Ermilov 	int		proto;
17144330006dSRuslan Ermilov 	char*		protoName;
17154330006dSRuslan Ermilov 	struct protoent *protoent;
17164330006dSRuslan Ermilov 
1717e53f7998SHiten Pandya 	strlcpy (buf, parms, sizeof(buf));
17184330006dSRuslan Ermilov /*
17194330006dSRuslan Ermilov  * Extract protocol.
17204330006dSRuslan Ermilov  */
17214330006dSRuslan Ermilov 	protoName = strtok(buf, " \t");
17224330006dSRuslan Ermilov 	if (!protoName)
17234330006dSRuslan Ermilov 		errx(1, "redirect_proto: missing protocol");
17244330006dSRuslan Ermilov 
17254330006dSRuslan Ermilov 	protoent = getprotobyname(protoName);
17264330006dSRuslan Ermilov 	if (protoent == NULL)
17274330006dSRuslan Ermilov 		errx(1, "redirect_proto: unknown protocol %s", protoName);
17284330006dSRuslan Ermilov 	else
17294330006dSRuslan Ermilov 		proto = protoent->p_proto;
17304330006dSRuslan Ermilov /*
17314330006dSRuslan Ermilov  * Extract local address.
17324330006dSRuslan Ermilov  */
17334330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
17344330006dSRuslan Ermilov 	if (!ptr)
17354330006dSRuslan Ermilov 		errx(1, "redirect_proto: missing local address");
17364330006dSRuslan Ermilov 	else
17374330006dSRuslan Ermilov 		StrToAddr(ptr, &localAddr);
17384330006dSRuslan Ermilov /*
17394330006dSRuslan Ermilov  * Extract optional public address.
17404330006dSRuslan Ermilov  */
17414330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
17424330006dSRuslan Ermilov 	if (ptr)
17434330006dSRuslan Ermilov 		StrToAddr(ptr, &publicAddr);
17444330006dSRuslan Ermilov 	else
17454330006dSRuslan Ermilov 		publicAddr.s_addr = INADDR_ANY;
17464330006dSRuslan Ermilov /*
17474330006dSRuslan Ermilov  * Extract optional remote address.
17484330006dSRuslan Ermilov  */
17494330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
17504330006dSRuslan Ermilov 	if (ptr)
17514330006dSRuslan Ermilov 		StrToAddr(ptr, &remoteAddr);
17524330006dSRuslan Ermilov 	else
17534330006dSRuslan Ermilov 		remoteAddr.s_addr = INADDR_ANY;
17544330006dSRuslan Ermilov /*
17554330006dSRuslan Ermilov  * Create aliasing link.
17564330006dSRuslan Ermilov  */
175722c62477SPoul-Henning Kamp 	(void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
17584330006dSRuslan Ermilov 				       proto);
17594330006dSRuslan Ermilov }
17604330006dSRuslan Ermilov 
1761902cb50aSBrian Somers void SetupAddressRedirect (const char* parms)
176224084f9bSBrian Somers {
176324084f9bSBrian Somers 	char		buf[128];
176424084f9bSBrian Somers 	char*		ptr;
1765bd690510SRuslan Ermilov 	char*		separator;
176624084f9bSBrian Somers 	struct in_addr	localAddr;
176724084f9bSBrian Somers 	struct in_addr	publicAddr;
1768bd690510SRuslan Ermilov 	char*		serverPool;
176948ce8ca1SXin LI 	struct alias_link *aliaslink;
177024084f9bSBrian Somers 
1771e53f7998SHiten Pandya 	strlcpy (buf, parms, sizeof(buf));
177224084f9bSBrian Somers /*
177324084f9bSBrian Somers  * Extract local address.
177424084f9bSBrian Somers  */
177524084f9bSBrian Somers 	ptr = strtok (buf, " \t");
17760fc81af1SPhilippe Charnier 	if (!ptr)
17770fc81af1SPhilippe Charnier 		errx (1, "redirect_address: missing local address");
177824084f9bSBrian Somers 
1779bd690510SRuslan Ermilov 	separator = strchr(ptr, ',');
1780bd690510SRuslan Ermilov 	if (separator) {		/* LSNAT redirection syntax. */
1781bd690510SRuslan Ermilov 		localAddr.s_addr = INADDR_NONE;
1782bd690510SRuslan Ermilov 		serverPool = ptr;
1783bd690510SRuslan Ermilov 	} else {
178424084f9bSBrian Somers 		StrToAddr (ptr, &localAddr);
1785bd690510SRuslan Ermilov 		serverPool = NULL;
1786bd690510SRuslan Ermilov 	}
178724084f9bSBrian Somers /*
178824084f9bSBrian Somers  * Extract public address.
178924084f9bSBrian Somers  */
179024084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
17910fc81af1SPhilippe Charnier 	if (!ptr)
17920fc81af1SPhilippe Charnier 		errx (1, "redirect_address: missing public address");
179324084f9bSBrian Somers 
179424084f9bSBrian Somers 	StrToAddr (ptr, &publicAddr);
179548ce8ca1SXin LI 	aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1796bd690510SRuslan Ermilov 
1797bd690510SRuslan Ermilov /*
1798bd690510SRuslan Ermilov  * Setup LSNAT server pool.
1799bd690510SRuslan Ermilov  */
180048ce8ca1SXin LI 	if (serverPool != NULL && aliaslink != NULL) {
1801bd690510SRuslan Ermilov 		ptr = strtok(serverPool, ",");
1802bd690510SRuslan Ermilov 		while (ptr != NULL) {
1803bd690510SRuslan Ermilov 			StrToAddr(ptr, &localAddr);
180448ce8ca1SXin LI 			LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
1805bd690510SRuslan Ermilov 			ptr = strtok(NULL, ",");
1806bd690510SRuslan Ermilov 		}
1807bd690510SRuslan Ermilov 	}
180824084f9bSBrian Somers }
180924084f9bSBrian Somers 
1810902cb50aSBrian Somers void StrToAddr (const char* str, struct in_addr* addr)
181124084f9bSBrian Somers {
181224084f9bSBrian Somers 	struct hostent* hp;
181324084f9bSBrian Somers 
181424084f9bSBrian Somers 	if (inet_aton (str, addr))
181524084f9bSBrian Somers 		return;
181624084f9bSBrian Somers 
181724084f9bSBrian Somers 	hp = gethostbyname (str);
18180fc81af1SPhilippe Charnier 	if (!hp)
18190fc81af1SPhilippe Charnier 		errx (1, "unknown host %s", str);
182024084f9bSBrian Somers 
182124084f9bSBrian Somers 	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
182224084f9bSBrian Somers }
182324084f9bSBrian Somers 
1824902cb50aSBrian Somers u_short StrToPort (const char* str, const char* proto)
182524084f9bSBrian Somers {
182667a886fbSBrian Somers 	u_short		port;
182724084f9bSBrian Somers 	struct servent*	sp;
182824084f9bSBrian Somers 	char*		end;
182924084f9bSBrian Somers 
183024084f9bSBrian Somers 	port = strtol (str, &end, 10);
183124084f9bSBrian Somers 	if (end != str)
183227c20503SBrian Somers 		return htons (port);
183324084f9bSBrian Somers 
183424084f9bSBrian Somers 	sp = getservbyname (str, proto);
18350fc81af1SPhilippe Charnier 	if (!sp)
183629e3edccSPhilippe Charnier 		errx (1, "%s/%s: unknown service", str, proto);
183724084f9bSBrian Somers 
183824084f9bSBrian Somers 	return sp->s_port;
183924084f9bSBrian Somers }
184024084f9bSBrian Somers 
1841902cb50aSBrian Somers int StrToPortRange (const char* str, const char* proto, port_range *portRange)
18425d8ee958SBrian Somers {
18435d8ee958SBrian Somers 	char*           sep;
18445d8ee958SBrian Somers 	struct servent*	sp;
18455d8ee958SBrian Somers 	char*		end;
18465d8ee958SBrian Somers 	u_short         loPort;
18475d8ee958SBrian Somers 	u_short         hiPort;
18485d8ee958SBrian Somers 
18495d8ee958SBrian Somers 	/* First see if this is a service, return corresponding port if so. */
18505d8ee958SBrian Somers 	sp = getservbyname (str,proto);
18515d8ee958SBrian Somers 	if (sp) {
18525d8ee958SBrian Somers 	        SETLOPORT(*portRange, ntohs(sp->s_port));
18535d8ee958SBrian Somers 		SETNUMPORTS(*portRange, 1);
18545d8ee958SBrian Somers 		return 0;
18555d8ee958SBrian Somers 	}
18565d8ee958SBrian Somers 
18575d8ee958SBrian Somers 	/* Not a service, see if it's a single port or port range. */
18585d8ee958SBrian Somers 	sep = strchr (str, '-');
18595d8ee958SBrian Somers 	if (sep == NULL) {
18605d8ee958SBrian Somers 	        SETLOPORT(*portRange, strtol(str, &end, 10));
18615d8ee958SBrian Somers 		if (end != str) {
18625d8ee958SBrian Somers 		        /* Single port. */
18635d8ee958SBrian Somers 		        SETNUMPORTS(*portRange, 1);
18645d8ee958SBrian Somers 			return 0;
18655d8ee958SBrian Somers 		}
18665d8ee958SBrian Somers 
18675d8ee958SBrian Somers 		/* Error in port range field. */
186829e3edccSPhilippe Charnier 		errx (1, "%s/%s: unknown service", str, proto);
18695d8ee958SBrian Somers 	}
18705d8ee958SBrian Somers 
18715d8ee958SBrian Somers 	/* Port range, get the values and sanity check. */
18725d8ee958SBrian Somers 	sscanf (str, "%hu-%hu", &loPort, &hiPort);
18735d8ee958SBrian Somers 	SETLOPORT(*portRange, loPort);
18745d8ee958SBrian Somers 	SETNUMPORTS(*portRange, 0);	/* Error by default */
18755d8ee958SBrian Somers 	if (loPort <= hiPort)
18765d8ee958SBrian Somers 	        SETNUMPORTS(*portRange, hiPort - loPort + 1);
18775d8ee958SBrian Somers 
18785d8ee958SBrian Somers 	if (GETNUMPORTS(*portRange) == 0)
18795d8ee958SBrian Somers 	        errx (1, "invalid port range %s", str);
18805d8ee958SBrian Somers 
18815d8ee958SBrian Somers 	return 0;
18825d8ee958SBrian Somers }
18835d8ee958SBrian Somers 
18845d8ee958SBrian Somers 
1885902cb50aSBrian Somers int StrToProto (const char* str)
188624084f9bSBrian Somers {
188724084f9bSBrian Somers 	if (!strcmp (str, "tcp"))
188824084f9bSBrian Somers 		return IPPROTO_TCP;
188924084f9bSBrian Somers 
189024084f9bSBrian Somers 	if (!strcmp (str, "udp"))
189124084f9bSBrian Somers 		return IPPROTO_UDP;
189224084f9bSBrian Somers 
18930fc81af1SPhilippe Charnier 	errx (1, "unknown protocol %s. Expected tcp or udp", str);
189424084f9bSBrian Somers }
189524084f9bSBrian Somers 
1896902cb50aSBrian Somers int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
189724084f9bSBrian Somers {
189824084f9bSBrian Somers 	char*	ptr;
189924084f9bSBrian Somers 
190024084f9bSBrian Somers 	ptr = strchr (str, ':');
19010fc81af1SPhilippe Charnier 	if (!ptr)
19020fc81af1SPhilippe Charnier 		errx (1, "%s is missing port number", str);
190324084f9bSBrian Somers 
190424084f9bSBrian Somers 	*ptr = '\0';
190524084f9bSBrian Somers 	++ptr;
190624084f9bSBrian Somers 
190724084f9bSBrian Somers 	StrToAddr (str, addr);
19085d8ee958SBrian Somers 	return StrToPortRange (ptr, proto, portRange);
190924084f9bSBrian Somers }
1910bc4ebb98SRuslan Ermilov 
1911bc4ebb98SRuslan Ermilov static void
1912bc4ebb98SRuslan Ermilov SetupPunchFW(const char *strValue)
1913bc4ebb98SRuslan Ermilov {
1914bc4ebb98SRuslan Ermilov 	unsigned int base, num;
1915bc4ebb98SRuslan Ermilov 
1916bc4ebb98SRuslan Ermilov 	if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1917bc4ebb98SRuslan Ermilov 		errx(1, "punch_fw: basenumber:count parameter required");
1918bc4ebb98SRuslan Ermilov 
191922c62477SPoul-Henning Kamp 	LibAliasSetFWBase(mla, base, num);
192022c62477SPoul-Henning Kamp 	(void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1921bc4ebb98SRuslan Ermilov }
1922b07fbc17SJoe Marcus Clarke 
1923b07fbc17SJoe Marcus Clarke static void
1924b07fbc17SJoe Marcus Clarke SetupSkinnyPort(const char *strValue)
1925b07fbc17SJoe Marcus Clarke {
1926b07fbc17SJoe Marcus Clarke 	unsigned int port;
1927b07fbc17SJoe Marcus Clarke 
1928b07fbc17SJoe Marcus Clarke 	if (sscanf(strValue, "%u", &port) != 1)
1929b07fbc17SJoe Marcus Clarke 		errx(1, "skinny_port: port parameter required");
1930b07fbc17SJoe Marcus Clarke 
193122c62477SPoul-Henning Kamp 	LibAliasSetSkinnyPort(mla, port);
193222c62477SPoul-Henning Kamp }
193322c62477SPoul-Henning Kamp 
193422c62477SPoul-Henning Kamp static void
193522c62477SPoul-Henning Kamp NewInstance(const char *name)
193622c62477SPoul-Henning Kamp {
193722c62477SPoul-Henning Kamp 	struct instance *ip;
193822c62477SPoul-Henning Kamp 
193922c62477SPoul-Henning Kamp 	LIST_FOREACH(ip, &root, list) {
194022c62477SPoul-Henning Kamp 		if (!strcmp(ip->name, name)) {
194122c62477SPoul-Henning Kamp 			mla = ip->la;
194222c62477SPoul-Henning Kamp 			mip = ip;
194322c62477SPoul-Henning Kamp 			return;
194422c62477SPoul-Henning Kamp 		}
194522c62477SPoul-Henning Kamp 	}
194622c62477SPoul-Henning Kamp 	ninstance++;
194722c62477SPoul-Henning Kamp 	ip = calloc(sizeof *ip, 1);
194822c62477SPoul-Henning Kamp 	ip->name = strdup(name);
194922c62477SPoul-Henning Kamp 	ip->la = LibAliasInit (ip->la);
195022c62477SPoul-Henning Kamp 	ip->assignAliasAddr	= 0;
195122c62477SPoul-Henning Kamp 	ip->ifName		= NULL;
195222c62477SPoul-Henning Kamp  	ip->logDropped		= 0;
195322c62477SPoul-Henning Kamp 	ip->inPort		= 0;
195422c62477SPoul-Henning Kamp 	ip->outPort		= 0;
195522c62477SPoul-Henning Kamp 	ip->inOutPort		= 0;
195622c62477SPoul-Henning Kamp 	ip->aliasAddr.s_addr	= INADDR_NONE;
195722c62477SPoul-Henning Kamp 	ip->ifMTU		= -1;
195822c62477SPoul-Henning Kamp 	ip->aliasOverhead	= 12;
195922c62477SPoul-Henning Kamp 	LIST_INSERT_HEAD(&root, ip, list);
196022c62477SPoul-Henning Kamp 	mla = ip->la;
196122c62477SPoul-Henning Kamp 	mip = ip;
1962b07fbc17SJoe Marcus Clarke }
1963