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