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