xref: /freebsd/sbin/natd/natd.c (revision 2e3f49888ec8851bafb22011533217487764fdb0)
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 	{ Verbose,
1142 		0,
1143 		YesNo,
1144 		"[yes|no]",
1145 		"verbose mode, dump packet information",
1146 		"verbose",
1147 		"v" },
1148 
1149 	{ DynamicMode,
1150 		0,
1151 		YesNo,
1152 		"[yes|no]",
1153 		"dynamic mode, automatically detect interface address changes",
1154 		"dynamic",
1155 		NULL },
1156 
1157 	{ InPort,
1158 		0,
1159 		Service,
1160 		"number|service_name",
1161 		"set port for incoming packets",
1162 		"in_port",
1163 		"i" },
1164 
1165 	{ OutPort,
1166 		0,
1167 		Service,
1168 		"number|service_name",
1169 		"set port for outgoing packets",
1170 		"out_port",
1171 		"o" },
1172 
1173 	{ Port,
1174 		0,
1175 		Service,
1176 		"number|service_name",
1177 		"set port (defaults to natd/divert)",
1178 		"port",
1179 		"p" },
1180 
1181 	{ GlobalPort,
1182 		0,
1183 		Service,
1184 		"number|service_name",
1185 		"set globalport",
1186 		"globalport",
1187 		NULL },
1188 
1189 	{ AliasAddress,
1190 		0,
1191 		Address,
1192 		"x.x.x.x",
1193 		"address to use for aliasing",
1194 		"alias_address",
1195 		"a" },
1196 
1197 	{ TargetAddress,
1198 		0,
1199 		Address,
1200 		"x.x.x.x",
1201 		"address to use for incoming sessions",
1202 		"target_address",
1203 		"t" },
1204 
1205 	{ InterfaceName,
1206 		0,
1207 		String,
1208 	        "network_if_name",
1209 		"take aliasing address from interface",
1210 		"interface",
1211 		"n" },
1212 
1213 	{ ProxyRule,
1214 		0,
1215 		String,
1216 	        "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1217 		"a.b.c.d:yyyy",
1218 		"add transparent proxying / destination NAT",
1219 		"proxy_rule",
1220 		NULL },
1221 
1222 	{ RedirectPort,
1223 		0,
1224 		String,
1225 	        "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1226 	 	" [remote_addr[:remote_port_range]]",
1227 		"redirect a port (or ports) for incoming traffic",
1228 		"redirect_port",
1229 		NULL },
1230 
1231 	{ RedirectProto,
1232 		0,
1233 		String,
1234 	        "proto local_addr [public_addr] [remote_addr]",
1235 		"redirect packets of a given proto",
1236 		"redirect_proto",
1237 		NULL },
1238 
1239 	{ RedirectAddress,
1240 		0,
1241 		String,
1242 	        "local_addr[,...] public_addr",
1243 		"define mapping between local and public addresses",
1244 		"redirect_address",
1245 		NULL },
1246 
1247 	{ ConfigFile,
1248 		0,
1249 		String,
1250 		"file_name",
1251 		"read options from configuration file",
1252 		"config",
1253 		"f" },
1254 
1255 	{ LogDenied,
1256 		0,
1257 		YesNo,
1258 	        "[yes|no]",
1259 		"enable logging of denied incoming packets",
1260 		"log_denied",
1261 		NULL },
1262 
1263 	{ LogFacility,
1264 		0,
1265 		String,
1266 	        "facility",
1267 		"name of syslog facility to use for logging",
1268 		"log_facility",
1269 		NULL },
1270 
1271 	{ PunchFW,
1272 		0,
1273 		String,
1274 	        "basenumber:count",
1275 		"punch holes in the firewall for incoming FTP/IRC DCC connections",
1276 		"punch_fw",
1277 		NULL },
1278 
1279 	{ SkinnyPort,
1280 		0,
1281 		String,
1282 		"port",
1283 		"set the TCP port for use with the Skinny Station protocol",
1284 		"skinny_port",
1285 		NULL },
1286 
1287 	{ LogIpfwDenied,
1288 		0,
1289 		YesNo,
1290 	        "[yes|no]",
1291 		"log packets converted by natd, but denied by ipfw",
1292 		"log_ipfw_denied",
1293 		NULL },
1294 
1295 	{ PidFile,
1296 		0,
1297 		String,
1298 		"file_name",
1299 		"store PID in an alternate file",
1300 		"pid_file",
1301 		"P" },
1302 	{ Instance,
1303 		0,
1304 		String,
1305 		"instance name",
1306 		"name of aliasing engine instance",
1307 		"instance",
1308 		NULL },
1309 	{ ExitDelay,
1310 		0,
1311 		Numeric,
1312 		"ms",
1313 		"delay in ms before daemon exit after signal",
1314 		"exit_delay",
1315 		NULL },
1316 };
1317 
1318 static void ParseOption (const char* option, const char* parms)
1319 {
1320 	int			i;
1321 	struct OptionInfo*	info;
1322 	int			yesNoValue;
1323 	int			aliasValue;
1324 	int			numValue;
1325 	u_short			uNumValue;
1326 	const char*		strValue;
1327 	struct in_addr		addrValue;
1328 	int			max;
1329 	char*			end;
1330 	const CODE* 		fac_record = NULL;
1331 /*
1332  * Find option from table.
1333  */
1334 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
1335 	for (i = 0, info = optionTable; i < max; i++, info++) {
1336 
1337 		if (!strcmp (info->name, option))
1338 			break;
1339 
1340 		if (info->shortName)
1341 			if (!strcmp (info->shortName, option))
1342 				break;
1343 	}
1344 
1345 	if (i >= max) {
1346 
1347 		warnx ("unknown option %s", option);
1348 		Usage ();
1349 	}
1350 
1351 	uNumValue	= 0;
1352 	yesNoValue	= 0;
1353 	numValue	= 0;
1354 	strValue	= NULL;
1355 /*
1356  * Check parameters.
1357  */
1358 	switch (info->parm) {
1359 	case YesNo:
1360 		if (!parms)
1361 			parms = "yes";
1362 
1363 		if (!strcmp (parms, "yes"))
1364 			yesNoValue = 1;
1365 		else
1366 			if (!strcmp (parms, "no"))
1367 				yesNoValue = 0;
1368 			else
1369 				errx (1, "%s needs yes/no parameter", option);
1370 		break;
1371 
1372 	case Service:
1373 		if (!parms)
1374 			errx (1, "%s needs service name or "
1375 				 "port number parameter",
1376 				 option);
1377 
1378 		uNumValue = StrToPort (parms, "divert");
1379 		break;
1380 
1381 	case Numeric:
1382 		if (parms)
1383 			numValue = strtol (parms, &end, 10);
1384 		else
1385 			end = NULL;
1386 
1387 		if (end == parms)
1388 			errx (1, "%s needs numeric parameter", option);
1389 		break;
1390 
1391 	case String:
1392 		strValue = parms;
1393 		if (!strValue)
1394 			errx (1, "%s needs parameter", option);
1395 		break;
1396 
1397 	case None:
1398 		if (parms)
1399 			errx (1, "%s does not take parameters", option);
1400 		break;
1401 
1402 	case Address:
1403 		if (!parms)
1404 			errx (1, "%s needs address/host parameter", option);
1405 
1406 		StrToAddr (parms, &addrValue);
1407 		break;
1408 	}
1409 
1410 	switch (info->type) {
1411 	case LibAliasOption:
1412 
1413 		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1414 		LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
1415 		break;
1416 
1417 	case Verbose:
1418 		verbose = yesNoValue;
1419 		break;
1420 
1421 	case DynamicMode:
1422 		dynamicMode = yesNoValue;
1423 		break;
1424 
1425 	case InPort:
1426 		mip->inPort = uNumValue;
1427 		break;
1428 
1429 	case OutPort:
1430 		mip->outPort = uNumValue;
1431 		break;
1432 
1433 	case Port:
1434 		mip->inOutPort = uNumValue;
1435 		break;
1436 
1437 	case GlobalPort:
1438 		globalPort = uNumValue;
1439 		break;
1440 
1441 	case AliasAddress:
1442 		memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
1443 		break;
1444 
1445 	case TargetAddress:
1446 		LibAliasSetTarget(mla, addrValue);
1447 		break;
1448 
1449 	case RedirectPort:
1450 		SetupPortRedirect (strValue);
1451 		break;
1452 
1453 	case RedirectProto:
1454 		SetupProtoRedirect(strValue);
1455 		break;
1456 
1457 	case RedirectAddress:
1458 		SetupAddressRedirect (strValue);
1459 		break;
1460 
1461 	case ProxyRule:
1462 		LibAliasProxyRule (mla, strValue);
1463 		break;
1464 
1465 	case InterfaceName:
1466 		if (mip->ifName)
1467 			free (mip->ifName);
1468 
1469 		mip->ifName = strdup (strValue);
1470 		break;
1471 
1472 	case ConfigFile:
1473 		ReadConfigFile (strValue);
1474 		break;
1475 
1476 	case LogDenied:
1477 		mip->logDropped = yesNoValue;
1478 		break;
1479 
1480 	case LogFacility:
1481 
1482 		fac_record = facilitynames;
1483 		while (fac_record->c_name != NULL) {
1484 
1485 			if (!strcmp (fac_record->c_name, strValue)) {
1486 
1487 				logFacility = fac_record->c_val;
1488 				break;
1489 
1490 			}
1491 			else
1492 				fac_record++;
1493 		}
1494 
1495 		if(fac_record->c_name == NULL)
1496 			errx(1, "Unknown log facility name: %s", strValue);
1497 
1498 		break;
1499 
1500 	case PunchFW:
1501 		SetupPunchFW(strValue);
1502 		break;
1503 
1504 	case SkinnyPort:
1505 		SetupSkinnyPort(strValue);
1506 		break;
1507 
1508 	case LogIpfwDenied:
1509 		logIpfwDenied = yesNoValue;
1510 		break;
1511 
1512 	case PidFile:
1513 		pidName = strdup (strValue);
1514 		break;
1515 	case Instance:
1516 		NewInstance(strValue);
1517 		break;
1518 	case ExitDelay:
1519 		if (numValue < 0 || numValue > MAX_EXIT_DELAY)
1520 			errx(1, "Incorrect exit delay: %d", numValue);
1521 		exitDelay = numValue;
1522 		break;
1523 	}
1524 }
1525 
1526 void ReadConfigFile (const char* fileName)
1527 {
1528 	FILE*	file;
1529 	char	*buf;
1530 	size_t	len;
1531 	char	*ptr, *p;
1532 	char*	option;
1533 
1534 	file = fopen (fileName, "r");
1535 	if (!file)
1536 		err(1, "cannot open config file %s", fileName);
1537 
1538 	while ((buf = fgetln(file, &len)) != NULL) {
1539 		if (buf[len - 1] == '\n')
1540 			buf[len - 1] = '\0';
1541 		else
1542 			errx(1, "config file format error: "
1543 				"last line should end with newline");
1544 
1545 /*
1546  * Check for comments, strip off trailing spaces.
1547  */
1548 		if ((ptr = strchr(buf, '#')))
1549 			*ptr = '\0';
1550 		for (ptr = buf; isspace(*ptr); ++ptr)
1551 			continue;
1552 		if (*ptr == '\0')
1553 			continue;
1554 		for (p = strchr(buf, '\0'); isspace(*--p);)
1555 			continue;
1556 		*++p = '\0';
1557 
1558 /*
1559  * Extract option name.
1560  */
1561 		option = ptr;
1562 		while (*ptr && !isspace (*ptr))
1563 			++ptr;
1564 
1565 		if (*ptr != '\0') {
1566 
1567 			*ptr = '\0';
1568 			++ptr;
1569 		}
1570 /*
1571  * Skip white space between name and parms.
1572  */
1573 		while (*ptr && isspace (*ptr))
1574 			++ptr;
1575 
1576 		ParseOption (option, *ptr ? ptr : NULL);
1577 	}
1578 
1579 	fclose (file);
1580 }
1581 
1582 static void Usage(void)
1583 {
1584 	int			i;
1585 	int			max;
1586 	struct OptionInfo*	info;
1587 
1588 	fprintf (stderr, "Recognized options:\n\n");
1589 
1590 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
1591 	for (i = 0, info = optionTable; i < max; i++, info++) {
1592 
1593 		fprintf (stderr, "-%-20s %s\n", info->name,
1594 						info->parmDescription);
1595 
1596 		if (info->shortName)
1597 			fprintf (stderr, "-%-20s %s\n", info->shortName,
1598 							info->parmDescription);
1599 
1600 		fprintf (stderr, "      %s\n\n", info->description);
1601 	}
1602 
1603 	exit (1);
1604 }
1605 
1606 void SetupPortRedirect (const char* parms)
1607 {
1608 	char		*buf;
1609 	char*		ptr;
1610 	char*		serverPool;
1611 	struct in_addr	localAddr;
1612 	struct in_addr	publicAddr;
1613 	struct in_addr	remoteAddr;
1614 	port_range      portRange;
1615 	u_short         localPort      = 0;
1616 	u_short         publicPort     = 0;
1617 	u_short         remotePort     = 0;
1618 	u_short         numLocalPorts  = 0;
1619 	u_short         numPublicPorts = 0;
1620 	u_short         numRemotePorts = 0;
1621 	int		proto;
1622 	char*		protoName;
1623 	char*		separator;
1624 	int             i;
1625 	struct alias_link *aliaslink = NULL;
1626 
1627 	buf = strdup (parms);
1628 	if (!buf)
1629 		errx (1, "redirect_port: strdup() failed");
1630 /*
1631  * Extract protocol.
1632  */
1633 	protoName = strtok (buf, " \t");
1634 	if (!protoName)
1635 		errx (1, "redirect_port: missing protocol");
1636 
1637 	proto = StrToProto (protoName);
1638 /*
1639  * Extract local address.
1640  */
1641 	ptr = strtok (NULL, " \t");
1642 	if (!ptr)
1643 		errx (1, "redirect_port: missing local address");
1644 
1645 	separator = strchr(ptr, ',');
1646 	if (separator) {		/* LSNAT redirection syntax. */
1647 		localAddr.s_addr = INADDR_NONE;
1648 		localPort = ~0;
1649 		numLocalPorts = 1;
1650 		serverPool = ptr;
1651 	} else {
1652 		if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1653 			errx (1, "redirect_port: invalid local port range");
1654 
1655 		localPort     = GETLOPORT(portRange);
1656 		numLocalPorts = GETNUMPORTS(portRange);
1657 		serverPool = NULL;
1658 	}
1659 
1660 /*
1661  * Extract public port and optionally address.
1662  */
1663 	ptr = strtok (NULL, " \t");
1664 	if (!ptr)
1665 		errx (1, "redirect_port: missing public port");
1666 
1667 	separator = strchr (ptr, ':');
1668 	if (separator) {
1669 	        if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1670 		        errx (1, "redirect_port: invalid public port range");
1671 	}
1672 	else {
1673 		publicAddr.s_addr = INADDR_ANY;
1674 		if (StrToPortRange (ptr, protoName, &portRange) != 0)
1675 		        errx (1, "redirect_port: invalid public port range");
1676 	}
1677 
1678 	publicPort     = GETLOPORT(portRange);
1679 	numPublicPorts = GETNUMPORTS(portRange);
1680 
1681 /*
1682  * Extract remote address and optionally port.
1683  */
1684 	ptr = strtok (NULL, " \t");
1685 	if (ptr) {
1686 		separator = strchr (ptr, ':');
1687 		if (separator) {
1688 		        if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1689 			        errx (1, "redirect_port: invalid remote port range");
1690 		} else {
1691 		        SETLOPORT(portRange, 0);
1692 			SETNUMPORTS(portRange, 1);
1693 			StrToAddr (ptr, &remoteAddr);
1694 		}
1695 	}
1696 	else {
1697 	        SETLOPORT(portRange, 0);
1698 		SETNUMPORTS(portRange, 1);
1699 		remoteAddr.s_addr = INADDR_ANY;
1700 	}
1701 
1702 	remotePort     = GETLOPORT(portRange);
1703 	numRemotePorts = GETNUMPORTS(portRange);
1704 
1705 /*
1706  * Make sure port ranges match up, then add the redirect ports.
1707  */
1708 	if (numLocalPorts != numPublicPorts)
1709 	        errx (1, "redirect_port: port ranges must be equal in size");
1710 
1711 	/* Remote port range is allowed to be '0' which means all ports. */
1712 	if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1713 	        errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1714 
1715 	for (i = 0 ; i < numPublicPorts ; ++i) {
1716 	        /* If remotePort is all ports, set it to 0. */
1717 	        u_short remotePortCopy = remotePort + i;
1718 	        if (numRemotePorts == 1 && remotePort == 0)
1719 		        remotePortCopy = 0;
1720 
1721 		aliaslink = LibAliasRedirectPort (mla, localAddr,
1722 						htons(localPort + i),
1723 						remoteAddr,
1724 						htons(remotePortCopy),
1725 						publicAddr,
1726 						htons(publicPort + i),
1727 						proto);
1728 	}
1729 
1730 /*
1731  * Setup LSNAT server pool.
1732  */
1733 	if (serverPool != NULL && aliaslink != NULL) {
1734 		ptr = strtok(serverPool, ",");
1735 		while (ptr != NULL) {
1736 			if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1737 				errx(1, "redirect_port: invalid local port range");
1738 
1739 			localPort = GETLOPORT(portRange);
1740 			if (GETNUMPORTS(portRange) != 1)
1741 				errx(1, "redirect_port: local port must be single in this context");
1742 			LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
1743 			ptr = strtok(NULL, ",");
1744 		}
1745 	}
1746 
1747 	free (buf);
1748 }
1749 
1750 void
1751 SetupProtoRedirect(const char* parms)
1752 {
1753 	char		*buf;
1754 	char*		ptr;
1755 	struct in_addr	localAddr;
1756 	struct in_addr	publicAddr;
1757 	struct in_addr	remoteAddr;
1758 	int		proto;
1759 	char*		protoName;
1760 	struct protoent *protoent;
1761 
1762 	buf = strdup (parms);
1763 	if (!buf)
1764 		errx (1, "redirect_port: strdup() failed");
1765 /*
1766  * Extract protocol.
1767  */
1768 	protoName = strtok(buf, " \t");
1769 	if (!protoName)
1770 		errx(1, "redirect_proto: missing protocol");
1771 
1772 	protoent = getprotobyname(protoName);
1773 	if (protoent == NULL)
1774 		errx(1, "redirect_proto: unknown protocol %s", protoName);
1775 	else
1776 		proto = protoent->p_proto;
1777 /*
1778  * Extract local address.
1779  */
1780 	ptr = strtok(NULL, " \t");
1781 	if (!ptr)
1782 		errx(1, "redirect_proto: missing local address");
1783 	else
1784 		StrToAddr(ptr, &localAddr);
1785 /*
1786  * Extract optional public address.
1787  */
1788 	ptr = strtok(NULL, " \t");
1789 	if (ptr)
1790 		StrToAddr(ptr, &publicAddr);
1791 	else
1792 		publicAddr.s_addr = INADDR_ANY;
1793 /*
1794  * Extract optional remote address.
1795  */
1796 	ptr = strtok(NULL, " \t");
1797 	if (ptr)
1798 		StrToAddr(ptr, &remoteAddr);
1799 	else
1800 		remoteAddr.s_addr = INADDR_ANY;
1801 /*
1802  * Create aliasing link.
1803  */
1804 	(void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
1805 				       proto);
1806 
1807 	free (buf);
1808 }
1809 
1810 void SetupAddressRedirect (const char* parms)
1811 {
1812 	char		*buf;
1813 	char*		ptr;
1814 	char*		separator;
1815 	struct in_addr	localAddr;
1816 	struct in_addr	publicAddr;
1817 	char*		serverPool;
1818 	struct alias_link *aliaslink;
1819 
1820 	buf = strdup (parms);
1821 	if (!buf)
1822 		errx (1, "redirect_port: strdup() failed");
1823 /*
1824  * Extract local address.
1825  */
1826 	ptr = strtok (buf, " \t");
1827 	if (!ptr)
1828 		errx (1, "redirect_address: missing local address");
1829 
1830 	separator = strchr(ptr, ',');
1831 	if (separator) {		/* LSNAT redirection syntax. */
1832 		localAddr.s_addr = INADDR_NONE;
1833 		serverPool = ptr;
1834 	} else {
1835 		StrToAddr (ptr, &localAddr);
1836 		serverPool = NULL;
1837 	}
1838 /*
1839  * Extract public address.
1840  */
1841 	ptr = strtok (NULL, " \t");
1842 	if (!ptr)
1843 		errx (1, "redirect_address: missing public address");
1844 
1845 	StrToAddr (ptr, &publicAddr);
1846 	aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1847 
1848 /*
1849  * Setup LSNAT server pool.
1850  */
1851 	if (serverPool != NULL && aliaslink != NULL) {
1852 		ptr = strtok(serverPool, ",");
1853 		while (ptr != NULL) {
1854 			StrToAddr(ptr, &localAddr);
1855 			LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
1856 			ptr = strtok(NULL, ",");
1857 		}
1858 	}
1859 
1860 	free (buf);
1861 }
1862 
1863 void StrToAddr (const char* str, struct in_addr* addr)
1864 {
1865 	struct hostent* hp;
1866 
1867 	if (inet_aton (str, addr))
1868 		return;
1869 
1870 	hp = gethostbyname (str);
1871 	if (!hp)
1872 		errx (1, "unknown host %s", str);
1873 
1874 	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1875 }
1876 
1877 u_short StrToPort (const char* str, const char* proto)
1878 {
1879 	u_short		port;
1880 	struct servent*	sp;
1881 	char*		end;
1882 
1883 	port = strtol (str, &end, 10);
1884 	if (end != str)
1885 		return htons (port);
1886 
1887 	sp = getservbyname (str, proto);
1888 	if (!sp)
1889 		errx (1, "%s/%s: unknown service", str, proto);
1890 
1891 	return sp->s_port;
1892 }
1893 
1894 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1895 {
1896 	const char*	sep;
1897 	struct servent*	sp;
1898 	char*		end;
1899 	u_short         loPort;
1900 	u_short         hiPort;
1901 
1902 	/* First see if this is a service, return corresponding port if so. */
1903 	sp = getservbyname (str,proto);
1904 	if (sp) {
1905 	        SETLOPORT(*portRange, ntohs(sp->s_port));
1906 		SETNUMPORTS(*portRange, 1);
1907 		return 0;
1908 	}
1909 
1910 	/* Not a service, see if it's a single port or port range. */
1911 	sep = strchr (str, '-');
1912 	if (sep == NULL) {
1913 	        SETLOPORT(*portRange, strtol(str, &end, 10));
1914 		if (end != str) {
1915 		        /* Single port. */
1916 		        SETNUMPORTS(*portRange, 1);
1917 			return 0;
1918 		}
1919 
1920 		/* Error in port range field. */
1921 		errx (1, "%s/%s: unknown service", str, proto);
1922 	}
1923 
1924 	/* Port range, get the values and sanity check. */
1925 	sscanf (str, "%hu-%hu", &loPort, &hiPort);
1926 	SETLOPORT(*portRange, loPort);
1927 	SETNUMPORTS(*portRange, 0);	/* Error by default */
1928 	if (loPort <= hiPort)
1929 	        SETNUMPORTS(*portRange, hiPort - loPort + 1);
1930 
1931 	if (GETNUMPORTS(*portRange) == 0)
1932 	        errx (1, "invalid port range %s", str);
1933 
1934 	return 0;
1935 }
1936 
1937 
1938 static int
1939 StrToProto (const char* str)
1940 {
1941 	if (!strcmp (str, "tcp"))
1942 		return IPPROTO_TCP;
1943 
1944 	if (!strcmp (str, "udp"))
1945 		return IPPROTO_UDP;
1946 
1947 	errx (1, "unknown protocol %s. Expected tcp or udp", str);
1948 }
1949 
1950 static int
1951 StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange)
1952 {
1953 	char*	ptr;
1954 
1955 	ptr = strchr (str, ':');
1956 	if (!ptr)
1957 		errx (1, "%s is missing port number", str);
1958 
1959 	*ptr = '\0';
1960 	++ptr;
1961 
1962 	StrToAddr (str, addr);
1963 	return StrToPortRange (ptr, proto, portRange);
1964 }
1965 
1966 static void
1967 SetupPunchFW(const char *strValue)
1968 {
1969 	unsigned int base, num;
1970 
1971 	if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1972 		errx(1, "punch_fw: basenumber:count parameter required");
1973 
1974 	if (CheckIpfwRulenum(base + num - 1) == -1)
1975 		errx(1, "punch_fw: basenumber:count parameter should fit "
1976 			"the maximum allowed rule numbers");
1977 
1978 	LibAliasSetFWBase(mla, base, num);
1979 	(void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1980 }
1981 
1982 static void
1983 SetupSkinnyPort(const char *strValue)
1984 {
1985 	unsigned int port;
1986 
1987 	if (sscanf(strValue, "%u", &port) != 1)
1988 		errx(1, "skinny_port: port parameter required");
1989 
1990 	LibAliasSetSkinnyPort(mla, port);
1991 }
1992 
1993 static void
1994 NewInstance(const char *name)
1995 {
1996 	struct instance *ip;
1997 
1998 	LIST_FOREACH(ip, &root, list) {
1999 		if (!strcmp(ip->name, name)) {
2000 			mla = ip->la;
2001 			mip = ip;
2002 			return;
2003 		}
2004 	}
2005 	ninstance++;
2006 	ip = calloc(1, sizeof(*ip));
2007 	ip->name = strdup(name);
2008 	ip->la = LibAliasInit (ip->la);
2009 	ip->assignAliasAddr	= 0;
2010 	ip->ifName		= NULL;
2011  	ip->logDropped		= 0;
2012 	ip->inPort		= 0;
2013 	ip->outPort		= 0;
2014 	ip->inOutPort		= 0;
2015 	ip->aliasAddr.s_addr	= INADDR_NONE;
2016 	ip->ifMTU		= -1;
2017 	ip->aliasOverhead	= 12;
2018 	LIST_INSERT_HEAD(&root, ip, list);
2019 	mla = ip->la;
2020 	mip = ip;
2021 }
2022 
2023 static int
2024 CheckIpfwRulenum(unsigned int rnum)
2025 {
2026 	unsigned int default_rule;
2027 	size_t len = sizeof(default_rule);
2028 
2029 	if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len,
2030 		NULL, 0) == -1) {
2031 		warn("Failed to get the default ipfw rule number, using "
2032 		     "default historical value 65535.  The reason was");
2033 		default_rule = 65535;
2034 	}
2035 	if (rnum >= default_rule) {
2036 		return -1;
2037 	}
2038 
2039 	return 0;
2040 }
2041