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