xref: /dragonfly/sbin/natd/natd.c (revision d4ef6694)
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  */
14 
15 #define SYSLOG_NAMES
16 
17 #include <sys/param.h>
18 #include <sys/socket.h>
19 #include <sys/sysctl.h>
20 #include <sys/time.h>
21 
22 #include <netinet/in.h>
23 #include <netinet/in_systm.h>
24 #include <netinet/ip.h>
25 #include <netinet/tcp.h>
26 #include <netinet/udp.h>
27 #include <netinet/ip_icmp.h>
28 #include <net/if.h>
29 #include <net/if_dl.h>
30 #include <net/route.h>
31 #include <arpa/inet.h>
32 
33 #include <alias.h>
34 #include <ctype.h>
35 #include <err.h>
36 #include <errno.h>
37 #include <netdb.h>
38 #include <signal.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <syslog.h>
43 #include <unistd.h>
44 
45 #include "natd.h"
46 
47 /*
48  * Default values for input and output
49  * divert socket ports.
50  */
51 
52 #define	DEFAULT_SERVICE	"natd"
53 
54 /*
55  * Definition of a port range, and macros to deal with values.
56  * FORMAT:  HI 16-bits == first port in range, 0 == all ports.
57  *	    LO 16-bits == number of ports in range
58  * NOTES:   - Port values are not stored in network byte order.
59  */
60 
61 typedef u_long port_range;
62 
63 #define GETLOPORT(x)	 ((x) >> 0x10)
64 #define GETNUMPORTS(x)	 ((x) & 0x0000ffff)
65 #define GETHIPORT(x)	 (GETLOPORT((x)) + GETNUMPORTS((x)))
66 
67 /* Set y to be the low-port value in port_range variable x. */
68 #define SETLOPORT(x,y)	 ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
69 
70 /* Set y to be the number of ports in port_range variable x. */
71 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
72 
73 /*
74  * Function prototypes.
75  */
76 
77 static void	DoAliasing(int, int);
78 static void	DaemonMode(void);
79 static void	HandleRoutingInfo(int);
80 static void	Usage(void);
81 static char*	FormatPacket(struct ip *);
82 static void	PrintPacket(struct ip *);
83 static void	SyslogPacket(struct ip *, int, const char *);
84 static void	SetAliasAddressFromIfName(const char *);
85 static void	InitiateShutdown(int);
86 static void	Shutdown(int);
87 static void	RefreshAddr(int);
88 static void	ParseOption(const char *, const char *);
89 static void	ReadConfigFile(const char *);
90 static void	SetupPortRedirect(const char *);
91 static void	SetupProtoRedirect(const char *);
92 static void	SetupAddressRedirect(const char *);
93 static void	StrToAddr(const char *, struct in_addr *);
94 static u_short	StrToPort(const char *, const char *);
95 static int	StrToPortRange(const char *, const char *, port_range *);
96 static int	StrToProto(const char *);
97 static int	StrToAddrAndPortRange(const char *, struct in_addr *, char *, port_range *);
98 static void	ParseArgs(int, char **);
99 static void	SetupPunchFW(const char *);
100 
101 /*
102  * Globals.
103  */
104 
105 static	int			verbose;
106 static	int			background;
107 static	volatile sig_atomic_t	running;
108 static	volatile sig_atomic_t	assignAliasAddr;
109 static	char*			ifName;
110 static	int			ifIndex;
111 static	u_short			inPort;
112 static	u_short			outPort;
113 static	u_short			inOutPort;
114 static	struct in_addr		aliasAddr;
115 static	int			dynamicMode;
116 static	int			ifMTU;
117 static	int			aliasOverhead;
118 static	int			icmpSock;
119 static	int			dropIgnoredIncoming;
120 static	int			logDropped;
121 static	int			logFacility;
122 static	int			logIpfwDenied;
123 static	int			exitDelay;
124 
125 int
126 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 	struct sigaction	sa;
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 	exitDelay		= EXIT_DELAY;
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  * Check that valid aliasing address has been given.
175  */
176 	if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL)
177 		errx(1, "aliasing address not given");
178 
179 	if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL)
180 		errx(1, "both alias address and interface "
181 			"name are not allowed");
182 /*
183  * Check that valid port number is known.
184  */
185 	if (inPort != 0 || outPort != 0)
186 		if (inPort == 0 || outPort == 0)
187 			errx(1, "both input and output ports are required");
188 
189 	if (inPort == 0 && outPort == 0 && inOutPort == 0)
190 		ParseOption("port", DEFAULT_SERVICE);
191 
192 /*
193  * Check if ignored packets should be dropped.
194  */
195 	dropIgnoredIncoming = PacketAliasSetMode(0, 0);
196 	dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
197 /*
198  * Create divert sockets. Use only one socket if -p was specified
199  * on command line. Otherwise, create separate sockets for
200  * outgoing and incoming connnections.
201  */
202 	if (inOutPort) {
203 		divertInOut = socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT);
204 		if (divertInOut == -1)
205 			Quit("Unable to create divert socket.");
206 
207 		divertIn  = -1;
208 		divertOut = -1;
209 /*
210  * Bind socket.
211  */
212 
213 		addr.sin_family		= AF_INET;
214 		addr.sin_addr.s_addr	= INADDR_ANY;
215 		addr.sin_port		= inOutPort;
216 
217 		if (bind(divertInOut,
218 			 (struct sockaddr *)&addr,
219 			 sizeof addr) == -1)
220 			Quit("Unable to bind divert socket.");
221 	} else {
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 			routeSock = socket(PF_ROUTE, SOCK_RAW, 0);
261 			if (routeSock == -1)
262 				Quit("Unable to create routing info socket.");
263 
264 			assignAliasAddr = 1;
265 		} else
266 			SetAliasAddressFromIfName(ifName);
267 	}
268 /*
269  * Create socket for sending ICMP messages.
270  */
271 	icmpSock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
272 	if (icmpSock == -1)
273 		Quit("Unable to create ICMP socket.");
274 
275 /*
276  * And disable reads for the socket, otherwise it slowly fills
277  * up with received icmps which we do not use.
278  */
279 	shutdown(icmpSock, SHUT_RD);
280 
281 /*
282  * Become a daemon unless verbose mode was requested.
283  */
284 	if (!verbose)
285 		DaemonMode();
286 /*
287  * Catch signals to manage shutdown and
288  * refresh of interface address.
289  */
290 	sa.sa_flags = 0;
291 	sigemptyset(&sa.sa_mask);
292 	if (exitDelay)
293 		sa.sa_handler = InitiateShutdown;
294 	else
295 		sa.sa_handler = Shutdown;
296 	sigaction(SIGTERM, &sa, NULL);
297 	sa.sa_handler = RefreshAddr;
298 	sigaction(SIGHUP, &sa, NULL);
299 /*
300  * Set alias address if it has been given.
301  */
302 	if (aliasAddr.s_addr != INADDR_NONE)
303 		PacketAliasSetAddress(aliasAddr);
304 /*
305  * We need largest descriptor number for select.
306  */
307 
308 	fdMax = -1;
309 
310 	if (divertIn > fdMax)
311 		fdMax = divertIn;
312 
313 	if (divertOut > fdMax)
314 		fdMax = divertOut;
315 
316 	if (divertInOut > fdMax)
317 		fdMax = divertInOut;
318 
319 	if (routeSock > fdMax)
320 		fdMax = routeSock;
321 
322 	while (running) {
323 		if (divertInOut != -1 && !ifName) {
324 /*
325  * When using only one socket, just call
326  * DoAliasing repeatedly to process packets.
327  */
328 			DoAliasing(divertInOut, DONT_KNOW);
329 			continue;
330 		}
331 /*
332  * Build read mask from socket descriptors to select.
333  */
334 		FD_ZERO(&readMask);
335 /*
336  * Check if new packets are available.
337  */
338 		if (divertIn != -1)
339 			FD_SET(divertIn, &readMask);
340 
341 		if (divertOut != -1)
342 			FD_SET(divertOut, &readMask);
343 
344 		if (divertInOut != -1)
345 			FD_SET(divertInOut, &readMask);
346 /*
347  * Routing info is processed always.
348  */
349 		if (routeSock != -1)
350 			FD_SET(routeSock, &readMask);
351 
352 		if (select(fdMax + 1,
353 			   &readMask,
354 			   NULL,
355 			   NULL,
356 			   NULL) == -1) {
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
387 DaemonMode(void)
388 {
389 	FILE*	pidFile;
390 
391 	daemon(0, 0);
392 	background = 1;
393 
394 	pidFile = fopen(PIDFILE, "w");
395 	if (pidFile) {
396 		fprintf(pidFile, "%d\n", getpid());
397 		fclose(pidFile);
398 	}
399 }
400 
401 static void
402 ParseArgs(int argc, char **argv)
403 {
404 	int		arg;
405 	char*		opt;
406 	char		parmBuf[256];
407 	int		len; /* bounds checking */
408 
409 	for (arg = 1; arg < argc; arg++) {
410 		opt  = argv[arg];
411 		if (*opt != '-') {
412 			warnx("invalid option %s", opt);
413 			Usage();
414 		}
415 
416 		parmBuf[0] = '\0';
417 		len = 0;
418 
419 		while (arg < argc - 1) {
420 			if (argv[arg + 1][0] == '-')
421 				break;
422 
423 			if (len) {
424 				strncat(parmBuf, " ", sizeof(parmBuf) - (len + 1));
425 				len += strlen(parmBuf + len);
426 			}
427 
428 			++arg;
429 			strncat(parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
430 			len += strlen(parmBuf + len);
431 
432 		}
433 
434 		ParseOption(opt + 1, (len ? parmBuf : NULL));
435 
436 	}
437 }
438 
439 static void
440 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 		SetAliasAddressFromIfName(ifName);
454 		assignAliasAddr = 0;
455 	}
456 /*
457  * Get packet from socket.
458  */
459 	addrSize  = sizeof addr;
460 	origBytes = recvfrom(fd,
461 			     buf,
462 			     sizeof buf,
463 			     0,
464 			     (struct sockaddr *)&addr,
465 			     &addrSize);
466 
467 	if (origBytes == -1) {
468 		if (errno != EINTR)
469 			Warn("read from divert socket failed");
470 
471 		return;
472 	}
473 /*
474  * This is a IP packet.
475  */
476 	ip = (struct ip *)buf;
477 	if (direction == DONT_KNOW) {
478 		if (addr.sin_addr.s_addr == INADDR_ANY)
479 			direction = OUTPUT;
480 		else
481 			direction = INPUT;
482 	}
483 
484 	if (verbose) {
485 /*
486  * Print packet direction and protocol type.
487  */
488 		printf(direction == OUTPUT ? "Out " : "In  ");
489 
490 		switch (ip->ip_p) {
491 		case IPPROTO_TCP:
492 			printf("[TCP]  ");
493 			break;
494 
495 		case IPPROTO_UDP:
496 			printf("[UDP]  ");
497 			break;
498 
499 		case IPPROTO_ICMP:
500 			printf("[ICMP] ");
501 			break;
502 
503 		default:
504 			printf("[%d]	", ip->ip_p);
505 			break;
506 		}
507 /*
508  * Print addresses.
509  */
510 		PrintPacket(ip);
511 	}
512 
513 	if (direction == OUTPUT) {
514 /*
515  * Outgoing packets. Do aliasing.
516  */
517 		PacketAliasOut(buf, IP_MAXPACKET);
518 	} else {
519 /*
520  * Do aliasing.
521  */
522 		status = PacketAliasIn(buf, IP_MAXPACKET);
523 		if (status == PKT_ALIAS_IGNORED &&
524 		    dropIgnoredIncoming) {
525 			if (verbose)
526 				printf(" dropped.\n");
527 
528 			if (logDropped)
529 				SyslogPacket(ip, LOG_WARNING, "denied");
530 
531 			return;
532 		}
533 	}
534 /*
535  * Length might have changed during aliasing.
536  */
537 	bytes = ntohs(ip->ip_len);
538 /*
539  * Update alias overhead size for outgoing packets.
540  */
541 	if (direction == OUTPUT &&
542 	    bytes - origBytes > aliasOverhead)
543 		aliasOverhead = bytes - origBytes;
544 
545 	if (verbose) {
546 /*
547  * Print addresses after aliasing.
548  */
549 		printf(" aliased to\n");
550 		printf("	   ");
551 		PrintPacket(ip);
552 		printf("\n");
553 	}
554 
555 /*
556  * Put packet back for processing.
557  */
558 	wrote = sendto(fd,
559 		       buf,
560 		       bytes,
561 		       0,
562 		       (struct sockaddr *)&addr,
563 		       sizeof addr);
564 
565 	if (wrote != bytes) {
566 		if (errno == EMSGSIZE) {
567 			if (direction == OUTPUT &&
568 			    ifMTU != -1)
569 				SendNeedFragIcmp(icmpSock,
570 						 (struct ip *)buf,
571 						 ifMTU - aliasOverhead);
572 		} else if (errno == EACCES && logIpfwDenied) {
573 			sprintf(msgBuf, "failed to write packet back");
574 			Warn(msgBuf);
575 		}
576 	}
577 }
578 
579 static void
580 HandleRoutingInfo(int fd)
581 {
582 	int			bytes;
583 	struct if_msghdr	ifMsg;
584 /*
585  * Get packet from socket.
586  */
587 	bytes = read(fd, &ifMsg, sizeof ifMsg);
588 	if (bytes == -1) {
589 		Warn("read from routing socket failed");
590 		return;
591 	}
592 
593 	if (ifMsg.ifm_version != RTM_VERSION) {
594 		Warn("unexpected packet read from routing socket");
595 		return;
596 	}
597 
598 	if (verbose)
599 		printf("Routing message %#x received.\n", ifMsg.ifm_type);
600 
601 	if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO) &&
602 	    ifMsg.ifm_index == ifIndex) {
603 		if (verbose)
604 			printf("Interface address/MTU has probably changed.\n");
605 		assignAliasAddr = 1;
606 	}
607 }
608 
609 static void
610 PrintPacket(struct ip *ip)
611 {
612 	printf("%s", FormatPacket(ip));
613 }
614 
615 static void
616 SyslogPacket(struct ip *ip, int priority, const char *label)
617 {
618 	syslog(priority, "%s %s", label, FormatPacket(ip));
619 }
620 
621 static char*
622 FormatPacket(struct ip *ip)
623 {
624 	static char	buf[256];
625 	struct tcphdr*	tcphdr;
626 	struct udphdr*	udphdr;
627 	struct icmp*	icmphdr;
628 	char		src[20];
629 	char		dst[20];
630 
631 	strcpy(src, inet_ntoa(ip->ip_src));
632 	strcpy(dst, inet_ntoa(ip->ip_dst));
633 
634 	switch (ip->ip_p) {
635 	case IPPROTO_TCP:
636 		tcphdr = (struct tcphdr *)((char *)ip + (ip->ip_hl << 2));
637 		sprintf(buf, "[TCP] %s:%d -> %s:%d",
638 			     src,
639 			     ntohs(tcphdr->th_sport),
640 			     dst,
641 			     ntohs(tcphdr->th_dport));
642 		break;
643 
644 	case IPPROTO_UDP:
645 		udphdr = (struct udphdr *)((char *)ip + (ip->ip_hl << 2));
646 		sprintf(buf, "[UDP] %s:%d -> %s:%d",
647 			     src,
648 			     ntohs(udphdr->uh_sport),
649 			     dst,
650 			     ntohs(udphdr->uh_dport));
651 		break;
652 
653 	case IPPROTO_ICMP:
654 		icmphdr = (struct icmp *)((char *)ip + (ip->ip_hl << 2));
655 		sprintf(buf, "[ICMP] %s -> %s %u(%u)",
656 			     src,
657 			     dst,
658 			     icmphdr->icmp_type,
659 			     icmphdr->icmp_code);
660 		break;
661 
662 	default:
663 		sprintf(buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
664 		break;
665 	}
666 
667 	return buf;
668 }
669 
670 static void
671 SetAliasAddressFromIfName(const char *ifn)
672 {
673 	size_t needed;
674 	int mib[6];
675 	char *buf, *lim, *next;
676 	struct if_msghdr *ifm;
677 	struct ifa_msghdr *ifam;
678 	struct sockaddr_dl *s_dl;
679 	struct sockaddr_in *s_in;
680 
681 	mib[0] = CTL_NET;
682 	mib[1] = PF_ROUTE;
683 	mib[2] = 0;
684 	mib[3] = AF_INET;	/* Only IP addresses please */
685 	mib[4] = NET_RT_IFLIST;
686 	mib[5] = 0;		/* ifIndex??? */
687 /*
688  * Get interface data.
689  */
690 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
691 		err(1, "iflist-sysctl-estimate");
692 	if ((buf = malloc(needed)) == NULL)
693 		errx(1, "malloc failed");
694 	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
695 		err(1, "iflist-sysctl-get");
696 	lim = buf + needed;
697 /*
698  * Loop through interfaces until one with
699  * given name is found. This is done to
700  * find correct interface index for routing
701  * message processing.
702  */
703 	ifIndex	= 0;
704 	next = buf;
705 	while (next < lim) {
706 		ifm = (struct if_msghdr *)next;
707 		next += ifm->ifm_msglen;
708 		if (ifm->ifm_version != RTM_VERSION) {
709 			if (verbose)
710 				warnx("routing message version %d "
711 				      "not understood", ifm->ifm_version);
712 			continue;
713 		}
714 		if (ifm->ifm_type == RTM_IFINFO) {
715 			s_dl = (struct sockaddr_dl *)(ifm + 1);
716 			if (strlen(ifn) == s_dl->sdl_nlen &&
717 			    strncmp(ifn, s_dl->sdl_data, s_dl->sdl_nlen) == 0) {
718 				ifIndex = ifm->ifm_index;
719 				ifMTU = ifm->ifm_data.ifi_mtu;
720 				break;
721 			}
722 		}
723 	}
724 	if (!ifIndex)
725 		errx(1, "unknown interface name %s", ifn);
726 /*
727  * Get interface address.
728  */
729 	s_in = NULL;
730 	while (next < lim) {
731 		ifam = (struct ifa_msghdr *)next;
732 		next += ifam->ifam_msglen;
733 		if (ifam->ifam_version != RTM_VERSION) {
734 			if (verbose)
735 				warnx("routing message version %d "
736 				      "not understood", ifam->ifam_version);
737 			continue;
738 		}
739 		if (ifam->ifam_type != RTM_NEWADDR)
740 			break;
741 		if (ifam->ifam_addrs & RTA_IFA) {
742 			int i;
743 			char *cp = (char *)(ifam + 1);
744 
745 			for (i = 1; i < RTA_IFA; i <<= 1)
746 				if (ifam->ifam_addrs & i)
747 					RT_ADVANCE(cp, (struct sockaddr *)cp);
748 			if (((struct sockaddr *)cp)->sa_family == AF_INET) {
749 				s_in = (struct sockaddr_in *)cp;
750 				break;
751 			}
752 		}
753 	}
754 	if (s_in == NULL)
755 		errx(1, "%s: cannot get interface address", ifn);
756 
757 	PacketAliasSetAddress(s_in->sin_addr);
758 	syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
759 	       inet_ntoa(s_in->sin_addr), ifMTU);
760 
761 	free(buf);
762 }
763 
764 void
765 Quit(const char *msg)
766 {
767 	Warn(msg);
768 	exit(1);
769 }
770 
771 void
772 Warn(const char *msg)
773 {
774 	if (background)
775 		syslog(LOG_ALERT, "%s (%m)", msg);
776 	else
777 		warn("%s", msg);
778 }
779 
780 static void
781 RefreshAddr(int sig __unused)
782 {
783 	if (ifName)
784 		assignAliasAddr = 1;
785 }
786 
787 static void
788 InitiateShutdown(int sig __unused)
789 {
790 	struct sigaction sa;
791 /*
792  * Start timer to allow kernel gracefully
793  * shutdown existing connections when system
794  * is shut down.
795  */
796 	sa.sa_handler = Shutdown;
797 	sa.sa_flags = 0;
798 	sigemptyset(&sa.sa_mask);
799 	sigaction(SIGALRM, &sa, NULL);
800 	ualarm(exitDelay*1000, 1000);
801 }
802 
803 static void
804 Shutdown(int sig __unused)
805 {
806 	running = 0;
807 }
808 
809 /*
810  * Different options recognized by this program.
811  */
812 
813 enum Option {
814 	PacketAliasOption,
815 	Verbose,
816 	InPort,
817 	OutPort,
818 	Port,
819 	AliasAddress,
820 	TargetAddress,
821 	InterfaceName,
822 	RedirectPort,
823 	RedirectProto,
824 	RedirectAddress,
825 	ConfigFile,
826 	DynamicMode,
827 	ProxyRule,
828 	LogDenied,
829 	LogFacility,
830 	PunchFW,
831 	LogIpfwDenied,
832 	ExitDelay
833 };
834 
835 enum Param {
836 	YesNo,
837 	Numeric,
838 	String,
839 	None,
840 	Address,
841 	Service
842 };
843 
844 /*
845  * Option information structure (used by ParseOption).
846  */
847 
848 struct OptionInfo {
849 	enum Option		type;
850 	int			packetAliasOpt;
851 	enum Param		parm;
852 	const char*		parmDescription;
853 	const char*		description;
854 	const char*		name;
855 	const char*		shortName;
856 };
857 
858 /*
859  * Table of known options.
860  */
861 
862 static struct OptionInfo optionTable[] = {
863 	{ PacketAliasOption,
864 		PKT_ALIAS_UNREGISTERED_ONLY,
865 		YesNo,
866 		"[yes|no]",
867 		"alias only unregistered addresses",
868 		"unregistered_only",
869 		"u" },
870 
871 	{ PacketAliasOption,
872 		PKT_ALIAS_LOG,
873 		YesNo,
874 		"[yes|no]",
875 		"enable logging",
876 		"log",
877 		"l" },
878 
879 	{ PacketAliasOption,
880 		PKT_ALIAS_PROXY_ONLY,
881 		YesNo,
882 		"[yes|no]",
883 		"proxy only",
884 		"proxy_only",
885 		NULL },
886 
887 	{ PacketAliasOption,
888 		PKT_ALIAS_REVERSE,
889 		YesNo,
890 		"[yes|no]",
891 		"operate in reverse mode",
892 		"reverse",
893 		NULL },
894 
895 	{ PacketAliasOption,
896 		PKT_ALIAS_DENY_INCOMING,
897 		YesNo,
898 		"[yes|no]",
899 		"allow incoming connections",
900 		"deny_incoming",
901 		"d" },
902 
903 	{ PacketAliasOption,
904 		PKT_ALIAS_USE_SOCKETS,
905 		YesNo,
906 		"[yes|no]",
907 		"use sockets to inhibit port conflict",
908 		"use_sockets",
909 		"s" },
910 
911 	{ PacketAliasOption,
912 		PKT_ALIAS_SAME_PORTS,
913 		YesNo,
914 		"[yes|no]",
915 		"try to keep original port numbers for connections",
916 		"same_ports",
917 		"m" },
918 
919 	{ Verbose,
920 		0,
921 		YesNo,
922 		"[yes|no]",
923 		"verbose mode, dump packet information",
924 		"verbose",
925 		"v" },
926 
927 	{ DynamicMode,
928 		0,
929 		YesNo,
930 		"[yes|no]",
931 		"dynamic mode, automatically detect interface address changes",
932 		"dynamic",
933 		NULL },
934 
935 	{ InPort,
936 		0,
937 		Service,
938 		"number|service_name",
939 		"set port for incoming packets",
940 		"in_port",
941 		"i" },
942 
943 	{ OutPort,
944 		0,
945 		Service,
946 		"number|service_name",
947 		"set port for outgoing packets",
948 		"out_port",
949 		"o" },
950 
951 	{ Port,
952 		0,
953 		Service,
954 		"number|service_name",
955 		"set port (defaults to natd/divert)",
956 		"port",
957 		"p" },
958 
959 	{ AliasAddress,
960 		0,
961 		Address,
962 		"x.x.x.x",
963 		"address to use for aliasing",
964 		"alias_address",
965 		"a" },
966 
967 	{ TargetAddress,
968 		0,
969 		Address,
970 		"x.x.x.x",
971 		"address to use for incoming sessions",
972 		"target_address",
973 		"t" },
974 
975 	{ InterfaceName,
976 		0,
977 		String,
978 		"network_if_name",
979 		"take aliasing address from interface",
980 		"interface",
981 		"n" },
982 
983 	{ ProxyRule,
984 		0,
985 		String,
986 		"[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
987 		"a.b.c.d:yyyy",
988 		"add transparent proxying / destination NAT",
989 		"proxy_rule",
990 		NULL },
991 
992 	{ RedirectPort,
993 		0,
994 		String,
995 		"tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
996 		" [remote_addr[:remote_port_range]]",
997 		"redirect a port (or ports) for incoming traffic",
998 		"redirect_port",
999 		NULL },
1000 
1001 	{ RedirectProto,
1002 		0,
1003 		String,
1004 		"proto local_addr [public_addr] [remote_addr]",
1005 		"redirect packets of a given proto",
1006 		"redirect_proto",
1007 		NULL },
1008 
1009 	{ RedirectAddress,
1010 		0,
1011 		String,
1012 		"local_addr[,...] public_addr",
1013 		"define mapping between local and public addresses",
1014 		"redirect_address",
1015 		NULL },
1016 
1017 	{ ConfigFile,
1018 		0,
1019 		String,
1020 		"file_name",
1021 		"read options from configuration file",
1022 		"config",
1023 		"f" },
1024 
1025 	{ LogDenied,
1026 		0,
1027 		YesNo,
1028 		"[yes|no]",
1029 		"enable logging of denied incoming packets",
1030 		"log_denied",
1031 		NULL },
1032 
1033 	{ LogFacility,
1034 		0,
1035 		String,
1036 		"facility",
1037 		"name of syslog facility to use for logging",
1038 		"log_facility",
1039 		NULL },
1040 
1041 	{ PunchFW,
1042 		0,
1043 		String,
1044 		"basenumber:count",
1045 		"punch holes in the firewall for incoming FTP/IRC DCC connections",
1046 		"punch_fw",
1047 		NULL },
1048 
1049 	{ LogIpfwDenied,
1050 		0,
1051 		YesNo,
1052 		"[yes|no]",
1053 		"log packets converted by natd, but denied by ipfw",
1054 		"log_ipfw_denied",
1055 		NULL },
1056 	{ ExitDelay,
1057 		0,
1058 		Numeric,
1059 		"ms",
1060 		"delay in ms before daemon exit after signal",
1061 		"exit_delay",
1062 		NULL },
1063 };
1064 
1065 static void
1066 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 		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 		warnx("unknown option %s", option);
1094 		Usage();
1095 	}
1096 
1097 	uNumValue	= 0;
1098 	yesNoValue	= 0;
1099 	numValue	= 0;
1100 	strValue	= NULL;
1101 /*
1102  * Check parameters.
1103  */
1104 	switch (info->parm) {
1105 	case YesNo:
1106 		if (!parms)
1107 			parms = "yes";
1108 
1109 		if (!strcmp(parms, "yes"))
1110 			yesNoValue = 1;
1111 		else
1112 			if (!strcmp(parms, "no"))
1113 				yesNoValue = 0;
1114 			else
1115 				errx(1, "%s needs yes/no parameter", option);
1116 		break;
1117 
1118 	case Service:
1119 		if (!parms)
1120 			errx(1, "%s needs service name or "
1121 				"port number parameter",
1122 				option);
1123 
1124 		uNumValue = StrToPort(parms, "divert");
1125 		break;
1126 
1127 	case Numeric:
1128 		if (parms)
1129 			numValue = strtol(parms, &end, 10);
1130 		else
1131 			end = NULL;
1132 
1133 		if (end == parms)
1134 			errx(1, "%s needs numeric parameter", option);
1135 		break;
1136 
1137 	case String:
1138 		strValue = parms;
1139 		if (!strValue)
1140 			errx(1, "%s needs parameter", option);
1141 		break;
1142 
1143 	case None:
1144 		if (parms)
1145 			errx(1, "%s does not take parameters", option);
1146 		break;
1147 
1148 	case Address:
1149 		if (!parms)
1150 			errx(1, "%s needs address/host parameter", option);
1151 
1152 		StrToAddr(parms, &addrValue);
1153 		break;
1154 	}
1155 
1156 	switch (info->type) {
1157 	case PacketAliasOption:
1158 
1159 		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1160 		PacketAliasSetMode(aliasValue, info->packetAliasOpt);
1161 		break;
1162 
1163 	case Verbose:
1164 		verbose = yesNoValue;
1165 		break;
1166 
1167 	case DynamicMode:
1168 		dynamicMode = yesNoValue;
1169 		break;
1170 
1171 	case InPort:
1172 		inPort = uNumValue;
1173 		break;
1174 
1175 	case OutPort:
1176 		outPort = uNumValue;
1177 		break;
1178 
1179 	case Port:
1180 		inOutPort = uNumValue;
1181 		break;
1182 
1183 	case AliasAddress:
1184 		memcpy(&aliasAddr, &addrValue, sizeof(struct in_addr));
1185 		break;
1186 
1187 	case TargetAddress:
1188 		PacketAliasSetTarget(addrValue);
1189 		break;
1190 
1191 	case RedirectPort:
1192 		SetupPortRedirect(strValue);
1193 		break;
1194 
1195 	case RedirectProto:
1196 		SetupProtoRedirect(strValue);
1197 		break;
1198 
1199 	case RedirectAddress:
1200 		SetupAddressRedirect(strValue);
1201 		break;
1202 
1203 	case ProxyRule:
1204 		PacketAliasProxyRule(strValue);
1205 		break;
1206 
1207 	case InterfaceName:
1208 		if (ifName)
1209 			free(ifName);
1210 
1211 		ifName = strdup(strValue);
1212 		break;
1213 
1214 	case ConfigFile:
1215 		ReadConfigFile(strValue);
1216 		break;
1217 
1218 	case LogDenied:
1219 		logDropped = yesNoValue;
1220 		break;
1221 
1222 	case LogFacility:
1223 
1224 		fac_record = facilitynames;
1225 		while (fac_record->c_name != NULL) {
1226 			if (!strcmp(fac_record->c_name, strValue)) {
1227 				logFacility = fac_record->c_val;
1228 				break;
1229 
1230 			} else
1231 				fac_record++;
1232 		}
1233 
1234 		if(fac_record->c_name == NULL)
1235 			errx(1, "Unknown log facility name: %s", strValue);
1236 
1237 		break;
1238 
1239 	case PunchFW:
1240 		SetupPunchFW(strValue);
1241 		break;
1242 
1243 	case LogIpfwDenied:
1244 		logIpfwDenied = yesNoValue;
1245 		break;
1246 	case ExitDelay:
1247 		if (numValue < 0 || numValue > MAX_EXIT_DELAY)
1248 			errx(1, "Incorrect exit delay: %d", numValue);
1249 		exitDelay = numValue;
1250 		break;
1251 	}
1252 }
1253 
1254 void
1255 ReadConfigFile(const char *fileName)
1256 {
1257 	FILE*	file;
1258 	char	*buf;
1259 	size_t	len;
1260 	char	*ptr, *p;
1261 	char*	option;
1262 
1263 	file = fopen(fileName, "r");
1264 	if (!file)
1265 		err(1, "cannot open config file %s", fileName);
1266 
1267 	while ((buf = fgetln(file, &len)) != NULL) {
1268 		if (buf[len - 1] == '\n')
1269 			buf[len - 1] = '\0';
1270 		else
1271 			errx(1, "config file format error: "
1272 				"last line should end with newline");
1273 
1274 /*
1275  * Check for comments, strip off trailing spaces.
1276  */
1277 		if ((ptr = strchr(buf, '#')))
1278 			*ptr = '\0';
1279 		for (ptr = buf; isspace(*ptr); ++ptr)
1280 			continue;
1281 		if (*ptr == '\0')
1282 			continue;
1283 		for (p = strchr(buf, '\0'); isspace(*--p);)
1284 			continue;
1285 		*++p = '\0';
1286 
1287 /*
1288  * Extract option name.
1289  */
1290 		option = ptr;
1291 		while (*ptr && !isspace(*ptr))
1292 			++ptr;
1293 
1294 		if (*ptr != '\0') {
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
1311 Usage(void)
1312 {
1313 	int			i;
1314 	int			max;
1315 	struct OptionInfo*	info;
1316 
1317 	fprintf(stderr, "Recognized options:\n\n");
1318 
1319 	max = sizeof(optionTable) / sizeof(struct OptionInfo);
1320 	for (i = 0, info = optionTable; i < max; i++, info++) {
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
1335 SetupPortRedirect(const char *parms)
1336 {
1337 	char		buf[128];
1338 	char*		ptr;
1339 	char*		serverPool;
1340 	struct in_addr	localAddr;
1341 	struct in_addr	publicAddr;
1342 	struct in_addr	remoteAddr;
1343 	port_range	portRange;
1344 	u_short		localPort      = 0;
1345 	u_short		publicPort     = 0;
1346 	u_short		remotePort     = 0;
1347 	u_short		numLocalPorts  = 0;
1348 	u_short		numPublicPorts = 0;
1349 	u_short		numRemotePorts = 0;
1350 	int		proto;
1351 	char*		protoName;
1352 	char*		separator;
1353 	int		i;
1354 	struct alias_link *alink = NULL;
1355 
1356 	strcpy(buf, parms);
1357 /*
1358  * Extract protocol.
1359  */
1360 	protoName = strtok(buf, " \t");
1361 	if (!protoName)
1362 		errx(1, "redirect_port: missing protocol");
1363 
1364 	proto = StrToProto(protoName);
1365 /*
1366  * Extract local address.
1367  */
1368 	ptr = strtok(NULL, " \t");
1369 	if (!ptr)
1370 		errx(1, "redirect_port: missing local address");
1371 
1372 	separator = strchr(ptr, ',');
1373 	if (separator) {		/* LSNAT redirection syntax. */
1374 		localAddr.s_addr = INADDR_NONE;
1375 		localPort = ~0;
1376 		numLocalPorts = 1;
1377 		serverPool = ptr;
1378 	} else {
1379 		if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0 )
1380 			errx(1, "redirect_port: invalid local port range");
1381 
1382 		localPort     = GETLOPORT(portRange);
1383 		numLocalPorts = GETNUMPORTS(portRange);
1384 		serverPool = NULL;
1385 	}
1386 
1387 /*
1388  * Extract public port and optionally address.
1389  */
1390 	ptr = strtok(NULL, " \t");
1391 	if (!ptr)
1392 		errx(1, "redirect_port: missing public port");
1393 
1394 	separator = strchr(ptr, ':');
1395 	if (separator) {
1396 		if (StrToAddrAndPortRange(ptr, &publicAddr, protoName, &portRange) != 0 )
1397 			errx(1, "redirect_port: invalid public port range");
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 	} 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 		alink = 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 && alink != 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(alink, 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 	PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr, proto);
1526 }
1527 
1528 void
1529 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 *alink;
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 	alink = PacketAliasRedirectAddr(localAddr, publicAddr);
1564 
1565 /*
1566  * Setup LSNAT server pool.
1567  */
1568 	if (serverPool != NULL && alink != NULL) {
1569 		ptr = strtok(serverPool, ",");
1570 		while (ptr != NULL) {
1571 			StrToAddr(ptr, &localAddr);
1572 			PacketAliasAddServer(alink, localAddr, htons(~0));
1573 			ptr = strtok(NULL, ",");
1574 		}
1575 	}
1576 }
1577 
1578 void
1579 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
1594 StrToPort(const char *str, const char *proto)
1595 {
1596 	u_short		port;
1597 	struct servent*	sp;
1598 	char*		end;
1599 
1600 	port = strtol(str, &end, 10);
1601 	if (end != str)
1602 		return htons(port);
1603 
1604 	sp = getservbyname(str, proto);
1605 	if (!sp)
1606 		errx(1, "unknown service %s/%s", str, proto);
1607 
1608 	return sp->s_port;
1609 }
1610 
1611 int
1612 StrToPortRange(const char *str, const char *proto, port_range *portRange)
1613 {
1614 	char*		sep;
1615 	struct servent*	sp;
1616 	char*		end;
1617 	u_short		loPort;
1618 	u_short		hiPort;
1619 
1620 	/* First see if this is a service, return corresponding port if so. */
1621 	sp = getservbyname(str,proto);
1622 	if (sp) {
1623 		SETLOPORT(*portRange, ntohs(sp->s_port));
1624 		SETNUMPORTS(*portRange, 1);
1625 		return 0;
1626 	}
1627 
1628 	/* Not a service, see if it's a single port or port range. */
1629 	sep = strchr(str, '-');
1630 	if (sep == NULL) {
1631 		SETLOPORT(*portRange, strtol(str, &end, 10));
1632 		if (end != str) {
1633 			/* Single port. */
1634 			SETNUMPORTS(*portRange, 1);
1635 			return 0;
1636 		}
1637 
1638 		/* Error in port range field. */
1639 		errx(1, "unknown service %s/%s", str, proto);
1640 	}
1641 
1642 	/* Port range, get the values and sanity check. */
1643 	sscanf(str, "%hu-%hu", &loPort, &hiPort);
1644 	SETLOPORT(*portRange, loPort);
1645 	SETNUMPORTS(*portRange, 0);	/* Error by default */
1646 	if (loPort <= hiPort)
1647 		SETNUMPORTS(*portRange, hiPort - loPort + 1);
1648 
1649 	if (GETNUMPORTS(*portRange) == 0)
1650 		errx(1, "invalid port range %s", str);
1651 
1652 	return 0;
1653 }
1654 
1655 
1656 int
1657 StrToProto(const char *str)
1658 {
1659 	if (!strcmp(str, "tcp"))
1660 		return IPPROTO_TCP;
1661 
1662 	if (!strcmp(str, "udp"))
1663 		return IPPROTO_UDP;
1664 
1665 	errx(1, "unknown protocol %s. Expected tcp or udp", str);
1666 }
1667 
1668 int
1669 StrToAddrAndPortRange(const char *str, struct in_addr *addr, char *proto, port_range *portRange)
1670 {
1671 	char*	ptr;
1672 
1673 	ptr = strchr(str, ':');
1674 	if (!ptr)
1675 		errx(1, "%s is missing port number", str);
1676 
1677 	*ptr = '\0';
1678 	++ptr;
1679 
1680 	StrToAddr(str, addr);
1681 	return StrToPortRange(ptr, proto, portRange);
1682 }
1683 
1684 static void
1685 SetupPunchFW(const char *strValue)
1686 {
1687 	unsigned int base, num;
1688 
1689 	if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1690 		errx(1, "punch_fw: basenumber:count parameter required");
1691 
1692 	PacketAliasSetFWBase(base, num);
1693 	PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1694 }
1695