126781Sbrian/*
226781Sbrian * natd - Network Address Translation Daemon for FreeBSD.
326781Sbrian *
432026Salex * This software is provided free of charge, with no
526781Sbrian * warranty of any kind, either expressed or implied.
626781Sbrian * Use at your own risk.
726781Sbrian *
826781Sbrian * You may copy, modify and distribute this software (natd.c) freely.
926781Sbrian *
1028045Sbrian * Ari Suutari <suutari@iki.fi>
1126781Sbrian */
1226781Sbrian
13110415Scharnier#include <sys/cdefs.h>
14110415Scharnier__FBSDID("$FreeBSD$");
15110415Scharnier
1644558Sbrian#define SYSLOG_NAMES
1744558Sbrian
1826781Sbrian#include <sys/types.h>
1926781Sbrian#include <sys/socket.h>
2052200Sru#include <sys/sysctl.h>
2126781Sbrian#include <sys/time.h>
22131567Sphk#include <sys/queue.h>
2326781Sbrian
2426781Sbrian#include <netinet/in.h>
2526781Sbrian#include <netinet/in_systm.h>
2626781Sbrian#include <netinet/ip.h>
2726781Sbrian#include <machine/in_cksum.h>
2826781Sbrian#include <netinet/tcp.h>
2944558Sbrian#include <netinet/udp.h>
3044558Sbrian#include <netinet/ip_icmp.h>
3126781Sbrian#include <net/if.h>
3252200Sru#include <net/if_dl.h>
3326781Sbrian#include <net/route.h>
3426781Sbrian#include <arpa/inet.h>
3526781Sbrian
3630059Scharnier#include <alias.h>
3730059Scharnier#include <ctype.h>
3830059Scharnier#include <err.h>
3930059Scharnier#include <errno.h>
4030059Scharnier#include <netdb.h>
4130059Scharnier#include <signal.h>
4230059Scharnier#include <stdio.h>
4330059Scharnier#include <stdlib.h>
4430059Scharnier#include <string.h>
4526781Sbrian#include <syslog.h>
4630059Scharnier#include <unistd.h>
4731660Sbrian
4826781Sbrian#include "natd.h"
4926781Sbrian
50131567Sphkstruct instance {
51131567Sphk	const char		*name;
52131567Sphk	struct libalias		*la;
53131567Sphk	LIST_ENTRY(instance)	list;
54131567Sphk
55131567Sphk	int			ifIndex;
56131567Sphk	int			assignAliasAddr;
57131567Sphk	char*			ifName;
58131567Sphk	int			logDropped;
59131567Sphk	u_short			inPort;
60131567Sphk	u_short			outPort;
61131567Sphk	u_short			inOutPort;
62131567Sphk	struct in_addr		aliasAddr;
63131567Sphk	int			ifMTU;
64131567Sphk	int			aliasOverhead;
65131567Sphk	int			dropIgnoredIncoming;
66131567Sphk	int			divertIn;
67131567Sphk	int			divertOut;
68131567Sphk	int			divertInOut;
69131567Sphk};
70131567Sphk
71201145Santoinestatic LIST_HEAD(, instance) root = LIST_HEAD_INITIALIZER(root);
72131567Sphk
73131567Sphkstruct libalias *mla;
74227081Sedstatic struct instance *mip;
75227081Sedstatic int ninstance = 1;
76131567Sphk
7726781Sbrian/*
7826781Sbrian * Default values for input and output
7926781Sbrian * divert socket ports.
8026781Sbrian */
8126781Sbrian
8226781Sbrian#define	DEFAULT_SERVICE	"natd"
8326781Sbrian
8426781Sbrian/*
8545010Sbrian * Definition of a port range, and macros to deal with values.
8645010Sbrian * FORMAT:  HI 16-bits == first port in range, 0 == all ports.
8745010Sbrian *          LO 16-bits == number of ports in range
8845010Sbrian * NOTES:   - Port values are not stored in network byte order.
8945010Sbrian */
9045010Sbrian
9145010Sbriantypedef u_long port_range;
9245010Sbrian
9345010Sbrian#define GETLOPORT(x)     ((x) >> 0x10)
9445010Sbrian#define GETNUMPORTS(x)   ((x) & 0x0000ffff)
9545010Sbrian#define GETHIPORT(x)     (GETLOPORT((x)) + GETNUMPORTS((x)))
9645010Sbrian
9745010Sbrian/* Set y to be the low-port value in port_range variable x. */
9845010Sbrian#define SETLOPORT(x,y)   ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
9945010Sbrian
10045010Sbrian/* Set y to be the number of ports in port_range variable x. */
10145010Sbrian#define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
10245010Sbrian
10345010Sbrian/*
10426781Sbrian * Function prototypes.
10526781Sbrian */
10626781Sbrian
10744558Sbrianstatic void	DoAliasing (int fd, int direction);
10845011Sbrianstatic void	DaemonMode (void);
10931660Sbrianstatic void	HandleRoutingInfo (int fd);
11045011Sbrianstatic void	Usage (void);
11144558Sbrianstatic char*	FormatPacket (struct ip*);
11231660Sbrianstatic void	PrintPacket (struct ip*);
11345011Sbrianstatic void	SyslogPacket (struct ip*, int priority, const char *label);
114220736Ssobomaxstatic int	SetAliasAddressFromIfName (const char *ifName);
11545011Sbrianstatic void	InitiateShutdown (int);
11645011Sbrianstatic void	Shutdown (int);
11745011Sbrianstatic void	RefreshAddr (int);
11861726Srustatic void	ParseOption (const char* option, const char* parms);
11945011Sbrianstatic void	ReadConfigFile (const char* fileName);
12045011Sbrianstatic void	SetupPortRedirect (const char* parms);
12159921Srustatic void	SetupProtoRedirect(const char* parms);
12245011Sbrianstatic void	SetupAddressRedirect (const char* parms);
12345011Sbrianstatic void	StrToAddr (const char* str, struct in_addr* addr);
12445011Sbrianstatic u_short  StrToPort (const char* str, const char* proto);
12545011Sbrianstatic int      StrToPortRange (const char* str, const char* proto, port_range *portRange);
12645011Sbrianstatic int 	StrToProto (const char* str);
12745011Sbrianstatic int      StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange);
12831660Sbrianstatic void	ParseArgs (int argc, char** argv);
12962160Srustatic void	SetupPunchFW(const char *strValue);
130120372Smarcusstatic void	SetupSkinnyPort(const char *strValue);
131131567Sphkstatic void	NewInstance(const char *name);
132131567Sphkstatic void	DoGlobal (int fd);
133182825Srikstatic int	CheckIpfwRulenum(unsigned int rnum);
13426781Sbrian
13526781Sbrian/*
13626781Sbrian * Globals.
13726781Sbrian */
13826781Sbrian
13928045Sbrianstatic	int			verbose;
14028045Sbrianstatic 	int			background;
14128045Sbrianstatic	int			running;
142131567Sphkstatic	int			logFacility;
143131567Sphk
14428045Sbrianstatic 	int			dynamicMode;
14528045Sbrianstatic 	int			icmpSock;
14686954Srustatic	int			logIpfwDenied;
147145797Sdelphijstatic	const char*		pidName;
148131567Sphkstatic	int			routeSock;
149131567Sphkstatic	int			globalPort;
150131567Sphkstatic	int			divertGlobal;
151179937Smavstatic	int			exitDelay;
15226781Sbrian
153179937Smav
15426781Sbrianint main (int argc, char** argv)
15526781Sbrian{
15626781Sbrian	struct sockaddr_in	addr;
15726781Sbrian	fd_set			readMask;
15826781Sbrian	int			fdMax;
159220736Ssobomax	int			rval;
16026781Sbrian/*
16126781Sbrian * Initialize packet aliasing software.
16226781Sbrian * Done already here to be able to alter option bits
16326781Sbrian * during command line and configuration file processing.
16426781Sbrian */
165131567Sphk	NewInstance("default");
166131567Sphk
16726781Sbrian/*
16826781Sbrian * Parse options.
16926781Sbrian */
17026781Sbrian	verbose 		= 0;
17126781Sbrian	background		= 0;
17226781Sbrian	running			= 1;
17326781Sbrian	dynamicMode		= 0;
17444558Sbrian 	logFacility		= LOG_DAEMON;
17586955Sru	logIpfwDenied		= -1;
176118873Sru	pidName			= PIDFILE;
177131567Sphk	routeSock 		= -1;
178131567Sphk	icmpSock 		= -1;
179131567Sphk	fdMax	 		= -1;
180131567Sphk	divertGlobal		= -1;
181179937Smav	exitDelay		= EXIT_DELAY;
18226781Sbrian
18326781Sbrian	ParseArgs (argc, argv);
18426781Sbrian/*
18586955Sru * Log ipfw(8) denied packets by default in verbose mode.
18686955Sru */
18786955Sru	if (logIpfwDenied == -1)
18886955Sru		logIpfwDenied = verbose;
18986955Sru/*
19044558Sbrian * Open syslog channel.
19144558Sbrian */
19252200Sru	openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
19352200Sru		 logFacility);
194131567Sphk
195131567Sphk	LIST_FOREACH(mip, &root, list) {
196131567Sphk		mla = mip->la;
19744558Sbrian/*
198116319Sru * If not doing the transparent proxying only,
199116319Sru * check that valid aliasing address has been given.
20026781Sbrian */
201131567Sphk		if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL &&
202131567Sphk		    !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY))
203131567Sphk			errx (1, "instance %s: aliasing address not given", mip->name);
20426781Sbrian
205131567Sphk		if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL)
206131567Sphk			errx (1, "both alias address and interface "
207131567Sphk				 "name are not allowed");
20826781Sbrian/*
20926781Sbrian * Check that valid port number is known.
21026781Sbrian */
211131567Sphk		if (mip->inPort != 0 || mip->outPort != 0)
212131567Sphk			if (mip->inPort == 0 || mip->outPort == 0)
213131567Sphk				errx (1, "both input and output ports are required");
21426781Sbrian
215131567Sphk		if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0)
216131567Sphk			ParseOption ("port", DEFAULT_SERVICE);
21726781Sbrian
21826781Sbrian/*
21929163Sbrian * Check if ignored packets should be dropped.
22029163Sbrian */
221131567Sphk		mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0);
222131567Sphk		mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
22329163Sbrian/*
22426781Sbrian * Create divert sockets. Use only one socket if -p was specified
22526781Sbrian * on command line. Otherwise, create separate sockets for
226293290Sbdrewery * outgoing and incoming connections.
22726781Sbrian */
228131567Sphk		if (mip->inOutPort) {
22926781Sbrian
230131567Sphk			mip->divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
231131567Sphk			if (mip->divertInOut == -1)
232131567Sphk				Quit ("Unable to create divert socket.");
233131567Sphk			if (mip->divertInOut > fdMax)
234131567Sphk				fdMax = mip->divertInOut;
23526781Sbrian
236131567Sphk			mip->divertIn  = -1;
237131567Sphk			mip->divertOut = -1;
23826781Sbrian/*
23926781Sbrian * Bind socket.
24026781Sbrian */
24126781Sbrian
242131567Sphk			addr.sin_family		= AF_INET;
243131567Sphk			addr.sin_addr.s_addr	= INADDR_ANY;
244131567Sphk			addr.sin_port		= mip->inOutPort;
24526781Sbrian
246131567Sphk			if (bind (mip->divertInOut,
247131567Sphk				  (struct sockaddr*) &addr,
248131567Sphk				  sizeof addr) == -1)
249131567Sphk				Quit ("Unable to bind divert socket.");
250131567Sphk		}
251131567Sphk		else {
25226781Sbrian
253131567Sphk			mip->divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
254131567Sphk			if (mip->divertIn == -1)
255131567Sphk				Quit ("Unable to create incoming divert socket.");
256131567Sphk			if (mip->divertIn > fdMax)
257131567Sphk				fdMax = mip->divertIn;
25826781Sbrian
25926781Sbrian
260131567Sphk			mip->divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
261131567Sphk			if (mip->divertOut == -1)
262131567Sphk				Quit ("Unable to create outgoing divert socket.");
263131567Sphk			if (mip->divertOut > fdMax)
264131567Sphk				fdMax = mip->divertOut;
26526781Sbrian
266131567Sphk			mip->divertInOut = -1;
267131567Sphk
26826781Sbrian/*
26926781Sbrian * Bind divert sockets.
27026781Sbrian */
27126781Sbrian
272131567Sphk			addr.sin_family		= AF_INET;
273131567Sphk			addr.sin_addr.s_addr	= INADDR_ANY;
274131567Sphk			addr.sin_port		= mip->inPort;
27526781Sbrian
276131567Sphk			if (bind (mip->divertIn,
277131567Sphk				  (struct sockaddr*) &addr,
278131567Sphk				  sizeof addr) == -1)
279131567Sphk				Quit ("Unable to bind incoming divert socket.");
28026781Sbrian
281131567Sphk			addr.sin_family		= AF_INET;
282131567Sphk			addr.sin_addr.s_addr	= INADDR_ANY;
283131567Sphk			addr.sin_port		= mip->outPort;
28426781Sbrian
285131567Sphk			if (bind (mip->divertOut,
286131567Sphk				  (struct sockaddr*) &addr,
287131567Sphk				  sizeof addr) == -1)
288131567Sphk				Quit ("Unable to bind outgoing divert socket.");
289131567Sphk		}
29026781Sbrian/*
29151751Sru * Create routing socket if interface name specified and in dynamic mode.
29226781Sbrian */
293131567Sphk		if (mip->ifName) {
294131567Sphk			if (dynamicMode) {
29526781Sbrian
296131567Sphk				if (routeSock == -1)
297131567Sphk					routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
298131567Sphk				if (routeSock == -1)
299131567Sphk					Quit ("Unable to create routing info socket.");
300131567Sphk				if (routeSock > fdMax)
301131567Sphk					fdMax = routeSock;
30251751Sru
303131567Sphk				mip->assignAliasAddr = 1;
304131567Sphk			}
305220736Ssobomax			else {
306220736Ssobomax				do {
307220736Ssobomax					rval = SetAliasAddressFromIfName (mip->ifName);
308220808Ssobomax					if (background == 0 || dynamicMode == 0)
309220808Ssobomax						break;
310220808Ssobomax					if (rval == EAGAIN)
311220736Ssobomax						sleep(1);
312220808Ssobomax				} while (rval == EAGAIN);
313220736Ssobomax				if (rval != 0)
314220736Ssobomax					exit(1);
315220736Ssobomax			}
31651751Sru		}
317131567Sphk
31826781Sbrian	}
319131567Sphk	if (globalPort) {
320131567Sphk
321131567Sphk		divertGlobal = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
322131567Sphk		if (divertGlobal == -1)
323131567Sphk			Quit ("Unable to create divert socket.");
324131567Sphk		if (divertGlobal > fdMax)
325131567Sphk			fdMax = divertGlobal;
326131567Sphk
32726781Sbrian/*
328131567Sphk* Bind socket.
329131567Sphk*/
330131567Sphk
331131567Sphk		addr.sin_family		= AF_INET;
332131567Sphk		addr.sin_addr.s_addr	= INADDR_ANY;
333131567Sphk		addr.sin_port		= globalPort;
334131567Sphk
335131567Sphk		if (bind (divertGlobal,
336131567Sphk			  (struct sockaddr*) &addr,
337131567Sphk			  sizeof addr) == -1)
338131567Sphk			Quit ("Unable to bind global divert socket.");
339131567Sphk	}
340131567Sphk/*
34126781Sbrian * Create socket for sending ICMP messages.
34226781Sbrian */
34326781Sbrian	icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
34426781Sbrian	if (icmpSock == -1)
34526781Sbrian		Quit ("Unable to create ICMP socket.");
34645143Sbrian
34726781Sbrian/*
34845143Sbrian * And disable reads for the socket, otherwise it slowly fills
34945143Sbrian * up with received icmps which we do not use.
35045143Sbrian */
35145143Sbrian	shutdown(icmpSock, SHUT_RD);
35245143Sbrian
35345143Sbrian/*
35426781Sbrian * Become a daemon unless verbose mode was requested.
35526781Sbrian */
35626781Sbrian	if (!verbose)
35726781Sbrian		DaemonMode ();
35826781Sbrian/*
35926781Sbrian * Catch signals to manage shutdown and
36026781Sbrian * refresh of interface address.
36126781Sbrian */
36250810Sru	siginterrupt(SIGTERM, 1);
36350810Sru	siginterrupt(SIGHUP, 1);
364179937Smav	if (exitDelay)
365179937Smav		signal(SIGTERM, InitiateShutdown);
366179937Smav	else
367179937Smav		signal(SIGTERM, Shutdown);
36826781Sbrian	signal (SIGHUP, RefreshAddr);
36926781Sbrian/*
37026781Sbrian * Set alias address if it has been given.
37126781Sbrian */
372131567Sphk	mip = LIST_FIRST(&root);	/* XXX: simon */
373131567Sphk	LIST_FOREACH(mip, &root, list) {
374131567Sphk		mla = mip->la;
375131567Sphk		if (mip->aliasAddr.s_addr != INADDR_NONE)
376131567Sphk			LibAliasSetAddress (mla, mip->aliasAddr);
377131567Sphk	}
37826781Sbrian
37928045Sbrian	while (running) {
380131567Sphk		mip = LIST_FIRST(&root);	/* XXX: simon */
38128045Sbrian
382131567Sphk		if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) {
38328045Sbrian/*
38428045Sbrian * When using only one socket, just call
38528045Sbrian * DoAliasing repeatedly to process packets.
38628045Sbrian */
387131567Sphk			DoAliasing (mip->divertInOut, DONT_KNOW);
38828045Sbrian			continue;
38928045Sbrian		}
39026781Sbrian/*
39126781Sbrian * Build read mask from socket descriptors to select.
39226781Sbrian */
39328045Sbrian		FD_ZERO (&readMask);
39428045Sbrian/*
39589396Sru * Check if new packets are available.
39628045Sbrian */
397131567Sphk		LIST_FOREACH(mip, &root, list) {
398131567Sphk			if (mip->divertIn != -1)
399131567Sphk				FD_SET (mip->divertIn, &readMask);
40028045Sbrian
401131567Sphk			if (mip->divertOut != -1)
402131567Sphk				FD_SET (mip->divertOut, &readMask);
40326781Sbrian
404131567Sphk			if (mip->divertInOut != -1)
405131567Sphk				FD_SET (mip->divertInOut, &readMask);
406131567Sphk		}
40728045Sbrian/*
40828045Sbrian * Routing info is processed always.
40928045Sbrian */
41028045Sbrian		if (routeSock != -1)
41128045Sbrian			FD_SET (routeSock, &readMask);
41226781Sbrian
413131567Sphk		if (divertGlobal != -1)
414131567Sphk			FD_SET (divertGlobal, &readMask);
415131567Sphk
41628045Sbrian		if (select (fdMax + 1,
41728045Sbrian			    &readMask,
41828045Sbrian			    NULL,
41989396Sru			    NULL,
42028045Sbrian			    NULL) == -1) {
42126781Sbrian
42228045Sbrian			if (errno == EINTR)
42328045Sbrian				continue;
42426781Sbrian
42528045Sbrian			Quit ("Select failed.");
42628045Sbrian		}
42726781Sbrian
428131567Sphk		if (divertGlobal != -1)
429131567Sphk			if (FD_ISSET (divertGlobal, &readMask))
430131567Sphk				DoGlobal (divertGlobal);
431131567Sphk		LIST_FOREACH(mip, &root, list) {
432131567Sphk			mla = mip->la;
433131567Sphk			if (mip->divertIn != -1)
434131567Sphk				if (FD_ISSET (mip->divertIn, &readMask))
435131567Sphk					DoAliasing (mip->divertIn, INPUT);
43626781Sbrian
437131567Sphk			if (mip->divertOut != -1)
438131567Sphk				if (FD_ISSET (mip->divertOut, &readMask))
439131567Sphk					DoAliasing (mip->divertOut, OUTPUT);
44026781Sbrian
441131567Sphk			if (mip->divertInOut != -1)
442131567Sphk				if (FD_ISSET (mip->divertInOut, &readMask))
443131567Sphk					DoAliasing (mip->divertInOut, DONT_KNOW);
44426781Sbrian
445131567Sphk		}
44628045Sbrian		if (routeSock != -1)
44728045Sbrian			if (FD_ISSET (routeSock, &readMask))
44828045Sbrian				HandleRoutingInfo (routeSock);
44926781Sbrian	}
45026781Sbrian
45126781Sbrian	if (background)
452118873Sru		unlink (pidName);
45326781Sbrian
45426781Sbrian	return 0;
45526781Sbrian}
45626781Sbrian
457202531Sedstatic void DaemonMode(void)
45826781Sbrian{
45926781Sbrian	FILE*	pidFile;
46026781Sbrian
46126781Sbrian	daemon (0, 0);
46226781Sbrian	background = 1;
46326781Sbrian
464118873Sru	pidFile = fopen (pidName, "w");
46526781Sbrian	if (pidFile) {
46626781Sbrian
46726781Sbrian		fprintf (pidFile, "%d\n", getpid ());
46826781Sbrian		fclose (pidFile);
46926781Sbrian	}
47026781Sbrian}
47126781Sbrian
47226781Sbrianstatic void ParseArgs (int argc, char** argv)
47326781Sbrian{
47426781Sbrian	int		arg;
47526781Sbrian	char*		opt;
47626781Sbrian	char		parmBuf[256];
47759798Sjoe	int		len; /* bounds checking */
47826781Sbrian
47926781Sbrian	for (arg = 1; arg < argc; arg++) {
48026781Sbrian
48126781Sbrian		opt  = argv[arg];
48226781Sbrian		if (*opt != '-') {
48326781Sbrian
48430059Scharnier			warnx ("invalid option %s", opt);
48526781Sbrian			Usage ();
48626781Sbrian		}
48726781Sbrian
48826781Sbrian		parmBuf[0] = '\0';
48959798Sjoe		len = 0;
49026781Sbrian
49126781Sbrian		while (arg < argc - 1) {
49226781Sbrian
49326781Sbrian			if (argv[arg + 1][0] == '-')
49426781Sbrian				break;
49526781Sbrian
49661726Sru			if (len) {
49759798Sjoe				strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
49859798Sjoe				len += strlen(parmBuf + len);
49959798Sjoe			}
50026781Sbrian
50126781Sbrian			++arg;
50259798Sjoe			strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
50359798Sjoe			len += strlen(parmBuf + len);
50459798Sjoe
50526781Sbrian		}
50626781Sbrian
50761726Sru		ParseOption (opt + 1, (len ? parmBuf : NULL));
50859798Sjoe
50926781Sbrian	}
51026781Sbrian}
51126781Sbrian
512131567Sphkstatic void DoGlobal (int fd)
513131567Sphk{
514131567Sphk	int			bytes;
515131567Sphk	int			origBytes;
516131567Sphk	char			buf[IP_MAXPACKET];
517131567Sphk	struct sockaddr_in	addr;
518131567Sphk	int			wrote;
519145797Sdelphij	socklen_t		addrSize;
520131567Sphk	struct ip*		ip;
521131567Sphk	char			msgBuf[80];
522131567Sphk
523131567Sphk/*
524131567Sphk * Get packet from socket.
525131567Sphk */
526131567Sphk	addrSize  = sizeof addr;
527131567Sphk	origBytes = recvfrom (fd,
528131567Sphk			      buf,
529131567Sphk			      sizeof buf,
530131567Sphk			      0,
531131567Sphk			      (struct sockaddr*) &addr,
532131567Sphk			      &addrSize);
533131567Sphk
534131567Sphk	if (origBytes == -1) {
535131567Sphk
536131567Sphk		if (errno != EINTR)
537131567Sphk			Warn ("read from divert socket failed");
538131567Sphk
539131567Sphk		return;
540131567Sphk	}
541131567Sphk
542131567Sphk#if 0
543131567Sphk	if (mip->assignAliasAddr) {
544220736Ssobomax		if (SetAliasAddressFromIfName (mip->ifName) != 0)
545220736Ssobomax			exit(1);
546131567Sphk		mip->assignAliasAddr = 0;
547131567Sphk	}
548131567Sphk#endif
549131567Sphk/*
550131567Sphk * This is an IP packet.
551131567Sphk */
552131567Sphk	ip = (struct ip*) buf;
553131567Sphk
554131567Sphk	if (verbose) {
555131567Sphk/*
556131567Sphk * Print packet direction and protocol type.
557131567Sphk */
558131567Sphk		printf ("Glb ");
559131567Sphk
560131567Sphk		switch (ip->ip_p) {
561131567Sphk		case IPPROTO_TCP:
562131567Sphk			printf ("[TCP]  ");
563131567Sphk			break;
564131567Sphk
565131567Sphk		case IPPROTO_UDP:
566131567Sphk			printf ("[UDP]  ");
567131567Sphk			break;
568131567Sphk
569131567Sphk		case IPPROTO_ICMP:
570131567Sphk			printf ("[ICMP] ");
571131567Sphk			break;
572131567Sphk
573131567Sphk		default:
574131567Sphk			printf ("[%d]    ", ip->ip_p);
575131567Sphk			break;
576131567Sphk		}
577131567Sphk/*
578131567Sphk * Print addresses.
579131567Sphk */
580131567Sphk		PrintPacket (ip);
581131567Sphk	}
582131567Sphk
583131567Sphk	LIST_FOREACH(mip, &root, list) {
584131567Sphk		mla = mip->la;
585131567Sphk		if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED)
586131567Sphk			break;
587131567Sphk	}
588131567Sphk/*
589131567Sphk * Length might have changed during aliasing.
590131567Sphk */
591131567Sphk	bytes = ntohs (ip->ip_len);
592131567Sphk/*
593131567Sphk * Update alias overhead size for outgoing packets.
594131567Sphk */
595131567Sphk	if (mip != NULL && bytes - origBytes > mip->aliasOverhead)
596131567Sphk		mip->aliasOverhead = bytes - origBytes;
597131567Sphk
598131567Sphk	if (verbose) {
599131567Sphk
600131567Sphk/*
601131567Sphk * Print addresses after aliasing.
602131567Sphk */
603131567Sphk		printf (" aliased to\n");
604131567Sphk		printf ("           ");
605131567Sphk		PrintPacket (ip);
606131567Sphk		printf ("\n");
607131567Sphk	}
608131567Sphk
609131567Sphk/*
610131567Sphk * Put packet back for processing.
611131567Sphk */
612131567Sphk	wrote = sendto (fd,
613131567Sphk		        buf,
614131567Sphk	    		bytes,
615131567Sphk	    		0,
616131567Sphk	    		(struct sockaddr*) &addr,
617131567Sphk	    		sizeof addr);
618131567Sphk
619131567Sphk	if (wrote != bytes) {
620131567Sphk
621131567Sphk		if (errno == EMSGSIZE) {
622131567Sphk
623131567Sphk			if (mip->ifMTU != -1)
624131567Sphk				SendNeedFragIcmp (icmpSock,
625131567Sphk						  (struct ip*) buf,
626131567Sphk						  mip->ifMTU - mip->aliasOverhead);
627131567Sphk		}
628131567Sphk		else if (errno == EACCES && logIpfwDenied) {
629131567Sphk
630131567Sphk			sprintf (msgBuf, "failed to write packet back");
631131567Sphk			Warn (msgBuf);
632131567Sphk		}
633131567Sphk	}
634131567Sphk}
635131567Sphk
636131567Sphk
63744558Sbrianstatic void DoAliasing (int fd, int direction)
63826781Sbrian{
63926781Sbrian	int			bytes;
64026781Sbrian	int			origBytes;
64189396Sru	char			buf[IP_MAXPACKET];
64289396Sru	struct sockaddr_in	addr;
64389396Sru	int			wrote;
64429163Sbrian	int			status;
645145797Sdelphij	socklen_t		addrSize;
64626781Sbrian	struct ip*		ip;
64789396Sru	char			msgBuf[80];
648220736Ssobomax	int			rval;
64926781Sbrian
650131567Sphk	if (mip->assignAliasAddr) {
651220736Ssobomax		do {
652220736Ssobomax			rval = SetAliasAddressFromIfName (mip->ifName);
653220808Ssobomax			if (background == 0 || dynamicMode == 0)
654220808Ssobomax				break;
655220808Ssobomax			if (rval == EAGAIN)
656220736Ssobomax				sleep(1);
657220808Ssobomax		} while (rval == EAGAIN);
658220736Ssobomax		if (rval != 0)
659220736Ssobomax			exit(1);
660131567Sphk		mip->assignAliasAddr = 0;
66126781Sbrian	}
66226781Sbrian/*
66326781Sbrian * Get packet from socket.
66426781Sbrian */
66589396Sru	addrSize  = sizeof addr;
66626781Sbrian	origBytes = recvfrom (fd,
66789396Sru			      buf,
66889396Sru			      sizeof buf,
66926781Sbrian			      0,
67089396Sru			      (struct sockaddr*) &addr,
67126781Sbrian			      &addrSize);
67226781Sbrian
67326781Sbrian	if (origBytes == -1) {
67426781Sbrian
67526781Sbrian		if (errno != EINTR)
67630059Scharnier			Warn ("read from divert socket failed");
67726781Sbrian
67826781Sbrian		return;
67926781Sbrian	}
68026781Sbrian/*
681108533Sschweikh * This is an IP packet.
68226781Sbrian */
68389396Sru	ip = (struct ip*) buf;
68446080Simp	if (direction == DONT_KNOW) {
68589396Sru		if (addr.sin_addr.s_addr == INADDR_ANY)
68644558Sbrian			direction = OUTPUT;
68744558Sbrian		else
68844558Sbrian			direction = INPUT;
68946080Simp	}
69026781Sbrian
69126781Sbrian	if (verbose) {
69226781Sbrian/*
69326781Sbrian * Print packet direction and protocol type.
69426781Sbrian */
69544558Sbrian		printf (direction == OUTPUT ? "Out " : "In  ");
696131567Sphk		if (ninstance > 1)
697145797Sdelphij			printf ("{%s}", mip->name);
69826781Sbrian
69926781Sbrian		switch (ip->ip_p) {
70026781Sbrian		case IPPROTO_TCP:
70126781Sbrian			printf ("[TCP]  ");
70226781Sbrian			break;
70326781Sbrian
70426781Sbrian		case IPPROTO_UDP:
70526781Sbrian			printf ("[UDP]  ");
70626781Sbrian			break;
70726781Sbrian
70826781Sbrian		case IPPROTO_ICMP:
70926781Sbrian			printf ("[ICMP] ");
71026781Sbrian			break;
71126781Sbrian
71226781Sbrian		default:
71344558Sbrian			printf ("[%d]    ", ip->ip_p);
71426781Sbrian			break;
71526781Sbrian		}
71626781Sbrian/*
71726781Sbrian * Print addresses.
71826781Sbrian */
71926781Sbrian		PrintPacket (ip);
72026781Sbrian	}
72126781Sbrian
72244558Sbrian	if (direction == OUTPUT) {
72326781Sbrian/*
72426781Sbrian * Outgoing packets. Do aliasing.
72526781Sbrian */
726131567Sphk		LibAliasOut (mla, buf, IP_MAXPACKET);
72726781Sbrian	}
72826781Sbrian	else {
72944558Sbrian
73026781Sbrian/*
73126781Sbrian * Do aliasing.
73226781Sbrian */
733131567Sphk		status = LibAliasIn (mla, buf, IP_MAXPACKET);
73429163Sbrian		if (status == PKT_ALIAS_IGNORED &&
735131567Sphk		    mip->dropIgnoredIncoming) {
73629163Sbrian
73744558Sbrian			if (verbose)
73844558Sbrian				printf (" dropped.\n");
73944558Sbrian
740131567Sphk			if (mip->logDropped)
74144558Sbrian				SyslogPacket (ip, LOG_WARNING, "denied");
74244558Sbrian
74329163Sbrian			return;
74429163Sbrian		}
74526781Sbrian	}
74626781Sbrian/*
74726781Sbrian * Length might have changed during aliasing.
74826781Sbrian */
74926781Sbrian	bytes = ntohs (ip->ip_len);
75026781Sbrian/*
75126781Sbrian * Update alias overhead size for outgoing packets.
75226781Sbrian */
75344558Sbrian	if (direction == OUTPUT &&
754131567Sphk	    bytes - origBytes > mip->aliasOverhead)
755131567Sphk		mip->aliasOverhead = bytes - origBytes;
75626781Sbrian
75726781Sbrian	if (verbose) {
75826781Sbrian
75926781Sbrian/*
76026781Sbrian * Print addresses after aliasing.
76126781Sbrian */
76226781Sbrian		printf (" aliased to\n");
76326781Sbrian		printf ("           ");
76426781Sbrian		PrintPacket (ip);
76526781Sbrian		printf ("\n");
76626781Sbrian	}
76728045Sbrian
76826781Sbrian/*
76926781Sbrian * Put packet back for processing.
77026781Sbrian */
77126781Sbrian	wrote = sendto (fd,
77289396Sru		        buf,
77389396Sru	    		bytes,
77426781Sbrian	    		0,
77589396Sru	    		(struct sockaddr*) &addr,
77689396Sru	    		sizeof addr);
77726781Sbrian
77889396Sru	if (wrote != bytes) {
77926781Sbrian
78026781Sbrian		if (errno == EMSGSIZE) {
78126781Sbrian
78289396Sru			if (direction == OUTPUT &&
783131567Sphk			    mip->ifMTU != -1)
78426781Sbrian				SendNeedFragIcmp (icmpSock,
78589396Sru						  (struct ip*) buf,
786131567Sphk						  mip->ifMTU - mip->aliasOverhead);
78726781Sbrian		}
78886954Sru		else if (errno == EACCES && logIpfwDenied) {
78926781Sbrian
79078549Sjoe			sprintf (msgBuf, "failed to write packet back");
79126781Sbrian			Warn (msgBuf);
79226781Sbrian		}
79326781Sbrian	}
79426781Sbrian}
79526781Sbrian
79626781Sbrianstatic void HandleRoutingInfo (int fd)
79726781Sbrian{
79826781Sbrian	int			bytes;
79926781Sbrian	struct if_msghdr	ifMsg;
80026781Sbrian/*
80126781Sbrian * Get packet from socket.
80226781Sbrian */
80326781Sbrian	bytes = read (fd, &ifMsg, sizeof ifMsg);
80426781Sbrian	if (bytes == -1) {
80526781Sbrian
80630059Scharnier		Warn ("read from routing socket failed");
80726781Sbrian		return;
80826781Sbrian	}
80926781Sbrian
81026781Sbrian	if (ifMsg.ifm_version != RTM_VERSION) {
81126781Sbrian
81230059Scharnier		Warn ("unexpected packet read from routing socket");
81326781Sbrian		return;
81426781Sbrian	}
81526781Sbrian
81626781Sbrian	if (verbose)
81756587Sru		printf ("Routing message %#x received.\n", ifMsg.ifm_type);
81826781Sbrian
819131567Sphk	if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) {
820131567Sphk		LIST_FOREACH(mip, &root, list) {
821131567Sphk			mla = mip->la;
822131567Sphk			if (ifMsg.ifm_index == mip->ifIndex) {
823131567Sphk				if (verbose)
824131567Sphk					printf("Interface address/MTU has probably changed.\n");
825131567Sphk				mip->assignAliasAddr = 1;
826131567Sphk			}
827131567Sphk		}
82856587Sru	}
82926781Sbrian}
83026781Sbrian
83126781Sbrianstatic void PrintPacket (struct ip* ip)
83226781Sbrian{
83344558Sbrian	printf ("%s", FormatPacket (ip));
83444558Sbrian}
83544558Sbrian
83645011Sbrianstatic void SyslogPacket (struct ip* ip, int priority, const char *label)
83744558Sbrian{
83844558Sbrian	syslog (priority, "%s %s", label, FormatPacket (ip));
83944558Sbrian}
84044558Sbrian
84144558Sbrianstatic char* FormatPacket (struct ip* ip)
84244558Sbrian{
84344558Sbrian	static char	buf[256];
84426781Sbrian	struct tcphdr*	tcphdr;
84544558Sbrian	struct udphdr*	udphdr;
84644558Sbrian	struct icmp*	icmphdr;
84744558Sbrian	char		src[20];
84844558Sbrian	char		dst[20];
84926781Sbrian
85044558Sbrian	strcpy (src, inet_ntoa (ip->ip_src));
85144558Sbrian	strcpy (dst, inet_ntoa (ip->ip_dst));
85244558Sbrian
85344558Sbrian	switch (ip->ip_p) {
85444558Sbrian	case IPPROTO_TCP:
85526781Sbrian		tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
85644558Sbrian		sprintf (buf, "[TCP] %s:%d -> %s:%d",
85744558Sbrian			      src,
85844558Sbrian			      ntohs (tcphdr->th_sport),
85944558Sbrian			      dst,
86044558Sbrian			      ntohs (tcphdr->th_dport));
86144558Sbrian		break;
86226781Sbrian
86344558Sbrian	case IPPROTO_UDP:
86444558Sbrian		udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
86544558Sbrian		sprintf (buf, "[UDP] %s:%d -> %s:%d",
86644558Sbrian			      src,
86744558Sbrian			      ntohs (udphdr->uh_sport),
86844558Sbrian			      dst,
86944558Sbrian			      ntohs (udphdr->uh_dport));
87044558Sbrian		break;
87126781Sbrian
87244558Sbrian	case IPPROTO_ICMP:
87344558Sbrian		icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
87444654Sbrian		sprintf (buf, "[ICMP] %s -> %s %u(%u)",
87544558Sbrian			      src,
87644558Sbrian			      dst,
87744654Sbrian			      icmphdr->icmp_type,
87844654Sbrian			      icmphdr->icmp_code);
87944558Sbrian		break;
88044558Sbrian
88144558Sbrian	default:
88244558Sbrian		sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
88344558Sbrian		break;
88444558Sbrian	}
88544558Sbrian
88644558Sbrian	return buf;
88726781Sbrian}
88826781Sbrian
889220736Ssobomaxstatic int
89052200SruSetAliasAddressFromIfName(const char *ifn)
89126781Sbrian{
89252200Sru	size_t needed;
89352200Sru	int mib[6];
89452200Sru	char *buf, *lim, *next;
89552200Sru	struct if_msghdr *ifm;
89652200Sru	struct ifa_msghdr *ifam;
89752200Sru	struct sockaddr_dl *sdl;
89852200Sru	struct sockaddr_in *sin;
89926781Sbrian
90052200Sru	mib[0] = CTL_NET;
90152200Sru	mib[1] = PF_ROUTE;
90252200Sru	mib[2] = 0;
90352200Sru	mib[3] = AF_INET;	/* Only IP addresses please */
90452200Sru	mib[4] = NET_RT_IFLIST;
90552200Sru	mib[5] = 0;		/* ifIndex??? */
90626781Sbrian/*
90726781Sbrian * Get interface data.
90826781Sbrian */
90952200Sru	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
91052200Sru		err(1, "iflist-sysctl-estimate");
91152200Sru	if ((buf = malloc(needed)) == NULL)
91252200Sru		errx(1, "malloc failed");
913179607Sbrian	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1 && errno != ENOMEM)
91452200Sru		err(1, "iflist-sysctl-get");
91552200Sru	lim = buf + needed;
91626781Sbrian/*
91726781Sbrian * Loop through interfaces until one with
91826781Sbrian * given name is found. This is done to
91926781Sbrian * find correct interface index for routing
92026781Sbrian * message processing.
92126781Sbrian */
922131567Sphk	mip->ifIndex	= 0;
92352200Sru	next = buf;
92452200Sru	while (next < lim) {
92552200Sru		ifm = (struct if_msghdr *)next;
92652200Sru		next += ifm->ifm_msglen;
92752200Sru		if (ifm->ifm_version != RTM_VERSION) {
92852200Sru			if (verbose)
92952200Sru				warnx("routing message version %d "
93052200Sru				      "not understood", ifm->ifm_version);
93152200Sru			continue;
93226781Sbrian		}
93352200Sru		if (ifm->ifm_type == RTM_IFINFO) {
93452200Sru			sdl = (struct sockaddr_dl *)(ifm + 1);
93552200Sru			if (strlen(ifn) == sdl->sdl_nlen &&
93652200Sru			    strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
937131567Sphk				mip->ifIndex = ifm->ifm_index;
938131567Sphk				mip->ifMTU = ifm->ifm_data.ifi_mtu;
93952200Sru				break;
94052200Sru			}
94126781Sbrian		}
94226781Sbrian	}
943131567Sphk	if (!mip->ifIndex)
94452200Sru		errx(1, "unknown interface name %s", ifn);
94526781Sbrian/*
94652200Sru * Get interface address.
94726781Sbrian */
94852200Sru	sin = NULL;
94952200Sru	while (next < lim) {
95052200Sru		ifam = (struct ifa_msghdr *)next;
95152200Sru		next += ifam->ifam_msglen;
95252200Sru		if (ifam->ifam_version != RTM_VERSION) {
95352200Sru			if (verbose)
95452200Sru				warnx("routing message version %d "
95552200Sru				      "not understood", ifam->ifam_version);
95652200Sru			continue;
95752200Sru		}
95852200Sru		if (ifam->ifam_type != RTM_NEWADDR)
95952200Sru			break;
96052200Sru		if (ifam->ifam_addrs & RTA_IFA) {
96152200Sru			int i;
96252200Sru			char *cp = (char *)(ifam + 1);
96326781Sbrian
96452200Sru			for (i = 1; i < RTA_IFA; i <<= 1)
96552200Sru				if (ifam->ifam_addrs & i)
966128186Sluigi					cp += SA_SIZE((struct sockaddr *)cp);
96752200Sru			if (((struct sockaddr *)cp)->sa_family == AF_INET) {
96852200Sru				sin = (struct sockaddr_in *)cp;
96952200Sru				break;
97052200Sru			}
97152200Sru		}
97252200Sru	}
973220736Ssobomax	if (sin == NULL) {
974220736Ssobomax		warnx("%s: cannot get interface address", ifn);
975220736Ssobomax		free(buf);
976220806Ssobomax		return EAGAIN;
977220736Ssobomax	}
97826781Sbrian
979131567Sphk	LibAliasSetAddress(mla, sin->sin_addr);
98052200Sru	syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
981131567Sphk	       inet_ntoa(sin->sin_addr), mip->ifMTU);
98226781Sbrian
98352200Sru	free(buf);
984220736Ssobomax
985220736Ssobomax	return 0;
98626781Sbrian}
98726781Sbrian
98845011Sbrianvoid Quit (const char* msg)
98926781Sbrian{
99026781Sbrian	Warn (msg);
99126781Sbrian	exit (1);
99226781Sbrian}
99326781Sbrian
99445011Sbrianvoid Warn (const char* msg)
99526781Sbrian{
99626781Sbrian	if (background)
99726781Sbrian		syslog (LOG_ALERT, "%s (%m)", msg);
99826781Sbrian	else
99962882Skris		warn ("%s", msg);
100026781Sbrian}
100126781Sbrian
1002145797Sdelphijstatic void RefreshAddr (int sig __unused)
100326781Sbrian{
1004162674Spiso	LibAliasRefreshModules();
1005162674Spiso	if (mip != NULL && mip->ifName != NULL)
1006131567Sphk		mip->assignAliasAddr = 1;
100726781Sbrian}
100826781Sbrian
1009145797Sdelphijstatic void InitiateShutdown (int sig __unused)
101026781Sbrian{
101126781Sbrian/*
101226781Sbrian * Start timer to allow kernel gracefully
101326781Sbrian * shutdown existing connections when system
101426781Sbrian * is shut down.
101526781Sbrian */
101650810Sru	siginterrupt(SIGALRM, 1);
101726781Sbrian	signal (SIGALRM, Shutdown);
1018179937Smav	ualarm(exitDelay*1000, 1000);
101926781Sbrian}
102026781Sbrian
1021145797Sdelphijstatic void Shutdown (int sig __unused)
102226781Sbrian{
102326781Sbrian	running = 0;
102426781Sbrian}
102526781Sbrian
102626781Sbrian/*
102726781Sbrian * Different options recognized by this program.
102826781Sbrian */
102926781Sbrian
103026781Sbrianenum Option {
103126781Sbrian
1032131567Sphk	LibAliasOption,
1033131567Sphk	Instance,
103426781Sbrian	Verbose,
103526781Sbrian	InPort,
103626781Sbrian	OutPort,
103726781Sbrian	Port,
1038131567Sphk	GlobalPort,
103926781Sbrian	AliasAddress,
104060683Sru	TargetAddress,
104126781Sbrian	InterfaceName,
104226781Sbrian	RedirectPort,
104359921Sru	RedirectProto,
104426781Sbrian	RedirectAddress,
104526781Sbrian	ConfigFile,
104644558Sbrian	DynamicMode,
104744558Sbrian	ProxyRule,
104844558Sbrian 	LogDenied,
104962160Sru 	LogFacility,
105085770Sphk	PunchFW,
1051120372Smarcus	SkinnyPort,
1052118873Sru	LogIpfwDenied,
1053179937Smav	PidFile,
1054179937Smav	ExitDelay
105526781Sbrian};
105626781Sbrian
105726781Sbrianenum Param {
105826781Sbrian
105926781Sbrian	YesNo,
106026781Sbrian	Numeric,
106126781Sbrian	String,
106226781Sbrian	None,
106326781Sbrian	Address,
106426781Sbrian	Service
106526781Sbrian};
106626781Sbrian
106726781Sbrian/*
106826781Sbrian * Option information structure (used by ParseOption).
106926781Sbrian */
107026781Sbrian
107126781Sbrianstruct OptionInfo {
107226781Sbrian
107326781Sbrian	enum Option		type;
107426781Sbrian	int			packetAliasOpt;
107526781Sbrian	enum Param		parm;
107645011Sbrian	const char*		parmDescription;
107745011Sbrian	const char*		description;
107845011Sbrian	const char*		name;
107945011Sbrian	const char*		shortName;
108026781Sbrian};
108126781Sbrian
108226781Sbrian/*
108326781Sbrian * Table of known options.
108426781Sbrian */
108526781Sbrian
108626781Sbrianstatic struct OptionInfo optionTable[] = {
108726781Sbrian
1088131567Sphk	{ LibAliasOption,
108926781Sbrian		PKT_ALIAS_UNREGISTERED_ONLY,
109026781Sbrian		YesNo,
109126781Sbrian		"[yes|no]",
109226781Sbrian		"alias only unregistered addresses",
109326781Sbrian		"unregistered_only",
109426781Sbrian		"u" },
109526781Sbrian
1096131567Sphk	{ LibAliasOption,
109726781Sbrian		PKT_ALIAS_LOG,
109826781Sbrian		YesNo,
109926781Sbrian		"[yes|no]",
110026781Sbrian		"enable logging",
110126781Sbrian		"log",
110226781Sbrian		"l" },
110326781Sbrian
1104131567Sphk	{ LibAliasOption,
110544558Sbrian		PKT_ALIAS_PROXY_ONLY,
110644558Sbrian		YesNo,
110744558Sbrian		"[yes|no]",
110844558Sbrian		"proxy only",
110944558Sbrian		"proxy_only",
111044558Sbrian		NULL },
111144558Sbrian
1112131567Sphk	{ LibAliasOption,
111344558Sbrian		PKT_ALIAS_REVERSE,
111444558Sbrian		YesNo,
111544558Sbrian		"[yes|no]",
111644558Sbrian		"operate in reverse mode",
111744558Sbrian		"reverse",
111844558Sbrian		NULL },
111944558Sbrian
1120131567Sphk	{ LibAliasOption,
112126781Sbrian		PKT_ALIAS_DENY_INCOMING,
112226781Sbrian		YesNo,
112326781Sbrian		"[yes|no]",
112426781Sbrian		"allow incoming connections",
112526781Sbrian		"deny_incoming",
112626781Sbrian		"d" },
112726781Sbrian
1128131567Sphk	{ LibAliasOption,
112926781Sbrian		PKT_ALIAS_USE_SOCKETS,
113026781Sbrian		YesNo,
113126781Sbrian		"[yes|no]",
113226781Sbrian		"use sockets to inhibit port conflict",
113326781Sbrian		"use_sockets",
113426781Sbrian		"s" },
113526781Sbrian
1136131567Sphk	{ LibAliasOption,
113726781Sbrian		PKT_ALIAS_SAME_PORTS,
113826781Sbrian		YesNo,
113926781Sbrian		"[yes|no]",
114026781Sbrian		"try to keep original port numbers for connections",
114126781Sbrian		"same_ports",
114226781Sbrian		"m" },
114326781Sbrian
114426781Sbrian	{ Verbose,
114526781Sbrian		0,
114626781Sbrian		YesNo,
114726781Sbrian		"[yes|no]",
114826781Sbrian		"verbose mode, dump packet information",
114926781Sbrian		"verbose",
115026781Sbrian		"v" },
115126781Sbrian
115226781Sbrian	{ DynamicMode,
115326781Sbrian		0,
115426781Sbrian		YesNo,
115526781Sbrian		"[yes|no]",
115626781Sbrian		"dynamic mode, automatically detect interface address changes",
115726781Sbrian		"dynamic",
115826781Sbrian		NULL },
115926781Sbrian
116026781Sbrian	{ InPort,
116126781Sbrian		0,
116226781Sbrian		Service,
116326781Sbrian		"number|service_name",
116426781Sbrian		"set port for incoming packets",
116526781Sbrian		"in_port",
116626781Sbrian		"i" },
116726781Sbrian
116826781Sbrian	{ OutPort,
116926781Sbrian		0,
117026781Sbrian		Service,
117126781Sbrian		"number|service_name",
117226781Sbrian		"set port for outgoing packets",
117326781Sbrian		"out_port",
117426781Sbrian		"o" },
117526781Sbrian
117626781Sbrian	{ Port,
117726781Sbrian		0,
117826781Sbrian		Service,
117926781Sbrian		"number|service_name",
118026781Sbrian		"set port (defaults to natd/divert)",
118126781Sbrian		"port",
118226781Sbrian		"p" },
118326781Sbrian
1184131567Sphk	{ GlobalPort,
1185131567Sphk		0,
1186131567Sphk		Service,
1187131567Sphk		"number|service_name",
1188131567Sphk		"set globalport",
1189131567Sphk		"globalport",
1190131567Sphk		NULL },
1191131567Sphk
119226781Sbrian	{ AliasAddress,
119326781Sbrian		0,
119426781Sbrian		Address,
119526781Sbrian		"x.x.x.x",
119626781Sbrian		"address to use for aliasing",
119726781Sbrian		"alias_address",
119826781Sbrian		"a" },
119926781Sbrian
120060683Sru	{ TargetAddress,
120160683Sru		0,
120260683Sru		Address,
120360683Sru		"x.x.x.x",
120460683Sru		"address to use for incoming sessions",
120560683Sru		"target_address",
120660683Sru		"t" },
120760683Sru
120826781Sbrian	{ InterfaceName,
120926781Sbrian		0,
121026781Sbrian		String,
121126781Sbrian	        "network_if_name",
121226781Sbrian		"take aliasing address from interface",
121326781Sbrian		"interface",
121426781Sbrian		"n" },
121526781Sbrian
121644558Sbrian	{ ProxyRule,
121726781Sbrian		0,
121826781Sbrian		String,
121944558Sbrian	        "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
122044558Sbrian		"a.b.c.d:yyyy",
122144558Sbrian		"add transparent proxying / destination NAT",
122244558Sbrian		"proxy_rule",
122326781Sbrian		NULL },
122426781Sbrian
122526781Sbrian	{ RedirectPort,
122626781Sbrian		0,
122726781Sbrian		String,
122859703Sru	        "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
122945010Sbrian	 	" [remote_addr[:remote_port_range]]",
123045010Sbrian		"redirect a port (or ports) for incoming traffic",
123126781Sbrian		"redirect_port",
123226781Sbrian		NULL },
123326781Sbrian
123459921Sru	{ RedirectProto,
123559921Sru		0,
123659921Sru		String,
123759921Sru	        "proto local_addr [public_addr] [remote_addr]",
123859921Sru		"redirect packets of a given proto",
123959921Sru		"redirect_proto",
124059921Sru		NULL },
124159921Sru
124226781Sbrian	{ RedirectAddress,
124326781Sbrian		0,
124426781Sbrian		String,
124559703Sru	        "local_addr[,...] public_addr",
124626781Sbrian		"define mapping between local and public addresses",
124726781Sbrian		"redirect_address",
124826781Sbrian		NULL },
124926781Sbrian
125026781Sbrian	{ ConfigFile,
125126781Sbrian		0,
125226781Sbrian		String,
125326781Sbrian		"file_name",
125426781Sbrian		"read options from configuration file",
125526781Sbrian		"config",
125644558Sbrian		"f" },
125744558Sbrian
125844558Sbrian	{ LogDenied,
125944558Sbrian		0,
126044558Sbrian		YesNo,
126144558Sbrian	        "[yes|no]",
126244558Sbrian		"enable logging of denied incoming packets",
126344558Sbrian		"log_denied",
126444558Sbrian		NULL },
126544558Sbrian
126644558Sbrian	{ LogFacility,
126744558Sbrian		0,
126844558Sbrian		String,
126944558Sbrian	        "facility",
127044558Sbrian		"name of syslog facility to use for logging",
127144558Sbrian		"log_facility",
127262160Sru		NULL },
127362160Sru
127462160Sru	{ PunchFW,
127562160Sru		0,
127662160Sru		String,
127762160Sru	        "basenumber:count",
127862160Sru		"punch holes in the firewall for incoming FTP/IRC DCC connections",
127962160Sru		"punch_fw",
128085770Sphk		NULL },
128185770Sphk
1282120372Smarcus	{ SkinnyPort,
1283120372Smarcus		0,
1284120372Smarcus		String,
1285120372Smarcus		"port",
1286120372Smarcus		"set the TCP port for use with the Skinny Station protocol",
1287120372Smarcus		"skinny_port",
1288120372Smarcus		NULL },
1289120372Smarcus
129085770Sphk	{ LogIpfwDenied,
129185770Sphk		0,
129285770Sphk		YesNo,
129385770Sphk	        "[yes|no]",
129485770Sphk		"log packets converted by natd, but denied by ipfw",
129585770Sphk		"log_ipfw_denied",
129685770Sphk		NULL },
1297118873Sru
1298118873Sru	{ PidFile,
1299118873Sru		0,
1300118873Sru		String,
1301118873Sru		"file_name",
1302118873Sru		"store PID in an alternate file",
1303118873Sru		"pid_file",
1304118873Sru		"P" },
1305131567Sphk	{ Instance,
1306131567Sphk		0,
1307131567Sphk		String,
1308131567Sphk		"instance name",
1309131567Sphk		"name of aliasing engine instance",
1310131567Sphk		"instance",
1311131567Sphk		NULL },
1312179937Smav	{ ExitDelay,
1313179937Smav		0,
1314179937Smav		Numeric,
1315179937Smav		"ms",
1316179937Smav		"delay in ms before daemon exit after signal",
1317179937Smav		"exit_delay",
1318179937Smav		NULL },
131926781Sbrian};
132026781Sbrian
132161726Srustatic void ParseOption (const char* option, const char* parms)
132226781Sbrian{
132326781Sbrian	int			i;
132426781Sbrian	struct OptionInfo*	info;
132526781Sbrian	int			yesNoValue;
132626781Sbrian	int			aliasValue;
132726781Sbrian	int			numValue;
132831660Sbrian	u_short			uNumValue;
132945011Sbrian	const char*		strValue;
133026781Sbrian	struct in_addr		addrValue;
133126781Sbrian	int			max;
133226781Sbrian	char*			end;
1333241736Sed	const CODE* 		fac_record = NULL;
133426781Sbrian/*
133526781Sbrian * Find option from table.
133626781Sbrian */
133726781Sbrian	max = sizeof (optionTable) / sizeof (struct OptionInfo);
133826781Sbrian	for (i = 0, info = optionTable; i < max; i++, info++) {
133926781Sbrian
134026781Sbrian		if (!strcmp (info->name, option))
134126781Sbrian			break;
134226781Sbrian
134326781Sbrian		if (info->shortName)
134426781Sbrian			if (!strcmp (info->shortName, option))
134526781Sbrian				break;
134626781Sbrian	}
134726781Sbrian
134826781Sbrian	if (i >= max) {
134926781Sbrian
135030059Scharnier		warnx ("unknown option %s", option);
135126781Sbrian		Usage ();
135226781Sbrian	}
135326781Sbrian
135431660Sbrian	uNumValue	= 0;
135526781Sbrian	yesNoValue	= 0;
135626781Sbrian	numValue	= 0;
135726781Sbrian	strValue	= NULL;
135826781Sbrian/*
135926781Sbrian * Check parameters.
136026781Sbrian */
136126781Sbrian	switch (info->parm) {
136226781Sbrian	case YesNo:
136326781Sbrian		if (!parms)
136426781Sbrian			parms = "yes";
136526781Sbrian
136626781Sbrian		if (!strcmp (parms, "yes"))
136726781Sbrian			yesNoValue = 1;
136826781Sbrian		else
136926781Sbrian			if (!strcmp (parms, "no"))
137026781Sbrian				yesNoValue = 0;
137130059Scharnier			else
137231660Sbrian				errx (1, "%s needs yes/no parameter", option);
137326781Sbrian		break;
137426781Sbrian
137526781Sbrian	case Service:
137630059Scharnier		if (!parms)
137731660Sbrian			errx (1, "%s needs service name or "
137831660Sbrian				 "port number parameter",
137931660Sbrian				 option);
138026781Sbrian
138131660Sbrian		uNumValue = StrToPort (parms, "divert");
138226781Sbrian		break;
138326781Sbrian
138426781Sbrian	case Numeric:
138526781Sbrian		if (parms)
138626781Sbrian			numValue = strtol (parms, &end, 10);
138726781Sbrian		else
138845011Sbrian			end = NULL;
138926781Sbrian
139030059Scharnier		if (end == parms)
139131660Sbrian			errx (1, "%s needs numeric parameter", option);
139226781Sbrian		break;
139326781Sbrian
139426781Sbrian	case String:
139526781Sbrian		strValue = parms;
139630059Scharnier		if (!strValue)
139731660Sbrian			errx (1, "%s needs parameter", option);
139826781Sbrian		break;
139926781Sbrian
140026781Sbrian	case None:
140130059Scharnier		if (parms)
140231660Sbrian			errx (1, "%s does not take parameters", option);
140326781Sbrian		break;
140426781Sbrian
140526781Sbrian	case Address:
140630059Scharnier		if (!parms)
140731660Sbrian			errx (1, "%s needs address/host parameter", option);
140826781Sbrian
140926781Sbrian		StrToAddr (parms, &addrValue);
141026781Sbrian		break;
141126781Sbrian	}
141226781Sbrian
141326781Sbrian	switch (info->type) {
1414131567Sphk	case LibAliasOption:
141526781Sbrian
141626781Sbrian		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1417131567Sphk		LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
141826781Sbrian		break;
141926781Sbrian
142026781Sbrian	case Verbose:
142126781Sbrian		verbose = yesNoValue;
142226781Sbrian		break;
142326781Sbrian
142426781Sbrian	case DynamicMode:
142526781Sbrian		dynamicMode = yesNoValue;
142626781Sbrian		break;
142726781Sbrian
142826781Sbrian	case InPort:
1429131567Sphk		mip->inPort = uNumValue;
143026781Sbrian		break;
143126781Sbrian
143226781Sbrian	case OutPort:
1433131567Sphk		mip->outPort = uNumValue;
143426781Sbrian		break;
143526781Sbrian
143626781Sbrian	case Port:
1437131567Sphk		mip->inOutPort = uNumValue;
143826781Sbrian		break;
143926781Sbrian
1440131567Sphk	case GlobalPort:
1441131567Sphk		globalPort = uNumValue;
1442131567Sphk		break;
1443131567Sphk
144426781Sbrian	case AliasAddress:
1445131567Sphk		memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
144626781Sbrian		break;
144726781Sbrian
144860683Sru	case TargetAddress:
1449131567Sphk		LibAliasSetTarget(mla, addrValue);
145060683Sru		break;
145160683Sru
145226781Sbrian	case RedirectPort:
145326781Sbrian		SetupPortRedirect (strValue);
145426781Sbrian		break;
145526781Sbrian
145659921Sru	case RedirectProto:
145759921Sru		SetupProtoRedirect(strValue);
145859921Sru		break;
145959921Sru
146026781Sbrian	case RedirectAddress:
146126781Sbrian		SetupAddressRedirect (strValue);
146226781Sbrian		break;
146326781Sbrian
146444558Sbrian	case ProxyRule:
1465131567Sphk		LibAliasProxyRule (mla, strValue);
146644558Sbrian		break;
146744558Sbrian
146826781Sbrian	case InterfaceName:
1469131567Sphk		if (mip->ifName)
1470131567Sphk			free (mip->ifName);
147126781Sbrian
1472131567Sphk		mip->ifName = strdup (strValue);
147326781Sbrian		break;
147426781Sbrian
147526781Sbrian	case ConfigFile:
147626781Sbrian		ReadConfigFile (strValue);
147726781Sbrian		break;
147844558Sbrian
147944558Sbrian	case LogDenied:
1480131567Sphk		mip->logDropped = yesNoValue;
148144558Sbrian		break;
148244558Sbrian
148344558Sbrian	case LogFacility:
148444558Sbrian
148544558Sbrian		fac_record = facilitynames;
148644558Sbrian		while (fac_record->c_name != NULL) {
148744558Sbrian
148844558Sbrian			if (!strcmp (fac_record->c_name, strValue)) {
148944558Sbrian
149044558Sbrian				logFacility = fac_record->c_val;
149144558Sbrian				break;
149244558Sbrian
149344558Sbrian			}
149444558Sbrian			else
149544558Sbrian				fac_record++;
149644558Sbrian		}
149744558Sbrian
149844558Sbrian		if(fac_record->c_name == NULL)
149944558Sbrian			errx(1, "Unknown log facility name: %s", strValue);
150044558Sbrian
150144558Sbrian		break;
150262160Sru
150362160Sru	case PunchFW:
150462160Sru		SetupPunchFW(strValue);
150562160Sru		break;
150686954Sru
1507120372Smarcus	case SkinnyPort:
1508120372Smarcus		SetupSkinnyPort(strValue);
1509120372Smarcus		break;
1510120372Smarcus
151185770Sphk	case LogIpfwDenied:
1512241844Seadler		logIpfwDenied = yesNoValue;
151386954Sru		break;
1514118873Sru
1515118873Sru	case PidFile:
1516118873Sru		pidName = strdup (strValue);
1517118873Sru		break;
1518131567Sphk	case Instance:
1519131567Sphk		NewInstance(strValue);
1520131567Sphk		break;
1521179937Smav	case ExitDelay:
1522179937Smav		if (numValue < 0 || numValue > MAX_EXIT_DELAY)
1523179937Smav			errx(1, "Incorrect exit delay: %d", numValue);
1524179937Smav		exitDelay = numValue;
1525179937Smav		break;
152626781Sbrian	}
152726781Sbrian}
152826781Sbrian
152945011Sbrianvoid ReadConfigFile (const char* fileName)
153026781Sbrian{
153126781Sbrian	FILE*	file;
153257480Sru	char	*buf;
153357480Sru	size_t	len;
153451063Sru	char	*ptr, *p;
153526781Sbrian	char*	option;
153626781Sbrian
153726781Sbrian	file = fopen (fileName, "r");
153857480Sru	if (!file)
153957480Sru		err(1, "cannot open config file %s", fileName);
154026781Sbrian
154157480Sru	while ((buf = fgetln(file, &len)) != NULL) {
154257480Sru		if (buf[len - 1] == '\n')
154357480Sru			buf[len - 1] = '\0';
154457480Sru		else
154557480Sru			errx(1, "config file format error: "
154657480Sru				"last line should end with newline");
154726781Sbrian
154826781Sbrian/*
154951063Sru * Check for comments, strip off trailing spaces.
155026781Sbrian */
155151063Sru		if ((ptr = strchr(buf, '#')))
155251063Sru			*ptr = '\0';
155351063Sru		for (ptr = buf; isspace(*ptr); ++ptr)
155451063Sru			continue;
155526781Sbrian		if (*ptr == '\0')
155626781Sbrian			continue;
155751063Sru		for (p = strchr(buf, '\0'); isspace(*--p);)
155851063Sru			continue;
155951063Sru		*++p = '\0';
156051063Sru
156126781Sbrian/*
156226781Sbrian * Extract option name.
156326781Sbrian */
156426781Sbrian		option = ptr;
156526781Sbrian		while (*ptr && !isspace (*ptr))
156626781Sbrian			++ptr;
156726781Sbrian
156826781Sbrian		if (*ptr != '\0') {
156926781Sbrian
157026781Sbrian			*ptr = '\0';
157126781Sbrian			++ptr;
157226781Sbrian		}
157326781Sbrian/*
157426781Sbrian * Skip white space between name and parms.
157526781Sbrian */
157626781Sbrian		while (*ptr && isspace (*ptr))
157726781Sbrian			++ptr;
157826781Sbrian
157961726Sru		ParseOption (option, *ptr ? ptr : NULL);
158026781Sbrian	}
158126781Sbrian
158226781Sbrian	fclose (file);
158326781Sbrian}
158426781Sbrian
1585202531Sedstatic void Usage(void)
158626781Sbrian{
158726781Sbrian	int			i;
158826781Sbrian	int			max;
158926781Sbrian	struct OptionInfo*	info;
159026781Sbrian
159126781Sbrian	fprintf (stderr, "Recognized options:\n\n");
159226781Sbrian
159326781Sbrian	max = sizeof (optionTable) / sizeof (struct OptionInfo);
159426781Sbrian	for (i = 0, info = optionTable; i < max; i++, info++) {
159526781Sbrian
159626781Sbrian		fprintf (stderr, "-%-20s %s\n", info->name,
159726781Sbrian						info->parmDescription);
159826781Sbrian
159926781Sbrian		if (info->shortName)
160026781Sbrian			fprintf (stderr, "-%-20s %s\n", info->shortName,
160126781Sbrian							info->parmDescription);
160226781Sbrian
160326781Sbrian		fprintf (stderr, "      %s\n\n", info->description);
160426781Sbrian	}
160526781Sbrian
160626781Sbrian	exit (1);
160726781Sbrian}
160826781Sbrian
160945011Sbrianvoid SetupPortRedirect (const char* parms)
161026781Sbrian{
1611179935Smav	char		*buf;
161226781Sbrian	char*		ptr;
161359703Sru	char*		serverPool;
161426781Sbrian	struct in_addr	localAddr;
161526781Sbrian	struct in_addr	publicAddr;
161626781Sbrian	struct in_addr	remoteAddr;
161745010Sbrian	port_range      portRange;
161845010Sbrian	u_short         localPort      = 0;
161945010Sbrian	u_short         publicPort     = 0;
162045010Sbrian	u_short         remotePort     = 0;
162145010Sbrian	u_short         numLocalPorts  = 0;
162245010Sbrian	u_short         numPublicPorts = 0;
162345010Sbrian	u_short         numRemotePorts = 0;
162426781Sbrian	int		proto;
162526781Sbrian	char*		protoName;
162626781Sbrian	char*		separator;
162745010Sbrian	int             i;
1628145797Sdelphij	struct alias_link *aliaslink = NULL;
162926781Sbrian
1630179935Smav	buf = strdup (parms);
1631179935Smav	if (!buf)
1632179935Smav		errx (1, "redirect_port: strdup() failed");
163326781Sbrian/*
163426781Sbrian * Extract protocol.
163526781Sbrian */
163626781Sbrian	protoName = strtok (buf, " \t");
163730059Scharnier	if (!protoName)
163831660Sbrian		errx (1, "redirect_port: missing protocol");
163926781Sbrian
164026781Sbrian	proto = StrToProto (protoName);
164126781Sbrian/*
164226781Sbrian * Extract local address.
164326781Sbrian */
164426781Sbrian	ptr = strtok (NULL, " \t");
164530059Scharnier	if (!ptr)
164631660Sbrian		errx (1, "redirect_port: missing local address");
164726781Sbrian
164859703Sru	separator = strchr(ptr, ',');
164959703Sru	if (separator) {		/* LSNAT redirection syntax. */
165059703Sru		localAddr.s_addr = INADDR_NONE;
165159703Sru		localPort = ~0;
165259703Sru		numLocalPorts = 1;
165359703Sru		serverPool = ptr;
165459703Sru	} else {
165559703Sru		if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
165659703Sru			errx (1, "redirect_port: invalid local port range");
165745010Sbrian
165859703Sru		localPort     = GETLOPORT(portRange);
165959703Sru		numLocalPorts = GETNUMPORTS(portRange);
166059703Sru		serverPool = NULL;
166159703Sru	}
166245010Sbrian
166326781Sbrian/*
166447121Sbrian * Extract public port and optionally address.
166526781Sbrian */
166626781Sbrian	ptr = strtok (NULL, " \t");
166730059Scharnier	if (!ptr)
166831660Sbrian		errx (1, "redirect_port: missing public port");
166926781Sbrian
167026781Sbrian	separator = strchr (ptr, ':');
167145010Sbrian	if (separator) {
167245010Sbrian	        if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
167345010Sbrian		        errx (1, "redirect_port: invalid public port range");
167445010Sbrian	}
167526781Sbrian	else {
167626781Sbrian		publicAddr.s_addr = INADDR_ANY;
167745010Sbrian		if (StrToPortRange (ptr, protoName, &portRange) != 0)
167845010Sbrian		        errx (1, "redirect_port: invalid public port range");
167926781Sbrian	}
168026781Sbrian
168145010Sbrian	publicPort     = GETLOPORT(portRange);
168245010Sbrian	numPublicPorts = GETNUMPORTS(portRange);
168345010Sbrian
168426781Sbrian/*
168526781Sbrian * Extract remote address and optionally port.
168626781Sbrian */
168726781Sbrian	ptr = strtok (NULL, " \t");
168826781Sbrian	if (ptr) {
168926781Sbrian		separator = strchr (ptr, ':');
169046080Simp		if (separator) {
169145010Sbrian		        if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
169245010Sbrian			        errx (1, "redirect_port: invalid remote port range");
169346080Simp		} else {
169445010Sbrian		        SETLOPORT(portRange, 0);
169545010Sbrian			SETNUMPORTS(portRange, 1);
169626781Sbrian			StrToAddr (ptr, &remoteAddr);
169726781Sbrian		}
169826781Sbrian	}
169926781Sbrian	else {
170045010Sbrian	        SETLOPORT(portRange, 0);
170145010Sbrian		SETNUMPORTS(portRange, 1);
170226781Sbrian		remoteAddr.s_addr = INADDR_ANY;
170326781Sbrian	}
170426781Sbrian
170545010Sbrian	remotePort     = GETLOPORT(portRange);
170645010Sbrian	numRemotePorts = GETNUMPORTS(portRange);
170745010Sbrian
170845010Sbrian/*
170945010Sbrian * Make sure port ranges match up, then add the redirect ports.
171045010Sbrian */
171145010Sbrian	if (numLocalPorts != numPublicPorts)
171245010Sbrian	        errx (1, "redirect_port: port ranges must be equal in size");
171345010Sbrian
171445010Sbrian	/* Remote port range is allowed to be '0' which means all ports. */
171547122Sbrian	if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
171645010Sbrian	        errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
171745010Sbrian
171845010Sbrian	for (i = 0 ; i < numPublicPorts ; ++i) {
171945010Sbrian	        /* If remotePort is all ports, set it to 0. */
172045010Sbrian	        u_short remotePortCopy = remotePort + i;
172145010Sbrian	        if (numRemotePorts == 1 && remotePort == 0)
172245010Sbrian		        remotePortCopy = 0;
172345010Sbrian
1724145797Sdelphij		aliaslink = LibAliasRedirectPort (mla, localAddr,
172559703Sru						htons(localPort + i),
172659703Sru						remoteAddr,
172759703Sru						htons(remotePortCopy),
172859703Sru						publicAddr,
172959703Sru						htons(publicPort + i),
173059703Sru						proto);
173145010Sbrian	}
173259703Sru
173359703Sru/*
173459703Sru * Setup LSNAT server pool.
173559703Sru */
1736145797Sdelphij	if (serverPool != NULL && aliaslink != NULL) {
173759703Sru		ptr = strtok(serverPool, ",");
173859703Sru		while (ptr != NULL) {
173959703Sru			if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
174059703Sru				errx(1, "redirect_port: invalid local port range");
174159703Sru
174259703Sru			localPort = GETLOPORT(portRange);
174359703Sru			if (GETNUMPORTS(portRange) != 1)
174459703Sru				errx(1, "redirect_port: local port must be single in this context");
1745145797Sdelphij			LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
174659703Sru			ptr = strtok(NULL, ",");
174759703Sru		}
174859703Sru	}
1749179935Smav
1750179935Smav	free (buf);
175126781Sbrian}
175226781Sbrian
175359921Sruvoid
175459921SruSetupProtoRedirect(const char* parms)
175559921Sru{
1756179935Smav	char		*buf;
175759921Sru	char*		ptr;
175859921Sru	struct in_addr	localAddr;
175959921Sru	struct in_addr	publicAddr;
176059921Sru	struct in_addr	remoteAddr;
176159921Sru	int		proto;
176259921Sru	char*		protoName;
176359921Sru	struct protoent *protoent;
176459921Sru
1765179935Smav	buf = strdup (parms);
1766179935Smav	if (!buf)
1767179935Smav		errx (1, "redirect_port: strdup() failed");
176859921Sru/*
176959921Sru * Extract protocol.
177059921Sru */
177159921Sru	protoName = strtok(buf, " \t");
177259921Sru	if (!protoName)
177359921Sru		errx(1, "redirect_proto: missing protocol");
177459921Sru
177559921Sru	protoent = getprotobyname(protoName);
177659921Sru	if (protoent == NULL)
177759921Sru		errx(1, "redirect_proto: unknown protocol %s", protoName);
177859921Sru	else
177959921Sru		proto = protoent->p_proto;
178059921Sru/*
178159921Sru * Extract local address.
178259921Sru */
178359921Sru	ptr = strtok(NULL, " \t");
178459921Sru	if (!ptr)
178559921Sru		errx(1, "redirect_proto: missing local address");
178659921Sru	else
178759921Sru		StrToAddr(ptr, &localAddr);
178859921Sru/*
178959921Sru * Extract optional public address.
179059921Sru */
179159921Sru	ptr = strtok(NULL, " \t");
179259921Sru	if (ptr)
179359921Sru		StrToAddr(ptr, &publicAddr);
179459921Sru	else
179559921Sru		publicAddr.s_addr = INADDR_ANY;
179659921Sru/*
179759921Sru * Extract optional remote address.
179859921Sru */
179959921Sru	ptr = strtok(NULL, " \t");
180059921Sru	if (ptr)
180159921Sru		StrToAddr(ptr, &remoteAddr);
180259921Sru	else
180359921Sru		remoteAddr.s_addr = INADDR_ANY;
180459921Sru/*
180559921Sru * Create aliasing link.
180659921Sru */
1807131567Sphk	(void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
180859921Sru				       proto);
1809179935Smav
1810179935Smav	free (buf);
181159921Sru}
181259921Sru
181345011Sbrianvoid SetupAddressRedirect (const char* parms)
181426781Sbrian{
1815179935Smav	char		*buf;
181626781Sbrian	char*		ptr;
181759703Sru	char*		separator;
181826781Sbrian	struct in_addr	localAddr;
181926781Sbrian	struct in_addr	publicAddr;
182059703Sru	char*		serverPool;
1821145797Sdelphij	struct alias_link *aliaslink;
182226781Sbrian
1823179935Smav	buf = strdup (parms);
1824179935Smav	if (!buf)
1825179935Smav		errx (1, "redirect_port: strdup() failed");
182626781Sbrian/*
182726781Sbrian * Extract local address.
182826781Sbrian */
182926781Sbrian	ptr = strtok (buf, " \t");
183030059Scharnier	if (!ptr)
183131660Sbrian		errx (1, "redirect_address: missing local address");
183226781Sbrian
183359703Sru	separator = strchr(ptr, ',');
183459703Sru	if (separator) {		/* LSNAT redirection syntax. */
183559703Sru		localAddr.s_addr = INADDR_NONE;
183659703Sru		serverPool = ptr;
183759703Sru	} else {
183859703Sru		StrToAddr (ptr, &localAddr);
183959703Sru		serverPool = NULL;
184059703Sru	}
184126781Sbrian/*
184226781Sbrian * Extract public address.
184326781Sbrian */
184426781Sbrian	ptr = strtok (NULL, " \t");
184530059Scharnier	if (!ptr)
184631660Sbrian		errx (1, "redirect_address: missing public address");
184726781Sbrian
184826781Sbrian	StrToAddr (ptr, &publicAddr);
1849145797Sdelphij	aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
185059703Sru
185159703Sru/*
185259703Sru * Setup LSNAT server pool.
185359703Sru */
1854145797Sdelphij	if (serverPool != NULL && aliaslink != NULL) {
185559703Sru		ptr = strtok(serverPool, ",");
185659703Sru		while (ptr != NULL) {
185759703Sru			StrToAddr(ptr, &localAddr);
1858145797Sdelphij			LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
185959703Sru			ptr = strtok(NULL, ",");
186059703Sru		}
186159703Sru	}
1862179935Smav
1863179935Smav	free (buf);
186426781Sbrian}
186526781Sbrian
186645011Sbrianvoid StrToAddr (const char* str, struct in_addr* addr)
186726781Sbrian{
186826781Sbrian	struct hostent* hp;
186926781Sbrian
187026781Sbrian	if (inet_aton (str, addr))
187126781Sbrian		return;
187226781Sbrian
187326781Sbrian	hp = gethostbyname (str);
187430059Scharnier	if (!hp)
187531660Sbrian		errx (1, "unknown host %s", str);
187626781Sbrian
187726781Sbrian	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
187826781Sbrian}
187926781Sbrian
188045011Sbrianu_short StrToPort (const char* str, const char* proto)
188126781Sbrian{
188231660Sbrian	u_short		port;
188326781Sbrian	struct servent*	sp;
188426781Sbrian	char*		end;
188526781Sbrian
188626781Sbrian	port = strtol (str, &end, 10);
188726781Sbrian	if (end != str)
188831576Sbrian		return htons (port);
188926781Sbrian
189026781Sbrian	sp = getservbyname (str, proto);
189130059Scharnier	if (!sp)
1892110415Scharnier		errx (1, "%s/%s: unknown service", str, proto);
189326781Sbrian
189426781Sbrian	return sp->s_port;
189526781Sbrian}
189626781Sbrian
189745011Sbrianint StrToPortRange (const char* str, const char* proto, port_range *portRange)
189845010Sbrian{
189945010Sbrian	char*           sep;
190045010Sbrian	struct servent*	sp;
190145010Sbrian	char*		end;
190245010Sbrian	u_short         loPort;
190345010Sbrian	u_short         hiPort;
190445010Sbrian
190545010Sbrian	/* First see if this is a service, return corresponding port if so. */
190645010Sbrian	sp = getservbyname (str,proto);
190745010Sbrian	if (sp) {
190845010Sbrian	        SETLOPORT(*portRange, ntohs(sp->s_port));
190945010Sbrian		SETNUMPORTS(*portRange, 1);
191045010Sbrian		return 0;
191145010Sbrian	}
191245010Sbrian
191345010Sbrian	/* Not a service, see if it's a single port or port range. */
191445010Sbrian	sep = strchr (str, '-');
191545010Sbrian	if (sep == NULL) {
191645010Sbrian	        SETLOPORT(*portRange, strtol(str, &end, 10));
191745010Sbrian		if (end != str) {
191845010Sbrian		        /* Single port. */
191945010Sbrian		        SETNUMPORTS(*portRange, 1);
192045010Sbrian			return 0;
192145010Sbrian		}
192245010Sbrian
192345010Sbrian		/* Error in port range field. */
1924110415Scharnier		errx (1, "%s/%s: unknown service", str, proto);
192545010Sbrian	}
192645010Sbrian
192745010Sbrian	/* Port range, get the values and sanity check. */
192845010Sbrian	sscanf (str, "%hu-%hu", &loPort, &hiPort);
192945010Sbrian	SETLOPORT(*portRange, loPort);
193045010Sbrian	SETNUMPORTS(*portRange, 0);	/* Error by default */
193145010Sbrian	if (loPort <= hiPort)
193245010Sbrian	        SETNUMPORTS(*portRange, hiPort - loPort + 1);
193345010Sbrian
193445010Sbrian	if (GETNUMPORTS(*portRange) == 0)
193545010Sbrian	        errx (1, "invalid port range %s", str);
193645010Sbrian
193745010Sbrian	return 0;
193845010Sbrian}
193945010Sbrian
194045010Sbrian
194145011Sbrianint StrToProto (const char* str)
194226781Sbrian{
194326781Sbrian	if (!strcmp (str, "tcp"))
194426781Sbrian		return IPPROTO_TCP;
194526781Sbrian
194626781Sbrian	if (!strcmp (str, "udp"))
194726781Sbrian		return IPPROTO_UDP;
194826781Sbrian
194931660Sbrian	errx (1, "unknown protocol %s. Expected tcp or udp", str);
195026781Sbrian}
195126781Sbrian
195245011Sbrianint StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
195326781Sbrian{
195426781Sbrian	char*	ptr;
195526781Sbrian
195626781Sbrian	ptr = strchr (str, ':');
195730059Scharnier	if (!ptr)
195831660Sbrian		errx (1, "%s is missing port number", str);
195926781Sbrian
196026781Sbrian	*ptr = '\0';
196126781Sbrian	++ptr;
196226781Sbrian
196326781Sbrian	StrToAddr (str, addr);
196445010Sbrian	return StrToPortRange (ptr, proto, portRange);
196526781Sbrian}
196662160Sru
196762160Srustatic void
196862160SruSetupPunchFW(const char *strValue)
196962160Sru{
197062160Sru	unsigned int base, num;
197162160Sru
197262160Sru	if (sscanf(strValue, "%u:%u", &base, &num) != 2)
197362160Sru		errx(1, "punch_fw: basenumber:count parameter required");
197462160Sru
1975182825Srik	if (CheckIpfwRulenum(base + num - 1) == -1)
1976182825Srik		errx(1, "punch_fw: basenumber:count parameter should fit "
1977182825Srik			"the maximum allowed rule numbers");
1978182825Srik
1979131567Sphk	LibAliasSetFWBase(mla, base, num);
1980131567Sphk	(void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
198162160Sru}
1982120372Smarcus
1983120372Smarcusstatic void
1984120372SmarcusSetupSkinnyPort(const char *strValue)
1985120372Smarcus{
1986120372Smarcus	unsigned int port;
1987120372Smarcus
1988120372Smarcus	if (sscanf(strValue, "%u", &port) != 1)
1989120372Smarcus		errx(1, "skinny_port: port parameter required");
1990120372Smarcus
1991131567Sphk	LibAliasSetSkinnyPort(mla, port);
1992120372Smarcus}
1993131567Sphk
1994131567Sphkstatic void
1995131567SphkNewInstance(const char *name)
1996131567Sphk{
1997131567Sphk	struct instance *ip;
1998131567Sphk
1999131567Sphk	LIST_FOREACH(ip, &root, list) {
2000131567Sphk		if (!strcmp(ip->name, name)) {
2001131567Sphk			mla = ip->la;
2002131567Sphk			mip = ip;
2003131567Sphk			return;
2004131567Sphk		}
2005131567Sphk	}
2006131567Sphk	ninstance++;
2007131567Sphk	ip = calloc(sizeof *ip, 1);
2008131567Sphk	ip->name = strdup(name);
2009131567Sphk	ip->la = LibAliasInit (ip->la);
2010131567Sphk	ip->assignAliasAddr	= 0;
2011131567Sphk	ip->ifName		= NULL;
2012131567Sphk 	ip->logDropped		= 0;
2013131567Sphk	ip->inPort		= 0;
2014131567Sphk	ip->outPort		= 0;
2015131567Sphk	ip->inOutPort		= 0;
2016131567Sphk	ip->aliasAddr.s_addr	= INADDR_NONE;
2017131567Sphk	ip->ifMTU		= -1;
2018131567Sphk	ip->aliasOverhead	= 12;
2019131567Sphk	LIST_INSERT_HEAD(&root, ip, list);
2020131567Sphk	mla = ip->la;
2021131567Sphk	mip = ip;
2022131567Sphk}
2023182825Srik
2024182825Srikstatic int
2025182825SrikCheckIpfwRulenum(unsigned int rnum)
2026182825Srik{
2027182825Srik	unsigned int default_rule;
2028182825Srik	size_t len = sizeof(default_rule);
2029182825Srik
2030182825Srik	if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len,
2031182825Srik		NULL, 0) == -1) {
2032182825Srik		warn("Failed to get the default ipfw rule number, using "
2033182825Srik		     "default historical value 65535.  The reason was");
2034182825Srik		default_rule = 65535;
2035182825Srik	}
2036182825Srik	if (rnum >= default_rule) {
2037182825Srik		return -1;
2038182825Srik	}
2039182825Srik
2040182825Srik	return 0;
2041182825Srik}
2042