xref: /freebsd/sbin/natd/natd.c (revision 3daff2423f4472a590e703b7f705104cf7660c8c)
124084f9bSBrian Somers /*
224084f9bSBrian Somers  * natd - Network Address Translation Daemon for FreeBSD.
324084f9bSBrian Somers  *
4f13f9fadSAlexander Langer  * This software is provided free of charge, with no
524084f9bSBrian Somers  * warranty of any kind, either expressed or implied.
624084f9bSBrian Somers  * Use at your own risk.
724084f9bSBrian Somers  *
824084f9bSBrian Somers  * You may copy, modify and distribute this software (natd.c) freely.
924084f9bSBrian Somers  *
10fb994b07SBrian Somers  * Ari Suutari <suutari@iki.fi>
1124084f9bSBrian Somers  *
127f3dea24SPeter Wemm  * $FreeBSD$
1324084f9bSBrian Somers  */
1424084f9bSBrian Somers 
1559a7c613SBrian Somers #define SYSLOG_NAMES
1659a7c613SBrian Somers 
1724084f9bSBrian Somers #include <sys/types.h>
1824084f9bSBrian Somers #include <sys/socket.h>
194c04fa4cSRuslan Ermilov #include <sys/sysctl.h>
2024084f9bSBrian Somers #include <sys/time.h>
2124084f9bSBrian Somers 
2224084f9bSBrian Somers #include <netinet/in.h>
2324084f9bSBrian Somers #include <netinet/in_systm.h>
2424084f9bSBrian Somers #include <netinet/ip.h>
2524084f9bSBrian Somers #include <machine/in_cksum.h>
2624084f9bSBrian Somers #include <netinet/tcp.h>
2759a7c613SBrian Somers #include <netinet/udp.h>
2859a7c613SBrian Somers #include <netinet/ip_icmp.h>
2924084f9bSBrian Somers #include <net/if.h>
304c04fa4cSRuslan Ermilov #include <net/if_dl.h>
3124084f9bSBrian Somers #include <net/route.h>
3224084f9bSBrian Somers #include <arpa/inet.h>
3324084f9bSBrian Somers 
3424084f9bSBrian Somers #include <alias.h>
350fc81af1SPhilippe Charnier #include <ctype.h>
360fc81af1SPhilippe Charnier #include <err.h>
370fc81af1SPhilippe Charnier #include <errno.h>
380fc81af1SPhilippe Charnier #include <netdb.h>
390fc81af1SPhilippe Charnier #include <signal.h>
400fc81af1SPhilippe Charnier #include <stdio.h>
410fc81af1SPhilippe Charnier #include <stdlib.h>
420fc81af1SPhilippe Charnier #include <string.h>
430fc81af1SPhilippe Charnier #include <syslog.h>
440fc81af1SPhilippe Charnier #include <unistd.h>
4567a886fbSBrian Somers 
4624084f9bSBrian Somers #include "natd.h"
4724084f9bSBrian Somers 
4824084f9bSBrian Somers /*
4924084f9bSBrian Somers  * Default values for input and output
5024084f9bSBrian Somers  * divert socket ports.
5124084f9bSBrian Somers  */
5224084f9bSBrian Somers 
5324084f9bSBrian Somers #define	DEFAULT_SERVICE	"natd"
5424084f9bSBrian Somers 
5524084f9bSBrian Somers /*
565d8ee958SBrian Somers  * Definition of a port range, and macros to deal with values.
575d8ee958SBrian Somers  * FORMAT:  HI 16-bits == first port in range, 0 == all ports.
585d8ee958SBrian Somers  *          LO 16-bits == number of ports in range
595d8ee958SBrian Somers  * NOTES:   - Port values are not stored in network byte order.
605d8ee958SBrian Somers  */
615d8ee958SBrian Somers 
625d8ee958SBrian Somers typedef u_long port_range;
635d8ee958SBrian Somers 
645d8ee958SBrian Somers #define GETLOPORT(x)     ((x) >> 0x10)
655d8ee958SBrian Somers #define GETNUMPORTS(x)   ((x) & 0x0000ffff)
665d8ee958SBrian Somers #define GETHIPORT(x)     (GETLOPORT((x)) + GETNUMPORTS((x)))
675d8ee958SBrian Somers 
685d8ee958SBrian Somers /* Set y to be the low-port value in port_range variable x. */
695d8ee958SBrian Somers #define SETLOPORT(x,y)   ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
705d8ee958SBrian Somers 
715d8ee958SBrian Somers /* Set y to be the number of ports in port_range variable x. */
725d8ee958SBrian Somers #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y))
735d8ee958SBrian Somers 
745d8ee958SBrian Somers /*
7524084f9bSBrian Somers  * Function prototypes.
7624084f9bSBrian Somers  */
7724084f9bSBrian Somers 
7859a7c613SBrian Somers static void	DoAliasing (int fd, int direction);
79902cb50aSBrian Somers static void	DaemonMode (void);
8024084f9bSBrian Somers static void	HandleRoutingInfo (int fd);
81902cb50aSBrian Somers static void	Usage (void);
8259a7c613SBrian Somers static char*	FormatPacket (struct ip*);
8324084f9bSBrian Somers static void	PrintPacket (struct ip*);
84902cb50aSBrian Somers static void	SyslogPacket (struct ip*, int priority, const char *label);
854c04fa4cSRuslan Ermilov static void	SetAliasAddressFromIfName (const char *ifName);
86902cb50aSBrian Somers static void	InitiateShutdown (int);
87902cb50aSBrian Somers static void	Shutdown (int);
88902cb50aSBrian Somers static void	RefreshAddr (int);
89b0f55af6SRuslan Ermilov static void	ParseOption (const char* option, const char* parms);
90902cb50aSBrian Somers static void	ReadConfigFile (const char* fileName);
91902cb50aSBrian Somers static void	SetupPortRedirect (const char* parms);
924330006dSRuslan Ermilov static void	SetupProtoRedirect(const char* parms);
93902cb50aSBrian Somers static void	SetupAddressRedirect (const char* parms);
94902cb50aSBrian Somers static void	StrToAddr (const char* str, struct in_addr* addr);
95902cb50aSBrian Somers static u_short  StrToPort (const char* str, const char* proto);
96902cb50aSBrian Somers static int      StrToPortRange (const char* str, const char* proto, port_range *portRange);
97902cb50aSBrian Somers static int 	StrToProto (const char* str);
98902cb50aSBrian Somers static int      StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange);
9924084f9bSBrian Somers static void	ParseArgs (int argc, char** argv);
100bc4ebb98SRuslan Ermilov static void	SetupPunchFW(const char *strValue);
10124084f9bSBrian Somers 
10224084f9bSBrian Somers /*
10324084f9bSBrian Somers  * Globals.
10424084f9bSBrian Somers  */
10524084f9bSBrian Somers 
10624084f9bSBrian Somers static	int			verbose;
10724084f9bSBrian Somers static 	int			background;
10824084f9bSBrian Somers static	int			running;
10924084f9bSBrian Somers static	int			assignAliasAddr;
11024084f9bSBrian Somers static	char*			ifName;
11124084f9bSBrian Somers static  int			ifIndex;
11267a886fbSBrian Somers static	u_short			inPort;
11367a886fbSBrian Somers static	u_short			outPort;
11467a886fbSBrian Somers static	u_short			inOutPort;
11524084f9bSBrian Somers static	struct in_addr		aliasAddr;
11624084f9bSBrian Somers static 	int			dynamicMode;
11724084f9bSBrian Somers static  int			ifMTU;
11824084f9bSBrian Somers static	int			aliasOverhead;
11924084f9bSBrian Somers static 	int			icmpSock;
120f9b06d5cSBrian Somers static  int			dropIgnoredIncoming;
12159a7c613SBrian Somers static  int			logDropped;
12259a7c613SBrian Somers static	int			logFacility;
1233843533eSRuslan Ermilov static	int			logIpfwDenied;
12424084f9bSBrian Somers 
12524084f9bSBrian Somers int main (int argc, char** argv)
12624084f9bSBrian Somers {
12724084f9bSBrian Somers 	int			divertIn;
12824084f9bSBrian Somers 	int			divertOut;
12924084f9bSBrian Somers 	int			divertInOut;
13024084f9bSBrian Somers 	int			routeSock;
13124084f9bSBrian Somers 	struct sockaddr_in	addr;
13224084f9bSBrian Somers 	fd_set			readMask;
13324084f9bSBrian Somers 	int			fdMax;
13424084f9bSBrian Somers /*
13524084f9bSBrian Somers  * Initialize packet aliasing software.
13624084f9bSBrian Somers  * Done already here to be able to alter option bits
13724084f9bSBrian Somers  * during command line and configuration file processing.
13824084f9bSBrian Somers  */
139fb994b07SBrian Somers 	PacketAliasInit ();
14024084f9bSBrian Somers /*
14124084f9bSBrian Somers  * Parse options.
14224084f9bSBrian Somers  */
14324084f9bSBrian Somers 	inPort			= 0;
14424084f9bSBrian Somers 	outPort			= 0;
14524084f9bSBrian Somers 	verbose 		= 0;
14624084f9bSBrian Somers 	inOutPort		= 0;
14724084f9bSBrian Somers 	ifName			= NULL;
14824084f9bSBrian Somers 	ifMTU			= -1;
14924084f9bSBrian Somers 	background		= 0;
15024084f9bSBrian Somers 	running			= 1;
15124084f9bSBrian Somers 	assignAliasAddr		= 0;
15224084f9bSBrian Somers 	aliasAddr.s_addr	= INADDR_NONE;
15324084f9bSBrian Somers 	aliasOverhead		= 12;
15424084f9bSBrian Somers 	dynamicMode		= 0;
15559a7c613SBrian Somers  	logDropped		= 0;
15659a7c613SBrian Somers  	logFacility		= LOG_DAEMON;
157c0956cf8SRuslan Ermilov 	logIpfwDenied		= -1;
15824084f9bSBrian Somers 
15924084f9bSBrian Somers 	ParseArgs (argc, argv);
16024084f9bSBrian Somers /*
161c0956cf8SRuslan Ermilov  * Log ipfw(8) denied packets by default in verbose mode.
162c0956cf8SRuslan Ermilov  */
163c0956cf8SRuslan Ermilov 	if (logIpfwDenied == -1)
164c0956cf8SRuslan Ermilov 		logIpfwDenied = verbose;
165c0956cf8SRuslan Ermilov /*
16659a7c613SBrian Somers  * Open syslog channel.
16759a7c613SBrian Somers  */
1684c04fa4cSRuslan Ermilov 	openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
1694c04fa4cSRuslan Ermilov 		 logFacility);
17059a7c613SBrian Somers /*
17124084f9bSBrian Somers  * Check that valid aliasing address has been given.
17224084f9bSBrian Somers  */
1730fc81af1SPhilippe Charnier 	if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL)
1740fc81af1SPhilippe Charnier 		errx (1, "aliasing address not given");
17524084f9bSBrian Somers 
1760fc81af1SPhilippe Charnier 	if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL)
17767a886fbSBrian Somers 		errx (1, "both alias address and interface "
17867a886fbSBrian Somers 			 "name are not allowed");
17924084f9bSBrian Somers /*
18024084f9bSBrian Somers  * Check that valid port number is known.
18124084f9bSBrian Somers  */
18224084f9bSBrian Somers 	if (inPort != 0 || outPort != 0)
1830fc81af1SPhilippe Charnier 		if (inPort == 0 || outPort == 0)
1840fc81af1SPhilippe Charnier 			errx (1, "both input and output ports are required");
18524084f9bSBrian Somers 
18624084f9bSBrian Somers 	if (inPort == 0 && outPort == 0 && inOutPort == 0)
187b0f55af6SRuslan Ermilov 		ParseOption ("port", DEFAULT_SERVICE);
18824084f9bSBrian Somers 
18924084f9bSBrian Somers /*
190f9b06d5cSBrian Somers  * Check if ignored packets should be dropped.
191f9b06d5cSBrian Somers  */
192f9b06d5cSBrian Somers 	dropIgnoredIncoming = PacketAliasSetMode (0, 0);
193f9b06d5cSBrian Somers 	dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
194f9b06d5cSBrian Somers /*
19524084f9bSBrian Somers  * Create divert sockets. Use only one socket if -p was specified
19624084f9bSBrian Somers  * on command line. Otherwise, create separate sockets for
19724084f9bSBrian Somers  * outgoing and incoming connnections.
19824084f9bSBrian Somers  */
19924084f9bSBrian Somers 	if (inOutPort) {
20024084f9bSBrian Somers 
20124084f9bSBrian Somers 		divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
20224084f9bSBrian Somers 		if (divertInOut == -1)
20324084f9bSBrian Somers 			Quit ("Unable to create divert socket.");
20424084f9bSBrian Somers 
20524084f9bSBrian Somers 		divertIn  = -1;
20624084f9bSBrian Somers 		divertOut = -1;
20724084f9bSBrian Somers /*
20824084f9bSBrian Somers  * Bind socket.
20924084f9bSBrian Somers  */
21024084f9bSBrian Somers 
21124084f9bSBrian Somers 		addr.sin_family		= AF_INET;
21224084f9bSBrian Somers 		addr.sin_addr.s_addr	= INADDR_ANY;
21324084f9bSBrian Somers 		addr.sin_port		= inOutPort;
21424084f9bSBrian Somers 
21524084f9bSBrian Somers 		if (bind (divertInOut,
21624084f9bSBrian Somers 			  (struct sockaddr*) &addr,
21724084f9bSBrian Somers 			  sizeof addr) == -1)
21824084f9bSBrian Somers 			Quit ("Unable to bind divert socket.");
21924084f9bSBrian Somers 	}
22024084f9bSBrian Somers 	else {
22124084f9bSBrian Somers 
22224084f9bSBrian Somers 		divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
22324084f9bSBrian Somers 		if (divertIn == -1)
22424084f9bSBrian Somers 			Quit ("Unable to create incoming divert socket.");
22524084f9bSBrian Somers 
22624084f9bSBrian Somers 		divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
22724084f9bSBrian Somers 		if (divertOut == -1)
22824084f9bSBrian Somers 			Quit ("Unable to create outgoing divert socket.");
22924084f9bSBrian Somers 
23024084f9bSBrian Somers 		divertInOut = -1;
23124084f9bSBrian Somers 
23224084f9bSBrian Somers /*
23324084f9bSBrian Somers  * Bind divert sockets.
23424084f9bSBrian Somers  */
23524084f9bSBrian Somers 
23624084f9bSBrian Somers 		addr.sin_family		= AF_INET;
23724084f9bSBrian Somers 		addr.sin_addr.s_addr	= INADDR_ANY;
23824084f9bSBrian Somers 		addr.sin_port		= inPort;
23924084f9bSBrian Somers 
24024084f9bSBrian Somers 		if (bind (divertIn,
24124084f9bSBrian Somers 			  (struct sockaddr*) &addr,
24224084f9bSBrian Somers 			  sizeof addr) == -1)
24324084f9bSBrian Somers 			Quit ("Unable to bind incoming divert socket.");
24424084f9bSBrian Somers 
24524084f9bSBrian Somers 		addr.sin_family		= AF_INET;
24624084f9bSBrian Somers 		addr.sin_addr.s_addr	= INADDR_ANY;
24724084f9bSBrian Somers 		addr.sin_port		= outPort;
24824084f9bSBrian Somers 
24924084f9bSBrian Somers 		if (bind (divertOut,
25024084f9bSBrian Somers 			  (struct sockaddr*) &addr,
25124084f9bSBrian Somers 			  sizeof addr) == -1)
25224084f9bSBrian Somers 			Quit ("Unable to bind outgoing divert socket.");
25324084f9bSBrian Somers 	}
25424084f9bSBrian Somers /*
255f2da55a2SRuslan Ermilov  * Create routing socket if interface name specified and in dynamic mode.
25624084f9bSBrian Somers  */
257f2da55a2SRuslan Ermilov 	routeSock = -1;
258f2da55a2SRuslan Ermilov 	if (ifName) {
259f2da55a2SRuslan Ermilov 		if (dynamicMode) {
26024084f9bSBrian Somers 
26124084f9bSBrian Somers 			routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
26224084f9bSBrian Somers 			if (routeSock == -1)
26324084f9bSBrian Somers 				Quit ("Unable to create routing info socket.");
264f2da55a2SRuslan Ermilov 
265f2da55a2SRuslan Ermilov 			assignAliasAddr = 1;
26624084f9bSBrian Somers 		}
26724084f9bSBrian Somers 		else
268f2da55a2SRuslan Ermilov 			SetAliasAddressFromIfName (ifName);
269f2da55a2SRuslan Ermilov 	}
27024084f9bSBrian Somers /*
27124084f9bSBrian Somers  * Create socket for sending ICMP messages.
27224084f9bSBrian Somers  */
27324084f9bSBrian Somers 	icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
27424084f9bSBrian Somers 	if (icmpSock == -1)
27524084f9bSBrian Somers 		Quit ("Unable to create ICMP socket.");
276f3d64024SBrian Somers 
277f3d64024SBrian Somers /*
278f3d64024SBrian Somers  * And disable reads for the socket, otherwise it slowly fills
279f3d64024SBrian Somers  * up with received icmps which we do not use.
280f3d64024SBrian Somers  */
281f3d64024SBrian Somers 	shutdown(icmpSock, SHUT_RD);
282f3d64024SBrian Somers 
28324084f9bSBrian Somers /*
28424084f9bSBrian Somers  * Become a daemon unless verbose mode was requested.
28524084f9bSBrian Somers  */
28624084f9bSBrian Somers 	if (!verbose)
28724084f9bSBrian Somers 		DaemonMode ();
28824084f9bSBrian Somers /*
28924084f9bSBrian Somers  * Catch signals to manage shutdown and
29024084f9bSBrian Somers  * refresh of interface address.
29124084f9bSBrian Somers  */
292cd45c931SRuslan Ermilov 	siginterrupt(SIGTERM, 1);
293cd45c931SRuslan Ermilov 	siginterrupt(SIGHUP, 1);
29424084f9bSBrian Somers 	signal (SIGTERM, InitiateShutdown);
29524084f9bSBrian Somers 	signal (SIGHUP, RefreshAddr);
29624084f9bSBrian Somers /*
29724084f9bSBrian Somers  * Set alias address if it has been given.
29824084f9bSBrian Somers  */
29924084f9bSBrian Somers 	if (aliasAddr.s_addr != INADDR_NONE)
300fb994b07SBrian Somers 		PacketAliasSetAddress (aliasAddr);
30124084f9bSBrian Somers /*
30224084f9bSBrian Somers  * We need largest descriptor number for select.
30324084f9bSBrian Somers  */
30424084f9bSBrian Somers 
30524084f9bSBrian Somers 	fdMax = -1;
30624084f9bSBrian Somers 
30724084f9bSBrian Somers 	if (divertIn > fdMax)
30824084f9bSBrian Somers 		fdMax = divertIn;
30924084f9bSBrian Somers 
31024084f9bSBrian Somers 	if (divertOut > fdMax)
31124084f9bSBrian Somers 		fdMax = divertOut;
31224084f9bSBrian Somers 
31324084f9bSBrian Somers 	if (divertInOut > fdMax)
31424084f9bSBrian Somers 		fdMax = divertInOut;
31524084f9bSBrian Somers 
31624084f9bSBrian Somers 	if (routeSock > fdMax)
31724084f9bSBrian Somers 		fdMax = routeSock;
31824084f9bSBrian Somers 
31924084f9bSBrian Somers 	while (running) {
320fb994b07SBrian Somers 
3213daff242SRuslan Ermilov 		if (divertInOut != -1 && !ifName) {
322fb994b07SBrian Somers /*
323fb994b07SBrian Somers  * When using only one socket, just call
324fb994b07SBrian Somers  * DoAliasing repeatedly to process packets.
325fb994b07SBrian Somers  */
32659a7c613SBrian Somers 			DoAliasing (divertInOut, DONT_KNOW);
327fb994b07SBrian Somers 			continue;
328fb994b07SBrian Somers 		}
32924084f9bSBrian Somers /*
33024084f9bSBrian Somers  * Build read mask from socket descriptors to select.
33124084f9bSBrian Somers  */
33224084f9bSBrian Somers 		FD_ZERO (&readMask);
333fb994b07SBrian Somers /*
3343daff242SRuslan Ermilov  * Check if new packets are available.
335fb994b07SBrian Somers  */
33624084f9bSBrian Somers 		if (divertIn != -1)
33724084f9bSBrian Somers 			FD_SET (divertIn, &readMask);
33824084f9bSBrian Somers 
33924084f9bSBrian Somers 		if (divertOut != -1)
34024084f9bSBrian Somers 			FD_SET (divertOut, &readMask);
34124084f9bSBrian Somers 
34224084f9bSBrian Somers 		if (divertInOut != -1)
34324084f9bSBrian Somers 			FD_SET (divertInOut, &readMask);
344fb994b07SBrian Somers /*
345fb994b07SBrian Somers  * Routing info is processed always.
346fb994b07SBrian Somers  */
34724084f9bSBrian Somers 		if (routeSock != -1)
34824084f9bSBrian Somers 			FD_SET (routeSock, &readMask);
34924084f9bSBrian Somers 
35024084f9bSBrian Somers 		if (select (fdMax + 1,
35124084f9bSBrian Somers 			    &readMask,
3523daff242SRuslan Ermilov 			    NULL,
35324084f9bSBrian Somers 			    NULL,
35424084f9bSBrian Somers 			    NULL) == -1) {
35524084f9bSBrian Somers 
35624084f9bSBrian Somers 			if (errno == EINTR)
35724084f9bSBrian Somers 				continue;
35824084f9bSBrian Somers 
35924084f9bSBrian Somers 			Quit ("Select failed.");
36024084f9bSBrian Somers 		}
36124084f9bSBrian Somers 
36224084f9bSBrian Somers 		if (divertIn != -1)
36324084f9bSBrian Somers 			if (FD_ISSET (divertIn, &readMask))
36459a7c613SBrian Somers 				DoAliasing (divertIn, INPUT);
36524084f9bSBrian Somers 
36624084f9bSBrian Somers 		if (divertOut != -1)
36724084f9bSBrian Somers 			if (FD_ISSET (divertOut, &readMask))
36859a7c613SBrian Somers 				DoAliasing (divertOut, OUTPUT);
36924084f9bSBrian Somers 
37024084f9bSBrian Somers 		if (divertInOut != -1)
37124084f9bSBrian Somers 			if (FD_ISSET (divertInOut, &readMask))
37259a7c613SBrian Somers 				DoAliasing (divertInOut, DONT_KNOW);
37324084f9bSBrian Somers 
37424084f9bSBrian Somers 		if (routeSock != -1)
37524084f9bSBrian Somers 			if (FD_ISSET (routeSock, &readMask))
37624084f9bSBrian Somers 				HandleRoutingInfo (routeSock);
37724084f9bSBrian Somers 	}
37824084f9bSBrian Somers 
37924084f9bSBrian Somers 	if (background)
38024084f9bSBrian Somers 		unlink (PIDFILE);
38124084f9bSBrian Somers 
38224084f9bSBrian Somers 	return 0;
38324084f9bSBrian Somers }
38424084f9bSBrian Somers 
38524084f9bSBrian Somers static void DaemonMode ()
38624084f9bSBrian Somers {
38724084f9bSBrian Somers 	FILE*	pidFile;
38824084f9bSBrian Somers 
38924084f9bSBrian Somers 	daemon (0, 0);
39024084f9bSBrian Somers 	background = 1;
39124084f9bSBrian Somers 
39224084f9bSBrian Somers 	pidFile = fopen (PIDFILE, "w");
39324084f9bSBrian Somers 	if (pidFile) {
39424084f9bSBrian Somers 
39524084f9bSBrian Somers 		fprintf (pidFile, "%d\n", getpid ());
39624084f9bSBrian Somers 		fclose (pidFile);
39724084f9bSBrian Somers 	}
39824084f9bSBrian Somers }
39924084f9bSBrian Somers 
40024084f9bSBrian Somers static void ParseArgs (int argc, char** argv)
40124084f9bSBrian Somers {
40224084f9bSBrian Somers 	int		arg;
40324084f9bSBrian Somers 	char*		opt;
40424084f9bSBrian Somers 	char		parmBuf[256];
40530395bb5SJosef Karthauser 	int		len; /* bounds checking */
40624084f9bSBrian Somers 
40724084f9bSBrian Somers 	for (arg = 1; arg < argc; arg++) {
40824084f9bSBrian Somers 
40924084f9bSBrian Somers 		opt  = argv[arg];
41024084f9bSBrian Somers 		if (*opt != '-') {
41124084f9bSBrian Somers 
4120fc81af1SPhilippe Charnier 			warnx ("invalid option %s", opt);
41324084f9bSBrian Somers 			Usage ();
41424084f9bSBrian Somers 		}
41524084f9bSBrian Somers 
41624084f9bSBrian Somers 		parmBuf[0] = '\0';
41730395bb5SJosef Karthauser 		len = 0;
41824084f9bSBrian Somers 
41924084f9bSBrian Somers 		while (arg < argc - 1) {
42024084f9bSBrian Somers 
42124084f9bSBrian Somers 			if (argv[arg + 1][0] == '-')
42224084f9bSBrian Somers 				break;
42324084f9bSBrian Somers 
42430395bb5SJosef Karthauser 			if (len) {
42530395bb5SJosef Karthauser 				strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
42630395bb5SJosef Karthauser 				len += strlen(parmBuf + len);
42724084f9bSBrian Somers 			}
42824084f9bSBrian Somers 
42930395bb5SJosef Karthauser 			++arg;
43030395bb5SJosef Karthauser 			strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
43130395bb5SJosef Karthauser 			len += strlen(parmBuf + len);
43230395bb5SJosef Karthauser 
43330395bb5SJosef Karthauser 		}
43430395bb5SJosef Karthauser 
435b0f55af6SRuslan Ermilov 		ParseOption (opt + 1, (len ? parmBuf : NULL));
43630395bb5SJosef Karthauser 
43724084f9bSBrian Somers 	}
43824084f9bSBrian Somers }
43924084f9bSBrian Somers 
44059a7c613SBrian Somers static void DoAliasing (int fd, int direction)
44124084f9bSBrian Somers {
44224084f9bSBrian Somers 	int			bytes;
44324084f9bSBrian Somers 	int			origBytes;
4443daff242SRuslan Ermilov 	char			buf[IP_MAXPACKET];
4453daff242SRuslan Ermilov 	struct sockaddr_in	addr;
4463daff242SRuslan Ermilov 	int			wrote;
447f9b06d5cSBrian Somers 	int			status;
44824084f9bSBrian Somers 	int			addrSize;
44924084f9bSBrian Somers 	struct ip*		ip;
4503daff242SRuslan Ermilov 	char			msgBuf[80];
45124084f9bSBrian Somers 
45224084f9bSBrian Somers 	if (assignAliasAddr) {
45324084f9bSBrian Somers 
45424084f9bSBrian Somers 		SetAliasAddressFromIfName (ifName);
45524084f9bSBrian Somers 		assignAliasAddr = 0;
45624084f9bSBrian Somers 	}
45724084f9bSBrian Somers /*
45824084f9bSBrian Somers  * Get packet from socket.
45924084f9bSBrian Somers  */
4603daff242SRuslan Ermilov 	addrSize  = sizeof addr;
46124084f9bSBrian Somers 	origBytes = recvfrom (fd,
4623daff242SRuslan Ermilov 			      buf,
4633daff242SRuslan Ermilov 			      sizeof buf,
46424084f9bSBrian Somers 			      0,
4653daff242SRuslan Ermilov 			      (struct sockaddr*) &addr,
46624084f9bSBrian Somers 			      &addrSize);
46724084f9bSBrian Somers 
46824084f9bSBrian Somers 	if (origBytes == -1) {
46924084f9bSBrian Somers 
47024084f9bSBrian Somers 		if (errno != EINTR)
4710fc81af1SPhilippe Charnier 			Warn ("read from divert socket failed");
47224084f9bSBrian Somers 
47324084f9bSBrian Somers 		return;
47424084f9bSBrian Somers 	}
47524084f9bSBrian Somers /*
47624084f9bSBrian Somers  * This is a IP packet.
47724084f9bSBrian Somers  */
4783daff242SRuslan Ermilov 	ip = (struct ip*) buf;
479ebe70c8fSWarner Losh 	if (direction == DONT_KNOW) {
4803daff242SRuslan Ermilov 		if (addr.sin_addr.s_addr == INADDR_ANY)
48159a7c613SBrian Somers 			direction = OUTPUT;
48259a7c613SBrian Somers 		else
48359a7c613SBrian Somers 			direction = INPUT;
484ebe70c8fSWarner Losh 	}
48524084f9bSBrian Somers 
48624084f9bSBrian Somers 	if (verbose) {
48724084f9bSBrian Somers /*
48824084f9bSBrian Somers  * Print packet direction and protocol type.
48924084f9bSBrian Somers  */
49059a7c613SBrian Somers 		printf (direction == OUTPUT ? "Out " : "In  ");
49124084f9bSBrian Somers 
49224084f9bSBrian Somers 		switch (ip->ip_p) {
49324084f9bSBrian Somers 		case IPPROTO_TCP:
49424084f9bSBrian Somers 			printf ("[TCP]  ");
49524084f9bSBrian Somers 			break;
49624084f9bSBrian Somers 
49724084f9bSBrian Somers 		case IPPROTO_UDP:
49824084f9bSBrian Somers 			printf ("[UDP]  ");
49924084f9bSBrian Somers 			break;
50024084f9bSBrian Somers 
50124084f9bSBrian Somers 		case IPPROTO_ICMP:
50224084f9bSBrian Somers 			printf ("[ICMP] ");
50324084f9bSBrian Somers 			break;
50424084f9bSBrian Somers 
50524084f9bSBrian Somers 		default:
50659a7c613SBrian Somers 			printf ("[%d]    ", ip->ip_p);
50724084f9bSBrian Somers 			break;
50824084f9bSBrian Somers 		}
50924084f9bSBrian Somers /*
51024084f9bSBrian Somers  * Print addresses.
51124084f9bSBrian Somers  */
51224084f9bSBrian Somers 		PrintPacket (ip);
51324084f9bSBrian Somers 	}
51424084f9bSBrian Somers 
51559a7c613SBrian Somers 	if (direction == OUTPUT) {
51624084f9bSBrian Somers /*
51724084f9bSBrian Somers  * Outgoing packets. Do aliasing.
51824084f9bSBrian Somers  */
5193daff242SRuslan Ermilov 		PacketAliasOut (buf, IP_MAXPACKET);
52024084f9bSBrian Somers 	}
52124084f9bSBrian Somers 	else {
52259a7c613SBrian Somers 
52324084f9bSBrian Somers /*
52424084f9bSBrian Somers  * Do aliasing.
52524084f9bSBrian Somers  */
5263daff242SRuslan Ermilov 		status = PacketAliasIn (buf, IP_MAXPACKET);
527f9b06d5cSBrian Somers 		if (status == PKT_ALIAS_IGNORED &&
528f9b06d5cSBrian Somers 		    dropIgnoredIncoming) {
529f9b06d5cSBrian Somers 
53059a7c613SBrian Somers 			if (verbose)
531f9b06d5cSBrian Somers 				printf (" dropped.\n");
53259a7c613SBrian Somers 
53359a7c613SBrian Somers 			if (logDropped)
53459a7c613SBrian Somers 				SyslogPacket (ip, LOG_WARNING, "denied");
53559a7c613SBrian Somers 
536f9b06d5cSBrian Somers 			return;
537f9b06d5cSBrian Somers 		}
53824084f9bSBrian Somers 	}
53924084f9bSBrian Somers /*
54024084f9bSBrian Somers  * Length might have changed during aliasing.
54124084f9bSBrian Somers  */
54224084f9bSBrian Somers 	bytes = ntohs (ip->ip_len);
54324084f9bSBrian Somers /*
54424084f9bSBrian Somers  * Update alias overhead size for outgoing packets.
54524084f9bSBrian Somers  */
54659a7c613SBrian Somers 	if (direction == OUTPUT &&
54724084f9bSBrian Somers 	    bytes - origBytes > aliasOverhead)
54824084f9bSBrian Somers 		aliasOverhead = bytes - origBytes;
54924084f9bSBrian Somers 
55024084f9bSBrian Somers 	if (verbose) {
55124084f9bSBrian Somers 
55224084f9bSBrian Somers /*
55324084f9bSBrian Somers  * Print addresses after aliasing.
55424084f9bSBrian Somers  */
55524084f9bSBrian Somers 		printf (" aliased to\n");
55624084f9bSBrian Somers 		printf ("           ");
55724084f9bSBrian Somers 		PrintPacket (ip);
55824084f9bSBrian Somers 		printf ("\n");
55924084f9bSBrian Somers 	}
560fb994b07SBrian Somers 
56124084f9bSBrian Somers /*
56224084f9bSBrian Somers  * Put packet back for processing.
56324084f9bSBrian Somers  */
56424084f9bSBrian Somers 	wrote = sendto (fd,
5653daff242SRuslan Ermilov 		        buf,
5663daff242SRuslan Ermilov 	    		bytes,
56724084f9bSBrian Somers 	    		0,
5683daff242SRuslan Ermilov 	    		(struct sockaddr*) &addr,
5693daff242SRuslan Ermilov 	    		sizeof addr);
57024084f9bSBrian Somers 
5713daff242SRuslan Ermilov 	if (wrote != bytes) {
57224084f9bSBrian Somers 
57324084f9bSBrian Somers 		if (errno == EMSGSIZE) {
57424084f9bSBrian Somers 
5753daff242SRuslan Ermilov 			if (direction == OUTPUT &&
57624084f9bSBrian Somers 			    ifMTU != -1)
57724084f9bSBrian Somers 				SendNeedFragIcmp (icmpSock,
5783daff242SRuslan Ermilov 						  (struct ip*) buf,
57924084f9bSBrian Somers 						  ifMTU - aliasOverhead);
58024084f9bSBrian Somers 		}
5813843533eSRuslan Ermilov 		else if (errno == EACCES && logIpfwDenied) {
58224084f9bSBrian Somers 
583d782daf0SJosef Karthauser 			sprintf (msgBuf, "failed to write packet back");
58424084f9bSBrian Somers 			Warn (msgBuf);
58524084f9bSBrian Somers 		}
58624084f9bSBrian Somers 	}
58724084f9bSBrian Somers }
58824084f9bSBrian Somers 
58924084f9bSBrian Somers static void HandleRoutingInfo (int fd)
59024084f9bSBrian Somers {
59124084f9bSBrian Somers 	int			bytes;
59224084f9bSBrian Somers 	struct if_msghdr	ifMsg;
59324084f9bSBrian Somers /*
59424084f9bSBrian Somers  * Get packet from socket.
59524084f9bSBrian Somers  */
59624084f9bSBrian Somers 	bytes = read (fd, &ifMsg, sizeof ifMsg);
59724084f9bSBrian Somers 	if (bytes == -1) {
59824084f9bSBrian Somers 
5990fc81af1SPhilippe Charnier 		Warn ("read from routing socket failed");
60024084f9bSBrian Somers 		return;
60124084f9bSBrian Somers 	}
60224084f9bSBrian Somers 
60324084f9bSBrian Somers 	if (ifMsg.ifm_version != RTM_VERSION) {
60424084f9bSBrian Somers 
6050fc81af1SPhilippe Charnier 		Warn ("unexpected packet read from routing socket");
60624084f9bSBrian Somers 		return;
60724084f9bSBrian Somers 	}
60824084f9bSBrian Somers 
60924084f9bSBrian Somers 	if (verbose)
6106f3dbe5eSRuslan Ermilov 		printf ("Routing message %#x received.\n", ifMsg.ifm_type);
61124084f9bSBrian Somers 
6126f3dbe5eSRuslan Ermilov 	if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO) &&
6136f3dbe5eSRuslan Ermilov 	    ifMsg.ifm_index == ifIndex) {
6146f3dbe5eSRuslan Ermilov 		if (verbose)
6156f3dbe5eSRuslan Ermilov 			printf("Interface address/MTU has probably changed.\n");
61624084f9bSBrian Somers 		assignAliasAddr = 1;
61724084f9bSBrian Somers 	}
6186f3dbe5eSRuslan Ermilov }
61924084f9bSBrian Somers 
62024084f9bSBrian Somers static void PrintPacket (struct ip* ip)
62124084f9bSBrian Somers {
62259a7c613SBrian Somers 	printf ("%s", FormatPacket (ip));
62359a7c613SBrian Somers }
62459a7c613SBrian Somers 
625902cb50aSBrian Somers static void SyslogPacket (struct ip* ip, int priority, const char *label)
62659a7c613SBrian Somers {
62759a7c613SBrian Somers 	syslog (priority, "%s %s", label, FormatPacket (ip));
62859a7c613SBrian Somers }
62959a7c613SBrian Somers 
63059a7c613SBrian Somers static char* FormatPacket (struct ip* ip)
63159a7c613SBrian Somers {
63259a7c613SBrian Somers 	static char	buf[256];
63324084f9bSBrian Somers 	struct tcphdr*	tcphdr;
63459a7c613SBrian Somers 	struct udphdr*	udphdr;
63559a7c613SBrian Somers 	struct icmp*	icmphdr;
63659a7c613SBrian Somers 	char		src[20];
63759a7c613SBrian Somers 	char		dst[20];
63824084f9bSBrian Somers 
63959a7c613SBrian Somers 	strcpy (src, inet_ntoa (ip->ip_src));
64059a7c613SBrian Somers 	strcpy (dst, inet_ntoa (ip->ip_dst));
64159a7c613SBrian Somers 
64259a7c613SBrian Somers 	switch (ip->ip_p) {
64359a7c613SBrian Somers 	case IPPROTO_TCP:
64424084f9bSBrian Somers 		tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
64559a7c613SBrian Somers 		sprintf (buf, "[TCP] %s:%d -> %s:%d",
64659a7c613SBrian Somers 			      src,
64759a7c613SBrian Somers 			      ntohs (tcphdr->th_sport),
64859a7c613SBrian Somers 			      dst,
64959a7c613SBrian Somers 			      ntohs (tcphdr->th_dport));
65059a7c613SBrian Somers 		break;
65124084f9bSBrian Somers 
65259a7c613SBrian Somers 	case IPPROTO_UDP:
65359a7c613SBrian Somers 		udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
65459a7c613SBrian Somers 		sprintf (buf, "[UDP] %s:%d -> %s:%d",
65559a7c613SBrian Somers 			      src,
65659a7c613SBrian Somers 			      ntohs (udphdr->uh_sport),
65759a7c613SBrian Somers 			      dst,
65859a7c613SBrian Somers 			      ntohs (udphdr->uh_dport));
65959a7c613SBrian Somers 		break;
66024084f9bSBrian Somers 
66159a7c613SBrian Somers 	case IPPROTO_ICMP:
66259a7c613SBrian Somers 		icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
663b71e869dSBrian Somers 		sprintf (buf, "[ICMP] %s -> %s %u(%u)",
66459a7c613SBrian Somers 			      src,
66559a7c613SBrian Somers 			      dst,
666b71e869dSBrian Somers 			      icmphdr->icmp_type,
667b71e869dSBrian Somers 			      icmphdr->icmp_code);
66859a7c613SBrian Somers 		break;
66959a7c613SBrian Somers 
67059a7c613SBrian Somers 	default:
67159a7c613SBrian Somers 		sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
67259a7c613SBrian Somers 		break;
67359a7c613SBrian Somers 	}
67459a7c613SBrian Somers 
67559a7c613SBrian Somers 	return buf;
67624084f9bSBrian Somers }
67724084f9bSBrian Somers 
6784c04fa4cSRuslan Ermilov static void
6794c04fa4cSRuslan Ermilov SetAliasAddressFromIfName(const char *ifn)
68024084f9bSBrian Somers {
6814c04fa4cSRuslan Ermilov 	size_t needed;
6824c04fa4cSRuslan Ermilov 	int mib[6];
6834c04fa4cSRuslan Ermilov 	char *buf, *lim, *next;
6844c04fa4cSRuslan Ermilov 	struct if_msghdr *ifm;
6854c04fa4cSRuslan Ermilov 	struct ifa_msghdr *ifam;
6864c04fa4cSRuslan Ermilov 	struct sockaddr_dl *sdl;
6874c04fa4cSRuslan Ermilov 	struct sockaddr_in *sin;
68824084f9bSBrian Somers 
6894c04fa4cSRuslan Ermilov 	mib[0] = CTL_NET;
6904c04fa4cSRuslan Ermilov 	mib[1] = PF_ROUTE;
6914c04fa4cSRuslan Ermilov 	mib[2] = 0;
6924c04fa4cSRuslan Ermilov 	mib[3] = AF_INET;	/* Only IP addresses please */
6934c04fa4cSRuslan Ermilov 	mib[4] = NET_RT_IFLIST;
6944c04fa4cSRuslan Ermilov 	mib[5] = 0;		/* ifIndex??? */
69524084f9bSBrian Somers /*
69624084f9bSBrian Somers  * Get interface data.
69724084f9bSBrian Somers  */
6984c04fa4cSRuslan Ermilov 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
6994c04fa4cSRuslan Ermilov 		err(1, "iflist-sysctl-estimate");
7004c04fa4cSRuslan Ermilov 	if ((buf = malloc(needed)) == NULL)
7014c04fa4cSRuslan Ermilov 		errx(1, "malloc failed");
7024c04fa4cSRuslan Ermilov 	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
7034c04fa4cSRuslan Ermilov 		err(1, "iflist-sysctl-get");
7044c04fa4cSRuslan Ermilov 	lim = buf + needed;
70524084f9bSBrian Somers /*
70624084f9bSBrian Somers  * Loop through interfaces until one with
70724084f9bSBrian Somers  * given name is found. This is done to
70824084f9bSBrian Somers  * find correct interface index for routing
70924084f9bSBrian Somers  * message processing.
71024084f9bSBrian Somers  */
7114c04fa4cSRuslan Ermilov 	ifIndex	= 0;
7124c04fa4cSRuslan Ermilov 	next = buf;
7134c04fa4cSRuslan Ermilov 	while (next < lim) {
7144c04fa4cSRuslan Ermilov 		ifm = (struct if_msghdr *)next;
7154c04fa4cSRuslan Ermilov 		next += ifm->ifm_msglen;
7164c04fa4cSRuslan Ermilov 		if (ifm->ifm_version != RTM_VERSION) {
7174c04fa4cSRuslan Ermilov 			if (verbose)
7184c04fa4cSRuslan Ermilov 				warnx("routing message version %d "
7194c04fa4cSRuslan Ermilov 				      "not understood", ifm->ifm_version);
7204c04fa4cSRuslan Ermilov 			continue;
7214c04fa4cSRuslan Ermilov 		}
7224c04fa4cSRuslan Ermilov 		if (ifm->ifm_type == RTM_IFINFO) {
7234c04fa4cSRuslan Ermilov 			sdl = (struct sockaddr_dl *)(ifm + 1);
7244c04fa4cSRuslan Ermilov 			if (strlen(ifn) == sdl->sdl_nlen &&
7254c04fa4cSRuslan Ermilov 			    strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
7264c04fa4cSRuslan Ermilov 				ifIndex = ifm->ifm_index;
7274c04fa4cSRuslan Ermilov 				ifMTU = ifm->ifm_data.ifi_mtu;
72824084f9bSBrian Somers 				break;
72924084f9bSBrian Somers 			}
73024084f9bSBrian Somers 		}
73124084f9bSBrian Somers 	}
7324c04fa4cSRuslan Ermilov 	if (!ifIndex)
7334c04fa4cSRuslan Ermilov 		errx(1, "unknown interface name %s", ifn);
73424084f9bSBrian Somers /*
73524084f9bSBrian Somers  * Get interface address.
73624084f9bSBrian Somers  */
7374c04fa4cSRuslan Ermilov 	sin = NULL;
7384c04fa4cSRuslan Ermilov 	while (next < lim) {
7394c04fa4cSRuslan Ermilov 		ifam = (struct ifa_msghdr *)next;
7404c04fa4cSRuslan Ermilov 		next += ifam->ifam_msglen;
7414c04fa4cSRuslan Ermilov 		if (ifam->ifam_version != RTM_VERSION) {
7424c04fa4cSRuslan Ermilov 			if (verbose)
7434c04fa4cSRuslan Ermilov 				warnx("routing message version %d "
7444c04fa4cSRuslan Ermilov 				      "not understood", ifam->ifam_version);
7454c04fa4cSRuslan Ermilov 			continue;
7464c04fa4cSRuslan Ermilov 		}
7474c04fa4cSRuslan Ermilov 		if (ifam->ifam_type != RTM_NEWADDR)
7484c04fa4cSRuslan Ermilov 			break;
7494c04fa4cSRuslan Ermilov 		if (ifam->ifam_addrs & RTA_IFA) {
7504c04fa4cSRuslan Ermilov 			int i;
7514c04fa4cSRuslan Ermilov 			char *cp = (char *)(ifam + 1);
75224084f9bSBrian Somers 
7534c04fa4cSRuslan Ermilov #define ROUNDUP(a) \
7544c04fa4cSRuslan Ermilov 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
7554c04fa4cSRuslan Ermilov #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
7564c04fa4cSRuslan Ermilov 
7574c04fa4cSRuslan Ermilov 			for (i = 1; i < RTA_IFA; i <<= 1)
7584c04fa4cSRuslan Ermilov 				if (ifam->ifam_addrs & i)
7594c04fa4cSRuslan Ermilov 					ADVANCE(cp, (struct sockaddr *)cp);
7604c04fa4cSRuslan Ermilov 			if (((struct sockaddr *)cp)->sa_family == AF_INET) {
7614c04fa4cSRuslan Ermilov 				sin = (struct sockaddr_in *)cp;
7624c04fa4cSRuslan Ermilov 				break;
7634c04fa4cSRuslan Ermilov 			}
7644c04fa4cSRuslan Ermilov 		}
7654c04fa4cSRuslan Ermilov 	}
7664c04fa4cSRuslan Ermilov 	if (sin == NULL)
7674c04fa4cSRuslan Ermilov 		errx(1, "%s: cannot get interface address", ifn);
7684c04fa4cSRuslan Ermilov 
7694c04fa4cSRuslan Ermilov 	PacketAliasSetAddress(sin->sin_addr);
77024084f9bSBrian Somers 	syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
7714c04fa4cSRuslan Ermilov 	       inet_ntoa(sin->sin_addr), ifMTU);
77224084f9bSBrian Somers 
7734c04fa4cSRuslan Ermilov 	free(buf);
77424084f9bSBrian Somers }
77524084f9bSBrian Somers 
776902cb50aSBrian Somers void Quit (const char* msg)
77724084f9bSBrian Somers {
77824084f9bSBrian Somers 	Warn (msg);
77924084f9bSBrian Somers 	exit (1);
78024084f9bSBrian Somers }
78124084f9bSBrian Somers 
782902cb50aSBrian Somers void Warn (const char* msg)
78324084f9bSBrian Somers {
78424084f9bSBrian Somers 	if (background)
78524084f9bSBrian Somers 		syslog (LOG_ALERT, "%s (%m)", msg);
78624084f9bSBrian Somers 	else
78704d06bb6SKris Kennaway 		warn ("%s", msg);
78824084f9bSBrian Somers }
78924084f9bSBrian Somers 
790902cb50aSBrian Somers static void RefreshAddr (int sig)
79124084f9bSBrian Somers {
79224084f9bSBrian Somers 	if (ifName)
79324084f9bSBrian Somers 		assignAliasAddr = 1;
79424084f9bSBrian Somers }
79524084f9bSBrian Somers 
796902cb50aSBrian Somers static void InitiateShutdown (int sig)
79724084f9bSBrian Somers {
79824084f9bSBrian Somers /*
79924084f9bSBrian Somers  * Start timer to allow kernel gracefully
80024084f9bSBrian Somers  * shutdown existing connections when system
80124084f9bSBrian Somers  * is shut down.
80224084f9bSBrian Somers  */
803cd45c931SRuslan Ermilov 	siginterrupt(SIGALRM, 1);
80424084f9bSBrian Somers 	signal (SIGALRM, Shutdown);
80524084f9bSBrian Somers 	alarm (10);
80624084f9bSBrian Somers }
80724084f9bSBrian Somers 
808902cb50aSBrian Somers static void Shutdown (int sig)
80924084f9bSBrian Somers {
81024084f9bSBrian Somers 	running = 0;
81124084f9bSBrian Somers }
81224084f9bSBrian Somers 
81324084f9bSBrian Somers /*
81424084f9bSBrian Somers  * Different options recognized by this program.
81524084f9bSBrian Somers  */
81624084f9bSBrian Somers 
81724084f9bSBrian Somers enum Option {
81824084f9bSBrian Somers 
81924084f9bSBrian Somers 	PacketAliasOption,
82024084f9bSBrian Somers 	Verbose,
82124084f9bSBrian Somers 	InPort,
82224084f9bSBrian Somers 	OutPort,
82324084f9bSBrian Somers 	Port,
82424084f9bSBrian Somers 	AliasAddress,
82511c2b3bfSRuslan Ermilov 	TargetAddress,
82624084f9bSBrian Somers 	InterfaceName,
82724084f9bSBrian Somers 	RedirectPort,
8284330006dSRuslan Ermilov 	RedirectProto,
82924084f9bSBrian Somers 	RedirectAddress,
83024084f9bSBrian Somers 	ConfigFile,
83159a7c613SBrian Somers 	DynamicMode,
83259a7c613SBrian Somers 	ProxyRule,
83359a7c613SBrian Somers  	LogDenied,
834bc4ebb98SRuslan Ermilov  	LogFacility,
83584ef95bdSPoul-Henning Kamp 	PunchFW,
83684ef95bdSPoul-Henning Kamp 	LogIpfwDenied
83724084f9bSBrian Somers };
83824084f9bSBrian Somers 
83924084f9bSBrian Somers enum Param {
84024084f9bSBrian Somers 
84124084f9bSBrian Somers 	YesNo,
84224084f9bSBrian Somers 	Numeric,
84324084f9bSBrian Somers 	String,
84424084f9bSBrian Somers 	None,
84524084f9bSBrian Somers 	Address,
84624084f9bSBrian Somers 	Service
84724084f9bSBrian Somers };
84824084f9bSBrian Somers 
84924084f9bSBrian Somers /*
85024084f9bSBrian Somers  * Option information structure (used by ParseOption).
85124084f9bSBrian Somers  */
85224084f9bSBrian Somers 
85324084f9bSBrian Somers struct OptionInfo {
85424084f9bSBrian Somers 
85524084f9bSBrian Somers 	enum Option		type;
85624084f9bSBrian Somers 	int			packetAliasOpt;
85724084f9bSBrian Somers 	enum Param		parm;
858902cb50aSBrian Somers 	const char*		parmDescription;
859902cb50aSBrian Somers 	const char*		description;
860902cb50aSBrian Somers 	const char*		name;
861902cb50aSBrian Somers 	const char*		shortName;
86224084f9bSBrian Somers };
86324084f9bSBrian Somers 
86424084f9bSBrian Somers /*
86524084f9bSBrian Somers  * Table of known options.
86624084f9bSBrian Somers  */
86724084f9bSBrian Somers 
86824084f9bSBrian Somers static struct OptionInfo optionTable[] = {
86924084f9bSBrian Somers 
87024084f9bSBrian Somers 	{ PacketAliasOption,
87124084f9bSBrian Somers 		PKT_ALIAS_UNREGISTERED_ONLY,
87224084f9bSBrian Somers 		YesNo,
87324084f9bSBrian Somers 		"[yes|no]",
87424084f9bSBrian Somers 		"alias only unregistered addresses",
87524084f9bSBrian Somers 		"unregistered_only",
87624084f9bSBrian Somers 		"u" },
87724084f9bSBrian Somers 
87824084f9bSBrian Somers 	{ PacketAliasOption,
87924084f9bSBrian Somers 		PKT_ALIAS_LOG,
88024084f9bSBrian Somers 		YesNo,
88124084f9bSBrian Somers 		"[yes|no]",
88224084f9bSBrian Somers 		"enable logging",
88324084f9bSBrian Somers 		"log",
88424084f9bSBrian Somers 		"l" },
88524084f9bSBrian Somers 
88624084f9bSBrian Somers 	{ PacketAliasOption,
88759a7c613SBrian Somers 		PKT_ALIAS_PROXY_ONLY,
88859a7c613SBrian Somers 		YesNo,
88959a7c613SBrian Somers 		"[yes|no]",
89059a7c613SBrian Somers 		"proxy only",
89159a7c613SBrian Somers 		"proxy_only",
89259a7c613SBrian Somers 		NULL },
89359a7c613SBrian Somers 
89459a7c613SBrian Somers 	{ PacketAliasOption,
89559a7c613SBrian Somers 		PKT_ALIAS_REVERSE,
89659a7c613SBrian Somers 		YesNo,
89759a7c613SBrian Somers 		"[yes|no]",
89859a7c613SBrian Somers 		"operate in reverse mode",
89959a7c613SBrian Somers 		"reverse",
90059a7c613SBrian Somers 		NULL },
90159a7c613SBrian Somers 
90259a7c613SBrian Somers 	{ PacketAliasOption,
90324084f9bSBrian Somers 		PKT_ALIAS_DENY_INCOMING,
90424084f9bSBrian Somers 		YesNo,
90524084f9bSBrian Somers 		"[yes|no]",
90624084f9bSBrian Somers 		"allow incoming connections",
90724084f9bSBrian Somers 		"deny_incoming",
90824084f9bSBrian Somers 		"d" },
90924084f9bSBrian Somers 
91024084f9bSBrian Somers 	{ PacketAliasOption,
91124084f9bSBrian Somers 		PKT_ALIAS_USE_SOCKETS,
91224084f9bSBrian Somers 		YesNo,
91324084f9bSBrian Somers 		"[yes|no]",
91424084f9bSBrian Somers 		"use sockets to inhibit port conflict",
91524084f9bSBrian Somers 		"use_sockets",
91624084f9bSBrian Somers 		"s" },
91724084f9bSBrian Somers 
91824084f9bSBrian Somers 	{ PacketAliasOption,
91924084f9bSBrian Somers 		PKT_ALIAS_SAME_PORTS,
92024084f9bSBrian Somers 		YesNo,
92124084f9bSBrian Somers 		"[yes|no]",
92224084f9bSBrian Somers 		"try to keep original port numbers for connections",
92324084f9bSBrian Somers 		"same_ports",
92424084f9bSBrian Somers 		"m" },
92524084f9bSBrian Somers 
92624084f9bSBrian Somers 	{ Verbose,
92724084f9bSBrian Somers 		0,
92824084f9bSBrian Somers 		YesNo,
92924084f9bSBrian Somers 		"[yes|no]",
93024084f9bSBrian Somers 		"verbose mode, dump packet information",
93124084f9bSBrian Somers 		"verbose",
93224084f9bSBrian Somers 		"v" },
93324084f9bSBrian Somers 
93424084f9bSBrian Somers 	{ DynamicMode,
93524084f9bSBrian Somers 		0,
93624084f9bSBrian Somers 		YesNo,
93724084f9bSBrian Somers 		"[yes|no]",
93824084f9bSBrian Somers 		"dynamic mode, automatically detect interface address changes",
93924084f9bSBrian Somers 		"dynamic",
94024084f9bSBrian Somers 		NULL },
94124084f9bSBrian Somers 
94224084f9bSBrian Somers 	{ InPort,
94324084f9bSBrian Somers 		0,
94424084f9bSBrian Somers 		Service,
94524084f9bSBrian Somers 		"number|service_name",
94624084f9bSBrian Somers 		"set port for incoming packets",
94724084f9bSBrian Somers 		"in_port",
94824084f9bSBrian Somers 		"i" },
94924084f9bSBrian Somers 
95024084f9bSBrian Somers 	{ OutPort,
95124084f9bSBrian Somers 		0,
95224084f9bSBrian Somers 		Service,
95324084f9bSBrian Somers 		"number|service_name",
95424084f9bSBrian Somers 		"set port for outgoing packets",
95524084f9bSBrian Somers 		"out_port",
95624084f9bSBrian Somers 		"o" },
95724084f9bSBrian Somers 
95824084f9bSBrian Somers 	{ Port,
95924084f9bSBrian Somers 		0,
96024084f9bSBrian Somers 		Service,
96124084f9bSBrian Somers 		"number|service_name",
96224084f9bSBrian Somers 		"set port (defaults to natd/divert)",
96324084f9bSBrian Somers 		"port",
96424084f9bSBrian Somers 		"p" },
96524084f9bSBrian Somers 
96624084f9bSBrian Somers 	{ AliasAddress,
96724084f9bSBrian Somers 		0,
96824084f9bSBrian Somers 		Address,
96924084f9bSBrian Somers 		"x.x.x.x",
97024084f9bSBrian Somers 		"address to use for aliasing",
97124084f9bSBrian Somers 		"alias_address",
97224084f9bSBrian Somers 		"a" },
97324084f9bSBrian Somers 
97411c2b3bfSRuslan Ermilov 	{ TargetAddress,
97511c2b3bfSRuslan Ermilov 		0,
97611c2b3bfSRuslan Ermilov 		Address,
97711c2b3bfSRuslan Ermilov 		"x.x.x.x",
97811c2b3bfSRuslan Ermilov 		"address to use for incoming sessions",
97911c2b3bfSRuslan Ermilov 		"target_address",
98011c2b3bfSRuslan Ermilov 		"t" },
98111c2b3bfSRuslan Ermilov 
98224084f9bSBrian Somers 	{ InterfaceName,
98324084f9bSBrian Somers 		0,
98424084f9bSBrian Somers 		String,
98524084f9bSBrian Somers 	        "network_if_name",
98624084f9bSBrian Somers 		"take aliasing address from interface",
98724084f9bSBrian Somers 		"interface",
98824084f9bSBrian Somers 		"n" },
98924084f9bSBrian Somers 
99059a7c613SBrian Somers 	{ ProxyRule,
99124084f9bSBrian Somers 		0,
99224084f9bSBrian Somers 		String,
99359a7c613SBrian Somers 	        "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
99459a7c613SBrian Somers 		"a.b.c.d:yyyy",
99559a7c613SBrian Somers 		"add transparent proxying / destination NAT",
99659a7c613SBrian Somers 		"proxy_rule",
99724084f9bSBrian Somers 		NULL },
99824084f9bSBrian Somers 
99924084f9bSBrian Somers 	{ RedirectPort,
100024084f9bSBrian Somers 		0,
100124084f9bSBrian Somers 		String,
1002bd690510SRuslan Ermilov 	        "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
10035d8ee958SBrian Somers 	 	" [remote_addr[:remote_port_range]]",
10045d8ee958SBrian Somers 		"redirect a port (or ports) for incoming traffic",
100524084f9bSBrian Somers 		"redirect_port",
100624084f9bSBrian Somers 		NULL },
100724084f9bSBrian Somers 
10084330006dSRuslan Ermilov 	{ RedirectProto,
10094330006dSRuslan Ermilov 		0,
10104330006dSRuslan Ermilov 		String,
10114330006dSRuslan Ermilov 	        "proto local_addr [public_addr] [remote_addr]",
10124330006dSRuslan Ermilov 		"redirect packets of a given proto",
10134330006dSRuslan Ermilov 		"redirect_proto",
10144330006dSRuslan Ermilov 		NULL },
10154330006dSRuslan Ermilov 
101624084f9bSBrian Somers 	{ RedirectAddress,
101724084f9bSBrian Somers 		0,
101824084f9bSBrian Somers 		String,
1019bd690510SRuslan Ermilov 	        "local_addr[,...] public_addr",
102024084f9bSBrian Somers 		"define mapping between local and public addresses",
102124084f9bSBrian Somers 		"redirect_address",
102224084f9bSBrian Somers 		NULL },
102324084f9bSBrian Somers 
102424084f9bSBrian Somers 	{ ConfigFile,
102524084f9bSBrian Somers 		0,
102624084f9bSBrian Somers 		String,
102724084f9bSBrian Somers 		"file_name",
102824084f9bSBrian Somers 		"read options from configuration file",
102924084f9bSBrian Somers 		"config",
103059a7c613SBrian Somers 		"f" },
103159a7c613SBrian Somers 
103259a7c613SBrian Somers 	{ LogDenied,
103359a7c613SBrian Somers 		0,
103459a7c613SBrian Somers 		YesNo,
103559a7c613SBrian Somers 	        "[yes|no]",
103659a7c613SBrian Somers 		"enable logging of denied incoming packets",
103759a7c613SBrian Somers 		"log_denied",
103859a7c613SBrian Somers 		NULL },
103959a7c613SBrian Somers 
104059a7c613SBrian Somers 	{ LogFacility,
104159a7c613SBrian Somers 		0,
104259a7c613SBrian Somers 		String,
104359a7c613SBrian Somers 	        "facility",
104459a7c613SBrian Somers 		"name of syslog facility to use for logging",
104559a7c613SBrian Somers 		"log_facility",
1046bc4ebb98SRuslan Ermilov 		NULL },
104759a7c613SBrian Somers 
1048bc4ebb98SRuslan Ermilov 	{ PunchFW,
1049bc4ebb98SRuslan Ermilov 		0,
1050bc4ebb98SRuslan Ermilov 		String,
1051bc4ebb98SRuslan Ermilov 	        "basenumber:count",
1052bc4ebb98SRuslan Ermilov 		"punch holes in the firewall for incoming FTP/IRC DCC connections",
1053bc4ebb98SRuslan Ermilov 		"punch_fw",
105484ef95bdSPoul-Henning Kamp 		NULL },
105584ef95bdSPoul-Henning Kamp 
105684ef95bdSPoul-Henning Kamp 	{ LogIpfwDenied,
105784ef95bdSPoul-Henning Kamp 		0,
105884ef95bdSPoul-Henning Kamp 		YesNo,
105984ef95bdSPoul-Henning Kamp 	        "[yes|no]",
106084ef95bdSPoul-Henning Kamp 		"log packets converted by natd, but denied by ipfw",
106184ef95bdSPoul-Henning Kamp 		"log_ipfw_denied",
106284ef95bdSPoul-Henning Kamp 		NULL },
106324084f9bSBrian Somers };
106424084f9bSBrian Somers 
1065b0f55af6SRuslan Ermilov static void ParseOption (const char* option, const char* parms)
106624084f9bSBrian Somers {
106724084f9bSBrian Somers 	int			i;
106824084f9bSBrian Somers 	struct OptionInfo*	info;
106924084f9bSBrian Somers 	int			yesNoValue;
107024084f9bSBrian Somers 	int			aliasValue;
107124084f9bSBrian Somers 	int			numValue;
107267a886fbSBrian Somers 	u_short			uNumValue;
1073902cb50aSBrian Somers 	const char*		strValue;
107424084f9bSBrian Somers 	struct in_addr		addrValue;
107524084f9bSBrian Somers 	int			max;
107624084f9bSBrian Somers 	char*			end;
107759a7c613SBrian Somers 	CODE* 			fac_record = NULL;
107824084f9bSBrian Somers /*
107924084f9bSBrian Somers  * Find option from table.
108024084f9bSBrian Somers  */
108124084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
108224084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
108324084f9bSBrian Somers 
108424084f9bSBrian Somers 		if (!strcmp (info->name, option))
108524084f9bSBrian Somers 			break;
108624084f9bSBrian Somers 
108724084f9bSBrian Somers 		if (info->shortName)
108824084f9bSBrian Somers 			if (!strcmp (info->shortName, option))
108924084f9bSBrian Somers 				break;
109024084f9bSBrian Somers 	}
109124084f9bSBrian Somers 
109224084f9bSBrian Somers 	if (i >= max) {
109324084f9bSBrian Somers 
10940fc81af1SPhilippe Charnier 		warnx ("unknown option %s", option);
109524084f9bSBrian Somers 		Usage ();
109624084f9bSBrian Somers 	}
109724084f9bSBrian Somers 
109867a886fbSBrian Somers 	uNumValue	= 0;
109924084f9bSBrian Somers 	yesNoValue	= 0;
110024084f9bSBrian Somers 	numValue	= 0;
110124084f9bSBrian Somers 	strValue	= NULL;
110224084f9bSBrian Somers /*
110324084f9bSBrian Somers  * Check parameters.
110424084f9bSBrian Somers  */
110524084f9bSBrian Somers 	switch (info->parm) {
110624084f9bSBrian Somers 	case YesNo:
110724084f9bSBrian Somers 		if (!parms)
110824084f9bSBrian Somers 			parms = "yes";
110924084f9bSBrian Somers 
111024084f9bSBrian Somers 		if (!strcmp (parms, "yes"))
111124084f9bSBrian Somers 			yesNoValue = 1;
111224084f9bSBrian Somers 		else
111324084f9bSBrian Somers 			if (!strcmp (parms, "no"))
111424084f9bSBrian Somers 				yesNoValue = 0;
11150fc81af1SPhilippe Charnier 			else
11160fc81af1SPhilippe Charnier 				errx (1, "%s needs yes/no parameter", option);
111724084f9bSBrian Somers 		break;
111824084f9bSBrian Somers 
111924084f9bSBrian Somers 	case Service:
11200fc81af1SPhilippe Charnier 		if (!parms)
112167a886fbSBrian Somers 			errx (1, "%s needs service name or "
112267a886fbSBrian Somers 				 "port number parameter",
112367a886fbSBrian Somers 				 option);
112424084f9bSBrian Somers 
112567a886fbSBrian Somers 		uNumValue = StrToPort (parms, "divert");
112624084f9bSBrian Somers 		break;
112724084f9bSBrian Somers 
112824084f9bSBrian Somers 	case Numeric:
112924084f9bSBrian Somers 		if (parms)
113024084f9bSBrian Somers 			numValue = strtol (parms, &end, 10);
113124084f9bSBrian Somers 		else
1132902cb50aSBrian Somers 			end = NULL;
113324084f9bSBrian Somers 
11340fc81af1SPhilippe Charnier 		if (end == parms)
11350fc81af1SPhilippe Charnier 			errx (1, "%s needs numeric parameter", option);
113624084f9bSBrian Somers 		break;
113724084f9bSBrian Somers 
113824084f9bSBrian Somers 	case String:
113924084f9bSBrian Somers 		strValue = parms;
11400fc81af1SPhilippe Charnier 		if (!strValue)
11410fc81af1SPhilippe Charnier 			errx (1, "%s needs parameter", option);
114224084f9bSBrian Somers 		break;
114324084f9bSBrian Somers 
114424084f9bSBrian Somers 	case None:
11450fc81af1SPhilippe Charnier 		if (parms)
11460fc81af1SPhilippe Charnier 			errx (1, "%s does not take parameters", option);
114724084f9bSBrian Somers 		break;
114824084f9bSBrian Somers 
114924084f9bSBrian Somers 	case Address:
11500fc81af1SPhilippe Charnier 		if (!parms)
11510fc81af1SPhilippe Charnier 			errx (1, "%s needs address/host parameter", option);
115224084f9bSBrian Somers 
115324084f9bSBrian Somers 		StrToAddr (parms, &addrValue);
115424084f9bSBrian Somers 		break;
115524084f9bSBrian Somers 	}
115624084f9bSBrian Somers 
115724084f9bSBrian Somers 	switch (info->type) {
115824084f9bSBrian Somers 	case PacketAliasOption:
115924084f9bSBrian Somers 
116024084f9bSBrian Somers 		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1161fb994b07SBrian Somers 		PacketAliasSetMode (aliasValue, info->packetAliasOpt);
116224084f9bSBrian Somers 		break;
116324084f9bSBrian Somers 
116424084f9bSBrian Somers 	case Verbose:
116524084f9bSBrian Somers 		verbose = yesNoValue;
116624084f9bSBrian Somers 		break;
116724084f9bSBrian Somers 
116824084f9bSBrian Somers 	case DynamicMode:
116924084f9bSBrian Somers 		dynamicMode = yesNoValue;
117024084f9bSBrian Somers 		break;
117124084f9bSBrian Somers 
117224084f9bSBrian Somers 	case InPort:
117367a886fbSBrian Somers 		inPort = uNumValue;
117424084f9bSBrian Somers 		break;
117524084f9bSBrian Somers 
117624084f9bSBrian Somers 	case OutPort:
117767a886fbSBrian Somers 		outPort = uNumValue;
117824084f9bSBrian Somers 		break;
117924084f9bSBrian Somers 
118024084f9bSBrian Somers 	case Port:
118167a886fbSBrian Somers 		inOutPort = uNumValue;
118224084f9bSBrian Somers 		break;
118324084f9bSBrian Somers 
118424084f9bSBrian Somers 	case AliasAddress:
118524084f9bSBrian Somers 		memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
118624084f9bSBrian Somers 		break;
118724084f9bSBrian Somers 
118811c2b3bfSRuslan Ermilov 	case TargetAddress:
118911c2b3bfSRuslan Ermilov 		PacketAliasSetTarget(addrValue);
119011c2b3bfSRuslan Ermilov 		break;
119111c2b3bfSRuslan Ermilov 
119224084f9bSBrian Somers 	case RedirectPort:
119324084f9bSBrian Somers 		SetupPortRedirect (strValue);
119424084f9bSBrian Somers 		break;
119524084f9bSBrian Somers 
11964330006dSRuslan Ermilov 	case RedirectProto:
11974330006dSRuslan Ermilov 		SetupProtoRedirect(strValue);
11984330006dSRuslan Ermilov 		break;
11994330006dSRuslan Ermilov 
120024084f9bSBrian Somers 	case RedirectAddress:
120124084f9bSBrian Somers 		SetupAddressRedirect (strValue);
120224084f9bSBrian Somers 		break;
120324084f9bSBrian Somers 
120459a7c613SBrian Somers 	case ProxyRule:
120559a7c613SBrian Somers 		PacketAliasProxyRule (strValue);
120659a7c613SBrian Somers 		break;
120759a7c613SBrian Somers 
120824084f9bSBrian Somers 	case InterfaceName:
120924084f9bSBrian Somers 		if (ifName)
121024084f9bSBrian Somers 			free (ifName);
121124084f9bSBrian Somers 
121224084f9bSBrian Somers 		ifName = strdup (strValue);
121324084f9bSBrian Somers 		break;
121424084f9bSBrian Somers 
121524084f9bSBrian Somers 	case ConfigFile:
121624084f9bSBrian Somers 		ReadConfigFile (strValue);
121724084f9bSBrian Somers 		break;
121859a7c613SBrian Somers 
121959a7c613SBrian Somers 	case LogDenied:
12203843533eSRuslan Ermilov 		logDropped = yesNoValue;
122159a7c613SBrian Somers 		break;
122259a7c613SBrian Somers 
122359a7c613SBrian Somers 	case LogFacility:
122459a7c613SBrian Somers 
122559a7c613SBrian Somers 		fac_record = facilitynames;
122659a7c613SBrian Somers 		while (fac_record->c_name != NULL) {
122759a7c613SBrian Somers 
122859a7c613SBrian Somers 			if (!strcmp (fac_record->c_name, strValue)) {
122959a7c613SBrian Somers 
123059a7c613SBrian Somers 				logFacility = fac_record->c_val;
123159a7c613SBrian Somers 				break;
123259a7c613SBrian Somers 
123359a7c613SBrian Somers 			}
123459a7c613SBrian Somers 			else
123559a7c613SBrian Somers 				fac_record++;
123659a7c613SBrian Somers 		}
123759a7c613SBrian Somers 
123859a7c613SBrian Somers 		if(fac_record->c_name == NULL)
123959a7c613SBrian Somers 			errx(1, "Unknown log facility name: %s", strValue);
124059a7c613SBrian Somers 
124159a7c613SBrian Somers 		break;
1242bc4ebb98SRuslan Ermilov 
1243bc4ebb98SRuslan Ermilov 	case PunchFW:
1244bc4ebb98SRuslan Ermilov 		SetupPunchFW(strValue);
1245bc4ebb98SRuslan Ermilov 		break;
12463843533eSRuslan Ermilov 
124784ef95bdSPoul-Henning Kamp 	case LogIpfwDenied:
12483843533eSRuslan Ermilov 		logIpfwDenied = yesNoValue;;
12493843533eSRuslan Ermilov 		break;
125024084f9bSBrian Somers 	}
125124084f9bSBrian Somers }
125224084f9bSBrian Somers 
1253902cb50aSBrian Somers void ReadConfigFile (const char* fileName)
125424084f9bSBrian Somers {
125524084f9bSBrian Somers 	FILE*	file;
1256d99cc1daSRuslan Ermilov 	char	*buf;
1257d99cc1daSRuslan Ermilov 	size_t	len;
12582e7e7c71SRuslan Ermilov 	char	*ptr, *p;
125924084f9bSBrian Somers 	char*	option;
126024084f9bSBrian Somers 
126124084f9bSBrian Somers 	file = fopen (fileName, "r");
1262d99cc1daSRuslan Ermilov 	if (!file)
1263d99cc1daSRuslan Ermilov 		err(1, "cannot open config file %s", fileName);
126424084f9bSBrian Somers 
1265d99cc1daSRuslan Ermilov 	while ((buf = fgetln(file, &len)) != NULL) {
1266d99cc1daSRuslan Ermilov 		if (buf[len - 1] == '\n')
1267d99cc1daSRuslan Ermilov 			buf[len - 1] = '\0';
1268d99cc1daSRuslan Ermilov 		else
1269d99cc1daSRuslan Ermilov 			errx(1, "config file format error: "
1270d99cc1daSRuslan Ermilov 				"last line should end with newline");
127124084f9bSBrian Somers 
127224084f9bSBrian Somers /*
12732e7e7c71SRuslan Ermilov  * Check for comments, strip off trailing spaces.
127424084f9bSBrian Somers  */
12752e7e7c71SRuslan Ermilov 		if ((ptr = strchr(buf, '#')))
12762e7e7c71SRuslan Ermilov 			*ptr = '\0';
12772e7e7c71SRuslan Ermilov 		for (ptr = buf; isspace(*ptr); ++ptr)
12782e7e7c71SRuslan Ermilov 			continue;
127924084f9bSBrian Somers 		if (*ptr == '\0')
128024084f9bSBrian Somers 			continue;
12812e7e7c71SRuslan Ermilov 		for (p = strchr(buf, '\0'); isspace(*--p);)
12822e7e7c71SRuslan Ermilov 			continue;
12832e7e7c71SRuslan Ermilov 		*++p = '\0';
12842e7e7c71SRuslan Ermilov 
128524084f9bSBrian Somers /*
128624084f9bSBrian Somers  * Extract option name.
128724084f9bSBrian Somers  */
128824084f9bSBrian Somers 		option = ptr;
128924084f9bSBrian Somers 		while (*ptr && !isspace (*ptr))
129024084f9bSBrian Somers 			++ptr;
129124084f9bSBrian Somers 
129224084f9bSBrian Somers 		if (*ptr != '\0') {
129324084f9bSBrian Somers 
129424084f9bSBrian Somers 			*ptr = '\0';
129524084f9bSBrian Somers 			++ptr;
129624084f9bSBrian Somers 		}
129724084f9bSBrian Somers /*
129824084f9bSBrian Somers  * Skip white space between name and parms.
129924084f9bSBrian Somers  */
130024084f9bSBrian Somers 		while (*ptr && isspace (*ptr))
130124084f9bSBrian Somers 			++ptr;
130224084f9bSBrian Somers 
1303b0f55af6SRuslan Ermilov 		ParseOption (option, *ptr ? ptr : NULL);
130424084f9bSBrian Somers 	}
130524084f9bSBrian Somers 
130624084f9bSBrian Somers 	fclose (file);
130724084f9bSBrian Somers }
130824084f9bSBrian Somers 
130924084f9bSBrian Somers static void Usage ()
131024084f9bSBrian Somers {
131124084f9bSBrian Somers 	int			i;
131224084f9bSBrian Somers 	int			max;
131324084f9bSBrian Somers 	struct OptionInfo*	info;
131424084f9bSBrian Somers 
131524084f9bSBrian Somers 	fprintf (stderr, "Recognized options:\n\n");
131624084f9bSBrian Somers 
131724084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
131824084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
131924084f9bSBrian Somers 
132024084f9bSBrian Somers 		fprintf (stderr, "-%-20s %s\n", info->name,
132124084f9bSBrian Somers 						info->parmDescription);
132224084f9bSBrian Somers 
132324084f9bSBrian Somers 		if (info->shortName)
132424084f9bSBrian Somers 			fprintf (stderr, "-%-20s %s\n", info->shortName,
132524084f9bSBrian Somers 							info->parmDescription);
132624084f9bSBrian Somers 
132724084f9bSBrian Somers 		fprintf (stderr, "      %s\n\n", info->description);
132824084f9bSBrian Somers 	}
132924084f9bSBrian Somers 
133024084f9bSBrian Somers 	exit (1);
133124084f9bSBrian Somers }
133224084f9bSBrian Somers 
1333902cb50aSBrian Somers void SetupPortRedirect (const char* parms)
133424084f9bSBrian Somers {
133524084f9bSBrian Somers 	char		buf[128];
133624084f9bSBrian Somers 	char*		ptr;
1337bd690510SRuslan Ermilov 	char*		serverPool;
133824084f9bSBrian Somers 	struct in_addr	localAddr;
133924084f9bSBrian Somers 	struct in_addr	publicAddr;
134024084f9bSBrian Somers 	struct in_addr	remoteAddr;
13415d8ee958SBrian Somers 	port_range      portRange;
13425d8ee958SBrian Somers 	u_short         localPort      = 0;
13435d8ee958SBrian Somers 	u_short         publicPort     = 0;
13445d8ee958SBrian Somers 	u_short         remotePort     = 0;
13455d8ee958SBrian Somers 	u_short         numLocalPorts  = 0;
13465d8ee958SBrian Somers 	u_short         numPublicPorts = 0;
13475d8ee958SBrian Somers 	u_short         numRemotePorts = 0;
134824084f9bSBrian Somers 	int		proto;
134924084f9bSBrian Somers 	char*		protoName;
135024084f9bSBrian Somers 	char*		separator;
13515d8ee958SBrian Somers 	int             i;
1352bd690510SRuslan Ermilov 	struct alias_link *link = NULL;
135324084f9bSBrian Somers 
135424084f9bSBrian Somers 	strcpy (buf, parms);
135524084f9bSBrian Somers /*
135624084f9bSBrian Somers  * Extract protocol.
135724084f9bSBrian Somers  */
135824084f9bSBrian Somers 	protoName = strtok (buf, " \t");
13590fc81af1SPhilippe Charnier 	if (!protoName)
13600fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing protocol");
136124084f9bSBrian Somers 
136224084f9bSBrian Somers 	proto = StrToProto (protoName);
136324084f9bSBrian Somers /*
136424084f9bSBrian Somers  * Extract local address.
136524084f9bSBrian Somers  */
136624084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
13670fc81af1SPhilippe Charnier 	if (!ptr)
13680fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing local address");
136924084f9bSBrian Somers 
1370bd690510SRuslan Ermilov 	separator = strchr(ptr, ',');
1371bd690510SRuslan Ermilov 	if (separator) {		/* LSNAT redirection syntax. */
1372bd690510SRuslan Ermilov 		localAddr.s_addr = INADDR_NONE;
1373bd690510SRuslan Ermilov 		localPort = ~0;
1374bd690510SRuslan Ermilov 		numLocalPorts = 1;
1375bd690510SRuslan Ermilov 		serverPool = ptr;
1376bd690510SRuslan Ermilov 	} else {
13775d8ee958SBrian Somers 		if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
13785d8ee958SBrian Somers 			errx (1, "redirect_port: invalid local port range");
13795d8ee958SBrian Somers 
13805d8ee958SBrian Somers 		localPort     = GETLOPORT(portRange);
13815d8ee958SBrian Somers 		numLocalPorts = GETNUMPORTS(portRange);
1382bd690510SRuslan Ermilov 		serverPool = NULL;
1383bd690510SRuslan Ermilov 	}
13845d8ee958SBrian Somers 
138524084f9bSBrian Somers /*
13869c501140SBrian Somers  * Extract public port and optionally address.
138724084f9bSBrian Somers  */
138824084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
13890fc81af1SPhilippe Charnier 	if (!ptr)
13900fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing public port");
139124084f9bSBrian Somers 
139224084f9bSBrian Somers 	separator = strchr (ptr, ':');
13935d8ee958SBrian Somers 	if (separator) {
13945d8ee958SBrian Somers 	        if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
13955d8ee958SBrian Somers 		        errx (1, "redirect_port: invalid public port range");
139624084f9bSBrian Somers 	}
13975d8ee958SBrian Somers 	else {
13985d8ee958SBrian Somers 		publicAddr.s_addr = INADDR_ANY;
13995d8ee958SBrian Somers 		if (StrToPortRange (ptr, protoName, &portRange) != 0)
14005d8ee958SBrian Somers 		        errx (1, "redirect_port: invalid public port range");
14015d8ee958SBrian Somers 	}
14025d8ee958SBrian Somers 
14035d8ee958SBrian Somers 	publicPort     = GETLOPORT(portRange);
14045d8ee958SBrian Somers 	numPublicPorts = GETNUMPORTS(portRange);
140524084f9bSBrian Somers 
140624084f9bSBrian Somers /*
140724084f9bSBrian Somers  * Extract remote address and optionally port.
140824084f9bSBrian Somers  */
140924084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
141024084f9bSBrian Somers 	if (ptr) {
141124084f9bSBrian Somers 		separator = strchr (ptr, ':');
1412ebe70c8fSWarner Losh 		if (separator) {
14135d8ee958SBrian Somers 		        if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
14145d8ee958SBrian Somers 			        errx (1, "redirect_port: invalid remote port range");
1415ebe70c8fSWarner Losh 		} else {
14165d8ee958SBrian Somers 		        SETLOPORT(portRange, 0);
14175d8ee958SBrian Somers 			SETNUMPORTS(portRange, 1);
141824084f9bSBrian Somers 			StrToAddr (ptr, &remoteAddr);
141924084f9bSBrian Somers 		}
142024084f9bSBrian Somers 	}
142124084f9bSBrian Somers 	else {
14225d8ee958SBrian Somers 	        SETLOPORT(portRange, 0);
14235d8ee958SBrian Somers 		SETNUMPORTS(portRange, 1);
142424084f9bSBrian Somers 		remoteAddr.s_addr = INADDR_ANY;
142524084f9bSBrian Somers 	}
142624084f9bSBrian Somers 
14275d8ee958SBrian Somers 	remotePort     = GETLOPORT(portRange);
14285d8ee958SBrian Somers 	numRemotePorts = GETNUMPORTS(portRange);
14295d8ee958SBrian Somers 
14305d8ee958SBrian Somers /*
14315d8ee958SBrian Somers  * Make sure port ranges match up, then add the redirect ports.
14325d8ee958SBrian Somers  */
14335d8ee958SBrian Somers 	if (numLocalPorts != numPublicPorts)
14345d8ee958SBrian Somers 	        errx (1, "redirect_port: port ranges must be equal in size");
14355d8ee958SBrian Somers 
14365d8ee958SBrian Somers 	/* Remote port range is allowed to be '0' which means all ports. */
143729d97436SBrian Somers 	if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
14385d8ee958SBrian Somers 	        errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
14395d8ee958SBrian Somers 
14405d8ee958SBrian Somers 	for (i = 0 ; i < numPublicPorts ; ++i) {
14415d8ee958SBrian Somers 	        /* If remotePort is all ports, set it to 0. */
14425d8ee958SBrian Somers 	        u_short remotePortCopy = remotePort + i;
14435d8ee958SBrian Somers 	        if (numRemotePorts == 1 && remotePort == 0)
14445d8ee958SBrian Somers 		        remotePortCopy = 0;
14455d8ee958SBrian Somers 
1446bd690510SRuslan Ermilov 		link = PacketAliasRedirectPort (localAddr,
14475d8ee958SBrian Somers 						htons(localPort + i),
144824084f9bSBrian Somers 						remoteAddr,
14495d8ee958SBrian Somers 						htons(remotePortCopy),
145024084f9bSBrian Somers 						publicAddr,
14515d8ee958SBrian Somers 						htons(publicPort + i),
145224084f9bSBrian Somers 						proto);
145324084f9bSBrian Somers 	}
1454bd690510SRuslan Ermilov 
1455bd690510SRuslan Ermilov /*
1456bd690510SRuslan Ermilov  * Setup LSNAT server pool.
1457bd690510SRuslan Ermilov  */
1458bd690510SRuslan Ermilov 	if (serverPool != NULL && link != NULL) {
1459bd690510SRuslan Ermilov 		ptr = strtok(serverPool, ",");
1460bd690510SRuslan Ermilov 		while (ptr != NULL) {
1461bd690510SRuslan Ermilov 			if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1462bd690510SRuslan Ermilov 				errx(1, "redirect_port: invalid local port range");
1463bd690510SRuslan Ermilov 
1464bd690510SRuslan Ermilov 			localPort = GETLOPORT(portRange);
1465bd690510SRuslan Ermilov 			if (GETNUMPORTS(portRange) != 1)
1466bd690510SRuslan Ermilov 				errx(1, "redirect_port: local port must be single in this context");
1467bd690510SRuslan Ermilov 			PacketAliasAddServer(link, localAddr, htons(localPort));
1468bd690510SRuslan Ermilov 			ptr = strtok(NULL, ",");
1469bd690510SRuslan Ermilov 		}
1470bd690510SRuslan Ermilov 	}
14715d8ee958SBrian Somers }
147224084f9bSBrian Somers 
14734330006dSRuslan Ermilov void
14744330006dSRuslan Ermilov SetupProtoRedirect(const char* parms)
14754330006dSRuslan Ermilov {
14764330006dSRuslan Ermilov 	char		buf[128];
14774330006dSRuslan Ermilov 	char*		ptr;
14784330006dSRuslan Ermilov 	struct in_addr	localAddr;
14794330006dSRuslan Ermilov 	struct in_addr	publicAddr;
14804330006dSRuslan Ermilov 	struct in_addr	remoteAddr;
14814330006dSRuslan Ermilov 	int		proto;
14824330006dSRuslan Ermilov 	char*		protoName;
14834330006dSRuslan Ermilov 	struct protoent *protoent;
14844330006dSRuslan Ermilov 
14854330006dSRuslan Ermilov 	strcpy (buf, parms);
14864330006dSRuslan Ermilov /*
14874330006dSRuslan Ermilov  * Extract protocol.
14884330006dSRuslan Ermilov  */
14894330006dSRuslan Ermilov 	protoName = strtok(buf, " \t");
14904330006dSRuslan Ermilov 	if (!protoName)
14914330006dSRuslan Ermilov 		errx(1, "redirect_proto: missing protocol");
14924330006dSRuslan Ermilov 
14934330006dSRuslan Ermilov 	protoent = getprotobyname(protoName);
14944330006dSRuslan Ermilov 	if (protoent == NULL)
14954330006dSRuslan Ermilov 		errx(1, "redirect_proto: unknown protocol %s", protoName);
14964330006dSRuslan Ermilov 	else
14974330006dSRuslan Ermilov 		proto = protoent->p_proto;
14984330006dSRuslan Ermilov /*
14994330006dSRuslan Ermilov  * Extract local address.
15004330006dSRuslan Ermilov  */
15014330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
15024330006dSRuslan Ermilov 	if (!ptr)
15034330006dSRuslan Ermilov 		errx(1, "redirect_proto: missing local address");
15044330006dSRuslan Ermilov 	else
15054330006dSRuslan Ermilov 		StrToAddr(ptr, &localAddr);
15064330006dSRuslan Ermilov /*
15074330006dSRuslan Ermilov  * Extract optional public address.
15084330006dSRuslan Ermilov  */
15094330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
15104330006dSRuslan Ermilov 	if (ptr)
15114330006dSRuslan Ermilov 		StrToAddr(ptr, &publicAddr);
15124330006dSRuslan Ermilov 	else
15134330006dSRuslan Ermilov 		publicAddr.s_addr = INADDR_ANY;
15144330006dSRuslan Ermilov /*
15154330006dSRuslan Ermilov  * Extract optional remote address.
15164330006dSRuslan Ermilov  */
15174330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
15184330006dSRuslan Ermilov 	if (ptr)
15194330006dSRuslan Ermilov 		StrToAddr(ptr, &remoteAddr);
15204330006dSRuslan Ermilov 	else
15214330006dSRuslan Ermilov 		remoteAddr.s_addr = INADDR_ANY;
15224330006dSRuslan Ermilov /*
15234330006dSRuslan Ermilov  * Create aliasing link.
15244330006dSRuslan Ermilov  */
15254330006dSRuslan Ermilov 	(void)PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr,
15264330006dSRuslan Ermilov 				       proto);
15274330006dSRuslan Ermilov }
15284330006dSRuslan Ermilov 
1529902cb50aSBrian Somers void SetupAddressRedirect (const char* parms)
153024084f9bSBrian Somers {
153124084f9bSBrian Somers 	char		buf[128];
153224084f9bSBrian Somers 	char*		ptr;
1533bd690510SRuslan Ermilov 	char*		separator;
153424084f9bSBrian Somers 	struct in_addr	localAddr;
153524084f9bSBrian Somers 	struct in_addr	publicAddr;
1536bd690510SRuslan Ermilov 	char*		serverPool;
1537bd690510SRuslan Ermilov 	struct alias_link *link;
153824084f9bSBrian Somers 
153924084f9bSBrian Somers 	strcpy (buf, parms);
154024084f9bSBrian Somers /*
154124084f9bSBrian Somers  * Extract local address.
154224084f9bSBrian Somers  */
154324084f9bSBrian Somers 	ptr = strtok (buf, " \t");
15440fc81af1SPhilippe Charnier 	if (!ptr)
15450fc81af1SPhilippe Charnier 		errx (1, "redirect_address: missing local address");
154624084f9bSBrian Somers 
1547bd690510SRuslan Ermilov 	separator = strchr(ptr, ',');
1548bd690510SRuslan Ermilov 	if (separator) {		/* LSNAT redirection syntax. */
1549bd690510SRuslan Ermilov 		localAddr.s_addr = INADDR_NONE;
1550bd690510SRuslan Ermilov 		serverPool = ptr;
1551bd690510SRuslan Ermilov 	} else {
155224084f9bSBrian Somers 		StrToAddr (ptr, &localAddr);
1553bd690510SRuslan Ermilov 		serverPool = NULL;
1554bd690510SRuslan Ermilov 	}
155524084f9bSBrian Somers /*
155624084f9bSBrian Somers  * Extract public address.
155724084f9bSBrian Somers  */
155824084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
15590fc81af1SPhilippe Charnier 	if (!ptr)
15600fc81af1SPhilippe Charnier 		errx (1, "redirect_address: missing public address");
156124084f9bSBrian Somers 
156224084f9bSBrian Somers 	StrToAddr (ptr, &publicAddr);
1563bd690510SRuslan Ermilov 	link = PacketAliasRedirectAddr(localAddr, publicAddr);
1564bd690510SRuslan Ermilov 
1565bd690510SRuslan Ermilov /*
1566bd690510SRuslan Ermilov  * Setup LSNAT server pool.
1567bd690510SRuslan Ermilov  */
1568bd690510SRuslan Ermilov 	if (serverPool != NULL && link != NULL) {
1569bd690510SRuslan Ermilov 		ptr = strtok(serverPool, ",");
1570bd690510SRuslan Ermilov 		while (ptr != NULL) {
1571bd690510SRuslan Ermilov 			StrToAddr(ptr, &localAddr);
1572bd690510SRuslan Ermilov 			PacketAliasAddServer(link, localAddr, htons(~0));
1573bd690510SRuslan Ermilov 			ptr = strtok(NULL, ",");
1574bd690510SRuslan Ermilov 		}
1575bd690510SRuslan Ermilov 	}
157624084f9bSBrian Somers }
157724084f9bSBrian Somers 
1578902cb50aSBrian Somers void StrToAddr (const char* str, struct in_addr* addr)
157924084f9bSBrian Somers {
158024084f9bSBrian Somers 	struct hostent* hp;
158124084f9bSBrian Somers 
158224084f9bSBrian Somers 	if (inet_aton (str, addr))
158324084f9bSBrian Somers 		return;
158424084f9bSBrian Somers 
158524084f9bSBrian Somers 	hp = gethostbyname (str);
15860fc81af1SPhilippe Charnier 	if (!hp)
15870fc81af1SPhilippe Charnier 		errx (1, "unknown host %s", str);
158824084f9bSBrian Somers 
158924084f9bSBrian Somers 	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
159024084f9bSBrian Somers }
159124084f9bSBrian Somers 
1592902cb50aSBrian Somers u_short StrToPort (const char* str, const char* proto)
159324084f9bSBrian Somers {
159467a886fbSBrian Somers 	u_short		port;
159524084f9bSBrian Somers 	struct servent*	sp;
159624084f9bSBrian Somers 	char*		end;
159724084f9bSBrian Somers 
159824084f9bSBrian Somers 	port = strtol (str, &end, 10);
159924084f9bSBrian Somers 	if (end != str)
160027c20503SBrian Somers 		return htons (port);
160124084f9bSBrian Somers 
160224084f9bSBrian Somers 	sp = getservbyname (str, proto);
16030fc81af1SPhilippe Charnier 	if (!sp)
16040fc81af1SPhilippe Charnier 		errx (1, "unknown service %s/%s", str, proto);
160524084f9bSBrian Somers 
160624084f9bSBrian Somers 	return sp->s_port;
160724084f9bSBrian Somers }
160824084f9bSBrian Somers 
1609902cb50aSBrian Somers int StrToPortRange (const char* str, const char* proto, port_range *portRange)
16105d8ee958SBrian Somers {
16115d8ee958SBrian Somers 	char*           sep;
16125d8ee958SBrian Somers 	struct servent*	sp;
16135d8ee958SBrian Somers 	char*		end;
16145d8ee958SBrian Somers 	u_short         loPort;
16155d8ee958SBrian Somers 	u_short         hiPort;
16165d8ee958SBrian Somers 
16175d8ee958SBrian Somers 	/* First see if this is a service, return corresponding port if so. */
16185d8ee958SBrian Somers 	sp = getservbyname (str,proto);
16195d8ee958SBrian Somers 	if (sp) {
16205d8ee958SBrian Somers 	        SETLOPORT(*portRange, ntohs(sp->s_port));
16215d8ee958SBrian Somers 		SETNUMPORTS(*portRange, 1);
16225d8ee958SBrian Somers 		return 0;
16235d8ee958SBrian Somers 	}
16245d8ee958SBrian Somers 
16255d8ee958SBrian Somers 	/* Not a service, see if it's a single port or port range. */
16265d8ee958SBrian Somers 	sep = strchr (str, '-');
16275d8ee958SBrian Somers 	if (sep == NULL) {
16285d8ee958SBrian Somers 	        SETLOPORT(*portRange, strtol(str, &end, 10));
16295d8ee958SBrian Somers 		if (end != str) {
16305d8ee958SBrian Somers 		        /* Single port. */
16315d8ee958SBrian Somers 		        SETNUMPORTS(*portRange, 1);
16325d8ee958SBrian Somers 			return 0;
16335d8ee958SBrian Somers 		}
16345d8ee958SBrian Somers 
16355d8ee958SBrian Somers 		/* Error in port range field. */
16365d8ee958SBrian Somers 		errx (1, "unknown service %s/%s", str, proto);
16375d8ee958SBrian Somers 	}
16385d8ee958SBrian Somers 
16395d8ee958SBrian Somers 	/* Port range, get the values and sanity check. */
16405d8ee958SBrian Somers 	sscanf (str, "%hu-%hu", &loPort, &hiPort);
16415d8ee958SBrian Somers 	SETLOPORT(*portRange, loPort);
16425d8ee958SBrian Somers 	SETNUMPORTS(*portRange, 0);	/* Error by default */
16435d8ee958SBrian Somers 	if (loPort <= hiPort)
16445d8ee958SBrian Somers 	        SETNUMPORTS(*portRange, hiPort - loPort + 1);
16455d8ee958SBrian Somers 
16465d8ee958SBrian Somers 	if (GETNUMPORTS(*portRange) == 0)
16475d8ee958SBrian Somers 	        errx (1, "invalid port range %s", str);
16485d8ee958SBrian Somers 
16495d8ee958SBrian Somers 	return 0;
16505d8ee958SBrian Somers }
16515d8ee958SBrian Somers 
16525d8ee958SBrian Somers 
1653902cb50aSBrian Somers int StrToProto (const char* str)
165424084f9bSBrian Somers {
165524084f9bSBrian Somers 	if (!strcmp (str, "tcp"))
165624084f9bSBrian Somers 		return IPPROTO_TCP;
165724084f9bSBrian Somers 
165824084f9bSBrian Somers 	if (!strcmp (str, "udp"))
165924084f9bSBrian Somers 		return IPPROTO_UDP;
166024084f9bSBrian Somers 
16610fc81af1SPhilippe Charnier 	errx (1, "unknown protocol %s. Expected tcp or udp", str);
166224084f9bSBrian Somers }
166324084f9bSBrian Somers 
1664902cb50aSBrian Somers int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
166524084f9bSBrian Somers {
166624084f9bSBrian Somers 	char*	ptr;
166724084f9bSBrian Somers 
166824084f9bSBrian Somers 	ptr = strchr (str, ':');
16690fc81af1SPhilippe Charnier 	if (!ptr)
16700fc81af1SPhilippe Charnier 		errx (1, "%s is missing port number", str);
167124084f9bSBrian Somers 
167224084f9bSBrian Somers 	*ptr = '\0';
167324084f9bSBrian Somers 	++ptr;
167424084f9bSBrian Somers 
167524084f9bSBrian Somers 	StrToAddr (str, addr);
16765d8ee958SBrian Somers 	return StrToPortRange (ptr, proto, portRange);
167724084f9bSBrian Somers }
1678bc4ebb98SRuslan Ermilov 
1679bc4ebb98SRuslan Ermilov static void
1680bc4ebb98SRuslan Ermilov SetupPunchFW(const char *strValue)
1681bc4ebb98SRuslan Ermilov {
1682bc4ebb98SRuslan Ermilov 	unsigned int base, num;
1683bc4ebb98SRuslan Ermilov 
1684bc4ebb98SRuslan Ermilov 	if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1685bc4ebb98SRuslan Ermilov 		errx(1, "punch_fw: basenumber:count parameter required");
1686bc4ebb98SRuslan Ermilov 
1687bc4ebb98SRuslan Ermilov 	PacketAliasSetFWBase(base, num);
1688bc4ebb98SRuslan Ermilov 	(void)PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1689bc4ebb98SRuslan Ermilov }
1690