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