1/*
2 * natd - Network Address Translation Daemon for FreeBSD.
3 *
4 * This software is provided free of charge, with no
5 * warranty of any kind, either expressed or implied.
6 * Use at your own risk.
7 *
8 * You may copy, modify and distribute this software (natd.c) freely.
9 *
10 * Ari Suutari <suutari@iki.fi>
11 */
12
13#include <sys/cdefs.h>
14#define SYSLOG_NAMES
15
16#include <sys/types.h>
17#include <sys/socket.h>
18#include <sys/sysctl.h>
19#include <sys/time.h>
20#include <sys/queue.h>
21
22#include <netinet/in.h>
23#include <netinet/in_systm.h>
24#include <netinet/ip.h>
25#include <netinet/tcp.h>
26#include <netinet/udp.h>
27#include <netinet/ip_icmp.h>
28#include <net/if.h>
29#include <net/if_dl.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
47struct instance {
48	const char		*name;
49	struct libalias		*la;
50	LIST_ENTRY(instance)	list;
51
52	int			ifIndex;
53	int			assignAliasAddr;
54	char*			ifName;
55	int			logDropped;
56	u_short			inPort;
57	u_short			outPort;
58	u_short			inOutPort;
59	struct in_addr		aliasAddr;
60	int			ifMTU;
61	int			aliasOverhead;
62	int			dropIgnoredIncoming;
63	int			divertIn;
64	int			divertOut;
65	int			divertInOut;
66};
67
68static LIST_HEAD(, instance) root = LIST_HEAD_INITIALIZER(root);
69
70struct libalias *mla;
71static struct instance *mip;
72static int ninstance = 1;
73
74/*
75 * Default values for input and output
76 * divert socket ports.
77 */
78
79#define	DEFAULT_SERVICE	"natd"
80
81/*
82 * Definition of a port range, and macros to deal with values.
83 * FORMAT:  HI 16-bits == first port in range, 0 == all ports.
84 *          LO 16-bits == number of ports in range
85 * NOTES:   - Port values are not stored in network byte order.
86 */
87
88typedef u_long port_range;
89
90#define GETLOPORT(x)     ((x) >> 0x10)
91#define GETNUMPORTS(x)   ((x) & 0x0000ffff)
92#define GETHIPORT(x)     (GETLOPORT((x)) + GETNUMPORTS((x)))
93
94/* Set y to be the low-port value in port_range variable x. */
95#define SETLOPORT(x,y)   ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
96
97/* Set y to be the number of ports in port_range variable x. */
98#define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
99
100/*
101 * Function prototypes.
102 */
103
104static void	DoAliasing (int fd, int direction);
105static void	DaemonMode (void);
106static void	HandleRoutingInfo (int fd);
107static void	Usage (void);
108static char*	FormatPacket (struct ip*);
109static void	PrintPacket (struct ip*);
110static void	SyslogPacket (struct ip*, int priority, const char *label);
111static int	SetAliasAddressFromIfName (const char *ifName);
112static void	InitiateShutdown (int);
113static void	Shutdown (int);
114static void	RefreshAddr (int);
115static void	ParseOption (const char* option, const char* parms);
116static void	ReadConfigFile (const char* fileName);
117static void	SetupPortRedirect (const char* parms);
118static void	SetupProtoRedirect(const char* parms);
119static void	SetupAddressRedirect (const char* parms);
120static void	StrToAddr (const char* str, struct in_addr* addr);
121static u_short  StrToPort (const char* str, const char* proto);
122static int      StrToPortRange (const char* str, const char* proto, port_range *portRange);
123static int 	StrToProto (const char* str);
124static int      StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange);
125static void	ParseArgs (int argc, char** argv);
126static void	SetupPunchFW(const char *strValue);
127static void	SetupSkinnyPort(const char *strValue);
128static void	NewInstance(const char *name);
129static void	DoGlobal (int fd);
130static int	CheckIpfwRulenum(unsigned int rnum);
131
132/*
133 * Globals.
134 */
135
136static	int			verbose;
137static 	int			background;
138static	int			running;
139static	int			logFacility;
140
141static 	int			dynamicMode;
142static 	int			icmpSock;
143static	int			logIpfwDenied;
144static	const char*		pidName;
145static	int			routeSock;
146static	int			globalPort;
147static	int			divertGlobal;
148static	int			exitDelay;
149
150
151int main (int argc, char** argv)
152{
153	struct sockaddr_in	addr;
154	fd_set			readMask;
155	int			fdMax;
156	int			rval;
157/*
158 * Initialize packet aliasing software.
159 * Done already here to be able to alter option bits
160 * during command line and configuration file processing.
161 */
162	NewInstance("default");
163
164/*
165 * Parse options.
166 */
167	verbose 		= 0;
168	background		= 0;
169	running			= 1;
170	dynamicMode		= 0;
171 	logFacility		= LOG_DAEMON;
172	logIpfwDenied		= -1;
173	pidName			= PIDFILE;
174	routeSock 		= -1;
175	icmpSock 		= -1;
176	fdMax	 		= -1;
177	divertGlobal		= -1;
178	exitDelay		= EXIT_DELAY;
179
180	ParseArgs (argc, argv);
181/*
182 * Log ipfw(8) denied packets by default in verbose mode.
183 */
184	if (logIpfwDenied == -1)
185		logIpfwDenied = verbose;
186/*
187 * Open syslog channel.
188 */
189	openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
190		 logFacility);
191
192	LIST_FOREACH(mip, &root, list) {
193		mla = mip->la;
194/*
195 * If not doing the transparent proxying only,
196 * check that valid aliasing address has been given.
197 */
198		if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL &&
199		    !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY))
200			errx (1, "instance %s: aliasing address not given", mip->name);
201
202		if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL)
203			errx (1, "both alias address and interface "
204				 "name are not allowed");
205/*
206 * Check that valid port number is known.
207 */
208		if (mip->inPort != 0 || mip->outPort != 0)
209			if (mip->inPort == 0 || mip->outPort == 0)
210				errx (1, "both input and output ports are required");
211
212		if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0)
213			ParseOption ("port", DEFAULT_SERVICE);
214
215/*
216 * Check if ignored packets should be dropped.
217 */
218		mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0);
219		mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
220/*
221 * Create divert sockets. Use only one socket if -p was specified
222 * on command line. Otherwise, create separate sockets for
223 * outgoing and incoming connections.
224 */
225		if (mip->inOutPort) {
226
227			mip->divertInOut = socket(PF_DIVERT, SOCK_RAW, 0);
228			if (mip->divertInOut == -1)
229				Quit ("Unable to create divert socket.");
230			if (mip->divertInOut > fdMax)
231				fdMax = mip->divertInOut;
232
233			mip->divertIn  = -1;
234			mip->divertOut = -1;
235/*
236 * Bind socket.
237 */
238
239			addr.sin_family		= AF_INET;
240			addr.sin_addr.s_addr	= INADDR_ANY;
241			addr.sin_port		= mip->inOutPort;
242
243			if (bind (mip->divertInOut,
244				  (struct sockaddr*) &addr,
245				  sizeof addr) == -1)
246				Quit ("Unable to bind divert socket.");
247		}
248		else {
249
250			mip->divertIn = socket(PF_DIVERT, SOCK_RAW, 0);
251			if (mip->divertIn == -1)
252				Quit ("Unable to create incoming divert socket.");
253			if (mip->divertIn > fdMax)
254				fdMax = mip->divertIn;
255
256
257			mip->divertOut = socket(PF_DIVERT, SOCK_RAW, 0);
258			if (mip->divertOut == -1)
259				Quit ("Unable to create outgoing divert socket.");
260			if (mip->divertOut > fdMax)
261				fdMax = mip->divertOut;
262
263			mip->divertInOut = -1;
264
265/*
266 * Bind divert sockets.
267 */
268
269			addr.sin_family		= AF_INET;
270			addr.sin_addr.s_addr	= INADDR_ANY;
271			addr.sin_port		= mip->inPort;
272
273			if (bind (mip->divertIn,
274				  (struct sockaddr*) &addr,
275				  sizeof addr) == -1)
276				Quit ("Unable to bind incoming divert socket.");
277
278			addr.sin_family		= AF_INET;
279			addr.sin_addr.s_addr	= INADDR_ANY;
280			addr.sin_port		= mip->outPort;
281
282			if (bind (mip->divertOut,
283				  (struct sockaddr*) &addr,
284				  sizeof addr) == -1)
285				Quit ("Unable to bind outgoing divert socket.");
286		}
287/*
288 * Create routing socket if interface name specified and in dynamic mode.
289 */
290		if (mip->ifName) {
291			if (dynamicMode) {
292
293				if (routeSock == -1)
294					routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
295				if (routeSock == -1)
296					Quit ("Unable to create routing info socket.");
297				if (routeSock > fdMax)
298					fdMax = routeSock;
299
300				mip->assignAliasAddr = 1;
301			}
302			else {
303				do {
304					rval = SetAliasAddressFromIfName (mip->ifName);
305					if (background == 0 || dynamicMode == 0)
306						break;
307					if (rval == EAGAIN)
308						sleep(1);
309				} while (rval == EAGAIN);
310				if (rval != 0)
311					exit(1);
312			}
313		}
314
315	}
316	if (globalPort) {
317
318		divertGlobal = socket(PF_DIVERT, SOCK_RAW, 0);
319		if (divertGlobal == -1)
320			Quit ("Unable to create divert socket.");
321		if (divertGlobal > fdMax)
322			fdMax = divertGlobal;
323
324/*
325* Bind socket.
326*/
327
328		addr.sin_family		= AF_INET;
329		addr.sin_addr.s_addr	= INADDR_ANY;
330		addr.sin_port		= globalPort;
331
332		if (bind (divertGlobal,
333			  (struct sockaddr*) &addr,
334			  sizeof addr) == -1)
335			Quit ("Unable to bind global divert socket.");
336	}
337/*
338 * Create socket for sending ICMP messages.
339 */
340	icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
341	if (icmpSock == -1)
342		Quit ("Unable to create ICMP socket.");
343
344/*
345 * And disable reads for the socket, otherwise it slowly fills
346 * up with received icmps which we do not use.
347 */
348	shutdown(icmpSock, SHUT_RD);
349
350/*
351 * Become a daemon unless verbose mode was requested.
352 */
353	if (!verbose)
354		DaemonMode ();
355/*
356 * Catch signals to manage shutdown and
357 * refresh of interface address.
358 */
359	siginterrupt(SIGTERM, 1);
360	siginterrupt(SIGHUP, 1);
361	if (exitDelay)
362		signal(SIGTERM, InitiateShutdown);
363	else
364		signal(SIGTERM, Shutdown);
365	signal (SIGHUP, RefreshAddr);
366/*
367 * Set alias address if it has been given.
368 */
369	mip = LIST_FIRST(&root);	/* XXX: simon */
370	LIST_FOREACH(mip, &root, list) {
371		mla = mip->la;
372		if (mip->aliasAddr.s_addr != INADDR_NONE)
373			LibAliasSetAddress (mla, mip->aliasAddr);
374	}
375
376	while (running) {
377		mip = LIST_FIRST(&root);	/* XXX: simon */
378
379		if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) {
380/*
381 * When using only one socket, just call
382 * DoAliasing repeatedly to process packets.
383 */
384			DoAliasing (mip->divertInOut, DONT_KNOW);
385			continue;
386		}
387/*
388 * Build read mask from socket descriptors to select.
389 */
390		FD_ZERO (&readMask);
391/*
392 * Check if new packets are available.
393 */
394		LIST_FOREACH(mip, &root, list) {
395			if (mip->divertIn != -1)
396				FD_SET (mip->divertIn, &readMask);
397
398			if (mip->divertOut != -1)
399				FD_SET (mip->divertOut, &readMask);
400
401			if (mip->divertInOut != -1)
402				FD_SET (mip->divertInOut, &readMask);
403		}
404/*
405 * Routing info is processed always.
406 */
407		if (routeSock != -1)
408			FD_SET (routeSock, &readMask);
409
410		if (divertGlobal != -1)
411			FD_SET (divertGlobal, &readMask);
412
413		if (select (fdMax + 1,
414			    &readMask,
415			    NULL,
416			    NULL,
417			    NULL) == -1) {
418
419			if (errno == EINTR)
420				continue;
421
422			Quit ("Select failed.");
423		}
424
425		if (divertGlobal != -1)
426			if (FD_ISSET (divertGlobal, &readMask))
427				DoGlobal (divertGlobal);
428		LIST_FOREACH(mip, &root, list) {
429			mla = mip->la;
430			if (mip->divertIn != -1)
431				if (FD_ISSET (mip->divertIn, &readMask))
432					DoAliasing (mip->divertIn, INPUT);
433
434			if (mip->divertOut != -1)
435				if (FD_ISSET (mip->divertOut, &readMask))
436					DoAliasing (mip->divertOut, OUTPUT);
437
438			if (mip->divertInOut != -1)
439				if (FD_ISSET (mip->divertInOut, &readMask))
440					DoAliasing (mip->divertInOut, DONT_KNOW);
441
442		}
443		if (routeSock != -1)
444			if (FD_ISSET (routeSock, &readMask))
445				HandleRoutingInfo (routeSock);
446	}
447
448	if (background)
449		unlink (pidName);
450
451	return 0;
452}
453
454static void DaemonMode(void)
455{
456	FILE*	pidFile;
457
458	daemon (0, 0);
459	background = 1;
460
461	pidFile = fopen (pidName, "w");
462	if (pidFile) {
463
464		fprintf (pidFile, "%d\n", getpid ());
465		fclose (pidFile);
466	}
467}
468
469static void ParseArgs (int argc, char** argv)
470{
471	int		arg;
472	char*		opt;
473	char		parmBuf[256];
474	int		len; /* bounds checking */
475
476	for (arg = 1; arg < argc; arg++) {
477
478		opt  = argv[arg];
479		if (*opt != '-') {
480
481			warnx ("invalid option %s", opt);
482			Usage ();
483		}
484
485		parmBuf[0] = '\0';
486		len = 0;
487
488		while (arg < argc - 1) {
489
490			if (argv[arg + 1][0] == '-')
491				break;
492
493			if (len) {
494				strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
495				len += strlen(parmBuf + len);
496			}
497
498			++arg;
499			strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
500			len += strlen(parmBuf + len);
501
502		}
503
504		ParseOption (opt + 1, (len ? parmBuf : NULL));
505
506	}
507}
508
509static void DoGlobal (int fd)
510{
511	int			bytes;
512	int			origBytes;
513	char			buf[IP_MAXPACKET];
514	struct sockaddr_in	addr;
515	int			wrote;
516	socklen_t		addrSize;
517	struct ip*		ip;
518	char			msgBuf[80];
519
520/*
521 * Get packet from socket.
522 */
523	addrSize  = sizeof addr;
524	origBytes = recvfrom (fd,
525			      buf,
526			      sizeof buf,
527			      0,
528			      (struct sockaddr*) &addr,
529			      &addrSize);
530
531	if (origBytes == -1) {
532
533		if (errno != EINTR)
534			Warn ("read from divert socket failed");
535
536		return;
537	}
538
539#if 0
540	if (mip->assignAliasAddr) {
541		if (SetAliasAddressFromIfName (mip->ifName) != 0)
542			exit(1);
543		mip->assignAliasAddr = 0;
544	}
545#endif
546/*
547 * This is an IP packet.
548 */
549	ip = (struct ip*) buf;
550
551	if (verbose) {
552/*
553 * Print packet direction and protocol type.
554 */
555		printf ("Glb ");
556
557		switch (ip->ip_p) {
558		case IPPROTO_TCP:
559			printf ("[TCP]  ");
560			break;
561
562		case IPPROTO_UDP:
563			printf ("[UDP]  ");
564			break;
565
566		case IPPROTO_ICMP:
567			printf ("[ICMP] ");
568			break;
569
570		default:
571			printf ("[%d]    ", ip->ip_p);
572			break;
573		}
574/*
575 * Print addresses.
576 */
577		PrintPacket (ip);
578	}
579
580	LIST_FOREACH(mip, &root, list) {
581		mla = mip->la;
582		if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED)
583			break;
584	}
585/*
586 * Length might have changed during aliasing.
587 */
588	bytes = ntohs (ip->ip_len);
589/*
590 * Update alias overhead size for outgoing packets.
591 */
592	if (mip != NULL && bytes - origBytes > mip->aliasOverhead)
593		mip->aliasOverhead = bytes - origBytes;
594
595	if (verbose) {
596
597/*
598 * Print addresses after aliasing.
599 */
600		printf (" aliased to\n");
601		printf ("           ");
602		PrintPacket (ip);
603		printf ("\n");
604	}
605
606/*
607 * Put packet back for processing.
608 */
609	wrote = sendto (fd,
610		        buf,
611	    		bytes,
612	    		0,
613	    		(struct sockaddr*) &addr,
614	    		sizeof addr);
615
616	if (wrote != bytes) {
617
618		if (errno == EMSGSIZE && mip != NULL) {
619
620			if (mip->ifMTU != -1)
621				SendNeedFragIcmp (icmpSock,
622						  (struct ip*) buf,
623						  mip->ifMTU - mip->aliasOverhead);
624		}
625		else if (errno == EACCES && logIpfwDenied) {
626
627			sprintf (msgBuf, "failed to write packet back");
628			Warn (msgBuf);
629		}
630	}
631}
632
633
634static void DoAliasing (int fd, int direction)
635{
636	int			bytes;
637	int			origBytes;
638	char			buf[IP_MAXPACKET];
639	struct sockaddr_in	addr;
640	int			wrote;
641	int			status;
642	socklen_t		addrSize;
643	struct ip*		ip;
644	char			msgBuf[80];
645	int			rval;
646
647	if (mip->assignAliasAddr) {
648		do {
649			rval = SetAliasAddressFromIfName (mip->ifName);
650			if (background == 0 || dynamicMode == 0)
651				break;
652			if (rval == EAGAIN)
653				sleep(1);
654		} while (rval == EAGAIN);
655		if (rval != 0)
656			exit(1);
657		mip->assignAliasAddr = 0;
658	}
659/*
660 * Get packet from socket.
661 */
662	addrSize  = sizeof addr;
663	origBytes = recvfrom (fd,
664			      buf,
665			      sizeof buf,
666			      0,
667			      (struct sockaddr*) &addr,
668			      &addrSize);
669
670	if (origBytes == -1) {
671
672		if (errno != EINTR)
673			Warn ("read from divert socket failed");
674
675		return;
676	}
677/*
678 * This is an IP packet.
679 */
680	ip = (struct ip*) buf;
681	if (direction == DONT_KNOW) {
682		if (addr.sin_addr.s_addr == INADDR_ANY)
683			direction = OUTPUT;
684		else
685			direction = INPUT;
686	}
687
688	if (verbose) {
689/*
690 * Print packet direction and protocol type.
691 */
692		printf (direction == OUTPUT ? "Out " : "In  ");
693		if (ninstance > 1)
694			printf ("{%s}", mip->name);
695
696		switch (ip->ip_p) {
697		case IPPROTO_TCP:
698			printf ("[TCP]  ");
699			break;
700
701		case IPPROTO_UDP:
702			printf ("[UDP]  ");
703			break;
704
705		case IPPROTO_ICMP:
706			printf ("[ICMP] ");
707			break;
708
709		default:
710			printf ("[%d]    ", ip->ip_p);
711			break;
712		}
713/*
714 * Print addresses.
715 */
716		PrintPacket (ip);
717	}
718
719	if (direction == OUTPUT) {
720/*
721 * Outgoing packets. Do aliasing.
722 */
723		LibAliasOut (mla, buf, IP_MAXPACKET);
724	}
725	else {
726
727/*
728 * Do aliasing.
729 */
730		status = LibAliasIn (mla, buf, IP_MAXPACKET);
731		if (status == PKT_ALIAS_IGNORED &&
732		    mip->dropIgnoredIncoming) {
733
734			if (verbose)
735				printf (" dropped.\n");
736
737			if (mip->logDropped)
738				SyslogPacket (ip, LOG_WARNING, "denied");
739
740			return;
741		}
742	}
743/*
744 * Length might have changed during aliasing.
745 */
746	bytes = ntohs (ip->ip_len);
747/*
748 * Update alias overhead size for outgoing packets.
749 */
750	if (direction == OUTPUT &&
751	    bytes - origBytes > mip->aliasOverhead)
752		mip->aliasOverhead = bytes - origBytes;
753
754	if (verbose) {
755
756/*
757 * Print addresses after aliasing.
758 */
759		printf (" aliased to\n");
760		printf ("           ");
761		PrintPacket (ip);
762		printf ("\n");
763	}
764
765/*
766 * Put packet back for processing.
767 */
768	wrote = sendto (fd,
769		        buf,
770	    		bytes,
771	    		0,
772	    		(struct sockaddr*) &addr,
773	    		sizeof addr);
774
775	if (wrote != bytes) {
776
777		if (errno == EMSGSIZE) {
778
779			if (direction == OUTPUT &&
780			    mip->ifMTU != -1)
781				SendNeedFragIcmp (icmpSock,
782						  (struct ip*) buf,
783						  mip->ifMTU - mip->aliasOverhead);
784		}
785		else if (errno == EACCES && logIpfwDenied) {
786
787			sprintf (msgBuf, "failed to write packet back");
788			Warn (msgBuf);
789		}
790	}
791}
792
793static void HandleRoutingInfo (int fd)
794{
795	int			bytes;
796	struct if_msghdr	ifMsg;
797/*
798 * Get packet from socket.
799 */
800	bytes = read (fd, &ifMsg, sizeof ifMsg);
801	if (bytes == -1) {
802
803		Warn ("read from routing socket failed");
804		return;
805	}
806
807	if (ifMsg.ifm_version != RTM_VERSION) {
808
809		Warn ("unexpected packet read from routing socket");
810		return;
811	}
812
813	if (verbose)
814		printf ("Routing message %#x received.\n", ifMsg.ifm_type);
815
816	if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) {
817		LIST_FOREACH(mip, &root, list) {
818			mla = mip->la;
819			if (ifMsg.ifm_index == mip->ifIndex) {
820				if (verbose)
821					printf("Interface address/MTU has probably changed.\n");
822				mip->assignAliasAddr = 1;
823			}
824		}
825	}
826}
827
828static void PrintPacket (struct ip* ip)
829{
830	printf ("%s", FormatPacket (ip));
831}
832
833static void SyslogPacket (struct ip* ip, int priority, const char *label)
834{
835	syslog (priority, "%s %s", label, FormatPacket (ip));
836}
837
838static char* FormatPacket (struct ip* ip)
839{
840	static char	buf[256];
841	struct tcphdr*	tcphdr;
842	struct udphdr*	udphdr;
843	struct icmp*	icmphdr;
844	char		src[20];
845	char		dst[20];
846
847	strcpy (src, inet_ntoa (ip->ip_src));
848	strcpy (dst, inet_ntoa (ip->ip_dst));
849
850	switch (ip->ip_p) {
851	case IPPROTO_TCP:
852		tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
853		sprintf (buf, "[TCP] %s:%d -> %s:%d",
854			      src,
855			      ntohs (tcphdr->th_sport),
856			      dst,
857			      ntohs (tcphdr->th_dport));
858		break;
859
860	case IPPROTO_UDP:
861		udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
862		sprintf (buf, "[UDP] %s:%d -> %s:%d",
863			      src,
864			      ntohs (udphdr->uh_sport),
865			      dst,
866			      ntohs (udphdr->uh_dport));
867		break;
868
869	case IPPROTO_ICMP:
870		icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
871		sprintf (buf, "[ICMP] %s -> %s %u(%u)",
872			      src,
873			      dst,
874			      icmphdr->icmp_type,
875			      icmphdr->icmp_code);
876		break;
877
878	default:
879		sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
880		break;
881	}
882
883	return buf;
884}
885
886static int
887SetAliasAddressFromIfName(const char *ifn)
888{
889	size_t needed;
890	int mib[6];
891	char *buf, *lim, *next;
892	struct if_msghdr *ifm;
893	struct ifa_msghdr *ifam;
894	struct sockaddr_dl *sdl;
895	struct sockaddr_in *sin;
896
897	mib[0] = CTL_NET;
898	mib[1] = PF_ROUTE;
899	mib[2] = 0;
900	mib[3] = AF_INET;	/* Only IP addresses please */
901	mib[4] = NET_RT_IFLIST;
902	mib[5] = 0;		/* ifIndex??? */
903/*
904 * Get interface data.
905 */
906	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
907		err(1, "iflist-sysctl-estimate");
908	if ((buf = malloc(needed)) == NULL)
909		errx(1, "malloc failed");
910	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1 && errno != ENOMEM)
911		err(1, "iflist-sysctl-get");
912	lim = buf + needed;
913/*
914 * Loop through interfaces until one with
915 * given name is found. This is done to
916 * find correct interface index for routing
917 * message processing.
918 */
919	mip->ifIndex	= 0;
920	next = buf;
921	while (next < lim) {
922		ifm = (struct if_msghdr *)next;
923		next += ifm->ifm_msglen;
924		if (ifm->ifm_version != RTM_VERSION) {
925			if (verbose)
926				warnx("routing message version %d "
927				      "not understood", ifm->ifm_version);
928			continue;
929		}
930		if (ifm->ifm_type == RTM_IFINFO) {
931			sdl = (struct sockaddr_dl *)(ifm + 1);
932			if (strlen(ifn) == sdl->sdl_nlen &&
933			    strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
934				mip->ifIndex = ifm->ifm_index;
935				mip->ifMTU = ifm->ifm_data.ifi_mtu;
936				break;
937			}
938		}
939	}
940	if (!mip->ifIndex)
941		errx(1, "unknown interface name %s", ifn);
942/*
943 * Get interface address.
944 */
945	sin = NULL;
946	while (next < lim) {
947		ifam = (struct ifa_msghdr *)next;
948		next += ifam->ifam_msglen;
949		if (ifam->ifam_version != RTM_VERSION) {
950			if (verbose)
951				warnx("routing message version %d "
952				      "not understood", ifam->ifam_version);
953			continue;
954		}
955		if (ifam->ifam_type != RTM_NEWADDR)
956			break;
957		if (ifam->ifam_addrs & RTA_IFA) {
958			int i;
959			char *cp = (char *)(ifam + 1);
960
961			for (i = 1; i < RTA_IFA; i <<= 1)
962				if (ifam->ifam_addrs & i)
963					cp += SA_SIZE((struct sockaddr *)cp);
964			if (((struct sockaddr *)cp)->sa_family == AF_INET) {
965				sin = (struct sockaddr_in *)cp;
966				break;
967			}
968		}
969	}
970	if (sin == NULL) {
971		warnx("%s: cannot get interface address", ifn);
972		free(buf);
973		return EAGAIN;
974	}
975
976	LibAliasSetAddress(mla, sin->sin_addr);
977	syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
978	       inet_ntoa(sin->sin_addr), mip->ifMTU);
979
980	free(buf);
981
982	return 0;
983}
984
985void Quit (const char* msg)
986{
987	Warn (msg);
988	exit (1);
989}
990
991void Warn (const char* msg)
992{
993	if (background)
994		syslog (LOG_ALERT, "%s (%m)", msg);
995	else
996		warn ("%s", msg);
997}
998
999static void RefreshAddr (int sig __unused)
1000{
1001	LibAliasRefreshModules();
1002	if (mip != NULL && mip->ifName != NULL)
1003		mip->assignAliasAddr = 1;
1004}
1005
1006static void InitiateShutdown (int sig __unused)
1007{
1008/*
1009 * Start timer to allow kernel gracefully
1010 * shutdown existing connections when system
1011 * is shut down.
1012 */
1013	siginterrupt(SIGALRM, 1);
1014	signal (SIGALRM, Shutdown);
1015	ualarm(exitDelay*1000, 1000);
1016}
1017
1018static void Shutdown (int sig __unused)
1019{
1020	running = 0;
1021}
1022
1023/*
1024 * Different options recognized by this program.
1025 */
1026
1027enum Option {
1028
1029	LibAliasOption,
1030	Instance,
1031	Verbose,
1032	InPort,
1033	OutPort,
1034	Port,
1035	GlobalPort,
1036	AliasAddress,
1037	TargetAddress,
1038	InterfaceName,
1039	RedirectPort,
1040	RedirectProto,
1041	RedirectAddress,
1042	ConfigFile,
1043	DynamicMode,
1044	ProxyRule,
1045 	LogDenied,
1046 	LogFacility,
1047	PunchFW,
1048	SkinnyPort,
1049	LogIpfwDenied,
1050	PidFile,
1051	ExitDelay
1052};
1053
1054enum Param {
1055
1056	YesNo,
1057	Numeric,
1058	String,
1059	None,
1060	Address,
1061	Service
1062};
1063
1064/*
1065 * Option information structure (used by ParseOption).
1066 */
1067
1068struct OptionInfo {
1069
1070	enum Option		type;
1071	int			packetAliasOpt;
1072	enum Param		parm;
1073	const char*		parmDescription;
1074	const char*		description;
1075	const char*		name;
1076	const char*		shortName;
1077};
1078
1079/*
1080 * Table of known options.
1081 */
1082
1083static struct OptionInfo optionTable[] = {
1084
1085	{ LibAliasOption,
1086		PKT_ALIAS_UNREGISTERED_ONLY,
1087		YesNo,
1088		"[yes|no]",
1089		"alias only unregistered addresses",
1090		"unregistered_only",
1091		"u" },
1092
1093	{ LibAliasOption,
1094		PKT_ALIAS_LOG,
1095		YesNo,
1096		"[yes|no]",
1097		"enable logging",
1098		"log",
1099		"l" },
1100
1101	{ LibAliasOption,
1102		PKT_ALIAS_PROXY_ONLY,
1103		YesNo,
1104		"[yes|no]",
1105		"proxy only",
1106		"proxy_only",
1107		NULL },
1108
1109	{ LibAliasOption,
1110		PKT_ALIAS_REVERSE,
1111		YesNo,
1112		"[yes|no]",
1113		"operate in reverse mode",
1114		"reverse",
1115		NULL },
1116
1117	{ LibAliasOption,
1118		PKT_ALIAS_DENY_INCOMING,
1119		YesNo,
1120		"[yes|no]",
1121		"allow incoming connections",
1122		"deny_incoming",
1123		"d" },
1124
1125	{ LibAliasOption,
1126		PKT_ALIAS_USE_SOCKETS,
1127		YesNo,
1128		"[yes|no]",
1129		"use sockets to inhibit port conflict",
1130		"use_sockets",
1131		"s" },
1132
1133	{ LibAliasOption,
1134		PKT_ALIAS_SAME_PORTS,
1135		YesNo,
1136		"[yes|no]",
1137		"try to keep original port numbers for connections",
1138		"same_ports",
1139		"m" },
1140
1141	{ Verbose,
1142		0,
1143		YesNo,
1144		"[yes|no]",
1145		"verbose mode, dump packet information",
1146		"verbose",
1147		"v" },
1148
1149	{ DynamicMode,
1150		0,
1151		YesNo,
1152		"[yes|no]",
1153		"dynamic mode, automatically detect interface address changes",
1154		"dynamic",
1155		NULL },
1156
1157	{ InPort,
1158		0,
1159		Service,
1160		"number|service_name",
1161		"set port for incoming packets",
1162		"in_port",
1163		"i" },
1164
1165	{ OutPort,
1166		0,
1167		Service,
1168		"number|service_name",
1169		"set port for outgoing packets",
1170		"out_port",
1171		"o" },
1172
1173	{ Port,
1174		0,
1175		Service,
1176		"number|service_name",
1177		"set port (defaults to natd/divert)",
1178		"port",
1179		"p" },
1180
1181	{ GlobalPort,
1182		0,
1183		Service,
1184		"number|service_name",
1185		"set globalport",
1186		"globalport",
1187		NULL },
1188
1189	{ AliasAddress,
1190		0,
1191		Address,
1192		"x.x.x.x",
1193		"address to use for aliasing",
1194		"alias_address",
1195		"a" },
1196
1197	{ TargetAddress,
1198		0,
1199		Address,
1200		"x.x.x.x",
1201		"address to use for incoming sessions",
1202		"target_address",
1203		"t" },
1204
1205	{ InterfaceName,
1206		0,
1207		String,
1208	        "network_if_name",
1209		"take aliasing address from interface",
1210		"interface",
1211		"n" },
1212
1213	{ ProxyRule,
1214		0,
1215		String,
1216	        "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
1217		"a.b.c.d:yyyy",
1218		"add transparent proxying / destination NAT",
1219		"proxy_rule",
1220		NULL },
1221
1222	{ RedirectPort,
1223		0,
1224		String,
1225	        "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
1226	 	" [remote_addr[:remote_port_range]]",
1227		"redirect a port (or ports) for incoming traffic",
1228		"redirect_port",
1229		NULL },
1230
1231	{ RedirectProto,
1232		0,
1233		String,
1234	        "proto local_addr [public_addr] [remote_addr]",
1235		"redirect packets of a given proto",
1236		"redirect_proto",
1237		NULL },
1238
1239	{ RedirectAddress,
1240		0,
1241		String,
1242	        "local_addr[,...] public_addr",
1243		"define mapping between local and public addresses",
1244		"redirect_address",
1245		NULL },
1246
1247	{ ConfigFile,
1248		0,
1249		String,
1250		"file_name",
1251		"read options from configuration file",
1252		"config",
1253		"f" },
1254
1255	{ LogDenied,
1256		0,
1257		YesNo,
1258	        "[yes|no]",
1259		"enable logging of denied incoming packets",
1260		"log_denied",
1261		NULL },
1262
1263	{ LogFacility,
1264		0,
1265		String,
1266	        "facility",
1267		"name of syslog facility to use for logging",
1268		"log_facility",
1269		NULL },
1270
1271	{ PunchFW,
1272		0,
1273		String,
1274	        "basenumber:count",
1275		"punch holes in the firewall for incoming FTP/IRC DCC connections",
1276		"punch_fw",
1277		NULL },
1278
1279	{ SkinnyPort,
1280		0,
1281		String,
1282		"port",
1283		"set the TCP port for use with the Skinny Station protocol",
1284		"skinny_port",
1285		NULL },
1286
1287	{ LogIpfwDenied,
1288		0,
1289		YesNo,
1290	        "[yes|no]",
1291		"log packets converted by natd, but denied by ipfw",
1292		"log_ipfw_denied",
1293		NULL },
1294
1295	{ PidFile,
1296		0,
1297		String,
1298		"file_name",
1299		"store PID in an alternate file",
1300		"pid_file",
1301		"P" },
1302	{ Instance,
1303		0,
1304		String,
1305		"instance name",
1306		"name of aliasing engine instance",
1307		"instance",
1308		NULL },
1309	{ ExitDelay,
1310		0,
1311		Numeric,
1312		"ms",
1313		"delay in ms before daemon exit after signal",
1314		"exit_delay",
1315		NULL },
1316};
1317
1318static void ParseOption (const char* option, const char* parms)
1319{
1320	int			i;
1321	struct OptionInfo*	info;
1322	int			yesNoValue;
1323	int			aliasValue;
1324	int			numValue;
1325	u_short			uNumValue;
1326	const char*		strValue;
1327	struct in_addr		addrValue;
1328	int			max;
1329	char*			end;
1330	const CODE* 		fac_record = NULL;
1331/*
1332 * Find option from table.
1333 */
1334	max = sizeof (optionTable) / sizeof (struct OptionInfo);
1335	for (i = 0, info = optionTable; i < max; i++, info++) {
1336
1337		if (!strcmp (info->name, option))
1338			break;
1339
1340		if (info->shortName)
1341			if (!strcmp (info->shortName, option))
1342				break;
1343	}
1344
1345	if (i >= max) {
1346
1347		warnx ("unknown option %s", option);
1348		Usage ();
1349	}
1350
1351	uNumValue	= 0;
1352	yesNoValue	= 0;
1353	numValue	= 0;
1354	strValue	= NULL;
1355/*
1356 * Check parameters.
1357 */
1358	switch (info->parm) {
1359	case YesNo:
1360		if (!parms)
1361			parms = "yes";
1362
1363		if (!strcmp (parms, "yes"))
1364			yesNoValue = 1;
1365		else
1366			if (!strcmp (parms, "no"))
1367				yesNoValue = 0;
1368			else
1369				errx (1, "%s needs yes/no parameter", option);
1370		break;
1371
1372	case Service:
1373		if (!parms)
1374			errx (1, "%s needs service name or "
1375				 "port number parameter",
1376				 option);
1377
1378		uNumValue = StrToPort (parms, "divert");
1379		break;
1380
1381	case Numeric:
1382		if (parms)
1383			numValue = strtol (parms, &end, 10);
1384		else
1385			end = NULL;
1386
1387		if (end == parms)
1388			errx (1, "%s needs numeric parameter", option);
1389		break;
1390
1391	case String:
1392		strValue = parms;
1393		if (!strValue)
1394			errx (1, "%s needs parameter", option);
1395		break;
1396
1397	case None:
1398		if (parms)
1399			errx (1, "%s does not take parameters", option);
1400		break;
1401
1402	case Address:
1403		if (!parms)
1404			errx (1, "%s needs address/host parameter", option);
1405
1406		StrToAddr (parms, &addrValue);
1407		break;
1408	}
1409
1410	switch (info->type) {
1411	case LibAliasOption:
1412
1413		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1414		LibAliasSetMode (mla, aliasValue, info->packetAliasOpt);
1415		break;
1416
1417	case Verbose:
1418		verbose = yesNoValue;
1419		break;
1420
1421	case DynamicMode:
1422		dynamicMode = yesNoValue;
1423		break;
1424
1425	case InPort:
1426		mip->inPort = uNumValue;
1427		break;
1428
1429	case OutPort:
1430		mip->outPort = uNumValue;
1431		break;
1432
1433	case Port:
1434		mip->inOutPort = uNumValue;
1435		break;
1436
1437	case GlobalPort:
1438		globalPort = uNumValue;
1439		break;
1440
1441	case AliasAddress:
1442		memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr));
1443		break;
1444
1445	case TargetAddress:
1446		LibAliasSetTarget(mla, addrValue);
1447		break;
1448
1449	case RedirectPort:
1450		SetupPortRedirect (strValue);
1451		break;
1452
1453	case RedirectProto:
1454		SetupProtoRedirect(strValue);
1455		break;
1456
1457	case RedirectAddress:
1458		SetupAddressRedirect (strValue);
1459		break;
1460
1461	case ProxyRule:
1462		LibAliasProxyRule (mla, strValue);
1463		break;
1464
1465	case InterfaceName:
1466		if (mip->ifName)
1467			free (mip->ifName);
1468
1469		mip->ifName = strdup (strValue);
1470		break;
1471
1472	case ConfigFile:
1473		ReadConfigFile (strValue);
1474		break;
1475
1476	case LogDenied:
1477		mip->logDropped = yesNoValue;
1478		break;
1479
1480	case LogFacility:
1481
1482		fac_record = facilitynames;
1483		while (fac_record->c_name != NULL) {
1484
1485			if (!strcmp (fac_record->c_name, strValue)) {
1486
1487				logFacility = fac_record->c_val;
1488				break;
1489
1490			}
1491			else
1492				fac_record++;
1493		}
1494
1495		if(fac_record->c_name == NULL)
1496			errx(1, "Unknown log facility name: %s", strValue);
1497
1498		break;
1499
1500	case PunchFW:
1501		SetupPunchFW(strValue);
1502		break;
1503
1504	case SkinnyPort:
1505		SetupSkinnyPort(strValue);
1506		break;
1507
1508	case LogIpfwDenied:
1509		logIpfwDenied = yesNoValue;
1510		break;
1511
1512	case PidFile:
1513		pidName = strdup (strValue);
1514		break;
1515	case Instance:
1516		NewInstance(strValue);
1517		break;
1518	case ExitDelay:
1519		if (numValue < 0 || numValue > MAX_EXIT_DELAY)
1520			errx(1, "Incorrect exit delay: %d", numValue);
1521		exitDelay = numValue;
1522		break;
1523	}
1524}
1525
1526void ReadConfigFile (const char* fileName)
1527{
1528	FILE*	file;
1529	char	*buf;
1530	size_t	len;
1531	char	*ptr, *p;
1532	char*	option;
1533
1534	file = fopen (fileName, "r");
1535	if (!file)
1536		err(1, "cannot open config file %s", fileName);
1537
1538	while ((buf = fgetln(file, &len)) != NULL) {
1539		if (buf[len - 1] == '\n')
1540			buf[len - 1] = '\0';
1541		else
1542			errx(1, "config file format error: "
1543				"last line should end with newline");
1544
1545/*
1546 * Check for comments, strip off trailing spaces.
1547 */
1548		if ((ptr = strchr(buf, '#')))
1549			*ptr = '\0';
1550		for (ptr = buf; isspace(*ptr); ++ptr)
1551			continue;
1552		if (*ptr == '\0')
1553			continue;
1554		for (p = strchr(buf, '\0'); isspace(*--p);)
1555			continue;
1556		*++p = '\0';
1557
1558/*
1559 * Extract option name.
1560 */
1561		option = ptr;
1562		while (*ptr && !isspace (*ptr))
1563			++ptr;
1564
1565		if (*ptr != '\0') {
1566
1567			*ptr = '\0';
1568			++ptr;
1569		}
1570/*
1571 * Skip white space between name and parms.
1572 */
1573		while (*ptr && isspace (*ptr))
1574			++ptr;
1575
1576		ParseOption (option, *ptr ? ptr : NULL);
1577	}
1578
1579	fclose (file);
1580}
1581
1582static void Usage(void)
1583{
1584	int			i;
1585	int			max;
1586	struct OptionInfo*	info;
1587
1588	fprintf (stderr, "Recognized options:\n\n");
1589
1590	max = sizeof (optionTable) / sizeof (struct OptionInfo);
1591	for (i = 0, info = optionTable; i < max; i++, info++) {
1592
1593		fprintf (stderr, "-%-20s %s\n", info->name,
1594						info->parmDescription);
1595
1596		if (info->shortName)
1597			fprintf (stderr, "-%-20s %s\n", info->shortName,
1598							info->parmDescription);
1599
1600		fprintf (stderr, "      %s\n\n", info->description);
1601	}
1602
1603	exit (1);
1604}
1605
1606void SetupPortRedirect (const char* parms)
1607{
1608	char		*buf;
1609	char*		ptr;
1610	char*		serverPool;
1611	struct in_addr	localAddr;
1612	struct in_addr	publicAddr;
1613	struct in_addr	remoteAddr;
1614	port_range      portRange;
1615	u_short         localPort      = 0;
1616	u_short         publicPort     = 0;
1617	u_short         remotePort     = 0;
1618	u_short         numLocalPorts  = 0;
1619	u_short         numPublicPorts = 0;
1620	u_short         numRemotePorts = 0;
1621	int		proto;
1622	char*		protoName;
1623	char*		separator;
1624	int             i;
1625	struct alias_link *aliaslink = NULL;
1626
1627	buf = strdup (parms);
1628	if (!buf)
1629		errx (1, "redirect_port: strdup() failed");
1630/*
1631 * Extract protocol.
1632 */
1633	protoName = strtok (buf, " \t");
1634	if (!protoName)
1635		errx (1, "redirect_port: missing protocol");
1636
1637	proto = StrToProto (protoName);
1638/*
1639 * Extract local address.
1640 */
1641	ptr = strtok (NULL, " \t");
1642	if (!ptr)
1643		errx (1, "redirect_port: missing local address");
1644
1645	separator = strchr(ptr, ',');
1646	if (separator) {		/* LSNAT redirection syntax. */
1647		localAddr.s_addr = INADDR_NONE;
1648		localPort = ~0;
1649		numLocalPorts = 1;
1650		serverPool = ptr;
1651	} else {
1652		if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
1653			errx (1, "redirect_port: invalid local port range");
1654
1655		localPort     = GETLOPORT(portRange);
1656		numLocalPorts = GETNUMPORTS(portRange);
1657		serverPool = NULL;
1658	}
1659
1660/*
1661 * Extract public port and optionally address.
1662 */
1663	ptr = strtok (NULL, " \t");
1664	if (!ptr)
1665		errx (1, "redirect_port: missing public port");
1666
1667	separator = strchr (ptr, ':');
1668	if (separator) {
1669	        if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
1670		        errx (1, "redirect_port: invalid public port range");
1671	}
1672	else {
1673		publicAddr.s_addr = INADDR_ANY;
1674		if (StrToPortRange (ptr, protoName, &portRange) != 0)
1675		        errx (1, "redirect_port: invalid public port range");
1676	}
1677
1678	publicPort     = GETLOPORT(portRange);
1679	numPublicPorts = GETNUMPORTS(portRange);
1680
1681/*
1682 * Extract remote address and optionally port.
1683 */
1684	ptr = strtok (NULL, " \t");
1685	if (ptr) {
1686		separator = strchr (ptr, ':');
1687		if (separator) {
1688		        if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
1689			        errx (1, "redirect_port: invalid remote port range");
1690		} else {
1691		        SETLOPORT(portRange, 0);
1692			SETNUMPORTS(portRange, 1);
1693			StrToAddr (ptr, &remoteAddr);
1694		}
1695	}
1696	else {
1697	        SETLOPORT(portRange, 0);
1698		SETNUMPORTS(portRange, 1);
1699		remoteAddr.s_addr = INADDR_ANY;
1700	}
1701
1702	remotePort     = GETLOPORT(portRange);
1703	numRemotePorts = GETNUMPORTS(portRange);
1704
1705/*
1706 * Make sure port ranges match up, then add the redirect ports.
1707 */
1708	if (numLocalPorts != numPublicPorts)
1709	        errx (1, "redirect_port: port ranges must be equal in size");
1710
1711	/* Remote port range is allowed to be '0' which means all ports. */
1712	if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
1713	        errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
1714
1715	for (i = 0 ; i < numPublicPorts ; ++i) {
1716	        /* If remotePort is all ports, set it to 0. */
1717	        u_short remotePortCopy = remotePort + i;
1718	        if (numRemotePorts == 1 && remotePort == 0)
1719		        remotePortCopy = 0;
1720
1721		aliaslink = LibAliasRedirectPort (mla, localAddr,
1722						htons(localPort + i),
1723						remoteAddr,
1724						htons(remotePortCopy),
1725						publicAddr,
1726						htons(publicPort + i),
1727						proto);
1728	}
1729
1730/*
1731 * Setup LSNAT server pool.
1732 */
1733	if (serverPool != NULL && aliaslink != NULL) {
1734		ptr = strtok(serverPool, ",");
1735		while (ptr != NULL) {
1736			if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1737				errx(1, "redirect_port: invalid local port range");
1738
1739			localPort = GETLOPORT(portRange);
1740			if (GETNUMPORTS(portRange) != 1)
1741				errx(1, "redirect_port: local port must be single in this context");
1742			LibAliasAddServer(mla, aliaslink, localAddr, htons(localPort));
1743			ptr = strtok(NULL, ",");
1744		}
1745	}
1746
1747	free (buf);
1748}
1749
1750void
1751SetupProtoRedirect(const char* parms)
1752{
1753	char		*buf;
1754	char*		ptr;
1755	struct in_addr	localAddr;
1756	struct in_addr	publicAddr;
1757	struct in_addr	remoteAddr;
1758	int		proto;
1759	char*		protoName;
1760	struct protoent *protoent;
1761
1762	buf = strdup (parms);
1763	if (!buf)
1764		errx (1, "redirect_port: strdup() failed");
1765/*
1766 * Extract protocol.
1767 */
1768	protoName = strtok(buf, " \t");
1769	if (!protoName)
1770		errx(1, "redirect_proto: missing protocol");
1771
1772	protoent = getprotobyname(protoName);
1773	if (protoent == NULL)
1774		errx(1, "redirect_proto: unknown protocol %s", protoName);
1775	else
1776		proto = protoent->p_proto;
1777/*
1778 * Extract local address.
1779 */
1780	ptr = strtok(NULL, " \t");
1781	if (!ptr)
1782		errx(1, "redirect_proto: missing local address");
1783	else
1784		StrToAddr(ptr, &localAddr);
1785/*
1786 * Extract optional public address.
1787 */
1788	ptr = strtok(NULL, " \t");
1789	if (ptr)
1790		StrToAddr(ptr, &publicAddr);
1791	else
1792		publicAddr.s_addr = INADDR_ANY;
1793/*
1794 * Extract optional remote address.
1795 */
1796	ptr = strtok(NULL, " \t");
1797	if (ptr)
1798		StrToAddr(ptr, &remoteAddr);
1799	else
1800		remoteAddr.s_addr = INADDR_ANY;
1801/*
1802 * Create aliasing link.
1803 */
1804	(void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr,
1805				       proto);
1806
1807	free (buf);
1808}
1809
1810void SetupAddressRedirect (const char* parms)
1811{
1812	char		*buf;
1813	char*		ptr;
1814	char*		separator;
1815	struct in_addr	localAddr;
1816	struct in_addr	publicAddr;
1817	char*		serverPool;
1818	struct alias_link *aliaslink;
1819
1820	buf = strdup (parms);
1821	if (!buf)
1822		errx (1, "redirect_port: strdup() failed");
1823/*
1824 * Extract local address.
1825 */
1826	ptr = strtok (buf, " \t");
1827	if (!ptr)
1828		errx (1, "redirect_address: missing local address");
1829
1830	separator = strchr(ptr, ',');
1831	if (separator) {		/* LSNAT redirection syntax. */
1832		localAddr.s_addr = INADDR_NONE;
1833		serverPool = ptr;
1834	} else {
1835		StrToAddr (ptr, &localAddr);
1836		serverPool = NULL;
1837	}
1838/*
1839 * Extract public address.
1840 */
1841	ptr = strtok (NULL, " \t");
1842	if (!ptr)
1843		errx (1, "redirect_address: missing public address");
1844
1845	StrToAddr (ptr, &publicAddr);
1846	aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr);
1847
1848/*
1849 * Setup LSNAT server pool.
1850 */
1851	if (serverPool != NULL && aliaslink != NULL) {
1852		ptr = strtok(serverPool, ",");
1853		while (ptr != NULL) {
1854			StrToAddr(ptr, &localAddr);
1855			LibAliasAddServer(mla, aliaslink, localAddr, htons(~0));
1856			ptr = strtok(NULL, ",");
1857		}
1858	}
1859
1860	free (buf);
1861}
1862
1863void StrToAddr (const char* str, struct in_addr* addr)
1864{
1865	struct hostent* hp;
1866
1867	if (inet_aton (str, addr))
1868		return;
1869
1870	hp = gethostbyname (str);
1871	if (!hp)
1872		errx (1, "unknown host %s", str);
1873
1874	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
1875}
1876
1877u_short StrToPort (const char* str, const char* proto)
1878{
1879	u_short		port;
1880	struct servent*	sp;
1881	char*		end;
1882
1883	port = strtol (str, &end, 10);
1884	if (end != str)
1885		return htons (port);
1886
1887	sp = getservbyname (str, proto);
1888	if (!sp)
1889		errx (1, "%s/%s: unknown service", str, proto);
1890
1891	return sp->s_port;
1892}
1893
1894int StrToPortRange (const char* str, const char* proto, port_range *portRange)
1895{
1896	const char*	sep;
1897	struct servent*	sp;
1898	char*		end;
1899	u_short         loPort;
1900	u_short         hiPort;
1901
1902	/* First see if this is a service, return corresponding port if so. */
1903	sp = getservbyname (str,proto);
1904	if (sp) {
1905	        SETLOPORT(*portRange, ntohs(sp->s_port));
1906		SETNUMPORTS(*portRange, 1);
1907		return 0;
1908	}
1909
1910	/* Not a service, see if it's a single port or port range. */
1911	sep = strchr (str, '-');
1912	if (sep == NULL) {
1913	        SETLOPORT(*portRange, strtol(str, &end, 10));
1914		if (end != str) {
1915		        /* Single port. */
1916		        SETNUMPORTS(*portRange, 1);
1917			return 0;
1918		}
1919
1920		/* Error in port range field. */
1921		errx (1, "%s/%s: unknown service", str, proto);
1922	}
1923
1924	/* Port range, get the values and sanity check. */
1925	sscanf (str, "%hu-%hu", &loPort, &hiPort);
1926	SETLOPORT(*portRange, loPort);
1927	SETNUMPORTS(*portRange, 0);	/* Error by default */
1928	if (loPort <= hiPort)
1929	        SETNUMPORTS(*portRange, hiPort - loPort + 1);
1930
1931	if (GETNUMPORTS(*portRange) == 0)
1932	        errx (1, "invalid port range %s", str);
1933
1934	return 0;
1935}
1936
1937
1938static int
1939StrToProto (const char* str)
1940{
1941	if (!strcmp (str, "tcp"))
1942		return IPPROTO_TCP;
1943
1944	if (!strcmp (str, "udp"))
1945		return IPPROTO_UDP;
1946
1947	errx (1, "unknown protocol %s. Expected tcp or udp", str);
1948}
1949
1950static int
1951StrToAddrAndPortRange (char* str, struct in_addr* addr, char* proto, port_range *portRange)
1952{
1953	char*	ptr;
1954
1955	ptr = strchr (str, ':');
1956	if (!ptr)
1957		errx (1, "%s is missing port number", str);
1958
1959	*ptr = '\0';
1960	++ptr;
1961
1962	StrToAddr (str, addr);
1963	return StrToPortRange (ptr, proto, portRange);
1964}
1965
1966static void
1967SetupPunchFW(const char *strValue)
1968{
1969	unsigned int base, num;
1970
1971	if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1972		errx(1, "punch_fw: basenumber:count parameter required");
1973
1974	if (CheckIpfwRulenum(base + num - 1) == -1)
1975		errx(1, "punch_fw: basenumber:count parameter should fit "
1976			"the maximum allowed rule numbers");
1977
1978	LibAliasSetFWBase(mla, base, num);
1979	(void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1980}
1981
1982static void
1983SetupSkinnyPort(const char *strValue)
1984{
1985	unsigned int port;
1986
1987	if (sscanf(strValue, "%u", &port) != 1)
1988		errx(1, "skinny_port: port parameter required");
1989
1990	LibAliasSetSkinnyPort(mla, port);
1991}
1992
1993static void
1994NewInstance(const char *name)
1995{
1996	struct instance *ip;
1997
1998	LIST_FOREACH(ip, &root, list) {
1999		if (!strcmp(ip->name, name)) {
2000			mla = ip->la;
2001			mip = ip;
2002			return;
2003		}
2004	}
2005	ninstance++;
2006	ip = calloc(1, sizeof(*ip));
2007	ip->name = strdup(name);
2008	ip->la = LibAliasInit (ip->la);
2009	ip->assignAliasAddr	= 0;
2010	ip->ifName		= NULL;
2011 	ip->logDropped		= 0;
2012	ip->inPort		= 0;
2013	ip->outPort		= 0;
2014	ip->inOutPort		= 0;
2015	ip->aliasAddr.s_addr	= INADDR_NONE;
2016	ip->ifMTU		= -1;
2017	ip->aliasOverhead	= 12;
2018	LIST_INSERT_HEAD(&root, ip, list);
2019	mla = ip->la;
2020	mip = ip;
2021}
2022
2023static int
2024CheckIpfwRulenum(unsigned int rnum)
2025{
2026	unsigned int default_rule;
2027	size_t len = sizeof(default_rule);
2028
2029	if (sysctlbyname("net.inet.ip.fw.default_rule", &default_rule, &len,
2030		NULL, 0) == -1) {
2031		warn("Failed to get the default ipfw rule number, using "
2032		     "default historical value 65535.  The reason was");
2033		default_rule = 65535;
2034	}
2035	if (rnum >= default_rule) {
2036		return -1;
2037	}
2038
2039	return 0;
2040}
2041