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