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