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