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