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