xref: /freebsd/sbin/natd/natd.c (revision bc4ebb98dc561e3bd55a1c5f9f35d810182e419d)
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);
100fb994b07SBrian Somers static void	FlushPacketBuffer (int fd);
101bc4ebb98SRuslan Ermilov static void	SetupPunchFW(const char *strValue);
10224084f9bSBrian Somers 
10324084f9bSBrian Somers /*
10424084f9bSBrian Somers  * Globals.
10524084f9bSBrian Somers  */
10624084f9bSBrian Somers 
10724084f9bSBrian Somers static	int			verbose;
10824084f9bSBrian Somers static 	int			background;
10924084f9bSBrian Somers static	int			running;
11024084f9bSBrian Somers static	int			assignAliasAddr;
11124084f9bSBrian Somers static	char*			ifName;
11224084f9bSBrian Somers static  int			ifIndex;
11367a886fbSBrian Somers static	u_short			inPort;
11467a886fbSBrian Somers static	u_short			outPort;
11567a886fbSBrian Somers static	u_short			inOutPort;
11624084f9bSBrian Somers static	struct in_addr		aliasAddr;
11724084f9bSBrian Somers static 	int			dynamicMode;
11824084f9bSBrian Somers static  int			ifMTU;
11924084f9bSBrian Somers static	int			aliasOverhead;
12024084f9bSBrian Somers static 	int			icmpSock;
121fb994b07SBrian Somers static	char			packetBuf[IP_MAXPACKET];
122fb994b07SBrian Somers static 	int			packetLen;
123fb994b07SBrian Somers static	struct sockaddr_in	packetAddr;
124fb994b07SBrian Somers static 	int			packetSock;
12559a7c613SBrian Somers static 	int			packetDirection;
126f9b06d5cSBrian Somers static  int			dropIgnoredIncoming;
12759a7c613SBrian Somers static  int			logDropped;
12859a7c613SBrian Somers static	int			logFacility;
12924084f9bSBrian Somers 
13024084f9bSBrian Somers int main (int argc, char** argv)
13124084f9bSBrian Somers {
13224084f9bSBrian Somers 	int			divertIn;
13324084f9bSBrian Somers 	int			divertOut;
13424084f9bSBrian Somers 	int			divertInOut;
13524084f9bSBrian Somers 	int			routeSock;
13624084f9bSBrian Somers 	struct sockaddr_in	addr;
13724084f9bSBrian Somers 	fd_set			readMask;
138fb994b07SBrian Somers 	fd_set			writeMask;
13924084f9bSBrian Somers 	int			fdMax;
14024084f9bSBrian Somers /*
14124084f9bSBrian Somers  * Initialize packet aliasing software.
14224084f9bSBrian Somers  * Done already here to be able to alter option bits
14324084f9bSBrian Somers  * during command line and configuration file processing.
14424084f9bSBrian Somers  */
145fb994b07SBrian Somers 	PacketAliasInit ();
14624084f9bSBrian Somers /*
14724084f9bSBrian Somers  * Parse options.
14824084f9bSBrian Somers  */
14924084f9bSBrian Somers 	inPort			= 0;
15024084f9bSBrian Somers 	outPort			= 0;
15124084f9bSBrian Somers 	verbose 		= 0;
15224084f9bSBrian Somers 	inOutPort		= 0;
15324084f9bSBrian Somers 	ifName			= NULL;
15424084f9bSBrian Somers 	ifMTU			= -1;
15524084f9bSBrian Somers 	background		= 0;
15624084f9bSBrian Somers 	running			= 1;
15724084f9bSBrian Somers 	assignAliasAddr		= 0;
15824084f9bSBrian Somers 	aliasAddr.s_addr	= INADDR_NONE;
15924084f9bSBrian Somers 	aliasOverhead		= 12;
16024084f9bSBrian Somers 	dynamicMode		= 0;
16159a7c613SBrian Somers  	logDropped		= 0;
16259a7c613SBrian Somers  	logFacility		= LOG_DAEMON;
163fb994b07SBrian Somers /*
164fb994b07SBrian Somers  * Mark packet buffer empty.
165fb994b07SBrian Somers  */
166fb994b07SBrian Somers 	packetSock		= -1;
16759a7c613SBrian Somers 	packetDirection		= DONT_KNOW;
16824084f9bSBrian Somers 
16924084f9bSBrian Somers 	ParseArgs (argc, argv);
17024084f9bSBrian Somers /*
17159a7c613SBrian Somers  * Open syslog channel.
17259a7c613SBrian Somers  */
1734c04fa4cSRuslan Ermilov 	openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0),
1744c04fa4cSRuslan Ermilov 		 logFacility);
17559a7c613SBrian Somers /*
17624084f9bSBrian Somers  * Check that valid aliasing address has been given.
17724084f9bSBrian Somers  */
1780fc81af1SPhilippe Charnier 	if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL)
1790fc81af1SPhilippe Charnier 		errx (1, "aliasing address not given");
18024084f9bSBrian Somers 
1810fc81af1SPhilippe Charnier 	if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL)
18267a886fbSBrian Somers 		errx (1, "both alias address and interface "
18367a886fbSBrian Somers 			 "name are not allowed");
18424084f9bSBrian Somers /*
18524084f9bSBrian Somers  * Check that valid port number is known.
18624084f9bSBrian Somers  */
18724084f9bSBrian Somers 	if (inPort != 0 || outPort != 0)
1880fc81af1SPhilippe Charnier 		if (inPort == 0 || outPort == 0)
1890fc81af1SPhilippe Charnier 			errx (1, "both input and output ports are required");
19024084f9bSBrian Somers 
19124084f9bSBrian Somers 	if (inPort == 0 && outPort == 0 && inOutPort == 0)
192b0f55af6SRuslan Ermilov 		ParseOption ("port", DEFAULT_SERVICE);
19324084f9bSBrian Somers 
19424084f9bSBrian Somers /*
195f9b06d5cSBrian Somers  * Check if ignored packets should be dropped.
196f9b06d5cSBrian Somers  */
197f9b06d5cSBrian Somers 	dropIgnoredIncoming = PacketAliasSetMode (0, 0);
198f9b06d5cSBrian Somers 	dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
199f9b06d5cSBrian Somers /*
20024084f9bSBrian Somers  * Create divert sockets. Use only one socket if -p was specified
20124084f9bSBrian Somers  * on command line. Otherwise, create separate sockets for
20224084f9bSBrian Somers  * outgoing and incoming connnections.
20324084f9bSBrian Somers  */
20424084f9bSBrian Somers 	if (inOutPort) {
20524084f9bSBrian Somers 
20624084f9bSBrian Somers 		divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
20724084f9bSBrian Somers 		if (divertInOut == -1)
20824084f9bSBrian Somers 			Quit ("Unable to create divert socket.");
20924084f9bSBrian Somers 
21024084f9bSBrian Somers 		divertIn  = -1;
21124084f9bSBrian Somers 		divertOut = -1;
21224084f9bSBrian Somers /*
21324084f9bSBrian Somers  * Bind socket.
21424084f9bSBrian Somers  */
21524084f9bSBrian Somers 
21624084f9bSBrian Somers 		addr.sin_family		= AF_INET;
21724084f9bSBrian Somers 		addr.sin_addr.s_addr	= INADDR_ANY;
21824084f9bSBrian Somers 		addr.sin_port		= inOutPort;
21924084f9bSBrian Somers 
22024084f9bSBrian Somers 		if (bind (divertInOut,
22124084f9bSBrian Somers 			  (struct sockaddr*) &addr,
22224084f9bSBrian Somers 			  sizeof addr) == -1)
22324084f9bSBrian Somers 			Quit ("Unable to bind divert socket.");
22424084f9bSBrian Somers 	}
22524084f9bSBrian Somers 	else {
22624084f9bSBrian Somers 
22724084f9bSBrian Somers 		divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
22824084f9bSBrian Somers 		if (divertIn == -1)
22924084f9bSBrian Somers 			Quit ("Unable to create incoming divert socket.");
23024084f9bSBrian Somers 
23124084f9bSBrian Somers 		divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
23224084f9bSBrian Somers 		if (divertOut == -1)
23324084f9bSBrian Somers 			Quit ("Unable to create outgoing divert socket.");
23424084f9bSBrian Somers 
23524084f9bSBrian Somers 		divertInOut = -1;
23624084f9bSBrian Somers 
23724084f9bSBrian Somers /*
23824084f9bSBrian Somers  * Bind divert sockets.
23924084f9bSBrian Somers  */
24024084f9bSBrian Somers 
24124084f9bSBrian Somers 		addr.sin_family		= AF_INET;
24224084f9bSBrian Somers 		addr.sin_addr.s_addr	= INADDR_ANY;
24324084f9bSBrian Somers 		addr.sin_port		= inPort;
24424084f9bSBrian Somers 
24524084f9bSBrian Somers 		if (bind (divertIn,
24624084f9bSBrian Somers 			  (struct sockaddr*) &addr,
24724084f9bSBrian Somers 			  sizeof addr) == -1)
24824084f9bSBrian Somers 			Quit ("Unable to bind incoming divert socket.");
24924084f9bSBrian Somers 
25024084f9bSBrian Somers 		addr.sin_family		= AF_INET;
25124084f9bSBrian Somers 		addr.sin_addr.s_addr	= INADDR_ANY;
25224084f9bSBrian Somers 		addr.sin_port		= outPort;
25324084f9bSBrian Somers 
25424084f9bSBrian Somers 		if (bind (divertOut,
25524084f9bSBrian Somers 			  (struct sockaddr*) &addr,
25624084f9bSBrian Somers 			  sizeof addr) == -1)
25724084f9bSBrian Somers 			Quit ("Unable to bind outgoing divert socket.");
25824084f9bSBrian Somers 	}
25924084f9bSBrian Somers /*
260f2da55a2SRuslan Ermilov  * Create routing socket if interface name specified and in dynamic mode.
26124084f9bSBrian Somers  */
262f2da55a2SRuslan Ermilov 	routeSock = -1;
263f2da55a2SRuslan Ermilov 	if (ifName) {
264f2da55a2SRuslan Ermilov 		if (dynamicMode) {
26524084f9bSBrian Somers 
26624084f9bSBrian Somers 			routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
26724084f9bSBrian Somers 			if (routeSock == -1)
26824084f9bSBrian Somers 				Quit ("Unable to create routing info socket.");
269f2da55a2SRuslan Ermilov 
270f2da55a2SRuslan Ermilov 			assignAliasAddr = 1;
27124084f9bSBrian Somers 		}
27224084f9bSBrian Somers 		else
273f2da55a2SRuslan Ermilov 			SetAliasAddressFromIfName (ifName);
274f2da55a2SRuslan Ermilov 	}
27524084f9bSBrian Somers /*
27624084f9bSBrian Somers  * Create socket for sending ICMP messages.
27724084f9bSBrian Somers  */
27824084f9bSBrian Somers 	icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
27924084f9bSBrian Somers 	if (icmpSock == -1)
28024084f9bSBrian Somers 		Quit ("Unable to create ICMP socket.");
281f3d64024SBrian Somers 
282f3d64024SBrian Somers /*
283f3d64024SBrian Somers  * And disable reads for the socket, otherwise it slowly fills
284f3d64024SBrian Somers  * up with received icmps which we do not use.
285f3d64024SBrian Somers  */
286f3d64024SBrian Somers 	shutdown(icmpSock, SHUT_RD);
287f3d64024SBrian Somers 
28824084f9bSBrian Somers /*
28924084f9bSBrian Somers  * Become a daemon unless verbose mode was requested.
29024084f9bSBrian Somers  */
29124084f9bSBrian Somers 	if (!verbose)
29224084f9bSBrian Somers 		DaemonMode ();
29324084f9bSBrian Somers /*
29424084f9bSBrian Somers  * Catch signals to manage shutdown and
29524084f9bSBrian Somers  * refresh of interface address.
29624084f9bSBrian Somers  */
297cd45c931SRuslan Ermilov 	siginterrupt(SIGTERM, 1);
298cd45c931SRuslan Ermilov 	siginterrupt(SIGHUP, 1);
29924084f9bSBrian Somers 	signal (SIGTERM, InitiateShutdown);
30024084f9bSBrian Somers 	signal (SIGHUP, RefreshAddr);
30124084f9bSBrian Somers /*
30224084f9bSBrian Somers  * Set alias address if it has been given.
30324084f9bSBrian Somers  */
30424084f9bSBrian Somers 	if (aliasAddr.s_addr != INADDR_NONE)
305fb994b07SBrian Somers 		PacketAliasSetAddress (aliasAddr);
30624084f9bSBrian Somers /*
30724084f9bSBrian Somers  * We need largest descriptor number for select.
30824084f9bSBrian Somers  */
30924084f9bSBrian Somers 
31024084f9bSBrian Somers 	fdMax = -1;
31124084f9bSBrian Somers 
31224084f9bSBrian Somers 	if (divertIn > fdMax)
31324084f9bSBrian Somers 		fdMax = divertIn;
31424084f9bSBrian Somers 
31524084f9bSBrian Somers 	if (divertOut > fdMax)
31624084f9bSBrian Somers 		fdMax = divertOut;
31724084f9bSBrian Somers 
31824084f9bSBrian Somers 	if (divertInOut > fdMax)
31924084f9bSBrian Somers 		fdMax = divertInOut;
32024084f9bSBrian Somers 
32124084f9bSBrian Somers 	if (routeSock > fdMax)
32224084f9bSBrian Somers 		fdMax = routeSock;
32324084f9bSBrian Somers 
32424084f9bSBrian Somers 	while (running) {
325fb994b07SBrian Somers 
326fb994b07SBrian Somers 		if (divertInOut != -1 && !ifName && packetSock == -1) {
327fb994b07SBrian Somers /*
328fb994b07SBrian Somers  * When using only one socket, just call
329fb994b07SBrian Somers  * DoAliasing repeatedly to process packets.
330fb994b07SBrian Somers  */
33159a7c613SBrian Somers 			DoAliasing (divertInOut, DONT_KNOW);
332fb994b07SBrian Somers 			continue;
333fb994b07SBrian Somers 		}
33424084f9bSBrian Somers /*
33524084f9bSBrian Somers  * Build read mask from socket descriptors to select.
33624084f9bSBrian Somers  */
33724084f9bSBrian Somers 		FD_ZERO (&readMask);
338fb994b07SBrian Somers 		FD_ZERO (&writeMask);
33924084f9bSBrian Somers 
340fb994b07SBrian Somers /*
341fb994b07SBrian Somers  * If there is unsent packet in buffer, use select
342fb994b07SBrian Somers  * to check when socket comes writable again.
343fb994b07SBrian Somers  */
344fb994b07SBrian Somers 		if (packetSock != -1) {
345fb994b07SBrian Somers 
346fb994b07SBrian Somers 			FD_SET (packetSock, &writeMask);
347fb994b07SBrian Somers 		}
348fb994b07SBrian Somers 		else {
349fb994b07SBrian Somers /*
350fb994b07SBrian Somers  * No unsent packet exists - safe to check if
351fb994b07SBrian Somers  * new ones are available.
352fb994b07SBrian Somers  */
35324084f9bSBrian Somers 			if (divertIn != -1)
35424084f9bSBrian Somers 				FD_SET (divertIn, &readMask);
35524084f9bSBrian Somers 
35624084f9bSBrian Somers 			if (divertOut != -1)
35724084f9bSBrian Somers 				FD_SET (divertOut, &readMask);
35824084f9bSBrian Somers 
35924084f9bSBrian Somers 			if (divertInOut != -1)
36024084f9bSBrian Somers 				FD_SET (divertInOut, &readMask);
361fb994b07SBrian Somers 		}
362fb994b07SBrian Somers /*
363fb994b07SBrian Somers  * Routing info is processed always.
364fb994b07SBrian Somers  */
36524084f9bSBrian Somers 		if (routeSock != -1)
36624084f9bSBrian Somers 			FD_SET (routeSock, &readMask);
36724084f9bSBrian Somers 
36824084f9bSBrian Somers 		if (select (fdMax + 1,
36924084f9bSBrian Somers 			    &readMask,
370fb994b07SBrian Somers 			    &writeMask,
37124084f9bSBrian Somers 			    NULL,
37224084f9bSBrian Somers 			    NULL) == -1) {
37324084f9bSBrian Somers 
37424084f9bSBrian Somers 			if (errno == EINTR)
37524084f9bSBrian Somers 				continue;
37624084f9bSBrian Somers 
37724084f9bSBrian Somers 			Quit ("Select failed.");
37824084f9bSBrian Somers 		}
37924084f9bSBrian Somers 
380fb994b07SBrian Somers 		if (packetSock != -1)
381fb994b07SBrian Somers 			if (FD_ISSET (packetSock, &writeMask))
382fb994b07SBrian Somers 				FlushPacketBuffer (packetSock);
383fb994b07SBrian Somers 
38424084f9bSBrian Somers 		if (divertIn != -1)
38524084f9bSBrian Somers 			if (FD_ISSET (divertIn, &readMask))
38659a7c613SBrian Somers 				DoAliasing (divertIn, INPUT);
38724084f9bSBrian Somers 
38824084f9bSBrian Somers 		if (divertOut != -1)
38924084f9bSBrian Somers 			if (FD_ISSET (divertOut, &readMask))
39059a7c613SBrian Somers 				DoAliasing (divertOut, OUTPUT);
39124084f9bSBrian Somers 
39224084f9bSBrian Somers 		if (divertInOut != -1)
39324084f9bSBrian Somers 			if (FD_ISSET (divertInOut, &readMask))
39459a7c613SBrian Somers 				DoAliasing (divertInOut, DONT_KNOW);
39524084f9bSBrian Somers 
39624084f9bSBrian Somers 		if (routeSock != -1)
39724084f9bSBrian Somers 			if (FD_ISSET (routeSock, &readMask))
39824084f9bSBrian Somers 				HandleRoutingInfo (routeSock);
39924084f9bSBrian Somers 	}
40024084f9bSBrian Somers 
40124084f9bSBrian Somers 	if (background)
40224084f9bSBrian Somers 		unlink (PIDFILE);
40324084f9bSBrian Somers 
40424084f9bSBrian Somers 	return 0;
40524084f9bSBrian Somers }
40624084f9bSBrian Somers 
40724084f9bSBrian Somers static void DaemonMode ()
40824084f9bSBrian Somers {
40924084f9bSBrian Somers 	FILE*	pidFile;
41024084f9bSBrian Somers 
41124084f9bSBrian Somers 	daemon (0, 0);
41224084f9bSBrian Somers 	background = 1;
41324084f9bSBrian Somers 
41424084f9bSBrian Somers 	pidFile = fopen (PIDFILE, "w");
41524084f9bSBrian Somers 	if (pidFile) {
41624084f9bSBrian Somers 
41724084f9bSBrian Somers 		fprintf (pidFile, "%d\n", getpid ());
41824084f9bSBrian Somers 		fclose (pidFile);
41924084f9bSBrian Somers 	}
42024084f9bSBrian Somers }
42124084f9bSBrian Somers 
42224084f9bSBrian Somers static void ParseArgs (int argc, char** argv)
42324084f9bSBrian Somers {
42424084f9bSBrian Somers 	int		arg;
42524084f9bSBrian Somers 	char*		opt;
42624084f9bSBrian Somers 	char		parmBuf[256];
42730395bb5SJosef Karthauser 	int		len; /* bounds checking */
42824084f9bSBrian Somers 
42924084f9bSBrian Somers 	for (arg = 1; arg < argc; arg++) {
43024084f9bSBrian Somers 
43124084f9bSBrian Somers 		opt  = argv[arg];
43224084f9bSBrian Somers 		if (*opt != '-') {
43324084f9bSBrian Somers 
4340fc81af1SPhilippe Charnier 			warnx ("invalid option %s", opt);
43524084f9bSBrian Somers 			Usage ();
43624084f9bSBrian Somers 		}
43724084f9bSBrian Somers 
43824084f9bSBrian Somers 		parmBuf[0] = '\0';
43930395bb5SJosef Karthauser 		len = 0;
44024084f9bSBrian Somers 
44124084f9bSBrian Somers 		while (arg < argc - 1) {
44224084f9bSBrian Somers 
44324084f9bSBrian Somers 			if (argv[arg + 1][0] == '-')
44424084f9bSBrian Somers 				break;
44524084f9bSBrian Somers 
44630395bb5SJosef Karthauser 			if (len) {
44730395bb5SJosef Karthauser 				strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1));
44830395bb5SJosef Karthauser 				len += strlen(parmBuf + len);
44924084f9bSBrian Somers 			}
45024084f9bSBrian Somers 
45130395bb5SJosef Karthauser 			++arg;
45230395bb5SJosef Karthauser 			strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1));
45330395bb5SJosef Karthauser 			len += strlen(parmBuf + len);
45430395bb5SJosef Karthauser 
45530395bb5SJosef Karthauser 		}
45630395bb5SJosef Karthauser 
457b0f55af6SRuslan Ermilov 		ParseOption (opt + 1, (len ? parmBuf : NULL));
45830395bb5SJosef Karthauser 
45924084f9bSBrian Somers 	}
46024084f9bSBrian Somers }
46124084f9bSBrian Somers 
46259a7c613SBrian Somers static void DoAliasing (int fd, int direction)
46324084f9bSBrian Somers {
46424084f9bSBrian Somers 	int			bytes;
46524084f9bSBrian Somers 	int			origBytes;
466f9b06d5cSBrian Somers 	int			status;
46724084f9bSBrian Somers 	int			addrSize;
46824084f9bSBrian Somers 	struct ip*		ip;
46924084f9bSBrian Somers 
47024084f9bSBrian Somers 	if (assignAliasAddr) {
47124084f9bSBrian Somers 
47224084f9bSBrian Somers 		SetAliasAddressFromIfName (ifName);
47324084f9bSBrian Somers 		assignAliasAddr = 0;
47424084f9bSBrian Somers 	}
47524084f9bSBrian Somers /*
47624084f9bSBrian Somers  * Get packet from socket.
47724084f9bSBrian Somers  */
478fb994b07SBrian Somers 	addrSize  = sizeof packetAddr;
47924084f9bSBrian Somers 	origBytes = recvfrom (fd,
480fb994b07SBrian Somers 			      packetBuf,
481fb994b07SBrian Somers 			      sizeof packetBuf,
48224084f9bSBrian Somers 			      0,
483fb994b07SBrian Somers 			      (struct sockaddr*) &packetAddr,
48424084f9bSBrian Somers 			      &addrSize);
48524084f9bSBrian Somers 
48624084f9bSBrian Somers 	if (origBytes == -1) {
48724084f9bSBrian Somers 
48824084f9bSBrian Somers 		if (errno != EINTR)
4890fc81af1SPhilippe Charnier 			Warn ("read from divert socket failed");
49024084f9bSBrian Somers 
49124084f9bSBrian Somers 		return;
49224084f9bSBrian Somers 	}
49324084f9bSBrian Somers /*
49424084f9bSBrian Somers  * This is a IP packet.
49524084f9bSBrian Somers  */
496fb994b07SBrian Somers 	ip = (struct ip*) packetBuf;
497ebe70c8fSWarner Losh 	if (direction == DONT_KNOW) {
49859a7c613SBrian Somers 		if (packetAddr.sin_addr.s_addr == INADDR_ANY)
49959a7c613SBrian Somers 			direction = OUTPUT;
50059a7c613SBrian Somers 		else
50159a7c613SBrian Somers 			direction = INPUT;
502ebe70c8fSWarner Losh 	}
50324084f9bSBrian Somers 
50424084f9bSBrian Somers 	if (verbose) {
50524084f9bSBrian Somers /*
50624084f9bSBrian Somers  * Print packet direction and protocol type.
50724084f9bSBrian Somers  */
50859a7c613SBrian Somers 		printf (direction == OUTPUT ? "Out " : "In  ");
50924084f9bSBrian Somers 
51024084f9bSBrian Somers 		switch (ip->ip_p) {
51124084f9bSBrian Somers 		case IPPROTO_TCP:
51224084f9bSBrian Somers 			printf ("[TCP]  ");
51324084f9bSBrian Somers 			break;
51424084f9bSBrian Somers 
51524084f9bSBrian Somers 		case IPPROTO_UDP:
51624084f9bSBrian Somers 			printf ("[UDP]  ");
51724084f9bSBrian Somers 			break;
51824084f9bSBrian Somers 
51924084f9bSBrian Somers 		case IPPROTO_ICMP:
52024084f9bSBrian Somers 			printf ("[ICMP] ");
52124084f9bSBrian Somers 			break;
52224084f9bSBrian Somers 
52324084f9bSBrian Somers 		default:
52459a7c613SBrian Somers 			printf ("[%d]    ", ip->ip_p);
52524084f9bSBrian Somers 			break;
52624084f9bSBrian Somers 		}
52724084f9bSBrian Somers /*
52824084f9bSBrian Somers  * Print addresses.
52924084f9bSBrian Somers  */
53024084f9bSBrian Somers 		PrintPacket (ip);
53124084f9bSBrian Somers 	}
53224084f9bSBrian Somers 
53359a7c613SBrian Somers 	if (direction == OUTPUT) {
53424084f9bSBrian Somers /*
53524084f9bSBrian Somers  * Outgoing packets. Do aliasing.
53624084f9bSBrian Somers  */
537fb994b07SBrian Somers 		PacketAliasOut (packetBuf, IP_MAXPACKET);
53824084f9bSBrian Somers 	}
53924084f9bSBrian Somers 	else {
54059a7c613SBrian Somers 
54124084f9bSBrian Somers /*
54224084f9bSBrian Somers  * Do aliasing.
54324084f9bSBrian Somers  */
544f9b06d5cSBrian Somers 		status = PacketAliasIn (packetBuf, IP_MAXPACKET);
545f9b06d5cSBrian Somers 		if (status == PKT_ALIAS_IGNORED &&
546f9b06d5cSBrian Somers 		    dropIgnoredIncoming) {
547f9b06d5cSBrian Somers 
54859a7c613SBrian Somers 			if (verbose)
549f9b06d5cSBrian Somers 				printf (" dropped.\n");
55059a7c613SBrian Somers 
55159a7c613SBrian Somers 			if (logDropped)
55259a7c613SBrian Somers 				SyslogPacket (ip, LOG_WARNING, "denied");
55359a7c613SBrian Somers 
554f9b06d5cSBrian Somers 			return;
555f9b06d5cSBrian Somers 		}
55624084f9bSBrian Somers 	}
55724084f9bSBrian Somers /*
55824084f9bSBrian Somers  * Length might have changed during aliasing.
55924084f9bSBrian Somers  */
56024084f9bSBrian Somers 	bytes = ntohs (ip->ip_len);
56124084f9bSBrian Somers /*
56224084f9bSBrian Somers  * Update alias overhead size for outgoing packets.
56324084f9bSBrian Somers  */
56459a7c613SBrian Somers 	if (direction == OUTPUT &&
56524084f9bSBrian Somers 	    bytes - origBytes > aliasOverhead)
56624084f9bSBrian Somers 		aliasOverhead = bytes - origBytes;
56724084f9bSBrian Somers 
56824084f9bSBrian Somers 	if (verbose) {
56924084f9bSBrian Somers 
57024084f9bSBrian Somers /*
57124084f9bSBrian Somers  * Print addresses after aliasing.
57224084f9bSBrian Somers  */
57324084f9bSBrian Somers 		printf (" aliased to\n");
57424084f9bSBrian Somers 		printf ("           ");
57524084f9bSBrian Somers 		PrintPacket (ip);
57624084f9bSBrian Somers 		printf ("\n");
57724084f9bSBrian Somers 	}
578fb994b07SBrian Somers 
579fb994b07SBrian Somers 	packetLen  	= bytes;
580fb994b07SBrian Somers 	packetSock 	= fd;
58159a7c613SBrian Somers 	packetDirection = direction;
58259a7c613SBrian Somers 
583fb994b07SBrian Somers 	FlushPacketBuffer (fd);
584fb994b07SBrian Somers }
585fb994b07SBrian Somers 
586fb994b07SBrian Somers static void FlushPacketBuffer (int fd)
587fb994b07SBrian Somers {
588fb994b07SBrian Somers 	int			wrote;
589fb994b07SBrian Somers 	char			msgBuf[80];
59024084f9bSBrian Somers /*
59124084f9bSBrian Somers  * Put packet back for processing.
59224084f9bSBrian Somers  */
59324084f9bSBrian Somers 	wrote = sendto (fd,
594fb994b07SBrian Somers 		        packetBuf,
595fb994b07SBrian Somers 	    		packetLen,
59624084f9bSBrian Somers 	    		0,
597fb994b07SBrian Somers 	    		(struct sockaddr*) &packetAddr,
598fb994b07SBrian Somers 	    		sizeof packetAddr);
59924084f9bSBrian Somers 
600fb994b07SBrian Somers 	if (wrote != packetLen) {
601fb994b07SBrian Somers /*
602fb994b07SBrian Somers  * If buffer space is not available,
603fb994b07SBrian Somers  * just return. Main loop will take care of
604fb994b07SBrian Somers  * retrying send when space becomes available.
605fb994b07SBrian Somers  */
606fb994b07SBrian Somers 		if (errno == ENOBUFS)
607fb994b07SBrian Somers 			return;
60824084f9bSBrian Somers 
60924084f9bSBrian Somers 		if (errno == EMSGSIZE) {
61024084f9bSBrian Somers 
61159a7c613SBrian Somers 			if (packetDirection == OUTPUT &&
61224084f9bSBrian Somers 			    ifMTU != -1)
61324084f9bSBrian Somers 				SendNeedFragIcmp (icmpSock,
614fb994b07SBrian Somers 						  (struct ip*) packetBuf,
61524084f9bSBrian Somers 						  ifMTU - aliasOverhead);
61624084f9bSBrian Somers 		}
61724084f9bSBrian Somers 		else {
61824084f9bSBrian Somers 
6190fc81af1SPhilippe Charnier 			sprintf (msgBuf, "failed to write packet back");
62024084f9bSBrian Somers 			Warn (msgBuf);
62124084f9bSBrian Somers 		}
62224084f9bSBrian Somers 	}
623fb994b07SBrian Somers 
624fb994b07SBrian Somers 	packetSock = -1;
62524084f9bSBrian Somers }
62624084f9bSBrian Somers 
62724084f9bSBrian Somers static void HandleRoutingInfo (int fd)
62824084f9bSBrian Somers {
62924084f9bSBrian Somers 	int			bytes;
63024084f9bSBrian Somers 	struct if_msghdr	ifMsg;
63124084f9bSBrian Somers /*
63224084f9bSBrian Somers  * Get packet from socket.
63324084f9bSBrian Somers  */
63424084f9bSBrian Somers 	bytes = read (fd, &ifMsg, sizeof ifMsg);
63524084f9bSBrian Somers 	if (bytes == -1) {
63624084f9bSBrian Somers 
6370fc81af1SPhilippe Charnier 		Warn ("read from routing socket failed");
63824084f9bSBrian Somers 		return;
63924084f9bSBrian Somers 	}
64024084f9bSBrian Somers 
64124084f9bSBrian Somers 	if (ifMsg.ifm_version != RTM_VERSION) {
64224084f9bSBrian Somers 
6430fc81af1SPhilippe Charnier 		Warn ("unexpected packet read from routing socket");
64424084f9bSBrian Somers 		return;
64524084f9bSBrian Somers 	}
64624084f9bSBrian Somers 
64724084f9bSBrian Somers 	if (verbose)
6486f3dbe5eSRuslan Ermilov 		printf ("Routing message %#x received.\n", ifMsg.ifm_type);
64924084f9bSBrian Somers 
6506f3dbe5eSRuslan Ermilov 	if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO) &&
6516f3dbe5eSRuslan Ermilov 	    ifMsg.ifm_index == ifIndex) {
6526f3dbe5eSRuslan Ermilov 		if (verbose)
6536f3dbe5eSRuslan Ermilov 			printf("Interface address/MTU has probably changed.\n");
65424084f9bSBrian Somers 		assignAliasAddr = 1;
65524084f9bSBrian Somers 	}
6566f3dbe5eSRuslan Ermilov }
65724084f9bSBrian Somers 
65824084f9bSBrian Somers static void PrintPacket (struct ip* ip)
65924084f9bSBrian Somers {
66059a7c613SBrian Somers 	printf ("%s", FormatPacket (ip));
66159a7c613SBrian Somers }
66259a7c613SBrian Somers 
663902cb50aSBrian Somers static void SyslogPacket (struct ip* ip, int priority, const char *label)
66459a7c613SBrian Somers {
66559a7c613SBrian Somers 	syslog (priority, "%s %s", label, FormatPacket (ip));
66659a7c613SBrian Somers }
66759a7c613SBrian Somers 
66859a7c613SBrian Somers static char* FormatPacket (struct ip* ip)
66959a7c613SBrian Somers {
67059a7c613SBrian Somers 	static char	buf[256];
67124084f9bSBrian Somers 	struct tcphdr*	tcphdr;
67259a7c613SBrian Somers 	struct udphdr*	udphdr;
67359a7c613SBrian Somers 	struct icmp*	icmphdr;
67459a7c613SBrian Somers 	char		src[20];
67559a7c613SBrian Somers 	char		dst[20];
67624084f9bSBrian Somers 
67759a7c613SBrian Somers 	strcpy (src, inet_ntoa (ip->ip_src));
67859a7c613SBrian Somers 	strcpy (dst, inet_ntoa (ip->ip_dst));
67959a7c613SBrian Somers 
68059a7c613SBrian Somers 	switch (ip->ip_p) {
68159a7c613SBrian Somers 	case IPPROTO_TCP:
68224084f9bSBrian Somers 		tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
68359a7c613SBrian Somers 		sprintf (buf, "[TCP] %s:%d -> %s:%d",
68459a7c613SBrian Somers 			      src,
68559a7c613SBrian Somers 			      ntohs (tcphdr->th_sport),
68659a7c613SBrian Somers 			      dst,
68759a7c613SBrian Somers 			      ntohs (tcphdr->th_dport));
68859a7c613SBrian Somers 		break;
68924084f9bSBrian Somers 
69059a7c613SBrian Somers 	case IPPROTO_UDP:
69159a7c613SBrian Somers 		udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2));
69259a7c613SBrian Somers 		sprintf (buf, "[UDP] %s:%d -> %s:%d",
69359a7c613SBrian Somers 			      src,
69459a7c613SBrian Somers 			      ntohs (udphdr->uh_sport),
69559a7c613SBrian Somers 			      dst,
69659a7c613SBrian Somers 			      ntohs (udphdr->uh_dport));
69759a7c613SBrian Somers 		break;
69824084f9bSBrian Somers 
69959a7c613SBrian Somers 	case IPPROTO_ICMP:
70059a7c613SBrian Somers 		icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2));
701b71e869dSBrian Somers 		sprintf (buf, "[ICMP] %s -> %s %u(%u)",
70259a7c613SBrian Somers 			      src,
70359a7c613SBrian Somers 			      dst,
704b71e869dSBrian Somers 			      icmphdr->icmp_type,
705b71e869dSBrian Somers 			      icmphdr->icmp_code);
70659a7c613SBrian Somers 		break;
70759a7c613SBrian Somers 
70859a7c613SBrian Somers 	default:
70959a7c613SBrian Somers 		sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst);
71059a7c613SBrian Somers 		break;
71159a7c613SBrian Somers 	}
71259a7c613SBrian Somers 
71359a7c613SBrian Somers 	return buf;
71424084f9bSBrian Somers }
71524084f9bSBrian Somers 
7164c04fa4cSRuslan Ermilov static void
7174c04fa4cSRuslan Ermilov SetAliasAddressFromIfName(const char *ifn)
71824084f9bSBrian Somers {
7194c04fa4cSRuslan Ermilov 	size_t needed;
7204c04fa4cSRuslan Ermilov 	int mib[6];
7214c04fa4cSRuslan Ermilov 	char *buf, *lim, *next;
7224c04fa4cSRuslan Ermilov 	struct if_msghdr *ifm;
7234c04fa4cSRuslan Ermilov 	struct ifa_msghdr *ifam;
7244c04fa4cSRuslan Ermilov 	struct sockaddr_dl *sdl;
7254c04fa4cSRuslan Ermilov 	struct sockaddr_in *sin;
72624084f9bSBrian Somers 
7274c04fa4cSRuslan Ermilov 	mib[0] = CTL_NET;
7284c04fa4cSRuslan Ermilov 	mib[1] = PF_ROUTE;
7294c04fa4cSRuslan Ermilov 	mib[2] = 0;
7304c04fa4cSRuslan Ermilov 	mib[3] = AF_INET;	/* Only IP addresses please */
7314c04fa4cSRuslan Ermilov 	mib[4] = NET_RT_IFLIST;
7324c04fa4cSRuslan Ermilov 	mib[5] = 0;		/* ifIndex??? */
73324084f9bSBrian Somers /*
73424084f9bSBrian Somers  * Get interface data.
73524084f9bSBrian Somers  */
7364c04fa4cSRuslan Ermilov 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
7374c04fa4cSRuslan Ermilov 		err(1, "iflist-sysctl-estimate");
7384c04fa4cSRuslan Ermilov 	if ((buf = malloc(needed)) == NULL)
7394c04fa4cSRuslan Ermilov 		errx(1, "malloc failed");
7404c04fa4cSRuslan Ermilov 	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
7414c04fa4cSRuslan Ermilov 		err(1, "iflist-sysctl-get");
7424c04fa4cSRuslan Ermilov 	lim = buf + needed;
74324084f9bSBrian Somers /*
74424084f9bSBrian Somers  * Loop through interfaces until one with
74524084f9bSBrian Somers  * given name is found. This is done to
74624084f9bSBrian Somers  * find correct interface index for routing
74724084f9bSBrian Somers  * message processing.
74824084f9bSBrian Somers  */
7494c04fa4cSRuslan Ermilov 	ifIndex	= 0;
7504c04fa4cSRuslan Ermilov 	next = buf;
7514c04fa4cSRuslan Ermilov 	while (next < lim) {
7524c04fa4cSRuslan Ermilov 		ifm = (struct if_msghdr *)next;
7534c04fa4cSRuslan Ermilov 		next += ifm->ifm_msglen;
7544c04fa4cSRuslan Ermilov 		if (ifm->ifm_version != RTM_VERSION) {
7554c04fa4cSRuslan Ermilov 			if (verbose)
7564c04fa4cSRuslan Ermilov 				warnx("routing message version %d "
7574c04fa4cSRuslan Ermilov 				      "not understood", ifm->ifm_version);
7584c04fa4cSRuslan Ermilov 			continue;
7594c04fa4cSRuslan Ermilov 		}
7604c04fa4cSRuslan Ermilov 		if (ifm->ifm_type == RTM_IFINFO) {
7614c04fa4cSRuslan Ermilov 			sdl = (struct sockaddr_dl *)(ifm + 1);
7624c04fa4cSRuslan Ermilov 			if (strlen(ifn) == sdl->sdl_nlen &&
7634c04fa4cSRuslan Ermilov 			    strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
7644c04fa4cSRuslan Ermilov 				ifIndex = ifm->ifm_index;
7654c04fa4cSRuslan Ermilov 				ifMTU = ifm->ifm_data.ifi_mtu;
76624084f9bSBrian Somers 				break;
76724084f9bSBrian Somers 			}
76824084f9bSBrian Somers 		}
76924084f9bSBrian Somers 	}
7704c04fa4cSRuslan Ermilov 	if (!ifIndex)
7714c04fa4cSRuslan Ermilov 		errx(1, "unknown interface name %s", ifn);
77224084f9bSBrian Somers /*
77324084f9bSBrian Somers  * Get interface address.
77424084f9bSBrian Somers  */
7754c04fa4cSRuslan Ermilov 	sin = NULL;
7764c04fa4cSRuslan Ermilov 	while (next < lim) {
7774c04fa4cSRuslan Ermilov 		ifam = (struct ifa_msghdr *)next;
7784c04fa4cSRuslan Ermilov 		next += ifam->ifam_msglen;
7794c04fa4cSRuslan Ermilov 		if (ifam->ifam_version != RTM_VERSION) {
7804c04fa4cSRuslan Ermilov 			if (verbose)
7814c04fa4cSRuslan Ermilov 				warnx("routing message version %d "
7824c04fa4cSRuslan Ermilov 				      "not understood", ifam->ifam_version);
7834c04fa4cSRuslan Ermilov 			continue;
7844c04fa4cSRuslan Ermilov 		}
7854c04fa4cSRuslan Ermilov 		if (ifam->ifam_type != RTM_NEWADDR)
7864c04fa4cSRuslan Ermilov 			break;
7874c04fa4cSRuslan Ermilov 		if (ifam->ifam_addrs & RTA_IFA) {
7884c04fa4cSRuslan Ermilov 			int i;
7894c04fa4cSRuslan Ermilov 			char *cp = (char *)(ifam + 1);
79024084f9bSBrian Somers 
7914c04fa4cSRuslan Ermilov #define ROUNDUP(a) \
7924c04fa4cSRuslan Ermilov 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
7934c04fa4cSRuslan Ermilov #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
7944c04fa4cSRuslan Ermilov 
7954c04fa4cSRuslan Ermilov 			for (i = 1; i < RTA_IFA; i <<= 1)
7964c04fa4cSRuslan Ermilov 				if (ifam->ifam_addrs & i)
7974c04fa4cSRuslan Ermilov 					ADVANCE(cp, (struct sockaddr *)cp);
7984c04fa4cSRuslan Ermilov 			if (((struct sockaddr *)cp)->sa_family == AF_INET) {
7994c04fa4cSRuslan Ermilov 				sin = (struct sockaddr_in *)cp;
8004c04fa4cSRuslan Ermilov 				break;
8014c04fa4cSRuslan Ermilov 			}
8024c04fa4cSRuslan Ermilov 		}
8034c04fa4cSRuslan Ermilov 	}
8044c04fa4cSRuslan Ermilov 	if (sin == NULL)
8054c04fa4cSRuslan Ermilov 		errx(1, "%s: cannot get interface address", ifn);
8064c04fa4cSRuslan Ermilov 
8074c04fa4cSRuslan Ermilov 	PacketAliasSetAddress(sin->sin_addr);
80824084f9bSBrian Somers 	syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes",
8094c04fa4cSRuslan Ermilov 	       inet_ntoa(sin->sin_addr), ifMTU);
81024084f9bSBrian Somers 
8114c04fa4cSRuslan Ermilov 	free(buf);
81224084f9bSBrian Somers }
81324084f9bSBrian Somers 
814902cb50aSBrian Somers void Quit (const char* msg)
81524084f9bSBrian Somers {
81624084f9bSBrian Somers 	Warn (msg);
81724084f9bSBrian Somers 	exit (1);
81824084f9bSBrian Somers }
81924084f9bSBrian Somers 
820902cb50aSBrian Somers void Warn (const char* msg)
82124084f9bSBrian Somers {
82224084f9bSBrian Somers 	if (background)
82324084f9bSBrian Somers 		syslog (LOG_ALERT, "%s (%m)", msg);
82424084f9bSBrian Somers 	else
8250fc81af1SPhilippe Charnier 		warn (msg);
82624084f9bSBrian Somers }
82724084f9bSBrian Somers 
828902cb50aSBrian Somers static void RefreshAddr (int sig)
82924084f9bSBrian Somers {
83024084f9bSBrian Somers 	if (ifName)
83124084f9bSBrian Somers 		assignAliasAddr = 1;
83224084f9bSBrian Somers }
83324084f9bSBrian Somers 
834902cb50aSBrian Somers static void InitiateShutdown (int sig)
83524084f9bSBrian Somers {
83624084f9bSBrian Somers /*
83724084f9bSBrian Somers  * Start timer to allow kernel gracefully
83824084f9bSBrian Somers  * shutdown existing connections when system
83924084f9bSBrian Somers  * is shut down.
84024084f9bSBrian Somers  */
841cd45c931SRuslan Ermilov 	siginterrupt(SIGALRM, 1);
84224084f9bSBrian Somers 	signal (SIGALRM, Shutdown);
84324084f9bSBrian Somers 	alarm (10);
84424084f9bSBrian Somers }
84524084f9bSBrian Somers 
846902cb50aSBrian Somers static void Shutdown (int sig)
84724084f9bSBrian Somers {
84824084f9bSBrian Somers 	running = 0;
84924084f9bSBrian Somers }
85024084f9bSBrian Somers 
85124084f9bSBrian Somers /*
85224084f9bSBrian Somers  * Different options recognized by this program.
85324084f9bSBrian Somers  */
85424084f9bSBrian Somers 
85524084f9bSBrian Somers enum Option {
85624084f9bSBrian Somers 
85724084f9bSBrian Somers 	PacketAliasOption,
85824084f9bSBrian Somers 	Verbose,
85924084f9bSBrian Somers 	InPort,
86024084f9bSBrian Somers 	OutPort,
86124084f9bSBrian Somers 	Port,
86224084f9bSBrian Somers 	AliasAddress,
86311c2b3bfSRuslan Ermilov 	TargetAddress,
86424084f9bSBrian Somers 	InterfaceName,
86524084f9bSBrian Somers 	RedirectPort,
8664330006dSRuslan Ermilov 	RedirectProto,
86724084f9bSBrian Somers 	RedirectAddress,
86824084f9bSBrian Somers 	ConfigFile,
86959a7c613SBrian Somers 	DynamicMode,
87059a7c613SBrian Somers 	ProxyRule,
87159a7c613SBrian Somers  	LogDenied,
872bc4ebb98SRuslan Ermilov  	LogFacility,
873bc4ebb98SRuslan Ermilov 	PunchFW
87424084f9bSBrian Somers };
87524084f9bSBrian Somers 
87624084f9bSBrian Somers enum Param {
87724084f9bSBrian Somers 
87824084f9bSBrian Somers 	YesNo,
87924084f9bSBrian Somers 	Numeric,
88024084f9bSBrian Somers 	String,
88124084f9bSBrian Somers 	None,
88224084f9bSBrian Somers 	Address,
88324084f9bSBrian Somers 	Service
88424084f9bSBrian Somers };
88524084f9bSBrian Somers 
88624084f9bSBrian Somers /*
88724084f9bSBrian Somers  * Option information structure (used by ParseOption).
88824084f9bSBrian Somers  */
88924084f9bSBrian Somers 
89024084f9bSBrian Somers struct OptionInfo {
89124084f9bSBrian Somers 
89224084f9bSBrian Somers 	enum Option		type;
89324084f9bSBrian Somers 	int			packetAliasOpt;
89424084f9bSBrian Somers 	enum Param		parm;
895902cb50aSBrian Somers 	const char*		parmDescription;
896902cb50aSBrian Somers 	const char*		description;
897902cb50aSBrian Somers 	const char*		name;
898902cb50aSBrian Somers 	const char*		shortName;
89924084f9bSBrian Somers };
90024084f9bSBrian Somers 
90124084f9bSBrian Somers /*
90224084f9bSBrian Somers  * Table of known options.
90324084f9bSBrian Somers  */
90424084f9bSBrian Somers 
90524084f9bSBrian Somers static struct OptionInfo optionTable[] = {
90624084f9bSBrian Somers 
90724084f9bSBrian Somers 	{ PacketAliasOption,
90824084f9bSBrian Somers 		PKT_ALIAS_UNREGISTERED_ONLY,
90924084f9bSBrian Somers 		YesNo,
91024084f9bSBrian Somers 		"[yes|no]",
91124084f9bSBrian Somers 		"alias only unregistered addresses",
91224084f9bSBrian Somers 		"unregistered_only",
91324084f9bSBrian Somers 		"u" },
91424084f9bSBrian Somers 
91524084f9bSBrian Somers 	{ PacketAliasOption,
91624084f9bSBrian Somers 		PKT_ALIAS_LOG,
91724084f9bSBrian Somers 		YesNo,
91824084f9bSBrian Somers 		"[yes|no]",
91924084f9bSBrian Somers 		"enable logging",
92024084f9bSBrian Somers 		"log",
92124084f9bSBrian Somers 		"l" },
92224084f9bSBrian Somers 
92324084f9bSBrian Somers 	{ PacketAliasOption,
92459a7c613SBrian Somers 		PKT_ALIAS_PROXY_ONLY,
92559a7c613SBrian Somers 		YesNo,
92659a7c613SBrian Somers 		"[yes|no]",
92759a7c613SBrian Somers 		"proxy only",
92859a7c613SBrian Somers 		"proxy_only",
92959a7c613SBrian Somers 		NULL },
93059a7c613SBrian Somers 
93159a7c613SBrian Somers 	{ PacketAliasOption,
93259a7c613SBrian Somers 		PKT_ALIAS_REVERSE,
93359a7c613SBrian Somers 		YesNo,
93459a7c613SBrian Somers 		"[yes|no]",
93559a7c613SBrian Somers 		"operate in reverse mode",
93659a7c613SBrian Somers 		"reverse",
93759a7c613SBrian Somers 		NULL },
93859a7c613SBrian Somers 
93959a7c613SBrian Somers 	{ PacketAliasOption,
94024084f9bSBrian Somers 		PKT_ALIAS_DENY_INCOMING,
94124084f9bSBrian Somers 		YesNo,
94224084f9bSBrian Somers 		"[yes|no]",
94324084f9bSBrian Somers 		"allow incoming connections",
94424084f9bSBrian Somers 		"deny_incoming",
94524084f9bSBrian Somers 		"d" },
94624084f9bSBrian Somers 
94724084f9bSBrian Somers 	{ PacketAliasOption,
94824084f9bSBrian Somers 		PKT_ALIAS_USE_SOCKETS,
94924084f9bSBrian Somers 		YesNo,
95024084f9bSBrian Somers 		"[yes|no]",
95124084f9bSBrian Somers 		"use sockets to inhibit port conflict",
95224084f9bSBrian Somers 		"use_sockets",
95324084f9bSBrian Somers 		"s" },
95424084f9bSBrian Somers 
95524084f9bSBrian Somers 	{ PacketAliasOption,
95624084f9bSBrian Somers 		PKT_ALIAS_SAME_PORTS,
95724084f9bSBrian Somers 		YesNo,
95824084f9bSBrian Somers 		"[yes|no]",
95924084f9bSBrian Somers 		"try to keep original port numbers for connections",
96024084f9bSBrian Somers 		"same_ports",
96124084f9bSBrian Somers 		"m" },
96224084f9bSBrian Somers 
96324084f9bSBrian Somers 	{ Verbose,
96424084f9bSBrian Somers 		0,
96524084f9bSBrian Somers 		YesNo,
96624084f9bSBrian Somers 		"[yes|no]",
96724084f9bSBrian Somers 		"verbose mode, dump packet information",
96824084f9bSBrian Somers 		"verbose",
96924084f9bSBrian Somers 		"v" },
97024084f9bSBrian Somers 
97124084f9bSBrian Somers 	{ DynamicMode,
97224084f9bSBrian Somers 		0,
97324084f9bSBrian Somers 		YesNo,
97424084f9bSBrian Somers 		"[yes|no]",
97524084f9bSBrian Somers 		"dynamic mode, automatically detect interface address changes",
97624084f9bSBrian Somers 		"dynamic",
97724084f9bSBrian Somers 		NULL },
97824084f9bSBrian Somers 
97924084f9bSBrian Somers 	{ InPort,
98024084f9bSBrian Somers 		0,
98124084f9bSBrian Somers 		Service,
98224084f9bSBrian Somers 		"number|service_name",
98324084f9bSBrian Somers 		"set port for incoming packets",
98424084f9bSBrian Somers 		"in_port",
98524084f9bSBrian Somers 		"i" },
98624084f9bSBrian Somers 
98724084f9bSBrian Somers 	{ OutPort,
98824084f9bSBrian Somers 		0,
98924084f9bSBrian Somers 		Service,
99024084f9bSBrian Somers 		"number|service_name",
99124084f9bSBrian Somers 		"set port for outgoing packets",
99224084f9bSBrian Somers 		"out_port",
99324084f9bSBrian Somers 		"o" },
99424084f9bSBrian Somers 
99524084f9bSBrian Somers 	{ Port,
99624084f9bSBrian Somers 		0,
99724084f9bSBrian Somers 		Service,
99824084f9bSBrian Somers 		"number|service_name",
99924084f9bSBrian Somers 		"set port (defaults to natd/divert)",
100024084f9bSBrian Somers 		"port",
100124084f9bSBrian Somers 		"p" },
100224084f9bSBrian Somers 
100324084f9bSBrian Somers 	{ AliasAddress,
100424084f9bSBrian Somers 		0,
100524084f9bSBrian Somers 		Address,
100624084f9bSBrian Somers 		"x.x.x.x",
100724084f9bSBrian Somers 		"address to use for aliasing",
100824084f9bSBrian Somers 		"alias_address",
100924084f9bSBrian Somers 		"a" },
101024084f9bSBrian Somers 
101111c2b3bfSRuslan Ermilov 	{ TargetAddress,
101211c2b3bfSRuslan Ermilov 		0,
101311c2b3bfSRuslan Ermilov 		Address,
101411c2b3bfSRuslan Ermilov 		"x.x.x.x",
101511c2b3bfSRuslan Ermilov 		"address to use for incoming sessions",
101611c2b3bfSRuslan Ermilov 		"target_address",
101711c2b3bfSRuslan Ermilov 		"t" },
101811c2b3bfSRuslan Ermilov 
101924084f9bSBrian Somers 	{ InterfaceName,
102024084f9bSBrian Somers 		0,
102124084f9bSBrian Somers 		String,
102224084f9bSBrian Somers 	        "network_if_name",
102324084f9bSBrian Somers 		"take aliasing address from interface",
102424084f9bSBrian Somers 		"interface",
102524084f9bSBrian Somers 		"n" },
102624084f9bSBrian Somers 
102759a7c613SBrian Somers 	{ ProxyRule,
102824084f9bSBrian Somers 		0,
102924084f9bSBrian Somers 		String,
103059a7c613SBrian Somers 	        "[type encode_ip_hdr|encode_tcp_stream] port xxxx server "
103159a7c613SBrian Somers 		"a.b.c.d:yyyy",
103259a7c613SBrian Somers 		"add transparent proxying / destination NAT",
103359a7c613SBrian Somers 		"proxy_rule",
103424084f9bSBrian Somers 		NULL },
103524084f9bSBrian Somers 
103624084f9bSBrian Somers 	{ RedirectPort,
103724084f9bSBrian Somers 		0,
103824084f9bSBrian Somers 		String,
1039bd690510SRuslan Ermilov 	        "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range"
10405d8ee958SBrian Somers 	 	" [remote_addr[:remote_port_range]]",
10415d8ee958SBrian Somers 		"redirect a port (or ports) for incoming traffic",
104224084f9bSBrian Somers 		"redirect_port",
104324084f9bSBrian Somers 		NULL },
104424084f9bSBrian Somers 
10454330006dSRuslan Ermilov 	{ RedirectProto,
10464330006dSRuslan Ermilov 		0,
10474330006dSRuslan Ermilov 		String,
10484330006dSRuslan Ermilov 	        "proto local_addr [public_addr] [remote_addr]",
10494330006dSRuslan Ermilov 		"redirect packets of a given proto",
10504330006dSRuslan Ermilov 		"redirect_proto",
10514330006dSRuslan Ermilov 		NULL },
10524330006dSRuslan Ermilov 
105324084f9bSBrian Somers 	{ RedirectAddress,
105424084f9bSBrian Somers 		0,
105524084f9bSBrian Somers 		String,
1056bd690510SRuslan Ermilov 	        "local_addr[,...] public_addr",
105724084f9bSBrian Somers 		"define mapping between local and public addresses",
105824084f9bSBrian Somers 		"redirect_address",
105924084f9bSBrian Somers 		NULL },
106024084f9bSBrian Somers 
106124084f9bSBrian Somers 	{ ConfigFile,
106224084f9bSBrian Somers 		0,
106324084f9bSBrian Somers 		String,
106424084f9bSBrian Somers 		"file_name",
106524084f9bSBrian Somers 		"read options from configuration file",
106624084f9bSBrian Somers 		"config",
106759a7c613SBrian Somers 		"f" },
106859a7c613SBrian Somers 
106959a7c613SBrian Somers 	{ LogDenied,
107059a7c613SBrian Somers 		0,
107159a7c613SBrian Somers 		YesNo,
107259a7c613SBrian Somers 	        "[yes|no]",
107359a7c613SBrian Somers 		"enable logging of denied incoming packets",
107459a7c613SBrian Somers 		"log_denied",
107559a7c613SBrian Somers 		NULL },
107659a7c613SBrian Somers 
107759a7c613SBrian Somers 	{ LogFacility,
107859a7c613SBrian Somers 		0,
107959a7c613SBrian Somers 		String,
108059a7c613SBrian Somers 	        "facility",
108159a7c613SBrian Somers 		"name of syslog facility to use for logging",
108259a7c613SBrian Somers 		"log_facility",
1083bc4ebb98SRuslan Ermilov 		NULL },
108459a7c613SBrian Somers 
1085bc4ebb98SRuslan Ermilov 	{ PunchFW,
1086bc4ebb98SRuslan Ermilov 		0,
1087bc4ebb98SRuslan Ermilov 		String,
1088bc4ebb98SRuslan Ermilov 	        "basenumber:count",
1089bc4ebb98SRuslan Ermilov 		"punch holes in the firewall for incoming FTP/IRC DCC connections",
1090bc4ebb98SRuslan Ermilov 		"punch_fw",
1091bc4ebb98SRuslan Ermilov 		NULL }
109224084f9bSBrian Somers };
109324084f9bSBrian Somers 
1094b0f55af6SRuslan Ermilov static void ParseOption (const char* option, const char* parms)
109524084f9bSBrian Somers {
109624084f9bSBrian Somers 	int			i;
109724084f9bSBrian Somers 	struct OptionInfo*	info;
109824084f9bSBrian Somers 	int			yesNoValue;
109924084f9bSBrian Somers 	int			aliasValue;
110024084f9bSBrian Somers 	int			numValue;
110167a886fbSBrian Somers 	u_short			uNumValue;
1102902cb50aSBrian Somers 	const char*		strValue;
110324084f9bSBrian Somers 	struct in_addr		addrValue;
110424084f9bSBrian Somers 	int			max;
110524084f9bSBrian Somers 	char*			end;
110659a7c613SBrian Somers 	CODE* 			fac_record = NULL;
110724084f9bSBrian Somers /*
110824084f9bSBrian Somers  * Find option from table.
110924084f9bSBrian Somers  */
111024084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
111124084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
111224084f9bSBrian Somers 
111324084f9bSBrian Somers 		if (!strcmp (info->name, option))
111424084f9bSBrian Somers 			break;
111524084f9bSBrian Somers 
111624084f9bSBrian Somers 		if (info->shortName)
111724084f9bSBrian Somers 			if (!strcmp (info->shortName, option))
111824084f9bSBrian Somers 				break;
111924084f9bSBrian Somers 	}
112024084f9bSBrian Somers 
112124084f9bSBrian Somers 	if (i >= max) {
112224084f9bSBrian Somers 
11230fc81af1SPhilippe Charnier 		warnx ("unknown option %s", option);
112424084f9bSBrian Somers 		Usage ();
112524084f9bSBrian Somers 	}
112624084f9bSBrian Somers 
112767a886fbSBrian Somers 	uNumValue	= 0;
112824084f9bSBrian Somers 	yesNoValue	= 0;
112924084f9bSBrian Somers 	numValue	= 0;
113024084f9bSBrian Somers 	strValue	= NULL;
113124084f9bSBrian Somers /*
113224084f9bSBrian Somers  * Check parameters.
113324084f9bSBrian Somers  */
113424084f9bSBrian Somers 	switch (info->parm) {
113524084f9bSBrian Somers 	case YesNo:
113624084f9bSBrian Somers 		if (!parms)
113724084f9bSBrian Somers 			parms = "yes";
113824084f9bSBrian Somers 
113924084f9bSBrian Somers 		if (!strcmp (parms, "yes"))
114024084f9bSBrian Somers 			yesNoValue = 1;
114124084f9bSBrian Somers 		else
114224084f9bSBrian Somers 			if (!strcmp (parms, "no"))
114324084f9bSBrian Somers 				yesNoValue = 0;
11440fc81af1SPhilippe Charnier 			else
11450fc81af1SPhilippe Charnier 				errx (1, "%s needs yes/no parameter", option);
114624084f9bSBrian Somers 		break;
114724084f9bSBrian Somers 
114824084f9bSBrian Somers 	case Service:
11490fc81af1SPhilippe Charnier 		if (!parms)
115067a886fbSBrian Somers 			errx (1, "%s needs service name or "
115167a886fbSBrian Somers 				 "port number parameter",
115267a886fbSBrian Somers 				 option);
115324084f9bSBrian Somers 
115467a886fbSBrian Somers 		uNumValue = StrToPort (parms, "divert");
115524084f9bSBrian Somers 		break;
115624084f9bSBrian Somers 
115724084f9bSBrian Somers 	case Numeric:
115824084f9bSBrian Somers 		if (parms)
115924084f9bSBrian Somers 			numValue = strtol (parms, &end, 10);
116024084f9bSBrian Somers 		else
1161902cb50aSBrian Somers 			end = NULL;
116224084f9bSBrian Somers 
11630fc81af1SPhilippe Charnier 		if (end == parms)
11640fc81af1SPhilippe Charnier 			errx (1, "%s needs numeric parameter", option);
116524084f9bSBrian Somers 		break;
116624084f9bSBrian Somers 
116724084f9bSBrian Somers 	case String:
116824084f9bSBrian Somers 		strValue = parms;
11690fc81af1SPhilippe Charnier 		if (!strValue)
11700fc81af1SPhilippe Charnier 			errx (1, "%s needs parameter", option);
117124084f9bSBrian Somers 		break;
117224084f9bSBrian Somers 
117324084f9bSBrian Somers 	case None:
11740fc81af1SPhilippe Charnier 		if (parms)
11750fc81af1SPhilippe Charnier 			errx (1, "%s does not take parameters", option);
117624084f9bSBrian Somers 		break;
117724084f9bSBrian Somers 
117824084f9bSBrian Somers 	case Address:
11790fc81af1SPhilippe Charnier 		if (!parms)
11800fc81af1SPhilippe Charnier 			errx (1, "%s needs address/host parameter", option);
118124084f9bSBrian Somers 
118224084f9bSBrian Somers 		StrToAddr (parms, &addrValue);
118324084f9bSBrian Somers 		break;
118424084f9bSBrian Somers 	}
118524084f9bSBrian Somers 
118624084f9bSBrian Somers 	switch (info->type) {
118724084f9bSBrian Somers 	case PacketAliasOption:
118824084f9bSBrian Somers 
118924084f9bSBrian Somers 		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1190fb994b07SBrian Somers 		PacketAliasSetMode (aliasValue, info->packetAliasOpt);
119124084f9bSBrian Somers 		break;
119224084f9bSBrian Somers 
119324084f9bSBrian Somers 	case Verbose:
119424084f9bSBrian Somers 		verbose = yesNoValue;
119524084f9bSBrian Somers 		break;
119624084f9bSBrian Somers 
119724084f9bSBrian Somers 	case DynamicMode:
119824084f9bSBrian Somers 		dynamicMode = yesNoValue;
119924084f9bSBrian Somers 		break;
120024084f9bSBrian Somers 
120124084f9bSBrian Somers 	case InPort:
120267a886fbSBrian Somers 		inPort = uNumValue;
120324084f9bSBrian Somers 		break;
120424084f9bSBrian Somers 
120524084f9bSBrian Somers 	case OutPort:
120667a886fbSBrian Somers 		outPort = uNumValue;
120724084f9bSBrian Somers 		break;
120824084f9bSBrian Somers 
120924084f9bSBrian Somers 	case Port:
121067a886fbSBrian Somers 		inOutPort = uNumValue;
121124084f9bSBrian Somers 		break;
121224084f9bSBrian Somers 
121324084f9bSBrian Somers 	case AliasAddress:
121424084f9bSBrian Somers 		memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
121524084f9bSBrian Somers 		break;
121624084f9bSBrian Somers 
121711c2b3bfSRuslan Ermilov 	case TargetAddress:
121811c2b3bfSRuslan Ermilov 		PacketAliasSetTarget(addrValue);
121911c2b3bfSRuslan Ermilov 		break;
122011c2b3bfSRuslan Ermilov 
122124084f9bSBrian Somers 	case RedirectPort:
122224084f9bSBrian Somers 		SetupPortRedirect (strValue);
122324084f9bSBrian Somers 		break;
122424084f9bSBrian Somers 
12254330006dSRuslan Ermilov 	case RedirectProto:
12264330006dSRuslan Ermilov 		SetupProtoRedirect(strValue);
12274330006dSRuslan Ermilov 		break;
12284330006dSRuslan Ermilov 
122924084f9bSBrian Somers 	case RedirectAddress:
123024084f9bSBrian Somers 		SetupAddressRedirect (strValue);
123124084f9bSBrian Somers 		break;
123224084f9bSBrian Somers 
123359a7c613SBrian Somers 	case ProxyRule:
123459a7c613SBrian Somers 		PacketAliasProxyRule (strValue);
123559a7c613SBrian Somers 		break;
123659a7c613SBrian Somers 
123724084f9bSBrian Somers 	case InterfaceName:
123824084f9bSBrian Somers 		if (ifName)
123924084f9bSBrian Somers 			free (ifName);
124024084f9bSBrian Somers 
124124084f9bSBrian Somers 		ifName = strdup (strValue);
124224084f9bSBrian Somers 		break;
124324084f9bSBrian Somers 
124424084f9bSBrian Somers 	case ConfigFile:
124524084f9bSBrian Somers 		ReadConfigFile (strValue);
124624084f9bSBrian Somers 		break;
124759a7c613SBrian Somers 
124859a7c613SBrian Somers 	case LogDenied:
124959a7c613SBrian Somers 		logDropped = 1;
125059a7c613SBrian Somers 		break;
125159a7c613SBrian Somers 
125259a7c613SBrian Somers 	case LogFacility:
125359a7c613SBrian Somers 
125459a7c613SBrian Somers 		fac_record = facilitynames;
125559a7c613SBrian Somers 		while (fac_record->c_name != NULL) {
125659a7c613SBrian Somers 
125759a7c613SBrian Somers 			if (!strcmp (fac_record->c_name, strValue)) {
125859a7c613SBrian Somers 
125959a7c613SBrian Somers 				logFacility = fac_record->c_val;
126059a7c613SBrian Somers 				break;
126159a7c613SBrian Somers 
126259a7c613SBrian Somers 			}
126359a7c613SBrian Somers 			else
126459a7c613SBrian Somers 				fac_record++;
126559a7c613SBrian Somers 		}
126659a7c613SBrian Somers 
126759a7c613SBrian Somers 		if(fac_record->c_name == NULL)
126859a7c613SBrian Somers 			errx(1, "Unknown log facility name: %s", strValue);
126959a7c613SBrian Somers 
127059a7c613SBrian Somers 		break;
1271bc4ebb98SRuslan Ermilov 
1272bc4ebb98SRuslan Ermilov 	case PunchFW:
1273bc4ebb98SRuslan Ermilov 		SetupPunchFW(strValue);
1274bc4ebb98SRuslan Ermilov 		break;
127524084f9bSBrian Somers 	}
127624084f9bSBrian Somers }
127724084f9bSBrian Somers 
1278902cb50aSBrian Somers void ReadConfigFile (const char* fileName)
127924084f9bSBrian Somers {
128024084f9bSBrian Somers 	FILE*	file;
1281d99cc1daSRuslan Ermilov 	char	*buf;
1282d99cc1daSRuslan Ermilov 	size_t	len;
12832e7e7c71SRuslan Ermilov 	char	*ptr, *p;
128424084f9bSBrian Somers 	char*	option;
128524084f9bSBrian Somers 
128624084f9bSBrian Somers 	file = fopen (fileName, "r");
1287d99cc1daSRuslan Ermilov 	if (!file)
1288d99cc1daSRuslan Ermilov 		err(1, "cannot open config file %s", fileName);
128924084f9bSBrian Somers 
1290d99cc1daSRuslan Ermilov 	while ((buf = fgetln(file, &len)) != NULL) {
1291d99cc1daSRuslan Ermilov 		if (buf[len - 1] == '\n')
1292d99cc1daSRuslan Ermilov 			buf[len - 1] = '\0';
1293d99cc1daSRuslan Ermilov 		else
1294d99cc1daSRuslan Ermilov 			errx(1, "config file format error: "
1295d99cc1daSRuslan Ermilov 				"last line should end with newline");
129624084f9bSBrian Somers 
129724084f9bSBrian Somers /*
12982e7e7c71SRuslan Ermilov  * Check for comments, strip off trailing spaces.
129924084f9bSBrian Somers  */
13002e7e7c71SRuslan Ermilov 		if ((ptr = strchr(buf, '#')))
13012e7e7c71SRuslan Ermilov 			*ptr = '\0';
13022e7e7c71SRuslan Ermilov 		for (ptr = buf; isspace(*ptr); ++ptr)
13032e7e7c71SRuslan Ermilov 			continue;
130424084f9bSBrian Somers 		if (*ptr == '\0')
130524084f9bSBrian Somers 			continue;
13062e7e7c71SRuslan Ermilov 		for (p = strchr(buf, '\0'); isspace(*--p);)
13072e7e7c71SRuslan Ermilov 			continue;
13082e7e7c71SRuslan Ermilov 		*++p = '\0';
13092e7e7c71SRuslan Ermilov 
131024084f9bSBrian Somers /*
131124084f9bSBrian Somers  * Extract option name.
131224084f9bSBrian Somers  */
131324084f9bSBrian Somers 		option = ptr;
131424084f9bSBrian Somers 		while (*ptr && !isspace (*ptr))
131524084f9bSBrian Somers 			++ptr;
131624084f9bSBrian Somers 
131724084f9bSBrian Somers 		if (*ptr != '\0') {
131824084f9bSBrian Somers 
131924084f9bSBrian Somers 			*ptr = '\0';
132024084f9bSBrian Somers 			++ptr;
132124084f9bSBrian Somers 		}
132224084f9bSBrian Somers /*
132324084f9bSBrian Somers  * Skip white space between name and parms.
132424084f9bSBrian Somers  */
132524084f9bSBrian Somers 		while (*ptr && isspace (*ptr))
132624084f9bSBrian Somers 			++ptr;
132724084f9bSBrian Somers 
1328b0f55af6SRuslan Ermilov 		ParseOption (option, *ptr ? ptr : NULL);
132924084f9bSBrian Somers 	}
133024084f9bSBrian Somers 
133124084f9bSBrian Somers 	fclose (file);
133224084f9bSBrian Somers }
133324084f9bSBrian Somers 
133424084f9bSBrian Somers static void Usage ()
133524084f9bSBrian Somers {
133624084f9bSBrian Somers 	int			i;
133724084f9bSBrian Somers 	int			max;
133824084f9bSBrian Somers 	struct OptionInfo*	info;
133924084f9bSBrian Somers 
134024084f9bSBrian Somers 	fprintf (stderr, "Recognized options:\n\n");
134124084f9bSBrian Somers 
134224084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
134324084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
134424084f9bSBrian Somers 
134524084f9bSBrian Somers 		fprintf (stderr, "-%-20s %s\n", info->name,
134624084f9bSBrian Somers 						info->parmDescription);
134724084f9bSBrian Somers 
134824084f9bSBrian Somers 		if (info->shortName)
134924084f9bSBrian Somers 			fprintf (stderr, "-%-20s %s\n", info->shortName,
135024084f9bSBrian Somers 							info->parmDescription);
135124084f9bSBrian Somers 
135224084f9bSBrian Somers 		fprintf (stderr, "      %s\n\n", info->description);
135324084f9bSBrian Somers 	}
135424084f9bSBrian Somers 
135524084f9bSBrian Somers 	exit (1);
135624084f9bSBrian Somers }
135724084f9bSBrian Somers 
1358902cb50aSBrian Somers void SetupPortRedirect (const char* parms)
135924084f9bSBrian Somers {
136024084f9bSBrian Somers 	char		buf[128];
136124084f9bSBrian Somers 	char*		ptr;
1362bd690510SRuslan Ermilov 	char*		serverPool;
136324084f9bSBrian Somers 	struct in_addr	localAddr;
136424084f9bSBrian Somers 	struct in_addr	publicAddr;
136524084f9bSBrian Somers 	struct in_addr	remoteAddr;
13665d8ee958SBrian Somers 	port_range      portRange;
13675d8ee958SBrian Somers 	u_short         localPort      = 0;
13685d8ee958SBrian Somers 	u_short         publicPort     = 0;
13695d8ee958SBrian Somers 	u_short         remotePort     = 0;
13705d8ee958SBrian Somers 	u_short         numLocalPorts  = 0;
13715d8ee958SBrian Somers 	u_short         numPublicPorts = 0;
13725d8ee958SBrian Somers 	u_short         numRemotePorts = 0;
137324084f9bSBrian Somers 	int		proto;
137424084f9bSBrian Somers 	char*		protoName;
137524084f9bSBrian Somers 	char*		separator;
13765d8ee958SBrian Somers 	int             i;
1377bd690510SRuslan Ermilov 	struct alias_link *link = NULL;
137824084f9bSBrian Somers 
137924084f9bSBrian Somers 	strcpy (buf, parms);
138024084f9bSBrian Somers /*
138124084f9bSBrian Somers  * Extract protocol.
138224084f9bSBrian Somers  */
138324084f9bSBrian Somers 	protoName = strtok (buf, " \t");
13840fc81af1SPhilippe Charnier 	if (!protoName)
13850fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing protocol");
138624084f9bSBrian Somers 
138724084f9bSBrian Somers 	proto = StrToProto (protoName);
138824084f9bSBrian Somers /*
138924084f9bSBrian Somers  * Extract local address.
139024084f9bSBrian Somers  */
139124084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
13920fc81af1SPhilippe Charnier 	if (!ptr)
13930fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing local address");
139424084f9bSBrian Somers 
1395bd690510SRuslan Ermilov 	separator = strchr(ptr, ',');
1396bd690510SRuslan Ermilov 	if (separator) {		/* LSNAT redirection syntax. */
1397bd690510SRuslan Ermilov 		localAddr.s_addr = INADDR_NONE;
1398bd690510SRuslan Ermilov 		localPort = ~0;
1399bd690510SRuslan Ermilov 		numLocalPorts = 1;
1400bd690510SRuslan Ermilov 		serverPool = ptr;
1401bd690510SRuslan Ermilov 	} else {
14025d8ee958SBrian Somers 		if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
14035d8ee958SBrian Somers 			errx (1, "redirect_port: invalid local port range");
14045d8ee958SBrian Somers 
14055d8ee958SBrian Somers 		localPort     = GETLOPORT(portRange);
14065d8ee958SBrian Somers 		numLocalPorts = GETNUMPORTS(portRange);
1407bd690510SRuslan Ermilov 		serverPool = NULL;
1408bd690510SRuslan Ermilov 	}
14095d8ee958SBrian Somers 
141024084f9bSBrian Somers /*
14119c501140SBrian Somers  * Extract public port and optionally address.
141224084f9bSBrian Somers  */
141324084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
14140fc81af1SPhilippe Charnier 	if (!ptr)
14150fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing public port");
141624084f9bSBrian Somers 
141724084f9bSBrian Somers 	separator = strchr (ptr, ':');
14185d8ee958SBrian Somers 	if (separator) {
14195d8ee958SBrian Somers 	        if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
14205d8ee958SBrian Somers 		        errx (1, "redirect_port: invalid public port range");
142124084f9bSBrian Somers 	}
14225d8ee958SBrian Somers 	else {
14235d8ee958SBrian Somers 		publicAddr.s_addr = INADDR_ANY;
14245d8ee958SBrian Somers 		if (StrToPortRange (ptr, protoName, &portRange) != 0)
14255d8ee958SBrian Somers 		        errx (1, "redirect_port: invalid public port range");
14265d8ee958SBrian Somers 	}
14275d8ee958SBrian Somers 
14285d8ee958SBrian Somers 	publicPort     = GETLOPORT(portRange);
14295d8ee958SBrian Somers 	numPublicPorts = GETNUMPORTS(portRange);
143024084f9bSBrian Somers 
143124084f9bSBrian Somers /*
143224084f9bSBrian Somers  * Extract remote address and optionally port.
143324084f9bSBrian Somers  */
143424084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
143524084f9bSBrian Somers 	if (ptr) {
143624084f9bSBrian Somers 		separator = strchr (ptr, ':');
1437ebe70c8fSWarner Losh 		if (separator) {
14385d8ee958SBrian Somers 		        if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
14395d8ee958SBrian Somers 			        errx (1, "redirect_port: invalid remote port range");
1440ebe70c8fSWarner Losh 		} else {
14415d8ee958SBrian Somers 		        SETLOPORT(portRange, 0);
14425d8ee958SBrian Somers 			SETNUMPORTS(portRange, 1);
144324084f9bSBrian Somers 			StrToAddr (ptr, &remoteAddr);
144424084f9bSBrian Somers 		}
144524084f9bSBrian Somers 	}
144624084f9bSBrian Somers 	else {
14475d8ee958SBrian Somers 	        SETLOPORT(portRange, 0);
14485d8ee958SBrian Somers 		SETNUMPORTS(portRange, 1);
144924084f9bSBrian Somers 		remoteAddr.s_addr = INADDR_ANY;
145024084f9bSBrian Somers 	}
145124084f9bSBrian Somers 
14525d8ee958SBrian Somers 	remotePort     = GETLOPORT(portRange);
14535d8ee958SBrian Somers 	numRemotePorts = GETNUMPORTS(portRange);
14545d8ee958SBrian Somers 
14555d8ee958SBrian Somers /*
14565d8ee958SBrian Somers  * Make sure port ranges match up, then add the redirect ports.
14575d8ee958SBrian Somers  */
14585d8ee958SBrian Somers 	if (numLocalPorts != numPublicPorts)
14595d8ee958SBrian Somers 	        errx (1, "redirect_port: port ranges must be equal in size");
14605d8ee958SBrian Somers 
14615d8ee958SBrian Somers 	/* Remote port range is allowed to be '0' which means all ports. */
146229d97436SBrian Somers 	if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
14635d8ee958SBrian Somers 	        errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
14645d8ee958SBrian Somers 
14655d8ee958SBrian Somers 	for (i = 0 ; i < numPublicPorts ; ++i) {
14665d8ee958SBrian Somers 	        /* If remotePort is all ports, set it to 0. */
14675d8ee958SBrian Somers 	        u_short remotePortCopy = remotePort + i;
14685d8ee958SBrian Somers 	        if (numRemotePorts == 1 && remotePort == 0)
14695d8ee958SBrian Somers 		        remotePortCopy = 0;
14705d8ee958SBrian Somers 
1471bd690510SRuslan Ermilov 		link = PacketAliasRedirectPort (localAddr,
14725d8ee958SBrian Somers 						htons(localPort + i),
147324084f9bSBrian Somers 						remoteAddr,
14745d8ee958SBrian Somers 						htons(remotePortCopy),
147524084f9bSBrian Somers 						publicAddr,
14765d8ee958SBrian Somers 						htons(publicPort + i),
147724084f9bSBrian Somers 						proto);
147824084f9bSBrian Somers 	}
1479bd690510SRuslan Ermilov 
1480bd690510SRuslan Ermilov /*
1481bd690510SRuslan Ermilov  * Setup LSNAT server pool.
1482bd690510SRuslan Ermilov  */
1483bd690510SRuslan Ermilov 	if (serverPool != NULL && link != NULL) {
1484bd690510SRuslan Ermilov 		ptr = strtok(serverPool, ",");
1485bd690510SRuslan Ermilov 		while (ptr != NULL) {
1486bd690510SRuslan Ermilov 			if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1487bd690510SRuslan Ermilov 				errx(1, "redirect_port: invalid local port range");
1488bd690510SRuslan Ermilov 
1489bd690510SRuslan Ermilov 			localPort = GETLOPORT(portRange);
1490bd690510SRuslan Ermilov 			if (GETNUMPORTS(portRange) != 1)
1491bd690510SRuslan Ermilov 				errx(1, "redirect_port: local port must be single in this context");
1492bd690510SRuslan Ermilov 			PacketAliasAddServer(link, localAddr, htons(localPort));
1493bd690510SRuslan Ermilov 			ptr = strtok(NULL, ",");
1494bd690510SRuslan Ermilov 		}
1495bd690510SRuslan Ermilov 	}
14965d8ee958SBrian Somers }
149724084f9bSBrian Somers 
14984330006dSRuslan Ermilov void
14994330006dSRuslan Ermilov SetupProtoRedirect(const char* parms)
15004330006dSRuslan Ermilov {
15014330006dSRuslan Ermilov 	char		buf[128];
15024330006dSRuslan Ermilov 	char*		ptr;
15034330006dSRuslan Ermilov 	struct in_addr	localAddr;
15044330006dSRuslan Ermilov 	struct in_addr	publicAddr;
15054330006dSRuslan Ermilov 	struct in_addr	remoteAddr;
15064330006dSRuslan Ermilov 	int		proto;
15074330006dSRuslan Ermilov 	char*		protoName;
15084330006dSRuslan Ermilov 	struct protoent *protoent;
15094330006dSRuslan Ermilov 
15104330006dSRuslan Ermilov 	strcpy (buf, parms);
15114330006dSRuslan Ermilov /*
15124330006dSRuslan Ermilov  * Extract protocol.
15134330006dSRuslan Ermilov  */
15144330006dSRuslan Ermilov 	protoName = strtok(buf, " \t");
15154330006dSRuslan Ermilov 	if (!protoName)
15164330006dSRuslan Ermilov 		errx(1, "redirect_proto: missing protocol");
15174330006dSRuslan Ermilov 
15184330006dSRuslan Ermilov 	protoent = getprotobyname(protoName);
15194330006dSRuslan Ermilov 	if (protoent == NULL)
15204330006dSRuslan Ermilov 		errx(1, "redirect_proto: unknown protocol %s", protoName);
15214330006dSRuslan Ermilov 	else
15224330006dSRuslan Ermilov 		proto = protoent->p_proto;
15234330006dSRuslan Ermilov /*
15244330006dSRuslan Ermilov  * Extract local address.
15254330006dSRuslan Ermilov  */
15264330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
15274330006dSRuslan Ermilov 	if (!ptr)
15284330006dSRuslan Ermilov 		errx(1, "redirect_proto: missing local address");
15294330006dSRuslan Ermilov 	else
15304330006dSRuslan Ermilov 		StrToAddr(ptr, &localAddr);
15314330006dSRuslan Ermilov /*
15324330006dSRuslan Ermilov  * Extract optional public address.
15334330006dSRuslan Ermilov  */
15344330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
15354330006dSRuslan Ermilov 	if (ptr)
15364330006dSRuslan Ermilov 		StrToAddr(ptr, &publicAddr);
15374330006dSRuslan Ermilov 	else
15384330006dSRuslan Ermilov 		publicAddr.s_addr = INADDR_ANY;
15394330006dSRuslan Ermilov /*
15404330006dSRuslan Ermilov  * Extract optional remote address.
15414330006dSRuslan Ermilov  */
15424330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
15434330006dSRuslan Ermilov 	if (ptr)
15444330006dSRuslan Ermilov 		StrToAddr(ptr, &remoteAddr);
15454330006dSRuslan Ermilov 	else
15464330006dSRuslan Ermilov 		remoteAddr.s_addr = INADDR_ANY;
15474330006dSRuslan Ermilov /*
15484330006dSRuslan Ermilov  * Create aliasing link.
15494330006dSRuslan Ermilov  */
15504330006dSRuslan Ermilov 	(void)PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr,
15514330006dSRuslan Ermilov 				       proto);
15524330006dSRuslan Ermilov }
15534330006dSRuslan Ermilov 
1554902cb50aSBrian Somers void SetupAddressRedirect (const char* parms)
155524084f9bSBrian Somers {
155624084f9bSBrian Somers 	char		buf[128];
155724084f9bSBrian Somers 	char*		ptr;
1558bd690510SRuslan Ermilov 	char*		separator;
155924084f9bSBrian Somers 	struct in_addr	localAddr;
156024084f9bSBrian Somers 	struct in_addr	publicAddr;
1561bd690510SRuslan Ermilov 	char*		serverPool;
1562bd690510SRuslan Ermilov 	struct alias_link *link;
156324084f9bSBrian Somers 
156424084f9bSBrian Somers 	strcpy (buf, parms);
156524084f9bSBrian Somers /*
156624084f9bSBrian Somers  * Extract local address.
156724084f9bSBrian Somers  */
156824084f9bSBrian Somers 	ptr = strtok (buf, " \t");
15690fc81af1SPhilippe Charnier 	if (!ptr)
15700fc81af1SPhilippe Charnier 		errx (1, "redirect_address: missing local address");
157124084f9bSBrian Somers 
1572bd690510SRuslan Ermilov 	separator = strchr(ptr, ',');
1573bd690510SRuslan Ermilov 	if (separator) {		/* LSNAT redirection syntax. */
1574bd690510SRuslan Ermilov 		localAddr.s_addr = INADDR_NONE;
1575bd690510SRuslan Ermilov 		serverPool = ptr;
1576bd690510SRuslan Ermilov 	} else {
157724084f9bSBrian Somers 		StrToAddr (ptr, &localAddr);
1578bd690510SRuslan Ermilov 		serverPool = NULL;
1579bd690510SRuslan Ermilov 	}
158024084f9bSBrian Somers /*
158124084f9bSBrian Somers  * Extract public address.
158224084f9bSBrian Somers  */
158324084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
15840fc81af1SPhilippe Charnier 	if (!ptr)
15850fc81af1SPhilippe Charnier 		errx (1, "redirect_address: missing public address");
158624084f9bSBrian Somers 
158724084f9bSBrian Somers 	StrToAddr (ptr, &publicAddr);
1588bd690510SRuslan Ermilov 	link = PacketAliasRedirectAddr(localAddr, publicAddr);
1589bd690510SRuslan Ermilov 
1590bd690510SRuslan Ermilov /*
1591bd690510SRuslan Ermilov  * Setup LSNAT server pool.
1592bd690510SRuslan Ermilov  */
1593bd690510SRuslan Ermilov 	if (serverPool != NULL && link != NULL) {
1594bd690510SRuslan Ermilov 		ptr = strtok(serverPool, ",");
1595bd690510SRuslan Ermilov 		while (ptr != NULL) {
1596bd690510SRuslan Ermilov 			StrToAddr(ptr, &localAddr);
1597bd690510SRuslan Ermilov 			PacketAliasAddServer(link, localAddr, htons(~0));
1598bd690510SRuslan Ermilov 			ptr = strtok(NULL, ",");
1599bd690510SRuslan Ermilov 		}
1600bd690510SRuslan Ermilov 	}
160124084f9bSBrian Somers }
160224084f9bSBrian Somers 
1603902cb50aSBrian Somers void StrToAddr (const char* str, struct in_addr* addr)
160424084f9bSBrian Somers {
160524084f9bSBrian Somers 	struct hostent* hp;
160624084f9bSBrian Somers 
160724084f9bSBrian Somers 	if (inet_aton (str, addr))
160824084f9bSBrian Somers 		return;
160924084f9bSBrian Somers 
161024084f9bSBrian Somers 	hp = gethostbyname (str);
16110fc81af1SPhilippe Charnier 	if (!hp)
16120fc81af1SPhilippe Charnier 		errx (1, "unknown host %s", str);
161324084f9bSBrian Somers 
161424084f9bSBrian Somers 	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
161524084f9bSBrian Somers }
161624084f9bSBrian Somers 
1617902cb50aSBrian Somers u_short StrToPort (const char* str, const char* proto)
161824084f9bSBrian Somers {
161967a886fbSBrian Somers 	u_short		port;
162024084f9bSBrian Somers 	struct servent*	sp;
162124084f9bSBrian Somers 	char*		end;
162224084f9bSBrian Somers 
162324084f9bSBrian Somers 	port = strtol (str, &end, 10);
162424084f9bSBrian Somers 	if (end != str)
162527c20503SBrian Somers 		return htons (port);
162624084f9bSBrian Somers 
162724084f9bSBrian Somers 	sp = getservbyname (str, proto);
16280fc81af1SPhilippe Charnier 	if (!sp)
16290fc81af1SPhilippe Charnier 		errx (1, "unknown service %s/%s", str, proto);
163024084f9bSBrian Somers 
163124084f9bSBrian Somers 	return sp->s_port;
163224084f9bSBrian Somers }
163324084f9bSBrian Somers 
1634902cb50aSBrian Somers int StrToPortRange (const char* str, const char* proto, port_range *portRange)
16355d8ee958SBrian Somers {
16365d8ee958SBrian Somers 	char*           sep;
16375d8ee958SBrian Somers 	struct servent*	sp;
16385d8ee958SBrian Somers 	char*		end;
16395d8ee958SBrian Somers 	u_short         loPort;
16405d8ee958SBrian Somers 	u_short         hiPort;
16415d8ee958SBrian Somers 
16425d8ee958SBrian Somers 	/* First see if this is a service, return corresponding port if so. */
16435d8ee958SBrian Somers 	sp = getservbyname (str,proto);
16445d8ee958SBrian Somers 	if (sp) {
16455d8ee958SBrian Somers 	        SETLOPORT(*portRange, ntohs(sp->s_port));
16465d8ee958SBrian Somers 		SETNUMPORTS(*portRange, 1);
16475d8ee958SBrian Somers 		return 0;
16485d8ee958SBrian Somers 	}
16495d8ee958SBrian Somers 
16505d8ee958SBrian Somers 	/* Not a service, see if it's a single port or port range. */
16515d8ee958SBrian Somers 	sep = strchr (str, '-');
16525d8ee958SBrian Somers 	if (sep == NULL) {
16535d8ee958SBrian Somers 	        SETLOPORT(*portRange, strtol(str, &end, 10));
16545d8ee958SBrian Somers 		if (end != str) {
16555d8ee958SBrian Somers 		        /* Single port. */
16565d8ee958SBrian Somers 		        SETNUMPORTS(*portRange, 1);
16575d8ee958SBrian Somers 			return 0;
16585d8ee958SBrian Somers 		}
16595d8ee958SBrian Somers 
16605d8ee958SBrian Somers 		/* Error in port range field. */
16615d8ee958SBrian Somers 		errx (1, "unknown service %s/%s", str, proto);
16625d8ee958SBrian Somers 	}
16635d8ee958SBrian Somers 
16645d8ee958SBrian Somers 	/* Port range, get the values and sanity check. */
16655d8ee958SBrian Somers 	sscanf (str, "%hu-%hu", &loPort, &hiPort);
16665d8ee958SBrian Somers 	SETLOPORT(*portRange, loPort);
16675d8ee958SBrian Somers 	SETNUMPORTS(*portRange, 0);	/* Error by default */
16685d8ee958SBrian Somers 	if (loPort <= hiPort)
16695d8ee958SBrian Somers 	        SETNUMPORTS(*portRange, hiPort - loPort + 1);
16705d8ee958SBrian Somers 
16715d8ee958SBrian Somers 	if (GETNUMPORTS(*portRange) == 0)
16725d8ee958SBrian Somers 	        errx (1, "invalid port range %s", str);
16735d8ee958SBrian Somers 
16745d8ee958SBrian Somers 	return 0;
16755d8ee958SBrian Somers }
16765d8ee958SBrian Somers 
16775d8ee958SBrian Somers 
1678902cb50aSBrian Somers int StrToProto (const char* str)
167924084f9bSBrian Somers {
168024084f9bSBrian Somers 	if (!strcmp (str, "tcp"))
168124084f9bSBrian Somers 		return IPPROTO_TCP;
168224084f9bSBrian Somers 
168324084f9bSBrian Somers 	if (!strcmp (str, "udp"))
168424084f9bSBrian Somers 		return IPPROTO_UDP;
168524084f9bSBrian Somers 
16860fc81af1SPhilippe Charnier 	errx (1, "unknown protocol %s. Expected tcp or udp", str);
168724084f9bSBrian Somers }
168824084f9bSBrian Somers 
1689902cb50aSBrian Somers int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
169024084f9bSBrian Somers {
169124084f9bSBrian Somers 	char*	ptr;
169224084f9bSBrian Somers 
169324084f9bSBrian Somers 	ptr = strchr (str, ':');
16940fc81af1SPhilippe Charnier 	if (!ptr)
16950fc81af1SPhilippe Charnier 		errx (1, "%s is missing port number", str);
169624084f9bSBrian Somers 
169724084f9bSBrian Somers 	*ptr = '\0';
169824084f9bSBrian Somers 	++ptr;
169924084f9bSBrian Somers 
170024084f9bSBrian Somers 	StrToAddr (str, addr);
17015d8ee958SBrian Somers 	return StrToPortRange (ptr, proto, portRange);
170224084f9bSBrian Somers }
1703bc4ebb98SRuslan Ermilov 
1704bc4ebb98SRuslan Ermilov static void
1705bc4ebb98SRuslan Ermilov SetupPunchFW(const char *strValue)
1706bc4ebb98SRuslan Ermilov {
1707bc4ebb98SRuslan Ermilov 	unsigned int base, num;
1708bc4ebb98SRuslan Ermilov 
1709bc4ebb98SRuslan Ermilov 	if (sscanf(strValue, "%u:%u", &base, &num) != 2)
1710bc4ebb98SRuslan Ermilov 		errx(1, "punch_fw: basenumber:count parameter required");
1711bc4ebb98SRuslan Ermilov 
1712bc4ebb98SRuslan Ermilov 	PacketAliasSetFWBase(base, num);
1713bc4ebb98SRuslan Ermilov 	(void)PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
1714bc4ebb98SRuslan Ermilov }
1715