xref: /freebsd/sbin/natd/natd.c (revision 74bf4e164ba5851606a27d4feff27717452583e5)
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	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 	int			status;
503 	int			addrSize;
504 	struct ip*		ip;
505 	char			msgBuf[80];
506 
507 /*
508  * Get packet from socket.
509  */
510 	addrSize  = sizeof addr;
511 	origBytes = recvfrom (fd,
512 			      buf,
513 			      sizeof buf,
514 			      0,
515 			      (struct sockaddr*) &addr,
516 			      &addrSize);
517 
518 	if (origBytes == -1) {
519 
520 		if (errno != EINTR)
521 			Warn ("read from divert socket failed");
522 
523 		return;
524 	}
525 
526 #if 0
527 	if (mip->assignAliasAddr) {
528 		SetAliasAddressFromIfName (mip->ifName);
529 		mip->assignAliasAddr = 0;
530 	}
531 #endif
532 /*
533  * This is an IP packet.
534  */
535 	ip = (struct ip*) buf;
536 
537 	if (verbose) {
538 /*
539  * Print packet direction and protocol type.
540  */
541 		printf ("Glb ");
542 
543 		switch (ip->ip_p) {
544 		case IPPROTO_TCP:
545 			printf ("[TCP]  ");
546 			break;
547 
548 		case IPPROTO_UDP:
549 			printf ("[UDP]  ");
550 			break;
551 
552 		case IPPROTO_ICMP:
553 			printf ("[ICMP] ");
554 			break;
555 
556 		default:
557 			printf ("[%d]    ", ip->ip_p);
558 			break;
559 		}
560 /*
561  * Print addresses.
562  */
563 		PrintPacket (ip);
564 	}
565 
566 	LIST_FOREACH(mip, &root, list) {
567 		mla = mip->la;
568 		if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED)
569 			break;
570 	}
571 /*
572  * Length might have changed during aliasing.
573  */
574 	bytes = ntohs (ip->ip_len);
575 /*
576  * Update alias overhead size for outgoing packets.
577  */
578 	if (mip != NULL && bytes - origBytes > mip->aliasOverhead)
579 		mip->aliasOverhead = bytes - origBytes;
580 
581 	if (verbose) {
582 
583 /*
584  * Print addresses after aliasing.
585  */
586 		printf (" aliased to\n");
587 		printf ("           ");
588 		PrintPacket (ip);
589 		printf ("\n");
590 	}
591 
592 /*
593  * Put packet back for processing.
594  */
595 	wrote = sendto (fd,
596 		        buf,
597 	    		bytes,
598 	    		0,
599 	    		(struct sockaddr*) &addr,
600 	    		sizeof addr);
601 
602 	if (wrote != bytes) {
603 
604 		if (errno == EMSGSIZE) {
605 
606 			if (mip->ifMTU != -1)
607 				SendNeedFragIcmp (icmpSock,
608 						  (struct ip*) buf,
609 						  mip->ifMTU - mip->aliasOverhead);
610 		}
611 		else if (errno == EACCES && logIpfwDenied) {
612 
613 			sprintf (msgBuf, "failed to write packet back");
614 			Warn (msgBuf);
615 		}
616 	}
617 }
618 
619 
620 static void DoAliasing (int fd, int direction)
621 {
622 	int			bytes;
623 	int			origBytes;
624 	char			buf[IP_MAXPACKET];
625 	struct sockaddr_in	addr;
626 	int			wrote;
627 	int			status;
628 	int			addrSize;
629 	struct ip*		ip;
630 	char			msgBuf[80];
631 
632 	if (mip->assignAliasAddr) {
633 
634 		SetAliasAddressFromIfName (mip->ifName);
635 		mip->assignAliasAddr = 0;
636 	}
637 /*
638  * Get packet from socket.
639  */
640 	addrSize  = sizeof addr;
641 	origBytes = recvfrom (fd,
642 			      buf,
643 			      sizeof buf,
644 			      0,
645 			      (struct sockaddr*) &addr,
646 			      &addrSize);
647 
648 	if (origBytes == -1) {
649 
650 		if (errno != EINTR)
651 			Warn ("read from divert socket failed");
652 
653 		return;
654 	}
655 /*
656  * This is an IP packet.
657  */
658 	ip = (struct ip*) buf;
659 	if (direction == DONT_KNOW) {
660 		if (addr.sin_addr.s_addr == INADDR_ANY)
661 			direction = OUTPUT;
662 		else
663 			direction = INPUT;
664 	}
665 
666 	if (verbose) {
667 /*
668  * Print packet direction and protocol type.
669  */
670 		printf (direction == OUTPUT ? "Out " : "In  ");
671 		if (ninstance > 1)
672 			printf ("{%s} %08x", mip->name);
673 
674 		switch (ip->ip_p) {
675 		case IPPROTO_TCP:
676 			printf ("[TCP]  ");
677 			break;
678 
679 		case IPPROTO_UDP:
680 			printf ("[UDP]  ");
681 			break;
682 
683 		case IPPROTO_ICMP:
684 			printf ("[ICMP] ");
685 			break;
686 
687 		default:
688 			printf ("[%d]    ", ip->ip_p);
689 			break;
690 		}
691 /*
692  * Print addresses.
693  */
694 		PrintPacket (ip);
695 	}
696 
697 	if (direction == OUTPUT) {
698 /*
699  * Outgoing packets. Do aliasing.
700  */
701 		LibAliasOut (mla, buf, IP_MAXPACKET);
702 	}
703 	else {
704 
705 /*
706  * Do aliasing.
707  */
708 		status = LibAliasIn (mla, buf, IP_MAXPACKET);
709 		if (status == PKT_ALIAS_IGNORED &&
710 		    mip->dropIgnoredIncoming) {
711 
712 			if (verbose)
713 				printf (" dropped.\n");
714 
715 			if (mip->logDropped)
716 				SyslogPacket (ip, LOG_WARNING, "denied");
717 
718 			return;
719 		}
720 	}
721 /*
722  * Length might have changed during aliasing.
723  */
724 	bytes = ntohs (ip->ip_len);
725 /*
726  * Update alias overhead size for outgoing packets.
727  */
728 	if (direction == OUTPUT &&
729 	    bytes - origBytes > mip->aliasOverhead)
730 		mip->aliasOverhead = bytes - origBytes;
731 
732 	if (verbose) {
733 
734 /*
735  * Print addresses after aliasing.
736  */
737 		printf (" aliased to\n");
738 		printf ("           ");
739 		PrintPacket (ip);
740 		printf ("\n");
741 	}
742 
743 /*
744  * Put packet back for processing.
745  */
746 	wrote = sendto (fd,
747 		        buf,
748 	    		bytes,
749 	    		0,
750 	    		(struct sockaddr*) &addr,
751 	    		sizeof addr);
752 
753 	if (wrote != bytes) {
754 
755 		if (errno == EMSGSIZE) {
756 
757 			if (direction == OUTPUT &&
758 			    mip->ifMTU != -1)
759 				SendNeedFragIcmp (icmpSock,
760 						  (struct ip*) buf,
761 						  mip->ifMTU - mip->aliasOverhead);
762 		}
763 		else if (errno == EACCES && logIpfwDenied) {
764 
765 			sprintf (msgBuf, "failed to write packet back");
766 			Warn (msgBuf);
767 		}
768 	}
769 }
770 
771 static void HandleRoutingInfo (int fd)
772 {
773 	int			bytes;
774 	struct if_msghdr	ifMsg;
775 /*
776  * Get packet from socket.
777  */
778 	bytes = read (fd, &ifMsg, sizeof ifMsg);
779 	if (bytes == -1) {
780 
781 		Warn ("read from routing socket failed");
782 		return;
783 	}
784 
785 	if (ifMsg.ifm_version != RTM_VERSION) {
786 
787 		Warn ("unexpected packet read from routing socket");
788 		return;
789 	}
790 
791 	if (verbose)
792 		printf ("Routing message %#x received.\n", ifMsg.ifm_type);
793 
794 	if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) {
795 		LIST_FOREACH(mip, &root, list) {
796 			mla = mip->la;
797 			if (ifMsg.ifm_index == mip->ifIndex) {
798 				if (verbose)
799 					printf("Interface address/MTU has probably changed.\n");
800 				mip->assignAliasAddr = 1;
801 			}
802 		}
803 	}
804 }
805 
806 static void PrintPacket (struct ip* ip)
807 {
808 	printf ("%s", FormatPacket (ip));
809 }
810 
811 static void SyslogPacket (struct ip* ip, int priority, const char *label)
812 {
813 	syslog (priority, "%s %s", label, FormatPacket (ip));
814 }
815 
816 static char* FormatPacket (struct ip* ip)
817 {
818 	static char	buf[256];
819 	struct tcphdr*	tcphdr;
820 	struct udphdr*	udphdr;
821 	struct icmp*	icmphdr;
822 	char		src[20];
823 	char		dst[20];
824 
825 	strcpy (src, inet_ntoa (ip->ip_src));
826 	strcpy (dst, inet_ntoa (ip->ip_dst));
827 
828 	switch (ip->ip_p) {
829 	case IPPROTO_TCP:
830 		tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
831 		sprintf (buf, "[TCP] %s:%d -> %s:%d",
832 			      src,
833 			      ntohs (tcphdr->th_sport),
834 			      dst,
835 			      ntohs (tcphdr->th_dport));
836 		break;
837 
838 	case IPPROTO_UDP:
839 		udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
840 		sprintf (buf, "[UDP] %s:%d -> %s:%d",
841 			      src,
842 			      ntohs (udphdr->uh_sport),
843 			      dst,
844 			      ntohs (udphdr->uh_dport));
845 		break;
846 
847 	case IPPROTO_ICMP:
848 		icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
849 		sprintf (buf, "[ICMP] %s -> %s %u(%u)",
850 			      src,
851 			      dst,
852 			      icmphdr->icmp_type,
853 			      icmphdr->icmp_code);
854 		break;
855 
856 	default:
857 		sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
858 		break;
859 	}
860 
861 	return buf;
862 }
863 
864 static void
865 SetAliasAddressFromIfName(const char *ifn)
866 {
867 	size_t needed;
868 	int mib[6];
869 	char *buf, *lim, *next;
870 	struct if_msghdr *ifm;
871 	struct ifa_msghdr *ifam;
872 	struct sockaddr_dl *sdl;
873 	struct sockaddr_in *sin;
874 
875 	mib[0] = CTL_NET;
876 	mib[1] = PF_ROUTE;
877 	mib[2] = 0;
878 	mib[3] = AF_INET;	/* Only IP addresses please */
879 	mib[4] = NET_RT_IFLIST;
880 	mib[5] = 0;		/* ifIndex??? */
881 /*
882  * Get interface data.
883  */
884 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
885 		err(1, "iflist-sysctl-estimate");
886 	if ((buf = malloc(needed)) == NULL)
887 		errx(1, "malloc failed");
888 	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
889 		err(1, "iflist-sysctl-get");
890 	lim = buf + needed;
891 /*
892  * Loop through interfaces until one with
893  * given name is found. This is done to
894  * find correct interface index for routing
895  * message processing.
896  */
897 	mip->ifIndex	= 0;
898 	next = buf;
899 	while (next < lim) {
900 		ifm = (struct if_msghdr *)next;
901 		next += ifm->ifm_msglen;
902 		if (ifm->ifm_version != RTM_VERSION) {
903 			if (verbose)
904 				warnx("routing message version %d "
905 				      "not understood", ifm->ifm_version);
906 			continue;
907 		}
908 		if (ifm->ifm_type == RTM_IFINFO) {
909 			sdl = (struct sockaddr_dl *)(ifm + 1);
910 			if (strlen(ifn) == sdl->sdl_nlen &&
911 			    strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
912 				mip->ifIndex = ifm->ifm_index;
913 				mip->ifMTU = ifm->ifm_data.ifi_mtu;
914 				break;
915 			}
916 		}
917 	}
918 	if (!mip->ifIndex)
919 		errx(1, "unknown interface name %s", ifn);
920 /*
921  * Get interface address.
922  */
923 	sin = NULL;
924 	while (next < lim) {
925 		ifam = (struct ifa_msghdr *)next;
926 		next += ifam->ifam_msglen;
927 		if (ifam->ifam_version != RTM_VERSION) {
928 			if (verbose)
929 				warnx("routing message version %d "
930 				      "not understood", ifam->ifam_version);
931 			continue;
932 		}
933 		if (ifam->ifam_type != RTM_NEWADDR)
934 			break;
935 		if (ifam->ifam_addrs & RTA_IFA) {
936 			int i;
937 			char *cp = (char *)(ifam + 1);
938 
939 			for (i = 1; i < RTA_IFA; i <<= 1)
940 				if (ifam->ifam_addrs & i)
941 					cp += SA_SIZE((struct sockaddr *)cp);
942 			if (((struct sockaddr *)cp)->sa_family == AF_INET) {
943 				sin = (struct sockaddr_in *)cp;
944 				break;
945 			}
946 		}
947 	}
948 	if (sin == NULL)
949 		errx(1, "%s: cannot get interface address", ifn);
950 
951 	LibAliasSetAddress(mla, sin->sin_addr);
952 	syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
953 	       inet_ntoa(sin->sin_addr), mip->ifMTU);
954 
955 	free(buf);
956 }
957 
958 void Quit (const char* msg)
959 {
960 	Warn (msg);
961 	exit (1);
962 }
963 
964 void Warn (const char* msg)
965 {
966 	if (background)
967 		syslog (LOG_ALERT, "%s (%m)", msg);
968 	else
969 		warn ("%s", msg);
970 }
971 
972 static void RefreshAddr (int sig)
973 {
974 	if (mip->ifName)
975 		mip->assignAliasAddr = 1;
976 }
977 
978 static void InitiateShutdown (int sig)
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)
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 *link = 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 		link = 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 && link != 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, link, 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 *link;
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 	link = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1796 
1797 /*
1798  * Setup LSNAT server pool.
1799  */
1800 	if (serverPool != NULL && link != NULL) {
1801 		ptr = strtok(serverPool, ",");
1802 		while (ptr != NULL) {
1803 			StrToAddr(ptr, &localAddr);
1804 			LibAliasAddServer(mla, link, 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