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