xref: /freebsd/sbin/natd/natd.c (revision 56ca39961bd1c9946a505c41c3fc634ef63fdd42)
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 	InterfaceName,
864 	RedirectPort,
865 	RedirectProto,
866 	RedirectAddress,
867 	ConfigFile,
868 	DynamicMode,
869 	PptpAlias,
870 	ProxyRule,
871  	LogDenied,
872  	LogFacility
873 };
874 
875 enum Param {
876 
877 	YesNo,
878 	Numeric,
879 	String,
880 	None,
881 	Address,
882 	Service
883 };
884 
885 /*
886  * Option information structure (used by ParseOption).
887  */
888 
889 struct OptionInfo {
890 
891 	enum Option		type;
892 	int			packetAliasOpt;
893 	enum Param		parm;
894 	const char*		parmDescription;
895 	const char*		description;
896 	const char*		name;
897 	const char*		shortName;
898 };
899 
900 /*
901  * Table of known options.
902  */
903 
904 static struct OptionInfo optionTable[] = {
905 
906 	{ PacketAliasOption,
907 		PKT_ALIAS_UNREGISTERED_ONLY,
908 		YesNo,
909 		"[yes|no]",
910 		"alias only unregistered addresses",
911 		"unregistered_only",
912 		"u" },
913 
914 	{ PacketAliasOption,
915 		PKT_ALIAS_LOG,
916 		YesNo,
917 		"[yes|no]",
918 		"enable logging",
919 		"log",
920 		"l" },
921 
922 	{ PacketAliasOption,
923 		PKT_ALIAS_PROXY_ONLY,
924 		YesNo,
925 		"[yes|no]",
926 		"proxy only",
927 		"proxy_only",
928 		NULL },
929 
930 	{ PacketAliasOption,
931 		PKT_ALIAS_REVERSE,
932 		YesNo,
933 		"[yes|no]",
934 		"operate in reverse mode",
935 		"reverse",
936 		NULL },
937 
938 	{ PacketAliasOption,
939 		PKT_ALIAS_DENY_INCOMING,
940 		YesNo,
941 		"[yes|no]",
942 		"allow incoming connections",
943 		"deny_incoming",
944 		"d" },
945 
946 	{ PacketAliasOption,
947 		PKT_ALIAS_USE_SOCKETS,
948 		YesNo,
949 		"[yes|no]",
950 		"use sockets to inhibit port conflict",
951 		"use_sockets",
952 		"s" },
953 
954 	{ PacketAliasOption,
955 		PKT_ALIAS_SAME_PORTS,
956 		YesNo,
957 		"[yes|no]",
958 		"try to keep original port numbers for connections",
959 		"same_ports",
960 		"m" },
961 
962 	{ Verbose,
963 		0,
964 		YesNo,
965 		"[yes|no]",
966 		"verbose mode, dump packet information",
967 		"verbose",
968 		"v" },
969 
970 	{ DynamicMode,
971 		0,
972 		YesNo,
973 		"[yes|no]",
974 		"dynamic mode, automatically detect interface address changes",
975 		"dynamic",
976 		NULL },
977 
978 	{ InPort,
979 		0,
980 		Service,
981 		"number|service_name",
982 		"set port for incoming packets",
983 		"in_port",
984 		"i" },
985 
986 	{ OutPort,
987 		0,
988 		Service,
989 		"number|service_name",
990 		"set port for outgoing packets",
991 		"out_port",
992 		"o" },
993 
994 	{ Port,
995 		0,
996 		Service,
997 		"number|service_name",
998 		"set port (defaults to natd/divert)",
999 		"port",
1000 		"p" },
1001 
1002 	{ AliasAddress,
1003 		0,
1004 		Address,
1005 		"x.x.x.x",
1006 		"address to use for aliasing",
1007 		"alias_address",
1008 		"a" },
1009 
1010 	{ InterfaceName,
1011 		0,
1012 		String,
1013 	        "network_if_name",
1014 		"take aliasing address from interface",
1015 		"interface",
1016 		"n" },
1017 
1018 	{ ProxyRule,
1019 		0,
1020 		String,
1021 	        "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1022 		"a.b.c.d:yyyy",
1023 		"add transparent proxying / destination NAT",
1024 		"proxy_rule",
1025 		NULL },
1026 
1027 	{ RedirectPort,
1028 		0,
1029 		String,
1030 	        "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1031 	 	" [remote_addr[:remote_port_range]]",
1032 		"redirect a port (or ports) for incoming traffic",
1033 		"redirect_port",
1034 		NULL },
1035 
1036 	{ RedirectProto,
1037 		0,
1038 		String,
1039 	        "proto local_addr [public_addr] [remote_addr]",
1040 		"redirect packets of a given proto",
1041 		"redirect_proto",
1042 		NULL },
1043 
1044 	{ RedirectAddress,
1045 		0,
1046 		String,
1047 	        "local_addr[,...] public_addr",
1048 		"define mapping between local and public addresses",
1049 		"redirect_address",
1050 		NULL },
1051 
1052        { PptpAlias,
1053 		0,
1054 		String,
1055 		"src",
1056 		"define inside machine for PPTP traffic",
1057 		"pptpalias",
1058 		NULL },
1059 
1060 	{ ConfigFile,
1061 		0,
1062 		String,
1063 		"file_name",
1064 		"read options from configuration file",
1065 		"config",
1066 		"f" },
1067 
1068 	{ LogDenied,
1069 		0,
1070 		YesNo,
1071 	        "[yes|no]",
1072 		"enable logging of denied incoming packets",
1073 		"log_denied",
1074 		NULL },
1075 
1076 	{ LogFacility,
1077 		0,
1078 		String,
1079 	        "facility",
1080 		"name of syslog facility to use for logging",
1081 		"log_facility",
1082 		NULL }
1083 
1084 };
1085 
1086 static void ParseOption (const char* option, const char* parms, int cmdLine)
1087 {
1088 	int			i;
1089 	struct OptionInfo*	info;
1090 	int			yesNoValue;
1091 	int			aliasValue;
1092 	int			numValue;
1093 	u_short			uNumValue;
1094 	const char*		strValue;
1095 	struct in_addr		addrValue;
1096 	int			max;
1097 	char*			end;
1098 	CODE* 			fac_record = NULL;
1099 /*
1100  * Find option from table.
1101  */
1102 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
1103 	for (i = 0, info = optionTable; i < max; i++, info++) {
1104 
1105 		if (!strcmp (info->name, option))
1106 			break;
1107 
1108 		if (info->shortName)
1109 			if (!strcmp (info->shortName, option))
1110 				break;
1111 	}
1112 
1113 	if (i >= max) {
1114 
1115 		warnx ("unknown option %s", option);
1116 		Usage ();
1117 	}
1118 
1119 	uNumValue	= 0;
1120 	yesNoValue	= 0;
1121 	numValue	= 0;
1122 	strValue	= NULL;
1123 /*
1124  * Check parameters.
1125  */
1126 	switch (info->parm) {
1127 	case YesNo:
1128 		if (!parms)
1129 			parms = "yes";
1130 
1131 		if (!strcmp (parms, "yes"))
1132 			yesNoValue = 1;
1133 		else
1134 			if (!strcmp (parms, "no"))
1135 				yesNoValue = 0;
1136 			else
1137 				errx (1, "%s needs yes/no parameter", option);
1138 		break;
1139 
1140 	case Service:
1141 		if (!parms)
1142 			errx (1, "%s needs service name or "
1143 				 "port number parameter",
1144 				 option);
1145 
1146 		uNumValue = StrToPort (parms, "divert");
1147 		break;
1148 
1149 	case Numeric:
1150 		if (parms)
1151 			numValue = strtol (parms, &end, 10);
1152 		else
1153 			end = NULL;
1154 
1155 		if (end == parms)
1156 			errx (1, "%s needs numeric parameter", option);
1157 		break;
1158 
1159 	case String:
1160 		strValue = parms;
1161 		if (!strValue)
1162 			errx (1, "%s needs parameter", option);
1163 		break;
1164 
1165 	case None:
1166 		if (parms)
1167 			errx (1, "%s does not take parameters", option);
1168 		break;
1169 
1170 	case Address:
1171 		if (!parms)
1172 			errx (1, "%s needs address/host parameter", option);
1173 
1174 		StrToAddr (parms, &addrValue);
1175 		break;
1176 	}
1177 
1178 	switch (info->type) {
1179 	case PacketAliasOption:
1180 
1181 		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1182 		PacketAliasSetMode (aliasValue, info->packetAliasOpt);
1183 		break;
1184 
1185 	case Verbose:
1186 		verbose = yesNoValue;
1187 		break;
1188 
1189 	case DynamicMode:
1190 		dynamicMode = yesNoValue;
1191 		break;
1192 
1193 	case InPort:
1194 		inPort = uNumValue;
1195 		break;
1196 
1197 	case OutPort:
1198 		outPort = uNumValue;
1199 		break;
1200 
1201 	case Port:
1202 		inOutPort = uNumValue;
1203 		break;
1204 
1205 	case AliasAddress:
1206 		memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
1207 		break;
1208 
1209 	case RedirectPort:
1210 		SetupPortRedirect (strValue);
1211 		break;
1212 
1213 	case RedirectProto:
1214 		SetupProtoRedirect(strValue);
1215 		break;
1216 
1217 	case RedirectAddress:
1218 		SetupAddressRedirect (strValue);
1219 		break;
1220 
1221 	case PptpAlias:
1222 		SetupPptpAlias (strValue);
1223 		break;
1224 
1225 	case ProxyRule:
1226 		PacketAliasProxyRule (strValue);
1227 		break;
1228 
1229 	case InterfaceName:
1230 		if (ifName)
1231 			free (ifName);
1232 
1233 		ifName = strdup (strValue);
1234 		break;
1235 
1236 	case ConfigFile:
1237 		ReadConfigFile (strValue);
1238 		break;
1239 
1240 	case LogDenied:
1241 		logDropped = 1;
1242 		break;
1243 
1244 	case LogFacility:
1245 
1246 		fac_record = facilitynames;
1247 		while (fac_record->c_name != NULL) {
1248 
1249 			if (!strcmp (fac_record->c_name, strValue)) {
1250 
1251 				logFacility = fac_record->c_val;
1252 				break;
1253 
1254 			}
1255 			else
1256 				fac_record++;
1257 		}
1258 
1259 		if(fac_record->c_name == NULL)
1260 			errx(1, "Unknown log facility name: %s", strValue);
1261 
1262 		break;
1263 	}
1264 }
1265 
1266 void ReadConfigFile (const char* fileName)
1267 {
1268 	FILE*	file;
1269 	char	*buf;
1270 	size_t	len;
1271 	char	*ptr, *p;
1272 	char*	option;
1273 
1274 	file = fopen (fileName, "r");
1275 	if (!file)
1276 		err(1, "cannot open config file %s", fileName);
1277 
1278 	while ((buf = fgetln(file, &len)) != NULL) {
1279 		if (buf[len - 1] == '\n')
1280 			buf[len - 1] = '\0';
1281 		else
1282 			errx(1, "config file format error: "
1283 				"last line should end with newline");
1284 
1285 /*
1286  * Check for comments, strip off trailing spaces.
1287  */
1288 		if ((ptr = strchr(buf, '#')))
1289 			*ptr = '\0';
1290 		for (ptr = buf; isspace(*ptr); ++ptr)
1291 			continue;
1292 		if (*ptr == '\0')
1293 			continue;
1294 		for (p = strchr(buf, '\0'); isspace(*--p);)
1295 			continue;
1296 		*++p = '\0';
1297 
1298 /*
1299  * Extract option name.
1300  */
1301 		option = ptr;
1302 		while (*ptr && !isspace (*ptr))
1303 			++ptr;
1304 
1305 		if (*ptr != '\0') {
1306 
1307 			*ptr = '\0';
1308 			++ptr;
1309 		}
1310 /*
1311  * Skip white space between name and parms.
1312  */
1313 		while (*ptr && isspace (*ptr))
1314 			++ptr;
1315 
1316 		ParseOption (option, *ptr ? ptr : NULL, 0);
1317 	}
1318 
1319 	fclose (file);
1320 }
1321 
1322 static void Usage ()
1323 {
1324 	int			i;
1325 	int			max;
1326 	struct OptionInfo*	info;
1327 
1328 	fprintf (stderr, "Recognized options:\n\n");
1329 
1330 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
1331 	for (i = 0, info = optionTable; i < max; i++, info++) {
1332 
1333 		fprintf (stderr, "-%-20s %s\n", info->name,
1334 						info->parmDescription);
1335 
1336 		if (info->shortName)
1337 			fprintf (stderr, "-%-20s %s\n", info->shortName,
1338 							info->parmDescription);
1339 
1340 		fprintf (stderr, "      %s\n\n", info->description);
1341 	}
1342 
1343 	exit (1);
1344 }
1345 
1346 void SetupPptpAlias (const char* parms)
1347 {
1348 	char		buf[128];
1349 	char*		ptr;
1350 	struct in_addr	srcAddr;
1351 
1352 	strcpy (buf, parms);
1353 
1354 /*
1355  * Extract source address.
1356  */
1357 	ptr = strtok (buf, " \t");
1358 	if (!ptr)
1359 		errx(1, "pptpalias: missing src address");
1360 
1361 	StrToAddr (ptr, &srcAddr);
1362 	PacketAliasPptp (srcAddr);
1363 }
1364 
1365 void SetupPortRedirect (const char* parms)
1366 {
1367 	char		buf[128];
1368 	char*		ptr;
1369 	char*		serverPool;
1370 	struct in_addr	localAddr;
1371 	struct in_addr	publicAddr;
1372 	struct in_addr	remoteAddr;
1373 	port_range      portRange;
1374 	u_short         localPort      = 0;
1375 	u_short         publicPort     = 0;
1376 	u_short         remotePort     = 0;
1377 	u_short         numLocalPorts  = 0;
1378 	u_short         numPublicPorts = 0;
1379 	u_short         numRemotePorts = 0;
1380 	int		proto;
1381 	char*		protoName;
1382 	char*		separator;
1383 	int             i;
1384 	struct alias_link *link = NULL;
1385 
1386 	strcpy (buf, parms);
1387 /*
1388  * Extract protocol.
1389  */
1390 	protoName = strtok (buf, " \t");
1391 	if (!protoName)
1392 		errx (1, "redirect_port: missing protocol");
1393 
1394 	proto = StrToProto (protoName);
1395 /*
1396  * Extract local address.
1397  */
1398 	ptr = strtok (NULL, " \t");
1399 	if (!ptr)
1400 		errx (1, "redirect_port: missing local address");
1401 
1402 	separator = strchr(ptr, ',');
1403 	if (separator) {		/* LSNAT redirection syntax. */
1404 		localAddr.s_addr = INADDR_NONE;
1405 		localPort = ~0;
1406 		numLocalPorts = 1;
1407 		serverPool = ptr;
1408 	} else {
1409 		if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1410 			errx (1, "redirect_port: invalid local port range");
1411 
1412 		localPort     = GETLOPORT(portRange);
1413 		numLocalPorts = GETNUMPORTS(portRange);
1414 		serverPool = NULL;
1415 	}
1416 
1417 /*
1418  * Extract public port and optionally address.
1419  */
1420 	ptr = strtok (NULL, " \t");
1421 	if (!ptr)
1422 		errx (1, "redirect_port: missing public port");
1423 
1424 	separator = strchr (ptr, ':');
1425 	if (separator) {
1426 	        if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1427 		        errx (1, "redirect_port: invalid public port range");
1428 	}
1429 	else {
1430 		publicAddr.s_addr = INADDR_ANY;
1431 		if (StrToPortRange (ptr, protoName, &portRange) != 0)
1432 		        errx (1, "redirect_port: invalid public port range");
1433 	}
1434 
1435 	publicPort     = GETLOPORT(portRange);
1436 	numPublicPorts = GETNUMPORTS(portRange);
1437 
1438 /*
1439  * Extract remote address and optionally port.
1440  */
1441 	ptr = strtok (NULL, " \t");
1442 	if (ptr) {
1443 		separator = strchr (ptr, ':');
1444 		if (separator) {
1445 		        if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1446 			        errx (1, "redirect_port: invalid remote port range");
1447 		} else {
1448 		        SETLOPORT(portRange, 0);
1449 			SETNUMPORTS(portRange, 1);
1450 			StrToAddr (ptr, &remoteAddr);
1451 		}
1452 	}
1453 	else {
1454 	        SETLOPORT(portRange, 0);
1455 		SETNUMPORTS(portRange, 1);
1456 		remoteAddr.s_addr = INADDR_ANY;
1457 	}
1458 
1459 	remotePort     = GETLOPORT(portRange);
1460 	numRemotePorts = GETNUMPORTS(portRange);
1461 
1462 /*
1463  * Make sure port ranges match up, then add the redirect ports.
1464  */
1465 	if (numLocalPorts != numPublicPorts)
1466 	        errx (1, "redirect_port: port ranges must be equal in size");
1467 
1468 	/* Remote port range is allowed to be '0' which means all ports. */
1469 	if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1470 	        errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1471 
1472 	for (i = 0 ; i < numPublicPorts ; ++i) {
1473 	        /* If remotePort is all ports, set it to 0. */
1474 	        u_short remotePortCopy = remotePort + i;
1475 	        if (numRemotePorts == 1 && remotePort == 0)
1476 		        remotePortCopy = 0;
1477 
1478 		link = PacketAliasRedirectPort (localAddr,
1479 						htons(localPort + i),
1480 						remoteAddr,
1481 						htons(remotePortCopy),
1482 						publicAddr,
1483 						htons(publicPort + i),
1484 						proto);
1485 	}
1486 
1487 /*
1488  * Setup LSNAT server pool.
1489  */
1490 	if (serverPool != NULL && link != NULL) {
1491 		ptr = strtok(serverPool, ",");
1492 		while (ptr != NULL) {
1493 			if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1494 				errx(1, "redirect_port: invalid local port range");
1495 
1496 			localPort = GETLOPORT(portRange);
1497 			if (GETNUMPORTS(portRange) != 1)
1498 				errx(1, "redirect_port: local port must be single in this context");
1499 			PacketAliasAddServer(link, localAddr, htons(localPort));
1500 			ptr = strtok(NULL, ",");
1501 		}
1502 	}
1503 }
1504 
1505 void
1506 SetupProtoRedirect(const char* parms)
1507 {
1508 	char		buf[128];
1509 	char*		ptr;
1510 	struct in_addr	localAddr;
1511 	struct in_addr	publicAddr;
1512 	struct in_addr	remoteAddr;
1513 	int		proto;
1514 	char*		protoName;
1515 	struct protoent *protoent;
1516 
1517 	strcpy (buf, parms);
1518 /*
1519  * Extract protocol.
1520  */
1521 	protoName = strtok(buf, " \t");
1522 	if (!protoName)
1523 		errx(1, "redirect_proto: missing protocol");
1524 
1525 	protoent = getprotobyname(protoName);
1526 	if (protoent == NULL)
1527 		errx(1, "redirect_proto: unknown protocol %s", protoName);
1528 	else
1529 		proto = protoent->p_proto;
1530 /*
1531  * Extract local address.
1532  */
1533 	ptr = strtok(NULL, " \t");
1534 	if (!ptr)
1535 		errx(1, "redirect_proto: missing local address");
1536 	else
1537 		StrToAddr(ptr, &localAddr);
1538 /*
1539  * Extract optional public address.
1540  */
1541 	ptr = strtok(NULL, " \t");
1542 	if (ptr)
1543 		StrToAddr(ptr, &publicAddr);
1544 	else
1545 		publicAddr.s_addr = INADDR_ANY;
1546 /*
1547  * Extract optional remote address.
1548  */
1549 	ptr = strtok(NULL, " \t");
1550 	if (ptr)
1551 		StrToAddr(ptr, &remoteAddr);
1552 	else
1553 		remoteAddr.s_addr = INADDR_ANY;
1554 /*
1555  * Create aliasing link.
1556  */
1557 	(void)PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr,
1558 				       proto);
1559 }
1560 
1561 void SetupAddressRedirect (const char* parms)
1562 {
1563 	char		buf[128];
1564 	char*		ptr;
1565 	char*		separator;
1566 	struct in_addr	localAddr;
1567 	struct in_addr	publicAddr;
1568 	char*		serverPool;
1569 	struct alias_link *link;
1570 
1571 	strcpy (buf, parms);
1572 /*
1573  * Extract local address.
1574  */
1575 	ptr = strtok (buf, " \t");
1576 	if (!ptr)
1577 		errx (1, "redirect_address: missing local address");
1578 
1579 	separator = strchr(ptr, ',');
1580 	if (separator) {		/* LSNAT redirection syntax. */
1581 		localAddr.s_addr = INADDR_NONE;
1582 		serverPool = ptr;
1583 	} else {
1584 		StrToAddr (ptr, &localAddr);
1585 		serverPool = NULL;
1586 	}
1587 /*
1588  * Extract public address.
1589  */
1590 	ptr = strtok (NULL, " \t");
1591 	if (!ptr)
1592 		errx (1, "redirect_address: missing public address");
1593 
1594 	StrToAddr (ptr, &publicAddr);
1595 	link = PacketAliasRedirectAddr(localAddr, publicAddr);
1596 
1597 /*
1598  * Setup LSNAT server pool.
1599  */
1600 	if (serverPool != NULL && link != NULL) {
1601 		ptr = strtok(serverPool, ",");
1602 		while (ptr != NULL) {
1603 			StrToAddr(ptr, &localAddr);
1604 			PacketAliasAddServer(link, localAddr, htons(~0));
1605 			ptr = strtok(NULL, ",");
1606 		}
1607 	}
1608 }
1609 
1610 void StrToAddr (const char* str, struct in_addr* addr)
1611 {
1612 	struct hostent* hp;
1613 
1614 	if (inet_aton (str, addr))
1615 		return;
1616 
1617 	hp = gethostbyname (str);
1618 	if (!hp)
1619 		errx (1, "unknown host %s", str);
1620 
1621 	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1622 }
1623 
1624 u_short StrToPort (const char* str, const char* proto)
1625 {
1626 	u_short		port;
1627 	struct servent*	sp;
1628 	char*		end;
1629 
1630 	port = strtol (str, &end, 10);
1631 	if (end != str)
1632 		return htons (port);
1633 
1634 	sp = getservbyname (str, proto);
1635 	if (!sp)
1636 		errx (1, "unknown service %s/%s", str, proto);
1637 
1638 	return sp->s_port;
1639 }
1640 
1641 int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1642 {
1643 	char*           sep;
1644 	struct servent*	sp;
1645 	char*		end;
1646 	u_short         loPort;
1647 	u_short         hiPort;
1648 
1649 	/* First see if this is a service, return corresponding port if so. */
1650 	sp = getservbyname (str,proto);
1651 	if (sp) {
1652 	        SETLOPORT(*portRange, ntohs(sp->s_port));
1653 		SETNUMPORTS(*portRange, 1);
1654 		return 0;
1655 	}
1656 
1657 	/* Not a service, see if it's a single port or port range. */
1658 	sep = strchr (str, '-');
1659 	if (sep == NULL) {
1660 	        SETLOPORT(*portRange, strtol(str, &end, 10));
1661 		if (end != str) {
1662 		        /* Single port. */
1663 		        SETNUMPORTS(*portRange, 1);
1664 			return 0;
1665 		}
1666 
1667 		/* Error in port range field. */
1668 		errx (1, "unknown service %s/%s", str, proto);
1669 	}
1670 
1671 	/* Port range, get the values and sanity check. */
1672 	sscanf (str, "%hu-%hu", &loPort, &hiPort);
1673 	SETLOPORT(*portRange, loPort);
1674 	SETNUMPORTS(*portRange, 0);	/* Error by default */
1675 	if (loPort <= hiPort)
1676 	        SETNUMPORTS(*portRange, hiPort - loPort + 1);
1677 
1678 	if (GETNUMPORTS(*portRange) == 0)
1679 	        errx (1, "invalid port range %s", str);
1680 
1681 	return 0;
1682 }
1683 
1684 
1685 int StrToProto (const char* str)
1686 {
1687 	if (!strcmp (str, "tcp"))
1688 		return IPPROTO_TCP;
1689 
1690 	if (!strcmp (str, "udp"))
1691 		return IPPROTO_UDP;
1692 
1693 	errx (1, "unknown protocol %s. Expected tcp or udp", str);
1694 }
1695 
1696 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
1697 {
1698 	char*	ptr;
1699 
1700 	ptr = strchr (str, ':');
1701 	if (!ptr)
1702 		errx (1, "%s is missing port number", str);
1703 
1704 	*ptr = '\0';
1705 	++ptr;
1706 
1707 	StrToAddr (str, addr);
1708 	return StrToPortRange (ptr, proto, portRange);
1709 }
1710