1/*
2 * natd - Network Address Translation Daemon for FreeBSD.
3 *
4 * This software is provided free of charge, with no
5 * warranty of any kind, either expressed or implied.
6 * Use at your own risk.
7 *
8 * You may copy, modify and distribute this software (natd.c) freely.
9 *
10 * Ari Suutari <suutari@iki.fi>
11 */
12
13#include <sys/cdefs.h>
14__FBSDID("$FreeBSD: stable/11/sbin/natd/natd.c 307697 2016-10-21 03:10:05Z araujo $");
15
16#define SYSLOG_NAMES
17
18#include <sys/types.h>
19#include <sys/socket.h>
20#include <sys/sysctl.h>
21#include <sys/time.h>
22#include <sys/queue.h>
23
24#include <netinet/in.h>
25#include <netinet/in_systm.h>
26#include <netinet/ip.h>
27#include <machine/in_cksum.h>
28#include <netinet/tcp.h>
29#include <netinet/udp.h>
30#include <netinet/ip_icmp.h>
31#include <net/if.h>
32#include <net/if_dl.h>
33#include <net/route.h>
34#include <arpa/inet.h>
35
36#include <alias.h>
37#include <ctype.h>
38#include <err.h>
39#include <errno.h>
40#include <netdb.h>
41#include <signal.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <syslog.h>
46#include <unistd.h>
47
48#include "natd.h"
49
50struct instance {
51	const char		*name;
52	struct libalias		*la;
53	LIST_ENTRY(instance)	list;
54
55	int			ifIndex;
56	int			assignAliasAddr;
57	char*			ifName;
58	int			logDropped;
59	u_short			inPort;
60	u_short			outPort;
61	u_short			inOutPort;
62	struct in_addr		aliasAddr;
63	int			ifMTU;
64	int			aliasOverhead;
65	int			dropIgnoredIncoming;
66	int			divertIn;
67	int			divertOut;
68	int			divertInOut;
69};
70
71static LIST_HEAD(, instance) root = LIST_HEAD_INITIALIZER(root);
72
73struct libalias *mla;
74static struct instance *mip;
75static int ninstance = 1;
76
77/*
78 * Default values for input and output
79 * divert socket ports.
80 */
81
82#define	DEFAULT_SERVICE	"natd"
83
84/*
85 * Definition of a port range, and macros to deal with values.
86 * FORMAT:  HI 16-bits == first port in range, 0 == all ports.
87 *          LO 16-bits == number of ports in range
88 * NOTES:   - Port values are not stored in network byte order.
89 */
90
91typedef u_long port_range;
92
93#define GETLOPORT(x)     ((x) >> 0x10)
94#define GETNUMPORTS(x)   ((x) & 0x0000ffff)
95#define GETHIPORT(x)     (GETLOPORT((x)) + GETNUMPORTS((x)))
96
97/* Set y to be the low-port value in port_range variable x. */
98#define SETLOPORT(x,y)   ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
99
100/* Set y to be the number of ports in port_range variable x. */
101#define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
102
103/*
104 * Function prototypes.
105 */
106
107static void	DoAliasing (int fd, int direction);
108static void	DaemonMode (void);
109static void	HandleRoutingInfo (int fd);
110static void	Usage (void);
111static char*	FormatPacket (struct ip*);
112static void	PrintPacket (struct ip*);
113static void	SyslogPacket (struct ip*, int priority, const char *label);
114static int	SetAliasAddressFromIfName (const char *ifName);
115static void	InitiateShutdown (int);
116static void	Shutdown (int);
117static void	RefreshAddr (int);
118static void	ParseOption (const char* option, const char* parms);
119static void	ReadConfigFile (const char* fileName);
120static void	SetupPortRedirect (const char* parms);
121static void	SetupProtoRedirect(const char* parms);
122static void	SetupAddressRedirect (const char* parms);
123static void	StrToAddr (const char* str, struct in_addr* addr);
124static u_short  StrToPort (const char* str, const char* proto);
125static int      StrToPortRange (const char* str, const char* proto, port_range *portRange);
126static int 	StrToProto (const char* str);
127static int      StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange);
128static void	ParseArgs (int argc, char** argv);
129static void	SetupPunchFW(const char *strValue);
130static void	SetupSkinnyPort(const char *strValue);
131static void	NewInstance(const char *name);
132static void	DoGlobal (int fd);
133static int	CheckIpfwRulenum(unsigned int rnum);
134
135/*
136 * Globals.
137 */
138
139static	int			verbose;
140static 	int			background;
141static	int			running;
142static	int			logFacility;
143
144static 	int			dynamicMode;
145static 	int			icmpSock;
146static	int			logIpfwDenied;
147static	const char*		pidName;
148static	int			routeSock;
149static	int			globalPort;
150static	int			divertGlobal;
151static	int			exitDelay;
152
153
154int main (int argc, char** argv)
155{
156	struct sockaddr_in	addr;
157	fd_set			readMask;
158	int			fdMax;
159	int			rval;
160/*
161 * Initialize packet aliasing software.
162 * Done already here to be able to alter option bits
163 * during command line and configuration file processing.
164 */
165	NewInstance("default");
166
167/*
168 * Parse options.
169 */
170	verbose 		= 0;
171	background		= 0;
172	running			= 1;
173	dynamicMode		= 0;
174 	logFacility		= LOG_DAEMON;
175	logIpfwDenied		= -1;
176	pidName			= PIDFILE;
177	routeSock 		= -1;
178	icmpSock 		= -1;
179	fdMax	 		= -1;
180	divertGlobal		= -1;
181	exitDelay		= EXIT_DELAY;
182
183	ParseArgs (argc, argv);
184/*
185 * Log ipfw(8) denied packets by default in verbose mode.
186 */
187	if (logIpfwDenied == -1)
188		logIpfwDenied = verbose;
189/*
190 * Open syslog channel.
191 */
192	openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
193		 logFacility);
194
195	LIST_FOREACH(mip, &root, list) {
196		mla = mip->la;
197/*
198 * If not doing the transparent proxying only,
199 * check that valid aliasing address has been given.
200 */
201		if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL &&
202		    !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY))
203			errx (1, "instance %s: aliasing address not given", mip->name);
204
205		if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL)
206			errx (1, "both alias address and interface "
207				 "name are not allowed");
208/*
209 * Check that valid port number is known.
210 */
211		if (mip->inPort != 0 || mip->outPort != 0)
212			if (mip->inPort == 0 || mip->outPort == 0)
213				errx (1, "both input and output ports are required");
214
215		if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0)
216			ParseOption ("port", DEFAULT_SERVICE);
217
218/*
219 * Check if ignored packets should be dropped.
220 */
221		mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0);
222		mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
223/*
224 * Create divert sockets. Use only one socket if -p was specified
225 * on command line. Otherwise, create separate sockets for
226 * outgoing and incoming connections.
227 */
228		if (mip->inOutPort) {
229
230			mip->divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
231			if (mip->divertInOut == -1)
232				Quit ("Unable to create divert socket.");
233			if (mip->divertInOut > fdMax)
234				fdMax = mip->divertInOut;
235
236			mip->divertIn  = -1;
237			mip->divertOut = -1;
238/*
239 * Bind socket.
240 */
241
242			addr.sin_family		= AF_INET;
243			addr.sin_addr.s_addr	= INADDR_ANY;
244			addr.sin_port		= mip->inOutPort;
245
246			if (bind (mip->divertInOut,
247				  (struct sockaddr*) &addr,
248				  sizeof addr) == -1)
249				Quit ("Unable to bind divert socket.");
250		}
251		else {
252
253			mip->divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
254			if (mip->divertIn == -1)
255				Quit ("Unable to create incoming divert socket.");
256			if (mip->divertIn > fdMax)
257				fdMax = mip->divertIn;
258
259
260			mip->divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
261			if (mip->divertOut == -1)
262				Quit ("Unable to create outgoing divert socket.");
263			if (mip->divertOut > fdMax)
264				fdMax = mip->divertOut;
265
266			mip->divertInOut = -1;
267
268/*
269 * Bind divert sockets.
270 */
271
272			addr.sin_family		= AF_INET;
273			addr.sin_addr.s_addr	= INADDR_ANY;
274			addr.sin_port		= mip->inPort;
275
276			if (bind (mip->divertIn,
277				  (struct sockaddr*) &addr,
278				  sizeof addr) == -1)
279				Quit ("Unable to bind incoming divert socket.");
280
281			addr.sin_family		= AF_INET;
282			addr.sin_addr.s_addr	= INADDR_ANY;
283			addr.sin_port		= mip->outPort;
284
285			if (bind (mip->divertOut,
286				  (struct sockaddr*) &addr,
287				  sizeof addr) == -1)
288				Quit ("Unable to bind outgoing divert socket.");
289		}
290/*
291 * Create routing socket if interface name specified and in dynamic mode.
292 */
293		if (mip->ifName) {
294			if (dynamicMode) {
295
296				if (routeSock == -1)
297					routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
298				if (routeSock == -1)
299					Quit ("Unable to create routing info socket.");
300				if (routeSock > fdMax)
301					fdMax = routeSock;
302
303				mip->assignAliasAddr = 1;
304			}
305			else {
306				do {
307					rval = SetAliasAddressFromIfName (mip->ifName);
308					if (background == 0 || dynamicMode == 0)
309						break;
310					if (rval == EAGAIN)
311						sleep(1);
312				} while (rval == EAGAIN);
313				if (rval != 0)
314					exit(1);
315			}
316		}
317
318	}
319	if (globalPort) {
320
321		divertGlobal = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
322		if (divertGlobal == -1)
323			Quit ("Unable to create divert socket.");
324		if (divertGlobal > fdMax)
325			fdMax = divertGlobal;
326
327/*
328* Bind socket.
329*/
330
331		addr.sin_family		= AF_INET;
332		addr.sin_addr.s_addr	= INADDR_ANY;
333		addr.sin_port		= globalPort;
334
335		if (bind (divertGlobal,
336			  (struct sockaddr*) &addr,
337			  sizeof addr) == -1)
338			Quit ("Unable to bind global divert socket.");
339	}
340/*
341 * Create socket for sending ICMP messages.
342 */
343	icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
344	if (icmpSock == -1)
345		Quit ("Unable to create ICMP socket.");
346
347/*
348 * And disable reads for the socket, otherwise it slowly fills
349 * up with received icmps which we do not use.
350 */
351	shutdown(icmpSock, SHUT_RD);
352
353/*
354 * Become a daemon unless verbose mode was requested.
355 */
356	if (!verbose)
357		DaemonMode ();
358/*
359 * Catch signals to manage shutdown and
360 * refresh of interface address.
361 */
362	siginterrupt(SIGTERM, 1);
363	siginterrupt(SIGHUP, 1);
364	if (exitDelay)
365		signal(SIGTERM, InitiateShutdown);
366	else
367		signal(SIGTERM, Shutdown);
368	signal (SIGHUP, RefreshAddr);
369/*
370 * Set alias address if it has been given.
371 */
372	mip = LIST_FIRST(&root);	/* XXX: simon */
373	LIST_FOREACH(mip, &root, list) {
374		mla = mip->la;
375		if (mip->aliasAddr.s_addr != INADDR_NONE)
376			LibAliasSetAddress (mla, mip->aliasAddr);
377	}
378
379	while (running) {
380		mip = LIST_FIRST(&root);	/* XXX: simon */
381
382		if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) {
383/*
384 * When using only one socket, just call
385 * DoAliasing repeatedly to process packets.
386 */
387			DoAliasing (mip->divertInOut, DONT_KNOW);
388			continue;
389		}
390/*
391 * Build read mask from socket descriptors to select.
392 */
393		FD_ZERO (&readMask);
394/*
395 * Check if new packets are available.
396 */
397		LIST_FOREACH(mip, &root, list) {
398			if (mip->divertIn != -1)
399				FD_SET (mip->divertIn, &readMask);
400
401			if (mip->divertOut != -1)
402				FD_SET (mip->divertOut, &readMask);
403
404			if (mip->divertInOut != -1)
405				FD_SET (mip->divertInOut, &readMask);
406		}
407/*
408 * Routing info is processed always.
409 */
410		if (routeSock != -1)
411			FD_SET (routeSock, &readMask);
412
413		if (divertGlobal != -1)
414			FD_SET (divertGlobal, &readMask);
415
416		if (select (fdMax + 1,
417			    &readMask,
418			    NULL,
419			    NULL,
420			    NULL) == -1) {
421
422			if (errno == EINTR)
423				continue;
424
425			Quit ("Select failed.");
426		}
427
428		if (divertGlobal != -1)
429			if (FD_ISSET (divertGlobal, &readMask))
430				DoGlobal (divertGlobal);
431		LIST_FOREACH(mip, &root, list) {
432			mla = mip->la;
433			if (mip->divertIn != -1)
434				if (FD_ISSET (mip->divertIn, &readMask))
435					DoAliasing (mip->divertIn, INPUT);
436
437			if (mip->divertOut != -1)
438				if (FD_ISSET (mip->divertOut, &readMask))
439					DoAliasing (mip->divertOut, OUTPUT);
440
441			if (mip->divertInOut != -1)
442				if (FD_ISSET (mip->divertInOut, &readMask))
443					DoAliasing (mip->divertInOut, DONT_KNOW);
444
445		}
446		if (routeSock != -1)
447			if (FD_ISSET (routeSock, &readMask))
448				HandleRoutingInfo (routeSock);
449	}
450
451	if (background)
452		unlink (pidName);
453
454	return 0;
455}
456
457static void DaemonMode(void)
458{
459	FILE*	pidFile;
460
461	daemon (0, 0);
462	background = 1;
463
464	pidFile = fopen (pidName, "w");
465	if (pidFile) {
466
467		fprintf (pidFile, "%d\n", getpid ());
468		fclose (pidFile);
469	}
470}
471
472static void ParseArgs (int argc, char** argv)
473{
474	int		arg;
475	char*		opt;
476	char		parmBuf[256];
477	int		len; /* bounds checking */
478
479	for (arg = 1; arg < argc; arg++) {
480
481		opt  = argv[arg];
482		if (*opt != '-') {
483
484			warnx ("invalid option %s", opt);
485			Usage ();
486		}
487
488		parmBuf[0] = '\0';
489		len = 0;
490
491		while (arg < argc - 1) {
492
493			if (argv[arg + 1][0] == '-')
494				break;
495
496			if (len) {
497				strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
498				len += strlen(parmBuf + len);
499			}
500
501			++arg;
502			strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
503			len += strlen(parmBuf + len);
504
505		}
506
507		ParseOption (opt + 1, (len ? parmBuf : NULL));
508
509	}
510}
511
512static void DoGlobal (int fd)
513{
514	int			bytes;
515	int			origBytes;
516	char			buf[IP_MAXPACKET];
517	struct sockaddr_in	addr;
518	int			wrote;
519	socklen_t		addrSize;
520	struct ip*		ip;
521	char			msgBuf[80];
522
523/*
524 * Get packet from socket.
525 */
526	addrSize  = sizeof addr;
527	origBytes = recvfrom (fd,
528			      buf,
529			      sizeof buf,
530			      0,
531			      (struct sockaddr*) &addr,
532			      &addrSize);
533
534	if (origBytes == -1) {
535
536		if (errno != EINTR)
537			Warn ("read from divert socket failed");
538
539		return;
540	}
541
542#if 0
543	if (mip->assignAliasAddr) {
544		if (SetAliasAddressFromIfName (mip->ifName) != 0)
545			exit(1);
546		mip->assignAliasAddr = 0;
547	}
548#endif
549/*
550 * This is an IP packet.
551 */
552	ip = (struct ip*) buf;
553
554	if (verbose) {
555/*
556 * Print packet direction and protocol type.
557 */
558		printf ("Glb ");
559
560		switch (ip->ip_p) {
561		case IPPROTO_TCP:
562			printf ("[TCP]  ");
563			break;
564
565		case IPPROTO_UDP:
566			printf ("[UDP]  ");
567			break;
568
569		case IPPROTO_ICMP:
570			printf ("[ICMP] ");
571			break;
572
573		default:
574			printf ("[%d]    ", ip->ip_p);
575			break;
576		}
577/*
578 * Print addresses.
579 */
580		PrintPacket (ip);
581	}
582
583	LIST_FOREACH(mip, &root, list) {
584		mla = mip->la;
585		if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED)
586			break;
587	}
588/*
589 * Length might have changed during aliasing.
590 */
591	bytes = ntohs (ip->ip_len);
592/*
593 * Update alias overhead size for outgoing packets.
594 */
595	if (mip != NULL && bytes - origBytes > mip->aliasOverhead)
596		mip->aliasOverhead = bytes - origBytes;
597
598	if (verbose) {
599
600/*
601 * Print addresses after aliasing.
602 */
603		printf (" aliased to\n");
604		printf ("           ");
605		PrintPacket (ip);
606		printf ("\n");
607	}
608
609/*
610 * Put packet back for processing.
611 */
612	wrote = sendto (fd,
613		        buf,
614	    		bytes,
615	    		0,
616	    		(struct sockaddr*) &addr,
617	    		sizeof addr);
618
619	if (wrote != bytes) {
620
621		if (errno == EMSGSIZE && mip != NULL) {
622
623			if (mip->ifMTU != -1)
624				SendNeedFragIcmp (icmpSock,
625						  (struct ip*) buf,
626						  mip->ifMTU - mip->aliasOverhead);
627		}
628		else if (errno == EACCES && logIpfwDenied) {
629
630			sprintf (msgBuf, "failed to write packet back");
631			Warn (msgBuf);
632		}
633	}
634}
635
636
637static void DoAliasing (int fd, int direction)
638{
639	int			bytes;
640	int			origBytes;
641	char			buf[IP_MAXPACKET];
642	struct sockaddr_in	addr;
643	int			wrote;
644	int			status;
645	socklen_t		addrSize;
646	struct ip*		ip;
647	char			msgBuf[80];
648	int			rval;
649
650	if (mip->assignAliasAddr) {
651		do {
652			rval = SetAliasAddressFromIfName (mip->ifName);
653			if (background == 0 || dynamicMode == 0)
654				break;
655			if (rval == EAGAIN)
656				sleep(1);
657		} while (rval == EAGAIN);
658		if (rval != 0)
659			exit(1);
660		mip->assignAliasAddr = 0;
661	}
662/*
663 * Get packet from socket.
664 */
665	addrSize  = sizeof addr;
666	origBytes = recvfrom (fd,
667			      buf,
668			      sizeof buf,
669			      0,
670			      (struct sockaddr*) &addr,
671			      &addrSize);
672
673	if (origBytes == -1) {
674
675		if (errno != EINTR)
676			Warn ("read from divert socket failed");
677
678		return;
679	}
680/*
681 * This is an IP packet.
682 */
683	ip = (struct ip*) buf;
684	if (direction == DONT_KNOW) {
685		if (addr.sin_addr.s_addr == INADDR_ANY)
686			direction = OUTPUT;
687		else
688			direction = INPUT;
689	}
690
691	if (verbose) {
692/*
693 * Print packet direction and protocol type.
694 */
695		printf (direction == OUTPUT ? "Out " : "In  ");
696		if (ninstance > 1)
697			printf ("{%s}", mip->name);
698
699		switch (ip->ip_p) {
700		case IPPROTO_TCP:
701			printf ("[TCP]  ");
702			break;
703
704		case IPPROTO_UDP:
705			printf ("[UDP]  ");
706			break;
707
708		case IPPROTO_ICMP:
709			printf ("[ICMP] ");
710			break;
711
712		default:
713			printf ("[%d]    ", ip->ip_p);
714			break;
715		}
716/*
717 * Print addresses.
718 */
719		PrintPacket (ip);
720	}
721
722	if (direction == OUTPUT) {
723/*
724 * Outgoing packets. Do aliasing.
725 */
726		LibAliasOut (mla, buf, IP_MAXPACKET);
727	}
728	else {
729
730/*
731 * Do aliasing.
732 */
733		status = LibAliasIn (mla, buf, IP_MAXPACKET);
734		if (status == PKT_ALIAS_IGNORED &&
735		    mip->dropIgnoredIncoming) {
736
737			if (verbose)
738				printf (" dropped.\n");
739
740			if (mip->logDropped)
741				SyslogPacket (ip, LOG_WARNING, "denied");
742
743			return;
744		}
745	}
746/*
747 * Length might have changed during aliasing.
748 */
749	bytes = ntohs (ip->ip_len);
750/*
751 * Update alias overhead size for outgoing packets.
752 */
753	if (direction == OUTPUT &&
754	    bytes - origBytes > mip->aliasOverhead)
755		mip->aliasOverhead = bytes - origBytes;
756
757	if (verbose) {
758
759/*
760 * Print addresses after aliasing.
761 */
762		printf (" aliased to\n");
763		printf ("           ");
764		PrintPacket (ip);
765		printf ("\n");
766	}
767
768/*
769 * Put packet back for processing.
770 */
771	wrote = sendto (fd,
772		        buf,
773	    		bytes,
774	    		0,
775	    		(struct sockaddr*) &addr,
776	    		sizeof addr);
777
778	if (wrote != bytes) {
779
780		if (errno == EMSGSIZE) {
781
782			if (direction == OUTPUT &&
783			    mip->ifMTU != -1)
784				SendNeedFragIcmp (icmpSock,
785						  (struct ip*) buf,
786						  mip->ifMTU - mip->aliasOverhead);
787		}
788		else if (errno == EACCES && logIpfwDenied) {
789
790			sprintf (msgBuf, "failed to write packet back");
791			Warn (msgBuf);
792		}
793	}
794}
795
796static void HandleRoutingInfo (int fd)
797{
798	int			bytes;
799	struct if_msghdr	ifMsg;
800/*
801 * Get packet from socket.
802 */
803	bytes = read (fd, &ifMsg, sizeof ifMsg);
804	if (bytes == -1) {
805
806		Warn ("read from routing socket failed");
807		return;
808	}
809
810	if (ifMsg.ifm_version != RTM_VERSION) {
811
812		Warn ("unexpected packet read from routing socket");
813		return;
814	}
815
816	if (verbose)
817		printf ("Routing message %#x received.\n", ifMsg.ifm_type);
818
819	if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) {
820		LIST_FOREACH(mip, &root, list) {
821			mla = mip->la;
822			if (ifMsg.ifm_index == mip->ifIndex) {
823				if (verbose)
824					printf("Interface address/MTU has probably changed.\n");
825				mip->assignAliasAddr = 1;
826			}
827		}
828	}
829}
830
831static void PrintPacket (struct ip* ip)
832{
833	printf ("%s", FormatPacket (ip));
834}
835
836static void SyslogPacket (struct ip* ip, int priority, const char *label)
837{
838	syslog (priority, "%s %s", label, FormatPacket (ip));
839}
840
841static char* FormatPacket (struct ip* ip)
842{
843	static char	buf[256];
844	struct tcphdr*	tcphdr;
845	struct udphdr*	udphdr;
846	struct icmp*	icmphdr;
847	char		src[20];
848	char		dst[20];
849
850	strcpy (src, inet_ntoa (ip->ip_src));
851	strcpy (dst, inet_ntoa (ip->ip_dst));
852
853	switch (ip->ip_p) {
854	case IPPROTO_TCP:
855		tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
856		sprintf (buf, "[TCP] %s:%d -> %s:%d",
857			      src,
858			      ntohs (tcphdr->th_sport),
859			      dst,
860			      ntohs (tcphdr->th_dport));
861		break;
862
863	case IPPROTO_UDP:
864		udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
865		sprintf (buf, "[UDP] %s:%d -> %s:%d",
866			      src,
867			      ntohs (udphdr->uh_sport),
868			      dst,
869			      ntohs (udphdr->uh_dport));
870		break;
871
872	case IPPROTO_ICMP:
873		icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
874		sprintf (buf, "[ICMP] %s -> %s %u(%u)",
875			      src,
876			      dst,
877			      icmphdr->icmp_type,
878			      icmphdr->icmp_code);
879		break;
880
881	default:
882		sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
883		break;
884	}
885
886	return buf;
887}
888
889static int
890SetAliasAddressFromIfName(const char *ifn)
891{
892	size_t needed;
893	int mib[6];
894	char *buf, *lim, *next;
895	struct if_msghdr *ifm;
896	struct ifa_msghdr *ifam;
897	struct sockaddr_dl *sdl;
898	struct sockaddr_in *sin;
899
900	mib[0] = CTL_NET;
901	mib[1] = PF_ROUTE;
902	mib[2] = 0;
903	mib[3] = AF_INET;	/* Only IP addresses please */
904	mib[4] = NET_RT_IFLIST;
905	mib[5] = 0;		/* ifIndex??? */
906/*
907 * Get interface data.
908 */
909	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
910		err(1, "iflist-sysctl-estimate");
911	if ((buf = malloc(needed)) == NULL)
912		errx(1, "malloc failed");
913	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1 && errno != ENOMEM)
914		err(1, "iflist-sysctl-get");
915	lim = buf + needed;
916/*
917 * Loop through interfaces until one with
918 * given name is found. This is done to
919 * find correct interface index for routing
920 * message processing.
921 */
922	mip->ifIndex	= 0;
923	next = buf;
924	while (next < lim) {
925		ifm = (struct if_msghdr *)next;
926		next += ifm->ifm_msglen;
927		if (ifm->ifm_version != RTM_VERSION) {
928			if (verbose)
929				warnx("routing message version %d "
930				      "not understood", ifm->ifm_version);
931			continue;
932		}
933		if (ifm->ifm_type == RTM_IFINFO) {
934			sdl = (struct sockaddr_dl *)(ifm + 1);
935			if (strlen(ifn) == sdl->sdl_nlen &&
936			    strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
937				mip->ifIndex = ifm->ifm_index;
938				mip->ifMTU = ifm->ifm_data.ifi_mtu;
939				break;
940			}
941		}
942	}
943	if (!mip->ifIndex)
944		errx(1, "unknown interface name %s", ifn);
945/*
946 * Get interface address.
947 */
948	sin = NULL;
949	while (next < lim) {
950		ifam = (struct ifa_msghdr *)next;
951		next += ifam->ifam_msglen;
952		if (ifam->ifam_version != RTM_VERSION) {
953			if (verbose)
954				warnx("routing message version %d "
955				      "not understood", ifam->ifam_version);
956			continue;
957		}
958		if (ifam->ifam_type != RTM_NEWADDR)
959			break;
960		if (ifam->ifam_addrs & RTA_IFA) {
961			int i;
962			char *cp = (char *)(ifam + 1);
963
964			for (i = 1; i < RTA_IFA; i <<= 1)
965				if (ifam->ifam_addrs & i)
966					cp += SA_SIZE((struct sockaddr *)cp);
967			if (((struct sockaddr *)cp)->sa_family == AF_INET) {
968				sin = (struct sockaddr_in *)cp;
969				break;
970			}
971		}
972	}
973	if (sin == NULL) {
974		warnx("%s: cannot get interface address", ifn);
975		free(buf);
976		return EAGAIN;
977	}
978
979	LibAliasSetAddress(mla, sin->sin_addr);
980	syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
981	       inet_ntoa(sin->sin_addr), mip->ifMTU);
982
983	free(buf);
984
985	return 0;
986}
987
988void Quit (const char* msg)
989{
990	Warn (msg);
991	exit (1);
992}
993
994void Warn (const char* msg)
995{
996	if (background)
997		syslog (LOG_ALERT, "%s (%m)", msg);
998	else
999		warn ("%s", msg);
1000}
1001
1002static void RefreshAddr (int sig __unused)
1003{
1004	LibAliasRefreshModules();
1005	if (mip != NULL && mip->ifName != NULL)
1006		mip->assignAliasAddr = 1;
1007}
1008
1009static void InitiateShutdown (int sig __unused)
1010{
1011/*
1012 * Start timer to allow kernel gracefully
1013 * shutdown existing connections when system
1014 * is shut down.
1015 */
1016	siginterrupt(SIGALRM, 1);
1017	signal (SIGALRM, Shutdown);
1018	ualarm(exitDelay*1000, 1000);
1019}
1020
1021static void Shutdown (int sig __unused)
1022{
1023	running = 0;
1024}
1025
1026/*
1027 * Different options recognized by this program.
1028 */
1029
1030enum Option {
1031
1032	LibAliasOption,
1033	Instance,
1034	Verbose,
1035	InPort,
1036	OutPort,
1037	Port,
1038	GlobalPort,
1039	AliasAddress,
1040	TargetAddress,
1041	InterfaceName,
1042	RedirectPort,
1043	RedirectProto,
1044	RedirectAddress,
1045	ConfigFile,
1046	DynamicMode,
1047	ProxyRule,
1048 	LogDenied,
1049 	LogFacility,
1050	PunchFW,
1051	SkinnyPort,
1052	LogIpfwDenied,
1053	PidFile,
1054	ExitDelay
1055};
1056
1057enum Param {
1058
1059	YesNo,
1060	Numeric,
1061	String,
1062	None,
1063	Address,
1064	Service
1065};
1066
1067/*
1068 * Option information structure (used by ParseOption).
1069 */
1070
1071struct OptionInfo {
1072
1073	enum Option		type;
1074	int			packetAliasOpt;
1075	enum Param		parm;
1076	const char*		parmDescription;
1077	const char*		description;
1078	const char*		name;
1079	const char*		shortName;
1080};
1081
1082/*
1083 * Table of known options.
1084 */
1085
1086static struct OptionInfo optionTable[] = {
1087
1088	{ LibAliasOption,
1089		PKT_ALIAS_UNREGISTERED_ONLY,
1090		YesNo,
1091		"[yes|no]",
1092		"alias only unregistered addresses",
1093		"unregistered_only",
1094		"u" },
1095
1096	{ LibAliasOption,
1097		PKT_ALIAS_LOG,
1098		YesNo,
1099		"[yes|no]",
1100		"enable logging",
1101		"log",
1102		"l" },
1103
1104	{ LibAliasOption,
1105		PKT_ALIAS_PROXY_ONLY,
1106		YesNo,
1107		"[yes|no]",
1108		"proxy only",
1109		"proxy_only",
1110		NULL },
1111
1112	{ LibAliasOption,
1113		PKT_ALIAS_REVERSE,
1114		YesNo,
1115		"[yes|no]",
1116		"operate in reverse mode",
1117		"reverse",
1118		NULL },
1119
1120	{ LibAliasOption,
1121		PKT_ALIAS_DENY_INCOMING,
1122		YesNo,
1123		"[yes|no]",
1124		"allow incoming connections",
1125		"deny_incoming",
1126		"d" },
1127
1128	{ LibAliasOption,
1129		PKT_ALIAS_USE_SOCKETS,
1130		YesNo,
1131		"[yes|no]",
1132		"use sockets to inhibit port conflict",
1133		"use_sockets",
1134		"s" },
1135
1136	{ LibAliasOption,
1137		PKT_ALIAS_SAME_PORTS,
1138		YesNo,
1139		"[yes|no]",
1140		"try to keep original port numbers for connections",
1141		"same_ports",
1142		"m" },
1143
1144	{ Verbose,
1145		0,
1146		YesNo,
1147		"[yes|no]",
1148		"verbose mode, dump packet information",
1149		"verbose",
1150		"v" },
1151
1152	{ DynamicMode,
1153		0,
1154		YesNo,
1155		"[yes|no]",
1156		"dynamic mode, automatically detect interface address changes",
1157		"dynamic",
1158		NULL },
1159
1160	{ InPort,
1161		0,
1162		Service,
1163		"number|service_name",
1164		"set port for incoming packets",
1165		"in_port",
1166		"i" },
1167
1168	{ OutPort,
1169		0,
1170		Service,
1171		"number|service_name",
1172		"set port for outgoing packets",
1173		"out_port",
1174		"o" },
1175
1176	{ Port,
1177		0,
1178		Service,
1179		"number|service_name",
1180		"set port (defaults to natd/divert)",
1181		"port",
1182		"p" },
1183
1184	{ GlobalPort,
1185		0,
1186		Service,
1187		"number|service_name",
1188		"set globalport",
1189		"globalport",
1190		NULL },
1191
1192	{ AliasAddress,
1193		0,
1194		Address,
1195		"x.x.x.x",
1196		"address to use for aliasing",
1197		"alias_address",
1198		"a" },
1199
1200	{ TargetAddress,
1201		0,
1202		Address,
1203		"x.x.x.x",
1204		"address to use for incoming sessions",
1205		"target_address",
1206		"t" },
1207
1208	{ InterfaceName,
1209		0,
1210		String,
1211	        "network_if_name",
1212		"take aliasing address from interface",
1213		"interface",
1214		"n" },
1215
1216	{ ProxyRule,
1217		0,
1218		String,
1219	        "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1220		"a.b.c.d:yyyy",
1221		"add transparent proxying / destination NAT",
1222		"proxy_rule",
1223		NULL },
1224
1225	{ RedirectPort,
1226		0,
1227		String,
1228	        "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1229	 	" [remote_addr[:remote_port_range]]",
1230		"redirect a port (or ports) for incoming traffic",
1231		"redirect_port",
1232		NULL },
1233
1234	{ RedirectProto,
1235		0,
1236		String,
1237	        "proto local_addr [public_addr] [remote_addr]",
1238		"redirect packets of a given proto",
1239		"redirect_proto",
1240		NULL },
1241
1242	{ RedirectAddress,
1243		0,
1244		String,
1245	        "local_addr[,...] public_addr",
1246		"define mapping between local and public addresses",
1247		"redirect_address",
1248		NULL },
1249
1250	{ ConfigFile,
1251		0,
1252		String,
1253		"file_name",
1254		"read options from configuration file",
1255		"config",
1256		"f" },
1257
1258	{ LogDenied,
1259		0,
1260		YesNo,
1261	        "[yes|no]",
1262		"enable logging of denied incoming packets",
1263		"log_denied",
1264		NULL },
1265
1266	{ LogFacility,
1267		0,
1268		String,
1269	        "facility",
1270		"name of syslog facility to use for logging",
1271		"log_facility",
1272		NULL },
1273
1274	{ PunchFW,
1275		0,
1276		String,
1277	        "basenumber:count",
1278		"punch holes in the firewall for incoming FTP/IRC DCC connections",
1279		"punch_fw",
1280		NULL },
1281
1282	{ SkinnyPort,
1283		0,
1284		String,
1285		"port",
1286		"set the TCP port for use with the Skinny Station protocol",
1287		"skinny_port",
1288		NULL },
1289
1290	{ LogIpfwDenied,
1291		0,
1292		YesNo,
1293	        "[yes|no]",
1294		"log packets converted by natd, but denied by ipfw",
1295		"log_ipfw_denied",
1296		NULL },
1297
1298	{ PidFile,
1299		0,
1300		String,
1301		"file_name",
1302		"store PID in an alternate file",
1303		"pid_file",
1304		"P" },
1305	{ Instance,
1306		0,
1307		String,
1308		"instance name",
1309		"name of aliasing engine instance",
1310		"instance",
1311		NULL },
1312	{ ExitDelay,
1313		0,
1314		Numeric,
1315		"ms",
1316		"delay in ms before daemon exit after signal",
1317		"exit_delay",
1318		NULL },
1319};
1320
1321static void ParseOption (const char* option, const char* parms)
1322{
1323	int			i;
1324	struct OptionInfo*	info;
1325	int			yesNoValue;
1326	int			aliasValue;
1327	int			numValue;
1328	u_short			uNumValue;
1329	const char*		strValue;
1330	struct in_addr		addrValue;
1331	int			max;
1332	char*			end;
1333	const CODE* 		fac_record = NULL;
1334/*
1335 * Find option from table.
1336 */
1337	max = sizeof (optionTable) / sizeof (struct OptionInfo);
1338	for (i = 0, info = optionTable; i < max; i++, info++) {
1339
1340		if (!strcmp (info->name, option))
1341			break;
1342
1343		if (info->shortName)
1344			if (!strcmp (info->shortName, option))
1345				break;
1346	}
1347
1348	if (i >= max) {
1349
1350		warnx ("unknown option %s", option);
1351		Usage ();
1352	}
1353
1354	uNumValue	= 0;
1355	yesNoValue	= 0;
1356	numValue	= 0;
1357	strValue	= NULL;
1358/*
1359 * Check parameters.
1360 */
1361	switch (info->parm) {
1362	case YesNo:
1363		if (!parms)
1364			parms = "yes";
1365
1366		if (!strcmp (parms, "yes"))
1367			yesNoValue = 1;
1368		else
1369			if (!strcmp (parms, "no"))
1370				yesNoValue = 0;
1371			else
1372				errx (1, "%s needs yes/no parameter", option);
1373		break;
1374
1375	case Service:
1376		if (!parms)
1377			errx (1, "%s needs service name or "
1378				 "port number parameter",
1379				 option);
1380
1381		uNumValue = StrToPort (parms, "divert");
1382		break;
1383
1384	case Numeric:
1385		if (parms)
1386			numValue = strtol (parms, &end, 10);
1387		else
1388			end = NULL;
1389
1390		if (end == parms)
1391			errx (1, "%s needs numeric parameter", option);
1392		break;
1393
1394	case String:
1395		strValue = parms;
1396		if (!strValue)
1397			errx (1, "%s needs parameter", option);
1398		break;
1399
1400	case None:
1401		if (parms)
1402			errx (1, "%s does not take parameters", option);
1403		break;
1404
1405	case Address:
1406		if (!parms)
1407			errx (1, "%s needs address/host parameter", option);
1408
1409		StrToAddr (parms, &addrValue);
1410		break;
1411	}
1412
1413	switch (info->type) {
1414	case LibAliasOption:
1415
1416		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1417		LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
1418		break;
1419
1420	case Verbose:
1421		verbose = yesNoValue;
1422		break;
1423
1424	case DynamicMode:
1425		dynamicMode = yesNoValue;
1426		break;
1427
1428	case InPort:
1429		mip->inPort = uNumValue;
1430		break;
1431
1432	case OutPort:
1433		mip->outPort = uNumValue;
1434		break;
1435
1436	case Port:
1437		mip->inOutPort = uNumValue;
1438		break;
1439
1440	case GlobalPort:
1441		globalPort = uNumValue;
1442		break;
1443
1444	case AliasAddress:
1445		memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
1446		break;
1447
1448	case TargetAddress:
1449		LibAliasSetTarget(mla, addrValue);
1450		break;
1451
1452	case RedirectPort:
1453		SetupPortRedirect (strValue);
1454		break;
1455
1456	case RedirectProto:
1457		SetupProtoRedirect(strValue);
1458		break;
1459
1460	case RedirectAddress:
1461		SetupAddressRedirect (strValue);
1462		break;
1463
1464	case ProxyRule:
1465		LibAliasProxyRule (mla, strValue);
1466		break;
1467
1468	case InterfaceName:
1469		if (mip->ifName)
1470			free (mip->ifName);
1471
1472		mip->ifName = strdup (strValue);
1473		break;
1474
1475	case ConfigFile:
1476		ReadConfigFile (strValue);
1477		break;
1478
1479	case LogDenied:
1480		mip->logDropped = yesNoValue;
1481		break;
1482
1483	case LogFacility:
1484
1485		fac_record = facilitynames;
1486		while (fac_record->c_name != NULL) {
1487
1488			if (!strcmp (fac_record->c_name, strValue)) {
1489
1490				logFacility = fac_record->c_val;
1491				break;
1492
1493			}
1494			else
1495				fac_record++;
1496		}
1497
1498		if(fac_record->c_name == NULL)
1499			errx(1, "Unknown log facility name: %s", strValue);
1500
1501		break;
1502
1503	case PunchFW:
1504		SetupPunchFW(strValue);
1505		break;
1506
1507	case SkinnyPort:
1508		SetupSkinnyPort(strValue);
1509		break;
1510
1511	case LogIpfwDenied:
1512		logIpfwDenied = yesNoValue;
1513		break;
1514
1515	case PidFile:
1516		pidName = strdup (strValue);
1517		break;
1518	case Instance:
1519		NewInstance(strValue);
1520		break;
1521	case ExitDelay:
1522		if (numValue < 0 || numValue > MAX_EXIT_DELAY)
1523			errx(1, "Incorrect exit delay: %d", numValue);
1524		exitDelay = numValue;
1525		break;
1526	}
1527}
1528
1529void ReadConfigFile (const char* fileName)
1530{
1531	FILE*	file;
1532	char	*buf;
1533	size_t	len;
1534	char	*ptr, *p;
1535	char*	option;
1536
1537	file = fopen (fileName, "r");
1538	if (!file)
1539		err(1, "cannot open config file %s", fileName);
1540
1541	while ((buf = fgetln(file, &len)) != NULL) {
1542		if (buf[len - 1] == '\n')
1543			buf[len - 1] = '\0';
1544		else
1545			errx(1, "config file format error: "
1546				"last line should end with newline");
1547
1548/*
1549 * Check for comments, strip off trailing spaces.
1550 */
1551		if ((ptr = strchr(buf, '#')))
1552			*ptr = '\0';
1553		for (ptr = buf; isspace(*ptr); ++ptr)
1554			continue;
1555		if (*ptr == '\0')
1556			continue;
1557		for (p = strchr(buf, '\0'); isspace(*--p);)
1558			continue;
1559		*++p = '\0';
1560
1561/*
1562 * Extract option name.
1563 */
1564		option = ptr;
1565		while (*ptr && !isspace (*ptr))
1566			++ptr;
1567
1568		if (*ptr != '\0') {
1569
1570			*ptr = '\0';
1571			++ptr;
1572		}
1573/*
1574 * Skip white space between name and parms.
1575 */
1576		while (*ptr && isspace (*ptr))
1577			++ptr;
1578
1579		ParseOption (option, *ptr ? ptr : NULL);
1580	}
1581
1582	fclose (file);
1583}
1584
1585static void Usage(void)
1586{
1587	int			i;
1588	int			max;
1589	struct OptionInfo*	info;
1590
1591	fprintf (stderr, "Recognized options:\n\n");
1592
1593	max = sizeof (optionTable) / sizeof (struct OptionInfo);
1594	for (i = 0, info = optionTable; i < max; i++, info++) {
1595
1596		fprintf (stderr, "-%-20s %s\n", info->name,
1597						info->parmDescription);
1598
1599		if (info->shortName)
1600			fprintf (stderr, "-%-20s %s\n", info->shortName,
1601							info->parmDescription);
1602
1603		fprintf (stderr, "      %s\n\n", info->description);
1604	}
1605
1606	exit (1);
1607}
1608
1609void SetupPortRedirect (const char* parms)
1610{
1611	char		*buf;
1612	char*		ptr;
1613	char*		serverPool;
1614	struct in_addr	localAddr;
1615	struct in_addr	publicAddr;
1616	struct in_addr	remoteAddr;
1617	port_range      portRange;
1618	u_short         localPort      = 0;
1619	u_short         publicPort     = 0;
1620	u_short         remotePort     = 0;
1621	u_short         numLocalPorts  = 0;
1622	u_short         numPublicPorts = 0;
1623	u_short         numRemotePorts = 0;
1624	int		proto;
1625	char*		protoName;
1626	char*		separator;
1627	int             i;
1628	struct alias_link *aliaslink = NULL;
1629
1630	buf = strdup (parms);
1631	if (!buf)
1632		errx (1, "redirect_port: strdup() failed");
1633/*
1634 * Extract protocol.
1635 */
1636	protoName = strtok (buf, " \t");
1637	if (!protoName)
1638		errx (1, "redirect_port: missing protocol");
1639
1640	proto = StrToProto (protoName);
1641/*
1642 * Extract local address.
1643 */
1644	ptr = strtok (NULL, " \t");
1645	if (!ptr)
1646		errx (1, "redirect_port: missing local address");
1647
1648	separator = strchr(ptr, ',');
1649	if (separator) {		/* LSNAT redirection syntax. */
1650		localAddr.s_addr = INADDR_NONE;
1651		localPort = ~0;
1652		numLocalPorts = 1;
1653		serverPool = ptr;
1654	} else {
1655		if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1656			errx (1, "redirect_port: invalid local port range");
1657
1658		localPort     = GETLOPORT(portRange);
1659		numLocalPorts = GETNUMPORTS(portRange);
1660		serverPool = NULL;
1661	}
1662
1663/*
1664 * Extract public port and optionally address.
1665 */
1666	ptr = strtok (NULL, " \t");
1667	if (!ptr)
1668		errx (1, "redirect_port: missing public port");
1669
1670	separator = strchr (ptr, ':');
1671	if (separator) {
1672	        if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1673		        errx (1, "redirect_port: invalid public port range");
1674	}
1675	else {
1676		publicAddr.s_addr = INADDR_ANY;
1677		if (StrToPortRange (ptr, protoName, &portRange) != 0)
1678		        errx (1, "redirect_port: invalid public port range");
1679	}
1680
1681	publicPort     = GETLOPORT(portRange);
1682	numPublicPorts = GETNUMPORTS(portRange);
1683
1684/*
1685 * Extract remote address and optionally port.
1686 */
1687	ptr = strtok (NULL, " \t");
1688	if (ptr) {
1689		separator = strchr (ptr, ':');
1690		if (separator) {
1691		        if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1692			        errx (1, "redirect_port: invalid remote port range");
1693		} else {
1694		        SETLOPORT(portRange, 0);
1695			SETNUMPORTS(portRange, 1);
1696			StrToAddr (ptr, &remoteAddr);
1697		}
1698	}
1699	else {
1700	        SETLOPORT(portRange, 0);
1701		SETNUMPORTS(portRange, 1);
1702		remoteAddr.s_addr = INADDR_ANY;
1703	}
1704
1705	remotePort     = GETLOPORT(portRange);
1706	numRemotePorts = GETNUMPORTS(portRange);
1707
1708/*
1709 * Make sure port ranges match up, then add the redirect ports.
1710 */
1711	if (numLocalPorts != numPublicPorts)
1712	        errx (1, "redirect_port: port ranges must be equal in size");
1713
1714	/* Remote port range is allowed to be '0' which means all ports. */
1715	if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1716	        errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1717
1718	for (i = 0 ; i < numPublicPorts ; ++i) {
1719	        /* If remotePort is all ports, set it to 0. */
1720	        u_short remotePortCopy = remotePort + i;
1721	        if (numRemotePorts == 1 && remotePort == 0)
1722		        remotePortCopy = 0;
1723
1724		aliaslink = LibAliasRedirectPort (mla, localAddr,
1725						htons(localPort + i),
1726						remoteAddr,
1727						htons(remotePortCopy),
1728						publicAddr,
1729						htons(publicPort + i),
1730						proto);
1731	}
1732
1733/*
1734 * Setup LSNAT server pool.
1735 */
1736	if (serverPool != NULL && aliaslink != NULL) {
1737		ptr = strtok(serverPool, ",");
1738		while (ptr != NULL) {
1739			if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1740				errx(1, "redirect_port: invalid local port range");
1741
1742			localPort = GETLOPORT(portRange);
1743			if (GETNUMPORTS(portRange) != 1)
1744				errx(1, "redirect_port: local port must be single in this context");
1745			LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
1746			ptr = strtok(NULL, ",");
1747		}
1748	}
1749
1750	free (buf);
1751}
1752
1753void
1754SetupProtoRedirect(const char* parms)
1755{
1756	char		*buf;
1757	char*		ptr;
1758	struct in_addr	localAddr;
1759	struct in_addr	publicAddr;
1760	struct in_addr	remoteAddr;
1761	int		proto;
1762	char*		protoName;
1763	struct protoent *protoent;
1764
1765	buf = strdup (parms);
1766	if (!buf)
1767		errx (1, "redirect_port: strdup() failed");
1768/*
1769 * Extract protocol.
1770 */
1771	protoName = strtok(buf, " \t");
1772	if (!protoName)
1773		errx(1, "redirect_proto: missing protocol");
1774
1775	protoent = getprotobyname(protoName);
1776	if (protoent == NULL)
1777		errx(1, "redirect_proto: unknown protocol %s", protoName);
1778	else
1779		proto = protoent->p_proto;
1780/*
1781 * Extract local address.
1782 */
1783	ptr = strtok(NULL, " \t");
1784	if (!ptr)
1785		errx(1, "redirect_proto: missing local address");
1786	else
1787		StrToAddr(ptr, &localAddr);
1788/*
1789 * Extract optional public address.
1790 */
1791	ptr = strtok(NULL, " \t");
1792	if (ptr)
1793		StrToAddr(ptr, &publicAddr);
1794	else
1795		publicAddr.s_addr = INADDR_ANY;
1796/*
1797 * Extract optional remote address.
1798 */
1799	ptr = strtok(NULL, " \t");
1800	if (ptr)
1801		StrToAddr(ptr, &remoteAddr);
1802	else
1803		remoteAddr.s_addr = INADDR_ANY;
1804/*
1805 * Create aliasing link.
1806 */
1807	(void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
1808				       proto);
1809
1810	free (buf);
1811}
1812
1813void SetupAddressRedirect (const char* parms)
1814{
1815	char		*buf;
1816	char*		ptr;
1817	char*		separator;
1818	struct in_addr	localAddr;
1819	struct in_addr	publicAddr;
1820	char*		serverPool;
1821	struct alias_link *aliaslink;
1822
1823	buf = strdup (parms);
1824	if (!buf)
1825		errx (1, "redirect_port: strdup() failed");
1826/*
1827 * Extract local address.
1828 */
1829	ptr = strtok (buf, " \t");
1830	if (!ptr)
1831		errx (1, "redirect_address: missing local address");
1832
1833	separator = strchr(ptr, ',');
1834	if (separator) {		/* LSNAT redirection syntax. */
1835		localAddr.s_addr = INADDR_NONE;
1836		serverPool = ptr;
1837	} else {
1838		StrToAddr (ptr, &localAddr);
1839		serverPool = NULL;
1840	}
1841/*
1842 * Extract public address.
1843 */
1844	ptr = strtok (NULL, " \t");
1845	if (!ptr)
1846		errx (1, "redirect_address: missing public address");
1847
1848	StrToAddr (ptr, &publicAddr);
1849	aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1850
1851/*
1852 * Setup LSNAT server pool.
1853 */
1854	if (serverPool != NULL && aliaslink != NULL) {
1855		ptr = strtok(serverPool, ",");
1856		while (ptr != NULL) {
1857			StrToAddr(ptr, &localAddr);
1858			LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
1859			ptr = strtok(NULL, ",");
1860		}
1861	}
1862
1863	free (buf);
1864}
1865
1866void StrToAddr (const char* str, struct in_addr* addr)
1867{
1868	struct hostent* hp;
1869
1870	if (inet_aton (str, addr))
1871		return;
1872
1873	hp = gethostbyname (str);
1874	if (!hp)
1875		errx (1, "unknown host %s", str);
1876
1877	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1878}
1879
1880u_short StrToPort (const char* str, const char* proto)
1881{
1882	u_short		port;
1883	struct servent*	sp;
1884	char*		end;
1885
1886	port = strtol (str, &end, 10);
1887	if (end != str)
1888		return htons (port);
1889
1890	sp = getservbyname (str, proto);
1891	if (!sp)
1892		errx (1, "%s/%s: unknown service", str, proto);
1893
1894	return sp->s_port;
1895}
1896
1897int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1898{
1899	const char*	sep;
1900	struct servent*	sp;
1901	char*		end;
1902	u_short         loPort;
1903	u_short         hiPort;
1904
1905	/* First see if this is a service, return corresponding port if so. */
1906	sp = getservbyname (str,proto);
1907	if (sp) {
1908	        SETLOPORT(*portRange, ntohs(sp->s_port));
1909		SETNUMPORTS(*portRange, 1);
1910		return 0;
1911	}
1912
1913	/* Not a service, see if it's a single port or port range. */
1914	sep = strchr (str, '-');
1915	if (sep == NULL) {
1916	        SETLOPORT(*portRange, strtol(str, &end, 10));
1917		if (end != str) {
1918		        /* Single port. */
1919		        SETNUMPORTS(*portRange, 1);
1920			return 0;
1921		}
1922
1923		/* Error in port range field. */
1924		errx (1, "%s/%s: unknown service", str, proto);
1925	}
1926
1927	/* Port range, get the values and sanity check. */
1928	sscanf (str, "%hu-%hu", &loPort, &hiPort);
1929	SETLOPORT(*portRange, loPort);
1930	SETNUMPORTS(*portRange, 0);	/* Error by default */
1931	if (loPort <= hiPort)
1932	        SETNUMPORTS(*portRange, hiPort - loPort + 1);
1933
1934	if (GETNUMPORTS(*portRange) == 0)
1935	        errx (1, "invalid port range %s", str);
1936
1937	return 0;
1938}
1939
1940
1941static int
1942StrToProto (const char* str)
1943{
1944	if (!strcmp (str, "tcp"))
1945		return IPPROTO_TCP;
1946
1947	if (!strcmp (str, "udp"))
1948		return IPPROTO_UDP;
1949
1950	errx (1, "unknown protocol %s. Expected tcp or udp", str);
1951}
1952
1953static int
1954StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange)
1955{
1956	char*	ptr;
1957
1958	ptr = strchr (str, ':');
1959	if (!ptr)
1960		errx (1, "%s is missing port number", str);
1961
1962	*ptr = '\0';
1963	++ptr;
1964
1965	StrToAddr (str, addr);
1966	return StrToPortRange (ptr, proto, portRange);
1967}
1968
1969static void
1970SetupPunchFW(const char *strValue)
1971{
1972	unsigned int base, num;
1973
1974	if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1975		errx(1, "punch_fw: basenumber:count parameter required");
1976
1977	if (CheckIpfwRulenum(base + num - 1) == -1)
1978		errx(1, "punch_fw: basenumber:count parameter should fit "
1979			"the maximum allowed rule numbers");
1980
1981	LibAliasSetFWBase(mla, base, num);
1982	(void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1983}
1984
1985static void
1986SetupSkinnyPort(const char *strValue)
1987{
1988	unsigned int port;
1989
1990	if (sscanf(strValue, "%u", &port) != 1)
1991		errx(1, "skinny_port: port parameter required");
1992
1993	LibAliasSetSkinnyPort(mla, port);
1994}
1995
1996static void
1997NewInstance(const char *name)
1998{
1999	struct instance *ip;
2000
2001	LIST_FOREACH(ip, &root, list) {
2002		if (!strcmp(ip->name, name)) {
2003			mla = ip->la;
2004			mip = ip;
2005			return;
2006		}
2007	}
2008	ninstance++;
2009	ip = calloc(1, sizeof(*ip));
2010	ip->name = strdup(name);
2011	ip->la = LibAliasInit (ip->la);
2012	ip->assignAliasAddr	= 0;
2013	ip->ifName		= NULL;
2014 	ip->logDropped		= 0;
2015	ip->inPort		= 0;
2016	ip->outPort		= 0;
2017	ip->inOutPort		= 0;
2018	ip->aliasAddr.s_addr	= INADDR_NONE;
2019	ip->ifMTU		= -1;
2020	ip->aliasOverhead	= 12;
2021	LIST_INSERT_HEAD(&root, ip, list);
2022	mla = ip->la;
2023	mip = ip;
2024}
2025
2026static int
2027CheckIpfwRulenum(unsigned int rnum)
2028{
2029	unsigned int default_rule;
2030	size_t len = sizeof(default_rule);
2031
2032	if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len,
2033		NULL, 0) == -1) {
2034		warn("Failed to get the default ipfw rule number, using "
2035		     "default historical value 65535.  The reason was");
2036		default_rule = 65535;
2037	}
2038	if (rnum >= default_rule) {
2039		return -1;
2040	}
2041
2042	return 0;
2043}
2044