xref: /freebsd/sbin/natd/natd.c (revision 64db83a8ab2d1f72a9b2174b39d2ef42b5b0580c)
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, int cmdLine);
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	SetupPptpAlias (const char* parms);
95 static void	StrToAddr (const char* str, struct in_addr* addr);
96 static u_short  StrToPort (const char* str, const char* proto);
97 static int      StrToPortRange (const char* str, const char* proto, port_range *portRange);
98 static int 	StrToProto (const char* str);
99 static int      StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange);
100 static void	ParseArgs (int argc, char** argv);
101 static void	FlushPacketBuffer (int fd);
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, 0);
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), 1);
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 (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 	PptpAlias,
871 	ProxyRule,
872  	LogDenied,
873  	LogFacility
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        { PptpAlias,
1062 		0,
1063 		String,
1064 		"src",
1065 		"define inside machine for PPTP traffic",
1066 		"pptpalias",
1067 		NULL },
1068 
1069 	{ ConfigFile,
1070 		0,
1071 		String,
1072 		"file_name",
1073 		"read options from configuration file",
1074 		"config",
1075 		"f" },
1076 
1077 	{ LogDenied,
1078 		0,
1079 		YesNo,
1080 	        "[yes|no]",
1081 		"enable logging of denied incoming packets",
1082 		"log_denied",
1083 		NULL },
1084 
1085 	{ LogFacility,
1086 		0,
1087 		String,
1088 	        "facility",
1089 		"name of syslog facility to use for logging",
1090 		"log_facility",
1091 		NULL }
1092 
1093 };
1094 
1095 static void ParseOption (const char* option, const char* parms, int cmdLine)
1096 {
1097 	int			i;
1098 	struct OptionInfo*	info;
1099 	int			yesNoValue;
1100 	int			aliasValue;
1101 	int			numValue;
1102 	u_short			uNumValue;
1103 	const char*		strValue;
1104 	struct in_addr		addrValue;
1105 	int			max;
1106 	char*			end;
1107 	CODE* 			fac_record = NULL;
1108 /*
1109  * Find option from table.
1110  */
1111 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
1112 	for (i = 0, info = optionTable; i < max; i++, info++) {
1113 
1114 		if (!strcmp (info->name, option))
1115 			break;
1116 
1117 		if (info->shortName)
1118 			if (!strcmp (info->shortName, option))
1119 				break;
1120 	}
1121 
1122 	if (i >= max) {
1123 
1124 		warnx ("unknown option %s", option);
1125 		Usage ();
1126 	}
1127 
1128 	uNumValue	= 0;
1129 	yesNoValue	= 0;
1130 	numValue	= 0;
1131 	strValue	= NULL;
1132 /*
1133  * Check parameters.
1134  */
1135 	switch (info->parm) {
1136 	case YesNo:
1137 		if (!parms)
1138 			parms = "yes";
1139 
1140 		if (!strcmp (parms, "yes"))
1141 			yesNoValue = 1;
1142 		else
1143 			if (!strcmp (parms, "no"))
1144 				yesNoValue = 0;
1145 			else
1146 				errx (1, "%s needs yes/no parameter", option);
1147 		break;
1148 
1149 	case Service:
1150 		if (!parms)
1151 			errx (1, "%s needs service name or "
1152 				 "port number parameter",
1153 				 option);
1154 
1155 		uNumValue = StrToPort (parms, "divert");
1156 		break;
1157 
1158 	case Numeric:
1159 		if (parms)
1160 			numValue = strtol (parms, &end, 10);
1161 		else
1162 			end = NULL;
1163 
1164 		if (end == parms)
1165 			errx (1, "%s needs numeric parameter", option);
1166 		break;
1167 
1168 	case String:
1169 		strValue = parms;
1170 		if (!strValue)
1171 			errx (1, "%s needs parameter", option);
1172 		break;
1173 
1174 	case None:
1175 		if (parms)
1176 			errx (1, "%s does not take parameters", option);
1177 		break;
1178 
1179 	case Address:
1180 		if (!parms)
1181 			errx (1, "%s needs address/host parameter", option);
1182 
1183 		StrToAddr (parms, &addrValue);
1184 		break;
1185 	}
1186 
1187 	switch (info->type) {
1188 	case PacketAliasOption:
1189 
1190 		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1191 		PacketAliasSetMode (aliasValue, info->packetAliasOpt);
1192 		break;
1193 
1194 	case Verbose:
1195 		verbose = yesNoValue;
1196 		break;
1197 
1198 	case DynamicMode:
1199 		dynamicMode = yesNoValue;
1200 		break;
1201 
1202 	case InPort:
1203 		inPort = uNumValue;
1204 		break;
1205 
1206 	case OutPort:
1207 		outPort = uNumValue;
1208 		break;
1209 
1210 	case Port:
1211 		inOutPort = uNumValue;
1212 		break;
1213 
1214 	case AliasAddress:
1215 		memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
1216 		break;
1217 
1218 	case TargetAddress:
1219 		PacketAliasSetTarget(addrValue);
1220 		break;
1221 
1222 	case RedirectPort:
1223 		SetupPortRedirect (strValue);
1224 		break;
1225 
1226 	case RedirectProto:
1227 		SetupProtoRedirect(strValue);
1228 		break;
1229 
1230 	case RedirectAddress:
1231 		SetupAddressRedirect (strValue);
1232 		break;
1233 
1234 	case PptpAlias:
1235 		SetupPptpAlias (strValue);
1236 		break;
1237 
1238 	case ProxyRule:
1239 		PacketAliasProxyRule (strValue);
1240 		break;
1241 
1242 	case InterfaceName:
1243 		if (ifName)
1244 			free (ifName);
1245 
1246 		ifName = strdup (strValue);
1247 		break;
1248 
1249 	case ConfigFile:
1250 		ReadConfigFile (strValue);
1251 		break;
1252 
1253 	case LogDenied:
1254 		logDropped = 1;
1255 		break;
1256 
1257 	case LogFacility:
1258 
1259 		fac_record = facilitynames;
1260 		while (fac_record->c_name != NULL) {
1261 
1262 			if (!strcmp (fac_record->c_name, strValue)) {
1263 
1264 				logFacility = fac_record->c_val;
1265 				break;
1266 
1267 			}
1268 			else
1269 				fac_record++;
1270 		}
1271 
1272 		if(fac_record->c_name == NULL)
1273 			errx(1, "Unknown log facility name: %s", strValue);
1274 
1275 		break;
1276 	}
1277 }
1278 
1279 void ReadConfigFile (const char* fileName)
1280 {
1281 	FILE*	file;
1282 	char	*buf;
1283 	size_t	len;
1284 	char	*ptr, *p;
1285 	char*	option;
1286 
1287 	file = fopen (fileName, "r");
1288 	if (!file)
1289 		err(1, "cannot open config file %s", fileName);
1290 
1291 	while ((buf = fgetln(file, &len)) != NULL) {
1292 		if (buf[len - 1] == '\n')
1293 			buf[len - 1] = '\0';
1294 		else
1295 			errx(1, "config file format error: "
1296 				"last line should end with newline");
1297 
1298 /*
1299  * Check for comments, strip off trailing spaces.
1300  */
1301 		if ((ptr = strchr(buf, '#')))
1302 			*ptr = '\0';
1303 		for (ptr = buf; isspace(*ptr); ++ptr)
1304 			continue;
1305 		if (*ptr == '\0')
1306 			continue;
1307 		for (p = strchr(buf, '\0'); isspace(*--p);)
1308 			continue;
1309 		*++p = '\0';
1310 
1311 /*
1312  * Extract option name.
1313  */
1314 		option = ptr;
1315 		while (*ptr && !isspace (*ptr))
1316 			++ptr;
1317 
1318 		if (*ptr != '\0') {
1319 
1320 			*ptr = '\0';
1321 			++ptr;
1322 		}
1323 /*
1324  * Skip white space between name and parms.
1325  */
1326 		while (*ptr && isspace (*ptr))
1327 			++ptr;
1328 
1329 		ParseOption (option, *ptr ? ptr : NULL, 0);
1330 	}
1331 
1332 	fclose (file);
1333 }
1334 
1335 static void Usage ()
1336 {
1337 	int			i;
1338 	int			max;
1339 	struct OptionInfo*	info;
1340 
1341 	fprintf (stderr, "Recognized options:\n\n");
1342 
1343 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
1344 	for (i = 0, info = optionTable; i < max; i++, info++) {
1345 
1346 		fprintf (stderr, "-%-20s %s\n", info->name,
1347 						info->parmDescription);
1348 
1349 		if (info->shortName)
1350 			fprintf (stderr, "-%-20s %s\n", info->shortName,
1351 							info->parmDescription);
1352 
1353 		fprintf (stderr, "      %s\n\n", info->description);
1354 	}
1355 
1356 	exit (1);
1357 }
1358 
1359 void SetupPptpAlias (const char* parms)
1360 {
1361 	char		buf[128];
1362 	char*		ptr;
1363 	struct in_addr	srcAddr;
1364 
1365 	strcpy (buf, parms);
1366 
1367 /*
1368  * Extract source address.
1369  */
1370 	ptr = strtok (buf, " \t");
1371 	if (!ptr)
1372 		errx(1, "pptpalias: missing src address");
1373 
1374 	StrToAddr (ptr, &srcAddr);
1375 	PacketAliasPptp (srcAddr);
1376 }
1377 
1378 void SetupPortRedirect (const char* parms)
1379 {
1380 	char		buf[128];
1381 	char*		ptr;
1382 	char*		serverPool;
1383 	struct in_addr	localAddr;
1384 	struct in_addr	publicAddr;
1385 	struct in_addr	remoteAddr;
1386 	port_range      portRange;
1387 	u_short         localPort      = 0;
1388 	u_short         publicPort     = 0;
1389 	u_short         remotePort     = 0;
1390 	u_short         numLocalPorts  = 0;
1391 	u_short         numPublicPorts = 0;
1392 	u_short         numRemotePorts = 0;
1393 	int		proto;
1394 	char*		protoName;
1395 	char*		separator;
1396 	int             i;
1397 	struct alias_link *link = NULL;
1398 
1399 	strcpy (buf, parms);
1400 /*
1401  * Extract protocol.
1402  */
1403 	protoName = strtok (buf, " \t");
1404 	if (!protoName)
1405 		errx (1, "redirect_port: missing protocol");
1406 
1407 	proto = StrToProto (protoName);
1408 /*
1409  * Extract local address.
1410  */
1411 	ptr = strtok (NULL, " \t");
1412 	if (!ptr)
1413 		errx (1, "redirect_port: missing local address");
1414 
1415 	separator = strchr(ptr, ',');
1416 	if (separator) {		/* LSNAT redirection syntax. */
1417 		localAddr.s_addr = INADDR_NONE;
1418 		localPort = ~0;
1419 		numLocalPorts = 1;
1420 		serverPool = ptr;
1421 	} else {
1422 		if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1423 			errx (1, "redirect_port: invalid local port range");
1424 
1425 		localPort     = GETLOPORT(portRange);
1426 		numLocalPorts = GETNUMPORTS(portRange);
1427 		serverPool = NULL;
1428 	}
1429 
1430 /*
1431  * Extract public port and optionally address.
1432  */
1433 	ptr = strtok (NULL, " \t");
1434 	if (!ptr)
1435 		errx (1, "redirect_port: missing public port");
1436 
1437 	separator = strchr (ptr, ':');
1438 	if (separator) {
1439 	        if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1440 		        errx (1, "redirect_port: invalid public port range");
1441 	}
1442 	else {
1443 		publicAddr.s_addr = INADDR_ANY;
1444 		if (StrToPortRange (ptr, protoName, &portRange) != 0)
1445 		        errx (1, "redirect_port: invalid public port range");
1446 	}
1447 
1448 	publicPort     = GETLOPORT(portRange);
1449 	numPublicPorts = GETNUMPORTS(portRange);
1450 
1451 /*
1452  * Extract remote address and optionally port.
1453  */
1454 	ptr = strtok (NULL, " \t");
1455 	if (ptr) {
1456 		separator = strchr (ptr, ':');
1457 		if (separator) {
1458 		        if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1459 			        errx (1, "redirect_port: invalid remote port range");
1460 		} else {
1461 		        SETLOPORT(portRange, 0);
1462 			SETNUMPORTS(portRange, 1);
1463 			StrToAddr (ptr, &remoteAddr);
1464 		}
1465 	}
1466 	else {
1467 	        SETLOPORT(portRange, 0);
1468 		SETNUMPORTS(portRange, 1);
1469 		remoteAddr.s_addr = INADDR_ANY;
1470 	}
1471 
1472 	remotePort     = GETLOPORT(portRange);
1473 	numRemotePorts = GETNUMPORTS(portRange);
1474 
1475 /*
1476  * Make sure port ranges match up, then add the redirect ports.
1477  */
1478 	if (numLocalPorts != numPublicPorts)
1479 	        errx (1, "redirect_port: port ranges must be equal in size");
1480 
1481 	/* Remote port range is allowed to be '0' which means all ports. */
1482 	if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1483 	        errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1484 
1485 	for (i = 0 ; i < numPublicPorts ; ++i) {
1486 	        /* If remotePort is all ports, set it to 0. */
1487 	        u_short remotePortCopy = remotePort + i;
1488 	        if (numRemotePorts == 1 && remotePort == 0)
1489 		        remotePortCopy = 0;
1490 
1491 		link = PacketAliasRedirectPort (localAddr,
1492 						htons(localPort + i),
1493 						remoteAddr,
1494 						htons(remotePortCopy),
1495 						publicAddr,
1496 						htons(publicPort + i),
1497 						proto);
1498 	}
1499 
1500 /*
1501  * Setup LSNAT server pool.
1502  */
1503 	if (serverPool != NULL && link != NULL) {
1504 		ptr = strtok(serverPool, ",");
1505 		while (ptr != NULL) {
1506 			if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1507 				errx(1, "redirect_port: invalid local port range");
1508 
1509 			localPort = GETLOPORT(portRange);
1510 			if (GETNUMPORTS(portRange) != 1)
1511 				errx(1, "redirect_port: local port must be single in this context");
1512 			PacketAliasAddServer(link, localAddr, htons(localPort));
1513 			ptr = strtok(NULL, ",");
1514 		}
1515 	}
1516 }
1517 
1518 void
1519 SetupProtoRedirect(const char* parms)
1520 {
1521 	char		buf[128];
1522 	char*		ptr;
1523 	struct in_addr	localAddr;
1524 	struct in_addr	publicAddr;
1525 	struct in_addr	remoteAddr;
1526 	int		proto;
1527 	char*		protoName;
1528 	struct protoent *protoent;
1529 
1530 	strcpy (buf, parms);
1531 /*
1532  * Extract protocol.
1533  */
1534 	protoName = strtok(buf, " \t");
1535 	if (!protoName)
1536 		errx(1, "redirect_proto: missing protocol");
1537 
1538 	protoent = getprotobyname(protoName);
1539 	if (protoent == NULL)
1540 		errx(1, "redirect_proto: unknown protocol %s", protoName);
1541 	else
1542 		proto = protoent->p_proto;
1543 /*
1544  * Extract local address.
1545  */
1546 	ptr = strtok(NULL, " \t");
1547 	if (!ptr)
1548 		errx(1, "redirect_proto: missing local address");
1549 	else
1550 		StrToAddr(ptr, &localAddr);
1551 /*
1552  * Extract optional public address.
1553  */
1554 	ptr = strtok(NULL, " \t");
1555 	if (ptr)
1556 		StrToAddr(ptr, &publicAddr);
1557 	else
1558 		publicAddr.s_addr = INADDR_ANY;
1559 /*
1560  * Extract optional remote address.
1561  */
1562 	ptr = strtok(NULL, " \t");
1563 	if (ptr)
1564 		StrToAddr(ptr, &remoteAddr);
1565 	else
1566 		remoteAddr.s_addr = INADDR_ANY;
1567 /*
1568  * Create aliasing link.
1569  */
1570 	(void)PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr,
1571 				       proto);
1572 }
1573 
1574 void SetupAddressRedirect (const char* parms)
1575 {
1576 	char		buf[128];
1577 	char*		ptr;
1578 	char*		separator;
1579 	struct in_addr	localAddr;
1580 	struct in_addr	publicAddr;
1581 	char*		serverPool;
1582 	struct alias_link *link;
1583 
1584 	strcpy (buf, parms);
1585 /*
1586  * Extract local address.
1587  */
1588 	ptr = strtok (buf, " \t");
1589 	if (!ptr)
1590 		errx (1, "redirect_address: missing local address");
1591 
1592 	separator = strchr(ptr, ',');
1593 	if (separator) {		/* LSNAT redirection syntax. */
1594 		localAddr.s_addr = INADDR_NONE;
1595 		serverPool = ptr;
1596 	} else {
1597 		StrToAddr (ptr, &localAddr);
1598 		serverPool = NULL;
1599 	}
1600 /*
1601  * Extract public address.
1602  */
1603 	ptr = strtok (NULL, " \t");
1604 	if (!ptr)
1605 		errx (1, "redirect_address: missing public address");
1606 
1607 	StrToAddr (ptr, &publicAddr);
1608 	link = PacketAliasRedirectAddr(localAddr, publicAddr);
1609 
1610 /*
1611  * Setup LSNAT server pool.
1612  */
1613 	if (serverPool != NULL && link != NULL) {
1614 		ptr = strtok(serverPool, ",");
1615 		while (ptr != NULL) {
1616 			StrToAddr(ptr, &localAddr);
1617 			PacketAliasAddServer(link, localAddr, htons(~0));
1618 			ptr = strtok(NULL, ",");
1619 		}
1620 	}
1621 }
1622 
1623 void StrToAddr (const char* str, struct in_addr* addr)
1624 {
1625 	struct hostent* hp;
1626 
1627 	if (inet_aton (str, addr))
1628 		return;
1629 
1630 	hp = gethostbyname (str);
1631 	if (!hp)
1632 		errx (1, "unknown host %s", str);
1633 
1634 	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1635 }
1636 
1637 u_short StrToPort (const char* str, const char* proto)
1638 {
1639 	u_short		port;
1640 	struct servent*	sp;
1641 	char*		end;
1642 
1643 	port = strtol (str, &end, 10);
1644 	if (end != str)
1645 		return htons (port);
1646 
1647 	sp = getservbyname (str, proto);
1648 	if (!sp)
1649 		errx (1, "unknown service %s/%s", str, proto);
1650 
1651 	return sp->s_port;
1652 }
1653 
1654 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1655 {
1656 	char*           sep;
1657 	struct servent*	sp;
1658 	char*		end;
1659 	u_short         loPort;
1660 	u_short         hiPort;
1661 
1662 	/* First see if this is a service, return corresponding port if so. */
1663 	sp = getservbyname (str,proto);
1664 	if (sp) {
1665 	        SETLOPORT(*portRange, ntohs(sp->s_port));
1666 		SETNUMPORTS(*portRange, 1);
1667 		return 0;
1668 	}
1669 
1670 	/* Not a service, see if it's a single port or port range. */
1671 	sep = strchr (str, '-');
1672 	if (sep == NULL) {
1673 	        SETLOPORT(*portRange, strtol(str, &end, 10));
1674 		if (end != str) {
1675 		        /* Single port. */
1676 		        SETNUMPORTS(*portRange, 1);
1677 			return 0;
1678 		}
1679 
1680 		/* Error in port range field. */
1681 		errx (1, "unknown service %s/%s", str, proto);
1682 	}
1683 
1684 	/* Port range, get the values and sanity check. */
1685 	sscanf (str, "%hu-%hu", &loPort, &hiPort);
1686 	SETLOPORT(*portRange, loPort);
1687 	SETNUMPORTS(*portRange, 0);	/* Error by default */
1688 	if (loPort <= hiPort)
1689 	        SETNUMPORTS(*portRange, hiPort - loPort + 1);
1690 
1691 	if (GETNUMPORTS(*portRange) == 0)
1692 	        errx (1, "invalid port range %s", str);
1693 
1694 	return 0;
1695 }
1696 
1697 
1698 int StrToProto (const char* str)
1699 {
1700 	if (!strcmp (str, "tcp"))
1701 		return IPPROTO_TCP;
1702 
1703 	if (!strcmp (str, "udp"))
1704 		return IPPROTO_UDP;
1705 
1706 	errx (1, "unknown protocol %s. Expected tcp or udp", str);
1707 }
1708 
1709 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
1710 {
1711 	char*	ptr;
1712 
1713 	ptr = strchr (str, ':');
1714 	if (!ptr)
1715 		errx (1, "%s is missing port number", str);
1716 
1717 	*ptr = '\0';
1718 	++ptr;
1719 
1720 	StrToAddr (str, addr);
1721 	return StrToPortRange (ptr, proto, portRange);
1722 }
1723