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