xref: /freebsd/sbin/natd/natd.c (revision 7773002178c8dbc52b44e4d705f07706409af8e4)
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 
13 #include <sys/cdefs.h>
14 __FBSDID("$FreeBSD$");
15 
16 #define SYSLOG_NAMES
17 
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/sysctl.h>
21 #include <sys/time.h>
22 
23 #include <netinet/in.h>
24 #include <netinet/in_systm.h>
25 #include <netinet/ip.h>
26 #include <machine/in_cksum.h>
27 #include <netinet/tcp.h>
28 #include <netinet/udp.h>
29 #include <netinet/ip_icmp.h>
30 #include <net/if.h>
31 #include <net/if_dl.h>
32 #include <net/route.h>
33 #include <arpa/inet.h>
34 
35 #include <alias.h>
36 #include <ctype.h>
37 #include <err.h>
38 #include <errno.h>
39 #include <netdb.h>
40 #include <signal.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <syslog.h>
45 #include <unistd.h>
46 
47 #include "natd.h"
48 
49 /*
50  * Default values for input and output
51  * divert socket ports.
52  */
53 
54 #define	DEFAULT_SERVICE	"natd"
55 
56 /*
57  * Definition of a port range, and macros to deal with values.
58  * FORMAT:  HI 16-bits == first port in range, 0 == all ports.
59  *          LO 16-bits == number of ports in range
60  * NOTES:   - Port values are not stored in network byte order.
61  */
62 
63 typedef u_long port_range;
64 
65 #define GETLOPORT(x)     ((x) >> 0x10)
66 #define GETNUMPORTS(x)   ((x) & 0x0000ffff)
67 #define GETHIPORT(x)     (GETLOPORT((x)) + GETNUMPORTS((x)))
68 
69 /* Set y to be the low-port value in port_range variable x. */
70 #define SETLOPORT(x,y)   ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
71 
72 /* Set y to be the number of ports in port_range variable x. */
73 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
74 
75 /*
76  * Function prototypes.
77  */
78 
79 static void	DoAliasing (int fd, int direction);
80 static void	DaemonMode (void);
81 static void	HandleRoutingInfo (int fd);
82 static void	Usage (void);
83 static char*	FormatPacket (struct ip*);
84 static void	PrintPacket (struct ip*);
85 static void	SyslogPacket (struct ip*, int priority, const char *label);
86 static void	SetAliasAddressFromIfName (const char *ifName);
87 static void	InitiateShutdown (int);
88 static void	Shutdown (int);
89 static void	RefreshAddr (int);
90 static void	ParseOption (const char* option, const char* parms);
91 static void	ReadConfigFile (const char* fileName);
92 static void	SetupPortRedirect (const char* parms);
93 static void	SetupProtoRedirect(const char* parms);
94 static void	SetupAddressRedirect (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	SetupPunchFW(const char *strValue);
102 static void	SetupSkinnyPort(const char *strValue);
103 
104 /*
105  * Globals.
106  */
107 
108 static	int			verbose;
109 static 	int			background;
110 static	int			running;
111 static	int			assignAliasAddr;
112 static	char*			ifName;
113 static  int			ifIndex;
114 static	u_short			inPort;
115 static	u_short			outPort;
116 static	u_short			inOutPort;
117 static	struct in_addr		aliasAddr;
118 static 	int			dynamicMode;
119 static  int			ifMTU;
120 static	int			aliasOverhead;
121 static 	int			icmpSock;
122 static  int			dropIgnoredIncoming;
123 static  int			logDropped;
124 static	int			logFacility;
125 static	int			logIpfwDenied;
126 static	char*			pidName;
127 
128 int main (int argc, char** argv)
129 {
130 	int			divertIn;
131 	int			divertOut;
132 	int			divertInOut;
133 	int			routeSock;
134 	struct sockaddr_in	addr;
135 	fd_set			readMask;
136 	int			fdMax;
137 /*
138  * Initialize packet aliasing software.
139  * Done already here to be able to alter option bits
140  * during command line and configuration file processing.
141  */
142 	PacketAliasInit ();
143 /*
144  * Parse options.
145  */
146 	inPort			= 0;
147 	outPort			= 0;
148 	verbose 		= 0;
149 	inOutPort		= 0;
150 	ifName			= NULL;
151 	ifMTU			= -1;
152 	background		= 0;
153 	running			= 1;
154 	assignAliasAddr		= 0;
155 	aliasAddr.s_addr	= INADDR_NONE;
156 	aliasOverhead		= 12;
157 	dynamicMode		= 0;
158  	logDropped		= 0;
159  	logFacility		= LOG_DAEMON;
160 	logIpfwDenied		= -1;
161 	pidName			= PIDFILE;
162 
163 	ParseArgs (argc, argv);
164 /*
165  * Log ipfw(8) denied packets by default in verbose mode.
166  */
167 	if (logIpfwDenied == -1)
168 		logIpfwDenied = verbose;
169 /*
170  * Open syslog channel.
171  */
172 	openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
173 		 logFacility);
174 /*
175  * If not doing the transparent proxying only,
176  * check that valid aliasing address has been given.
177  */
178 	if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL &&
179 	    !(PacketAliasSetMode(0,0) & PKT_ALIAS_PROXY_ONLY))
180 		errx (1, "aliasing address not given");
181 
182 	if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL)
183 		errx (1, "both alias address and interface "
184 			 "name are not allowed");
185 /*
186  * Check that valid port number is known.
187  */
188 	if (inPort != 0 || outPort != 0)
189 		if (inPort == 0 || outPort == 0)
190 			errx (1, "both input and output ports are required");
191 
192 	if (inPort == 0 && outPort == 0 && inOutPort == 0)
193 		ParseOption ("port", DEFAULT_SERVICE);
194 
195 /*
196  * Check if ignored packets should be dropped.
197  */
198 	dropIgnoredIncoming = PacketAliasSetMode (0, 0);
199 	dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
200 /*
201  * Create divert sockets. Use only one socket if -p was specified
202  * on command line. Otherwise, create separate sockets for
203  * outgoing and incoming connnections.
204  */
205 	if (inOutPort) {
206 
207 		divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
208 		if (divertInOut == -1)
209 			Quit ("Unable to create divert socket.");
210 
211 		divertIn  = -1;
212 		divertOut = -1;
213 /*
214  * Bind socket.
215  */
216 
217 		addr.sin_family		= AF_INET;
218 		addr.sin_addr.s_addr	= INADDR_ANY;
219 		addr.sin_port		= inOutPort;
220 
221 		if (bind (divertInOut,
222 			  (struct sockaddr*) &addr,
223 			  sizeof addr) == -1)
224 			Quit ("Unable to bind divert socket.");
225 	}
226 	else {
227 
228 		divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
229 		if (divertIn == -1)
230 			Quit ("Unable to create incoming divert socket.");
231 
232 		divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
233 		if (divertOut == -1)
234 			Quit ("Unable to create outgoing divert socket.");
235 
236 		divertInOut = -1;
237 
238 /*
239  * Bind divert sockets.
240  */
241 
242 		addr.sin_family		= AF_INET;
243 		addr.sin_addr.s_addr	= INADDR_ANY;
244 		addr.sin_port		= inPort;
245 
246 		if (bind (divertIn,
247 			  (struct sockaddr*) &addr,
248 			  sizeof addr) == -1)
249 			Quit ("Unable to bind incoming divert socket.");
250 
251 		addr.sin_family		= AF_INET;
252 		addr.sin_addr.s_addr	= INADDR_ANY;
253 		addr.sin_port		= outPort;
254 
255 		if (bind (divertOut,
256 			  (struct sockaddr*) &addr,
257 			  sizeof addr) == -1)
258 			Quit ("Unable to bind outgoing divert socket.");
259 	}
260 /*
261  * Create routing socket if interface name specified and in dynamic mode.
262  */
263 	routeSock = -1;
264 	if (ifName) {
265 		if (dynamicMode) {
266 
267 			routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
268 			if (routeSock == -1)
269 				Quit ("Unable to create routing info socket.");
270 
271 			assignAliasAddr = 1;
272 		}
273 		else
274 			SetAliasAddressFromIfName (ifName);
275 	}
276 /*
277  * Create socket for sending ICMP messages.
278  */
279 	icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
280 	if (icmpSock == -1)
281 		Quit ("Unable to create ICMP socket.");
282 
283 /*
284  * And disable reads for the socket, otherwise it slowly fills
285  * up with received icmps which we do not use.
286  */
287 	shutdown(icmpSock, SHUT_RD);
288 
289 /*
290  * Become a daemon unless verbose mode was requested.
291  */
292 	if (!verbose)
293 		DaemonMode ();
294 /*
295  * Catch signals to manage shutdown and
296  * refresh of interface address.
297  */
298 	siginterrupt(SIGTERM, 1);
299 	siginterrupt(SIGHUP, 1);
300 	signal (SIGTERM, InitiateShutdown);
301 	signal (SIGHUP, RefreshAddr);
302 /*
303  * Set alias address if it has been given.
304  */
305 	if (aliasAddr.s_addr != INADDR_NONE)
306 		PacketAliasSetAddress (aliasAddr);
307 /*
308  * We need largest descriptor number for select.
309  */
310 
311 	fdMax = -1;
312 
313 	if (divertIn > fdMax)
314 		fdMax = divertIn;
315 
316 	if (divertOut > fdMax)
317 		fdMax = divertOut;
318 
319 	if (divertInOut > fdMax)
320 		fdMax = divertInOut;
321 
322 	if (routeSock > fdMax)
323 		fdMax = routeSock;
324 
325 	while (running) {
326 
327 		if (divertInOut != -1 && !ifName) {
328 /*
329  * When using only one socket, just call
330  * DoAliasing repeatedly to process packets.
331  */
332 			DoAliasing (divertInOut, DONT_KNOW);
333 			continue;
334 		}
335 /*
336  * Build read mask from socket descriptors to select.
337  */
338 		FD_ZERO (&readMask);
339 /*
340  * Check if new packets are available.
341  */
342 		if (divertIn != -1)
343 			FD_SET (divertIn, &readMask);
344 
345 		if (divertOut != -1)
346 			FD_SET (divertOut, &readMask);
347 
348 		if (divertInOut != -1)
349 			FD_SET (divertInOut, &readMask);
350 /*
351  * Routing info is processed always.
352  */
353 		if (routeSock != -1)
354 			FD_SET (routeSock, &readMask);
355 
356 		if (select (fdMax + 1,
357 			    &readMask,
358 			    NULL,
359 			    NULL,
360 			    NULL) == -1) {
361 
362 			if (errno == EINTR)
363 				continue;
364 
365 			Quit ("Select failed.");
366 		}
367 
368 		if (divertIn != -1)
369 			if (FD_ISSET (divertIn, &readMask))
370 				DoAliasing (divertIn, INPUT);
371 
372 		if (divertOut != -1)
373 			if (FD_ISSET (divertOut, &readMask))
374 				DoAliasing (divertOut, OUTPUT);
375 
376 		if (divertInOut != -1)
377 			if (FD_ISSET (divertInOut, &readMask))
378 				DoAliasing (divertInOut, DONT_KNOW);
379 
380 		if (routeSock != -1)
381 			if (FD_ISSET (routeSock, &readMask))
382 				HandleRoutingInfo (routeSock);
383 	}
384 
385 	if (background)
386 		unlink (pidName);
387 
388 	return 0;
389 }
390 
391 static void DaemonMode ()
392 {
393 	FILE*	pidFile;
394 
395 	daemon (0, 0);
396 	background = 1;
397 
398 	pidFile = fopen (pidName, "w");
399 	if (pidFile) {
400 
401 		fprintf (pidFile, "%d\n", getpid ());
402 		fclose (pidFile);
403 	}
404 }
405 
406 static void ParseArgs (int argc, char** argv)
407 {
408 	int		arg;
409 	char*		opt;
410 	char		parmBuf[256];
411 	int		len; /* bounds checking */
412 
413 	for (arg = 1; arg < argc; arg++) {
414 
415 		opt  = argv[arg];
416 		if (*opt != '-') {
417 
418 			warnx ("invalid option %s", opt);
419 			Usage ();
420 		}
421 
422 		parmBuf[0] = '\0';
423 		len = 0;
424 
425 		while (arg < argc - 1) {
426 
427 			if (argv[arg + 1][0] == '-')
428 				break;
429 
430 			if (len) {
431 				strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
432 				len += strlen(parmBuf + len);
433 			}
434 
435 			++arg;
436 			strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
437 			len += strlen(parmBuf + len);
438 
439 		}
440 
441 		ParseOption (opt + 1, (len ? parmBuf : NULL));
442 
443 	}
444 }
445 
446 static void DoAliasing (int fd, int direction)
447 {
448 	int			bytes;
449 	int			origBytes;
450 	char			buf[IP_MAXPACKET];
451 	struct sockaddr_in	addr;
452 	int			wrote;
453 	int			status;
454 	int			addrSize;
455 	struct ip*		ip;
456 	char			msgBuf[80];
457 
458 	if (assignAliasAddr) {
459 
460 		SetAliasAddressFromIfName (ifName);
461 		assignAliasAddr = 0;
462 	}
463 /*
464  * Get packet from socket.
465  */
466 	addrSize  = sizeof addr;
467 	origBytes = recvfrom (fd,
468 			      buf,
469 			      sizeof buf,
470 			      0,
471 			      (struct sockaddr*) &addr,
472 			      &addrSize);
473 
474 	if (origBytes == -1) {
475 
476 		if (errno != EINTR)
477 			Warn ("read from divert socket failed");
478 
479 		return;
480 	}
481 /*
482  * This is an IP packet.
483  */
484 	ip = (struct ip*) buf;
485 	if (direction == DONT_KNOW) {
486 		if (addr.sin_addr.s_addr == INADDR_ANY)
487 			direction = OUTPUT;
488 		else
489 			direction = INPUT;
490 	}
491 
492 	if (verbose) {
493 /*
494  * Print packet direction and protocol type.
495  */
496 		printf (direction == OUTPUT ? "Out " : "In  ");
497 
498 		switch (ip->ip_p) {
499 		case IPPROTO_TCP:
500 			printf ("[TCP]  ");
501 			break;
502 
503 		case IPPROTO_UDP:
504 			printf ("[UDP]  ");
505 			break;
506 
507 		case IPPROTO_ICMP:
508 			printf ("[ICMP] ");
509 			break;
510 
511 		default:
512 			printf ("[%d]    ", ip->ip_p);
513 			break;
514 		}
515 /*
516  * Print addresses.
517  */
518 		PrintPacket (ip);
519 	}
520 
521 	if (direction == OUTPUT) {
522 /*
523  * Outgoing packets. Do aliasing.
524  */
525 		PacketAliasOut (buf, IP_MAXPACKET);
526 	}
527 	else {
528 
529 /*
530  * Do aliasing.
531  */
532 		status = PacketAliasIn (buf, IP_MAXPACKET);
533 		if (status == PKT_ALIAS_IGNORED &&
534 		    dropIgnoredIncoming) {
535 
536 			if (verbose)
537 				printf (" dropped.\n");
538 
539 			if (logDropped)
540 				SyslogPacket (ip, LOG_WARNING, "denied");
541 
542 			return;
543 		}
544 	}
545 /*
546  * Length might have changed during aliasing.
547  */
548 	bytes = ntohs (ip->ip_len);
549 /*
550  * Update alias overhead size for outgoing packets.
551  */
552 	if (direction == OUTPUT &&
553 	    bytes - origBytes > aliasOverhead)
554 		aliasOverhead = bytes - origBytes;
555 
556 	if (verbose) {
557 
558 /*
559  * Print addresses after aliasing.
560  */
561 		printf (" aliased to\n");
562 		printf ("           ");
563 		PrintPacket (ip);
564 		printf ("\n");
565 	}
566 
567 /*
568  * Put packet back for processing.
569  */
570 	wrote = sendto (fd,
571 		        buf,
572 	    		bytes,
573 	    		0,
574 	    		(struct sockaddr*) &addr,
575 	    		sizeof addr);
576 
577 	if (wrote != bytes) {
578 
579 		if (errno == EMSGSIZE) {
580 
581 			if (direction == OUTPUT &&
582 			    ifMTU != -1)
583 				SendNeedFragIcmp (icmpSock,
584 						  (struct ip*) buf,
585 						  ifMTU - aliasOverhead);
586 		}
587 		else if (errno == EACCES && logIpfwDenied) {
588 
589 			sprintf (msgBuf, "failed to write packet back");
590 			Warn (msgBuf);
591 		}
592 	}
593 }
594 
595 static void HandleRoutingInfo (int fd)
596 {
597 	int			bytes;
598 	struct if_msghdr	ifMsg;
599 /*
600  * Get packet from socket.
601  */
602 	bytes = read (fd, &ifMsg, sizeof ifMsg);
603 	if (bytes == -1) {
604 
605 		Warn ("read from routing socket failed");
606 		return;
607 	}
608 
609 	if (ifMsg.ifm_version != RTM_VERSION) {
610 
611 		Warn ("unexpected packet read from routing socket");
612 		return;
613 	}
614 
615 	if (verbose)
616 		printf ("Routing message %#x received.\n", ifMsg.ifm_type);
617 
618 	if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO) &&
619 	    ifMsg.ifm_index == ifIndex) {
620 		if (verbose)
621 			printf("Interface address/MTU has probably changed.\n");
622 		assignAliasAddr = 1;
623 	}
624 }
625 
626 static void PrintPacket (struct ip* ip)
627 {
628 	printf ("%s", FormatPacket (ip));
629 }
630 
631 static void SyslogPacket (struct ip* ip, int priority, const char *label)
632 {
633 	syslog (priority, "%s %s", label, FormatPacket (ip));
634 }
635 
636 static char* FormatPacket (struct ip* ip)
637 {
638 	static char	buf[256];
639 	struct tcphdr*	tcphdr;
640 	struct udphdr*	udphdr;
641 	struct icmp*	icmphdr;
642 	char		src[20];
643 	char		dst[20];
644 
645 	strcpy (src, inet_ntoa (ip->ip_src));
646 	strcpy (dst, inet_ntoa (ip->ip_dst));
647 
648 	switch (ip->ip_p) {
649 	case IPPROTO_TCP:
650 		tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
651 		sprintf (buf, "[TCP] %s:%d -> %s:%d",
652 			      src,
653 			      ntohs (tcphdr->th_sport),
654 			      dst,
655 			      ntohs (tcphdr->th_dport));
656 		break;
657 
658 	case IPPROTO_UDP:
659 		udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
660 		sprintf (buf, "[UDP] %s:%d -> %s:%d",
661 			      src,
662 			      ntohs (udphdr->uh_sport),
663 			      dst,
664 			      ntohs (udphdr->uh_dport));
665 		break;
666 
667 	case IPPROTO_ICMP:
668 		icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
669 		sprintf (buf, "[ICMP] %s -> %s %u(%u)",
670 			      src,
671 			      dst,
672 			      icmphdr->icmp_type,
673 			      icmphdr->icmp_code);
674 		break;
675 
676 	default:
677 		sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
678 		break;
679 	}
680 
681 	return buf;
682 }
683 
684 static void
685 SetAliasAddressFromIfName(const char *ifn)
686 {
687 	size_t needed;
688 	int mib[6];
689 	char *buf, *lim, *next;
690 	struct if_msghdr *ifm;
691 	struct ifa_msghdr *ifam;
692 	struct sockaddr_dl *sdl;
693 	struct sockaddr_in *sin;
694 
695 	mib[0] = CTL_NET;
696 	mib[1] = PF_ROUTE;
697 	mib[2] = 0;
698 	mib[3] = AF_INET;	/* Only IP addresses please */
699 	mib[4] = NET_RT_IFLIST;
700 	mib[5] = 0;		/* ifIndex??? */
701 /*
702  * Get interface data.
703  */
704 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
705 		err(1, "iflist-sysctl-estimate");
706 	if ((buf = malloc(needed)) == NULL)
707 		errx(1, "malloc failed");
708 	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
709 		err(1, "iflist-sysctl-get");
710 	lim = buf + needed;
711 /*
712  * Loop through interfaces until one with
713  * given name is found. This is done to
714  * find correct interface index for routing
715  * message processing.
716  */
717 	ifIndex	= 0;
718 	next = buf;
719 	while (next < lim) {
720 		ifm = (struct if_msghdr *)next;
721 		next += ifm->ifm_msglen;
722 		if (ifm->ifm_version != RTM_VERSION) {
723 			if (verbose)
724 				warnx("routing message version %d "
725 				      "not understood", ifm->ifm_version);
726 			continue;
727 		}
728 		if (ifm->ifm_type == RTM_IFINFO) {
729 			sdl = (struct sockaddr_dl *)(ifm + 1);
730 			if (strlen(ifn) == sdl->sdl_nlen &&
731 			    strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
732 				ifIndex = ifm->ifm_index;
733 				ifMTU = ifm->ifm_data.ifi_mtu;
734 				break;
735 			}
736 		}
737 	}
738 	if (!ifIndex)
739 		errx(1, "unknown interface name %s", ifn);
740 /*
741  * Get interface address.
742  */
743 	sin = NULL;
744 	while (next < lim) {
745 		ifam = (struct ifa_msghdr *)next;
746 		next += ifam->ifam_msglen;
747 		if (ifam->ifam_version != RTM_VERSION) {
748 			if (verbose)
749 				warnx("routing message version %d "
750 				      "not understood", ifam->ifam_version);
751 			continue;
752 		}
753 		if (ifam->ifam_type != RTM_NEWADDR)
754 			break;
755 		if (ifam->ifam_addrs & RTA_IFA) {
756 			int i;
757 			char *cp = (char *)(ifam + 1);
758 
759 #define ROUNDUP(a) \
760 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
761 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
762 
763 			for (i = 1; i < RTA_IFA; i <<= 1)
764 				if (ifam->ifam_addrs & i)
765 					ADVANCE(cp, (struct sockaddr *)cp);
766 			if (((struct sockaddr *)cp)->sa_family == AF_INET) {
767 				sin = (struct sockaddr_in *)cp;
768 				break;
769 			}
770 		}
771 	}
772 	if (sin == NULL)
773 		errx(1, "%s: cannot get interface address", ifn);
774 
775 	PacketAliasSetAddress(sin->sin_addr);
776 	syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
777 	       inet_ntoa(sin->sin_addr), ifMTU);
778 
779 	free(buf);
780 }
781 
782 void Quit (const char* msg)
783 {
784 	Warn (msg);
785 	exit (1);
786 }
787 
788 void Warn (const char* msg)
789 {
790 	if (background)
791 		syslog (LOG_ALERT, "%s (%m)", msg);
792 	else
793 		warn ("%s", msg);
794 }
795 
796 static void RefreshAddr (int sig)
797 {
798 	if (ifName)
799 		assignAliasAddr = 1;
800 }
801 
802 static void InitiateShutdown (int sig)
803 {
804 /*
805  * Start timer to allow kernel gracefully
806  * shutdown existing connections when system
807  * is shut down.
808  */
809 	siginterrupt(SIGALRM, 1);
810 	signal (SIGALRM, Shutdown);
811 	alarm (10);
812 }
813 
814 static void Shutdown (int sig)
815 {
816 	running = 0;
817 }
818 
819 /*
820  * Different options recognized by this program.
821  */
822 
823 enum Option {
824 
825 	PacketAliasOption,
826 	Verbose,
827 	InPort,
828 	OutPort,
829 	Port,
830 	AliasAddress,
831 	TargetAddress,
832 	InterfaceName,
833 	RedirectPort,
834 	RedirectProto,
835 	RedirectAddress,
836 	ConfigFile,
837 	DynamicMode,
838 	ProxyRule,
839  	LogDenied,
840  	LogFacility,
841 	PunchFW,
842 	SkinnyPort,
843 	LogIpfwDenied,
844 	PidFile
845 };
846 
847 enum Param {
848 
849 	YesNo,
850 	Numeric,
851 	String,
852 	None,
853 	Address,
854 	Service
855 };
856 
857 /*
858  * Option information structure (used by ParseOption).
859  */
860 
861 struct OptionInfo {
862 
863 	enum Option		type;
864 	int			packetAliasOpt;
865 	enum Param		parm;
866 	const char*		parmDescription;
867 	const char*		description;
868 	const char*		name;
869 	const char*		shortName;
870 };
871 
872 /*
873  * Table of known options.
874  */
875 
876 static struct OptionInfo optionTable[] = {
877 
878 	{ PacketAliasOption,
879 		PKT_ALIAS_UNREGISTERED_ONLY,
880 		YesNo,
881 		"[yes|no]",
882 		"alias only unregistered addresses",
883 		"unregistered_only",
884 		"u" },
885 
886 	{ PacketAliasOption,
887 		PKT_ALIAS_LOG,
888 		YesNo,
889 		"[yes|no]",
890 		"enable logging",
891 		"log",
892 		"l" },
893 
894 	{ PacketAliasOption,
895 		PKT_ALIAS_PROXY_ONLY,
896 		YesNo,
897 		"[yes|no]",
898 		"proxy only",
899 		"proxy_only",
900 		NULL },
901 
902 	{ PacketAliasOption,
903 		PKT_ALIAS_REVERSE,
904 		YesNo,
905 		"[yes|no]",
906 		"operate in reverse mode",
907 		"reverse",
908 		NULL },
909 
910 	{ PacketAliasOption,
911 		PKT_ALIAS_DENY_INCOMING,
912 		YesNo,
913 		"[yes|no]",
914 		"allow incoming connections",
915 		"deny_incoming",
916 		"d" },
917 
918 	{ PacketAliasOption,
919 		PKT_ALIAS_USE_SOCKETS,
920 		YesNo,
921 		"[yes|no]",
922 		"use sockets to inhibit port conflict",
923 		"use_sockets",
924 		"s" },
925 
926 	{ PacketAliasOption,
927 		PKT_ALIAS_SAME_PORTS,
928 		YesNo,
929 		"[yes|no]",
930 		"try to keep original port numbers for connections",
931 		"same_ports",
932 		"m" },
933 
934 	{ Verbose,
935 		0,
936 		YesNo,
937 		"[yes|no]",
938 		"verbose mode, dump packet information",
939 		"verbose",
940 		"v" },
941 
942 	{ DynamicMode,
943 		0,
944 		YesNo,
945 		"[yes|no]",
946 		"dynamic mode, automatically detect interface address changes",
947 		"dynamic",
948 		NULL },
949 
950 	{ InPort,
951 		0,
952 		Service,
953 		"number|service_name",
954 		"set port for incoming packets",
955 		"in_port",
956 		"i" },
957 
958 	{ OutPort,
959 		0,
960 		Service,
961 		"number|service_name",
962 		"set port for outgoing packets",
963 		"out_port",
964 		"o" },
965 
966 	{ Port,
967 		0,
968 		Service,
969 		"number|service_name",
970 		"set port (defaults to natd/divert)",
971 		"port",
972 		"p" },
973 
974 	{ AliasAddress,
975 		0,
976 		Address,
977 		"x.x.x.x",
978 		"address to use for aliasing",
979 		"alias_address",
980 		"a" },
981 
982 	{ TargetAddress,
983 		0,
984 		Address,
985 		"x.x.x.x",
986 		"address to use for incoming sessions",
987 		"target_address",
988 		"t" },
989 
990 	{ InterfaceName,
991 		0,
992 		String,
993 	        "network_if_name",
994 		"take aliasing address from interface",
995 		"interface",
996 		"n" },
997 
998 	{ ProxyRule,
999 		0,
1000 		String,
1001 	        "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1002 		"a.b.c.d:yyyy",
1003 		"add transparent proxying / destination NAT",
1004 		"proxy_rule",
1005 		NULL },
1006 
1007 	{ RedirectPort,
1008 		0,
1009 		String,
1010 	        "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1011 	 	" [remote_addr[:remote_port_range]]",
1012 		"redirect a port (or ports) for incoming traffic",
1013 		"redirect_port",
1014 		NULL },
1015 
1016 	{ RedirectProto,
1017 		0,
1018 		String,
1019 	        "proto local_addr [public_addr] [remote_addr]",
1020 		"redirect packets of a given proto",
1021 		"redirect_proto",
1022 		NULL },
1023 
1024 	{ RedirectAddress,
1025 		0,
1026 		String,
1027 	        "local_addr[,...] public_addr",
1028 		"define mapping between local and public addresses",
1029 		"redirect_address",
1030 		NULL },
1031 
1032 	{ ConfigFile,
1033 		0,
1034 		String,
1035 		"file_name",
1036 		"read options from configuration file",
1037 		"config",
1038 		"f" },
1039 
1040 	{ LogDenied,
1041 		0,
1042 		YesNo,
1043 	        "[yes|no]",
1044 		"enable logging of denied incoming packets",
1045 		"log_denied",
1046 		NULL },
1047 
1048 	{ LogFacility,
1049 		0,
1050 		String,
1051 	        "facility",
1052 		"name of syslog facility to use for logging",
1053 		"log_facility",
1054 		NULL },
1055 
1056 	{ PunchFW,
1057 		0,
1058 		String,
1059 	        "basenumber:count",
1060 		"punch holes in the firewall for incoming FTP/IRC DCC connections",
1061 		"punch_fw",
1062 		NULL },
1063 
1064 	{ SkinnyPort,
1065 		0,
1066 		String,
1067 		"port",
1068 		"set the TCP port for use with the Skinny Station protocol",
1069 		"skinny_port",
1070 		NULL },
1071 
1072 	{ LogIpfwDenied,
1073 		0,
1074 		YesNo,
1075 	        "[yes|no]",
1076 		"log packets converted by natd, but denied by ipfw",
1077 		"log_ipfw_denied",
1078 		NULL },
1079 
1080 	{ PidFile,
1081 		0,
1082 		String,
1083 		"file_name",
1084 		"store PID in an alternate file",
1085 		"pid_file",
1086 		"P" },
1087 };
1088 
1089 static void ParseOption (const char* option, const char* parms)
1090 {
1091 	int			i;
1092 	struct OptionInfo*	info;
1093 	int			yesNoValue;
1094 	int			aliasValue;
1095 	int			numValue;
1096 	u_short			uNumValue;
1097 	const char*		strValue;
1098 	struct in_addr		addrValue;
1099 	int			max;
1100 	char*			end;
1101 	CODE* 			fac_record = NULL;
1102 /*
1103  * Find option from table.
1104  */
1105 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
1106 	for (i = 0, info = optionTable; i < max; i++, info++) {
1107 
1108 		if (!strcmp (info->name, option))
1109 			break;
1110 
1111 		if (info->shortName)
1112 			if (!strcmp (info->shortName, option))
1113 				break;
1114 	}
1115 
1116 	if (i >= max) {
1117 
1118 		warnx ("unknown option %s", option);
1119 		Usage ();
1120 	}
1121 
1122 	uNumValue	= 0;
1123 	yesNoValue	= 0;
1124 	numValue	= 0;
1125 	strValue	= NULL;
1126 /*
1127  * Check parameters.
1128  */
1129 	switch (info->parm) {
1130 	case YesNo:
1131 		if (!parms)
1132 			parms = "yes";
1133 
1134 		if (!strcmp (parms, "yes"))
1135 			yesNoValue = 1;
1136 		else
1137 			if (!strcmp (parms, "no"))
1138 				yesNoValue = 0;
1139 			else
1140 				errx (1, "%s needs yes/no parameter", option);
1141 		break;
1142 
1143 	case Service:
1144 		if (!parms)
1145 			errx (1, "%s needs service name or "
1146 				 "port number parameter",
1147 				 option);
1148 
1149 		uNumValue = StrToPort (parms, "divert");
1150 		break;
1151 
1152 	case Numeric:
1153 		if (parms)
1154 			numValue = strtol (parms, &end, 10);
1155 		else
1156 			end = NULL;
1157 
1158 		if (end == parms)
1159 			errx (1, "%s needs numeric parameter", option);
1160 		break;
1161 
1162 	case String:
1163 		strValue = parms;
1164 		if (!strValue)
1165 			errx (1, "%s needs parameter", option);
1166 		break;
1167 
1168 	case None:
1169 		if (parms)
1170 			errx (1, "%s does not take parameters", option);
1171 		break;
1172 
1173 	case Address:
1174 		if (!parms)
1175 			errx (1, "%s needs address/host parameter", option);
1176 
1177 		StrToAddr (parms, &addrValue);
1178 		break;
1179 	}
1180 
1181 	switch (info->type) {
1182 	case PacketAliasOption:
1183 
1184 		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1185 		PacketAliasSetMode (aliasValue, info->packetAliasOpt);
1186 		break;
1187 
1188 	case Verbose:
1189 		verbose = yesNoValue;
1190 		break;
1191 
1192 	case DynamicMode:
1193 		dynamicMode = yesNoValue;
1194 		break;
1195 
1196 	case InPort:
1197 		inPort = uNumValue;
1198 		break;
1199 
1200 	case OutPort:
1201 		outPort = uNumValue;
1202 		break;
1203 
1204 	case Port:
1205 		inOutPort = uNumValue;
1206 		break;
1207 
1208 	case AliasAddress:
1209 		memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
1210 		break;
1211 
1212 	case TargetAddress:
1213 		PacketAliasSetTarget(addrValue);
1214 		break;
1215 
1216 	case RedirectPort:
1217 		SetupPortRedirect (strValue);
1218 		break;
1219 
1220 	case RedirectProto:
1221 		SetupProtoRedirect(strValue);
1222 		break;
1223 
1224 	case RedirectAddress:
1225 		SetupAddressRedirect (strValue);
1226 		break;
1227 
1228 	case ProxyRule:
1229 		PacketAliasProxyRule (strValue);
1230 		break;
1231 
1232 	case InterfaceName:
1233 		if (ifName)
1234 			free (ifName);
1235 
1236 		ifName = strdup (strValue);
1237 		break;
1238 
1239 	case ConfigFile:
1240 		ReadConfigFile (strValue);
1241 		break;
1242 
1243 	case LogDenied:
1244 		logDropped = yesNoValue;
1245 		break;
1246 
1247 	case LogFacility:
1248 
1249 		fac_record = facilitynames;
1250 		while (fac_record->c_name != NULL) {
1251 
1252 			if (!strcmp (fac_record->c_name, strValue)) {
1253 
1254 				logFacility = fac_record->c_val;
1255 				break;
1256 
1257 			}
1258 			else
1259 				fac_record++;
1260 		}
1261 
1262 		if(fac_record->c_name == NULL)
1263 			errx(1, "Unknown log facility name: %s", strValue);
1264 
1265 		break;
1266 
1267 	case PunchFW:
1268 		SetupPunchFW(strValue);
1269 		break;
1270 
1271 	case SkinnyPort:
1272 		SetupSkinnyPort(strValue);
1273 		break;
1274 
1275 	case LogIpfwDenied:
1276 		logIpfwDenied = yesNoValue;;
1277 		break;
1278 
1279 	case PidFile:
1280 		pidName = strdup (strValue);
1281 		break;
1282 	}
1283 }
1284 
1285 void ReadConfigFile (const char* fileName)
1286 {
1287 	FILE*	file;
1288 	char	*buf;
1289 	size_t	len;
1290 	char	*ptr, *p;
1291 	char*	option;
1292 
1293 	file = fopen (fileName, "r");
1294 	if (!file)
1295 		err(1, "cannot open config file %s", fileName);
1296 
1297 	while ((buf = fgetln(file, &len)) != NULL) {
1298 		if (buf[len - 1] == '\n')
1299 			buf[len - 1] = '\0';
1300 		else
1301 			errx(1, "config file format error: "
1302 				"last line should end with newline");
1303 
1304 /*
1305  * Check for comments, strip off trailing spaces.
1306  */
1307 		if ((ptr = strchr(buf, '#')))
1308 			*ptr = '\0';
1309 		for (ptr = buf; isspace(*ptr); ++ptr)
1310 			continue;
1311 		if (*ptr == '\0')
1312 			continue;
1313 		for (p = strchr(buf, '\0'); isspace(*--p);)
1314 			continue;
1315 		*++p = '\0';
1316 
1317 /*
1318  * Extract option name.
1319  */
1320 		option = ptr;
1321 		while (*ptr && !isspace (*ptr))
1322 			++ptr;
1323 
1324 		if (*ptr != '\0') {
1325 
1326 			*ptr = '\0';
1327 			++ptr;
1328 		}
1329 /*
1330  * Skip white space between name and parms.
1331  */
1332 		while (*ptr && isspace (*ptr))
1333 			++ptr;
1334 
1335 		ParseOption (option, *ptr ? ptr : NULL);
1336 	}
1337 
1338 	fclose (file);
1339 }
1340 
1341 static void Usage ()
1342 {
1343 	int			i;
1344 	int			max;
1345 	struct OptionInfo*	info;
1346 
1347 	fprintf (stderr, "Recognized options:\n\n");
1348 
1349 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
1350 	for (i = 0, info = optionTable; i < max; i++, info++) {
1351 
1352 		fprintf (stderr, "-%-20s %s\n", info->name,
1353 						info->parmDescription);
1354 
1355 		if (info->shortName)
1356 			fprintf (stderr, "-%-20s %s\n", info->shortName,
1357 							info->parmDescription);
1358 
1359 		fprintf (stderr, "      %s\n\n", info->description);
1360 	}
1361 
1362 	exit (1);
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, "%s/%s: unknown service", 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, "%s/%s: unknown service", 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 
1711 static void
1712 SetupPunchFW(const char *strValue)
1713 {
1714 	unsigned int base, num;
1715 
1716 	if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1717 		errx(1, "punch_fw: basenumber:count parameter required");
1718 
1719 	PacketAliasSetFWBase(base, num);
1720 	(void)PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1721 }
1722 
1723 static void
1724 SetupSkinnyPort(const char *strValue)
1725 {
1726 	unsigned int port;
1727 
1728 	if (sscanf(strValue, "%u", &port) != 1)
1729 		errx(1, "skinny_port: port parameter required");
1730 
1731 	PacketAliasSetSkinnyPort(port);
1732 }
1733