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