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