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