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