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