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