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