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