xref: /freebsd/sbin/natd/natd.c (revision b0f55af68fe8fc661eca744ea35e78d5098cf6bd)
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	SetupPptpAlias (const char* parms);
95902cb50aSBrian Somers static void	StrToAddr (const char* str, struct in_addr* addr);
96902cb50aSBrian Somers static u_short  StrToPort (const char* str, const char* proto);
97902cb50aSBrian Somers static int      StrToPortRange (const char* str, const char* proto, port_range *portRange);
98902cb50aSBrian Somers static int 	StrToProto (const char* str);
99902cb50aSBrian Somers static int      StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange);
10024084f9bSBrian Somers static void	ParseArgs (int argc, char** argv);
101fb994b07SBrian Somers static void	FlushPacketBuffer (int fd);
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 	PptpAlias,
87159a7c613SBrian Somers 	ProxyRule,
87259a7c613SBrian Somers  	LogDenied,
87359a7c613SBrian Somers  	LogFacility
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 
106159a7c613SBrian Somers        { PptpAlias,
106259a7c613SBrian Somers 		0,
106359a7c613SBrian Somers 		String,
106459a7c613SBrian Somers 		"src",
106559a7c613SBrian Somers 		"define inside machine for PPTP traffic",
106659a7c613SBrian Somers 		"pptpalias",
106759a7c613SBrian Somers 		NULL },
106859a7c613SBrian Somers 
106924084f9bSBrian Somers 	{ ConfigFile,
107024084f9bSBrian Somers 		0,
107124084f9bSBrian Somers 		String,
107224084f9bSBrian Somers 		"file_name",
107324084f9bSBrian Somers 		"read options from configuration file",
107424084f9bSBrian Somers 		"config",
107559a7c613SBrian Somers 		"f" },
107659a7c613SBrian Somers 
107759a7c613SBrian Somers 	{ LogDenied,
107859a7c613SBrian Somers 		0,
107959a7c613SBrian Somers 		YesNo,
108059a7c613SBrian Somers 	        "[yes|no]",
108159a7c613SBrian Somers 		"enable logging of denied incoming packets",
108259a7c613SBrian Somers 		"log_denied",
108359a7c613SBrian Somers 		NULL },
108459a7c613SBrian Somers 
108559a7c613SBrian Somers 	{ LogFacility,
108659a7c613SBrian Somers 		0,
108759a7c613SBrian Somers 		String,
108859a7c613SBrian Somers 	        "facility",
108959a7c613SBrian Somers 		"name of syslog facility to use for logging",
109059a7c613SBrian Somers 		"log_facility",
109159a7c613SBrian Somers 		NULL }
109259a7c613SBrian Somers 
109324084f9bSBrian Somers };
109424084f9bSBrian Somers 
1095b0f55af6SRuslan Ermilov static void ParseOption (const char* option, const char* parms)
109624084f9bSBrian Somers {
109724084f9bSBrian Somers 	int			i;
109824084f9bSBrian Somers 	struct OptionInfo*	info;
109924084f9bSBrian Somers 	int			yesNoValue;
110024084f9bSBrian Somers 	int			aliasValue;
110124084f9bSBrian Somers 	int			numValue;
110267a886fbSBrian Somers 	u_short			uNumValue;
1103902cb50aSBrian Somers 	const char*		strValue;
110424084f9bSBrian Somers 	struct in_addr		addrValue;
110524084f9bSBrian Somers 	int			max;
110624084f9bSBrian Somers 	char*			end;
110759a7c613SBrian Somers 	CODE* 			fac_record = NULL;
110824084f9bSBrian Somers /*
110924084f9bSBrian Somers  * Find option from table.
111024084f9bSBrian Somers  */
111124084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
111224084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
111324084f9bSBrian Somers 
111424084f9bSBrian Somers 		if (!strcmp (info->name, option))
111524084f9bSBrian Somers 			break;
111624084f9bSBrian Somers 
111724084f9bSBrian Somers 		if (info->shortName)
111824084f9bSBrian Somers 			if (!strcmp (info->shortName, option))
111924084f9bSBrian Somers 				break;
112024084f9bSBrian Somers 	}
112124084f9bSBrian Somers 
112224084f9bSBrian Somers 	if (i >= max) {
112324084f9bSBrian Somers 
11240fc81af1SPhilippe Charnier 		warnx ("unknown option %s", option);
112524084f9bSBrian Somers 		Usage ();
112624084f9bSBrian Somers 	}
112724084f9bSBrian Somers 
112867a886fbSBrian Somers 	uNumValue	= 0;
112924084f9bSBrian Somers 	yesNoValue	= 0;
113024084f9bSBrian Somers 	numValue	= 0;
113124084f9bSBrian Somers 	strValue	= NULL;
113224084f9bSBrian Somers /*
113324084f9bSBrian Somers  * Check parameters.
113424084f9bSBrian Somers  */
113524084f9bSBrian Somers 	switch (info->parm) {
113624084f9bSBrian Somers 	case YesNo:
113724084f9bSBrian Somers 		if (!parms)
113824084f9bSBrian Somers 			parms = "yes";
113924084f9bSBrian Somers 
114024084f9bSBrian Somers 		if (!strcmp (parms, "yes"))
114124084f9bSBrian Somers 			yesNoValue = 1;
114224084f9bSBrian Somers 		else
114324084f9bSBrian Somers 			if (!strcmp (parms, "no"))
114424084f9bSBrian Somers 				yesNoValue = 0;
11450fc81af1SPhilippe Charnier 			else
11460fc81af1SPhilippe Charnier 				errx (1, "%s needs yes/no parameter", option);
114724084f9bSBrian Somers 		break;
114824084f9bSBrian Somers 
114924084f9bSBrian Somers 	case Service:
11500fc81af1SPhilippe Charnier 		if (!parms)
115167a886fbSBrian Somers 			errx (1, "%s needs service name or "
115267a886fbSBrian Somers 				 "port number parameter",
115367a886fbSBrian Somers 				 option);
115424084f9bSBrian Somers 
115567a886fbSBrian Somers 		uNumValue = StrToPort (parms, "divert");
115624084f9bSBrian Somers 		break;
115724084f9bSBrian Somers 
115824084f9bSBrian Somers 	case Numeric:
115924084f9bSBrian Somers 		if (parms)
116024084f9bSBrian Somers 			numValue = strtol (parms, &end, 10);
116124084f9bSBrian Somers 		else
1162902cb50aSBrian Somers 			end = NULL;
116324084f9bSBrian Somers 
11640fc81af1SPhilippe Charnier 		if (end == parms)
11650fc81af1SPhilippe Charnier 			errx (1, "%s needs numeric parameter", option);
116624084f9bSBrian Somers 		break;
116724084f9bSBrian Somers 
116824084f9bSBrian Somers 	case String:
116924084f9bSBrian Somers 		strValue = parms;
11700fc81af1SPhilippe Charnier 		if (!strValue)
11710fc81af1SPhilippe Charnier 			errx (1, "%s needs parameter", option);
117224084f9bSBrian Somers 		break;
117324084f9bSBrian Somers 
117424084f9bSBrian Somers 	case None:
11750fc81af1SPhilippe Charnier 		if (parms)
11760fc81af1SPhilippe Charnier 			errx (1, "%s does not take parameters", option);
117724084f9bSBrian Somers 		break;
117824084f9bSBrian Somers 
117924084f9bSBrian Somers 	case Address:
11800fc81af1SPhilippe Charnier 		if (!parms)
11810fc81af1SPhilippe Charnier 			errx (1, "%s needs address/host parameter", option);
118224084f9bSBrian Somers 
118324084f9bSBrian Somers 		StrToAddr (parms, &addrValue);
118424084f9bSBrian Somers 		break;
118524084f9bSBrian Somers 	}
118624084f9bSBrian Somers 
118724084f9bSBrian Somers 	switch (info->type) {
118824084f9bSBrian Somers 	case PacketAliasOption:
118924084f9bSBrian Somers 
119024084f9bSBrian Somers 		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1191fb994b07SBrian Somers 		PacketAliasSetMode (aliasValue, info->packetAliasOpt);
119224084f9bSBrian Somers 		break;
119324084f9bSBrian Somers 
119424084f9bSBrian Somers 	case Verbose:
119524084f9bSBrian Somers 		verbose = yesNoValue;
119624084f9bSBrian Somers 		break;
119724084f9bSBrian Somers 
119824084f9bSBrian Somers 	case DynamicMode:
119924084f9bSBrian Somers 		dynamicMode = yesNoValue;
120024084f9bSBrian Somers 		break;
120124084f9bSBrian Somers 
120224084f9bSBrian Somers 	case InPort:
120367a886fbSBrian Somers 		inPort = uNumValue;
120424084f9bSBrian Somers 		break;
120524084f9bSBrian Somers 
120624084f9bSBrian Somers 	case OutPort:
120767a886fbSBrian Somers 		outPort = uNumValue;
120824084f9bSBrian Somers 		break;
120924084f9bSBrian Somers 
121024084f9bSBrian Somers 	case Port:
121167a886fbSBrian Somers 		inOutPort = uNumValue;
121224084f9bSBrian Somers 		break;
121324084f9bSBrian Somers 
121424084f9bSBrian Somers 	case AliasAddress:
121524084f9bSBrian Somers 		memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
121624084f9bSBrian Somers 		break;
121724084f9bSBrian Somers 
121811c2b3bfSRuslan Ermilov 	case TargetAddress:
121911c2b3bfSRuslan Ermilov 		PacketAliasSetTarget(addrValue);
122011c2b3bfSRuslan Ermilov 		break;
122111c2b3bfSRuslan Ermilov 
122224084f9bSBrian Somers 	case RedirectPort:
122324084f9bSBrian Somers 		SetupPortRedirect (strValue);
122424084f9bSBrian Somers 		break;
122524084f9bSBrian Somers 
12264330006dSRuslan Ermilov 	case RedirectProto:
12274330006dSRuslan Ermilov 		SetupProtoRedirect(strValue);
12284330006dSRuslan Ermilov 		break;
12294330006dSRuslan Ermilov 
123024084f9bSBrian Somers 	case RedirectAddress:
123124084f9bSBrian Somers 		SetupAddressRedirect (strValue);
123224084f9bSBrian Somers 		break;
123324084f9bSBrian Somers 
123459a7c613SBrian Somers 	case PptpAlias:
123559a7c613SBrian Somers 		SetupPptpAlias (strValue);
123659a7c613SBrian Somers 		break;
123759a7c613SBrian Somers 
123859a7c613SBrian Somers 	case ProxyRule:
123959a7c613SBrian Somers 		PacketAliasProxyRule (strValue);
124059a7c613SBrian Somers 		break;
124159a7c613SBrian Somers 
124224084f9bSBrian Somers 	case InterfaceName:
124324084f9bSBrian Somers 		if (ifName)
124424084f9bSBrian Somers 			free (ifName);
124524084f9bSBrian Somers 
124624084f9bSBrian Somers 		ifName = strdup (strValue);
124724084f9bSBrian Somers 		break;
124824084f9bSBrian Somers 
124924084f9bSBrian Somers 	case ConfigFile:
125024084f9bSBrian Somers 		ReadConfigFile (strValue);
125124084f9bSBrian Somers 		break;
125259a7c613SBrian Somers 
125359a7c613SBrian Somers 	case LogDenied:
125459a7c613SBrian Somers 		logDropped = 1;
125559a7c613SBrian Somers 		break;
125659a7c613SBrian Somers 
125759a7c613SBrian Somers 	case LogFacility:
125859a7c613SBrian Somers 
125959a7c613SBrian Somers 		fac_record = facilitynames;
126059a7c613SBrian Somers 		while (fac_record->c_name != NULL) {
126159a7c613SBrian Somers 
126259a7c613SBrian Somers 			if (!strcmp (fac_record->c_name, strValue)) {
126359a7c613SBrian Somers 
126459a7c613SBrian Somers 				logFacility = fac_record->c_val;
126559a7c613SBrian Somers 				break;
126659a7c613SBrian Somers 
126759a7c613SBrian Somers 			}
126859a7c613SBrian Somers 			else
126959a7c613SBrian Somers 				fac_record++;
127059a7c613SBrian Somers 		}
127159a7c613SBrian Somers 
127259a7c613SBrian Somers 		if(fac_record->c_name == NULL)
127359a7c613SBrian Somers 			errx(1, "Unknown log facility name: %s", strValue);
127459a7c613SBrian Somers 
127559a7c613SBrian Somers 		break;
127624084f9bSBrian Somers 	}
127724084f9bSBrian Somers }
127824084f9bSBrian Somers 
1279902cb50aSBrian Somers void ReadConfigFile (const char* fileName)
128024084f9bSBrian Somers {
128124084f9bSBrian Somers 	FILE*	file;
1282d99cc1daSRuslan Ermilov 	char	*buf;
1283d99cc1daSRuslan Ermilov 	size_t	len;
12842e7e7c71SRuslan Ermilov 	char	*ptr, *p;
128524084f9bSBrian Somers 	char*	option;
128624084f9bSBrian Somers 
128724084f9bSBrian Somers 	file = fopen (fileName, "r");
1288d99cc1daSRuslan Ermilov 	if (!file)
1289d99cc1daSRuslan Ermilov 		err(1, "cannot open config file %s", fileName);
129024084f9bSBrian Somers 
1291d99cc1daSRuslan Ermilov 	while ((buf = fgetln(file, &len)) != NULL) {
1292d99cc1daSRuslan Ermilov 		if (buf[len - 1] == '\n')
1293d99cc1daSRuslan Ermilov 			buf[len - 1] = '\0';
1294d99cc1daSRuslan Ermilov 		else
1295d99cc1daSRuslan Ermilov 			errx(1, "config file format error: "
1296d99cc1daSRuslan Ermilov 				"last line should end with newline");
129724084f9bSBrian Somers 
129824084f9bSBrian Somers /*
12992e7e7c71SRuslan Ermilov  * Check for comments, strip off trailing spaces.
130024084f9bSBrian Somers  */
13012e7e7c71SRuslan Ermilov 		if ((ptr = strchr(buf, '#')))
13022e7e7c71SRuslan Ermilov 			*ptr = '\0';
13032e7e7c71SRuslan Ermilov 		for (ptr = buf; isspace(*ptr); ++ptr)
13042e7e7c71SRuslan Ermilov 			continue;
130524084f9bSBrian Somers 		if (*ptr == '\0')
130624084f9bSBrian Somers 			continue;
13072e7e7c71SRuslan Ermilov 		for (p = strchr(buf, '\0'); isspace(*--p);)
13082e7e7c71SRuslan Ermilov 			continue;
13092e7e7c71SRuslan Ermilov 		*++p = '\0';
13102e7e7c71SRuslan Ermilov 
131124084f9bSBrian Somers /*
131224084f9bSBrian Somers  * Extract option name.
131324084f9bSBrian Somers  */
131424084f9bSBrian Somers 		option = ptr;
131524084f9bSBrian Somers 		while (*ptr && !isspace (*ptr))
131624084f9bSBrian Somers 			++ptr;
131724084f9bSBrian Somers 
131824084f9bSBrian Somers 		if (*ptr != '\0') {
131924084f9bSBrian Somers 
132024084f9bSBrian Somers 			*ptr = '\0';
132124084f9bSBrian Somers 			++ptr;
132224084f9bSBrian Somers 		}
132324084f9bSBrian Somers /*
132424084f9bSBrian Somers  * Skip white space between name and parms.
132524084f9bSBrian Somers  */
132624084f9bSBrian Somers 		while (*ptr && isspace (*ptr))
132724084f9bSBrian Somers 			++ptr;
132824084f9bSBrian Somers 
1329b0f55af6SRuslan Ermilov 		ParseOption (option, *ptr ? ptr : NULL);
133024084f9bSBrian Somers 	}
133124084f9bSBrian Somers 
133224084f9bSBrian Somers 	fclose (file);
133324084f9bSBrian Somers }
133424084f9bSBrian Somers 
133524084f9bSBrian Somers static void Usage ()
133624084f9bSBrian Somers {
133724084f9bSBrian Somers 	int			i;
133824084f9bSBrian Somers 	int			max;
133924084f9bSBrian Somers 	struct OptionInfo*	info;
134024084f9bSBrian Somers 
134124084f9bSBrian Somers 	fprintf (stderr, "Recognized options:\n\n");
134224084f9bSBrian Somers 
134324084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
134424084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
134524084f9bSBrian Somers 
134624084f9bSBrian Somers 		fprintf (stderr, "-%-20s %s\n", info->name,
134724084f9bSBrian Somers 						info->parmDescription);
134824084f9bSBrian Somers 
134924084f9bSBrian Somers 		if (info->shortName)
135024084f9bSBrian Somers 			fprintf (stderr, "-%-20s %s\n", info->shortName,
135124084f9bSBrian Somers 							info->parmDescription);
135224084f9bSBrian Somers 
135324084f9bSBrian Somers 		fprintf (stderr, "      %s\n\n", info->description);
135424084f9bSBrian Somers 	}
135524084f9bSBrian Somers 
135624084f9bSBrian Somers 	exit (1);
135724084f9bSBrian Somers }
135824084f9bSBrian Somers 
1359902cb50aSBrian Somers void SetupPptpAlias (const char* parms)
136024084f9bSBrian Somers {
136124084f9bSBrian Somers 	char		buf[128];
136224084f9bSBrian Somers 	char*		ptr;
136324084f9bSBrian Somers 	struct in_addr	srcAddr;
136424084f9bSBrian Somers 
136524084f9bSBrian Somers 	strcpy (buf, parms);
136624084f9bSBrian Somers 
136724084f9bSBrian Somers /*
136824084f9bSBrian Somers  * Extract source address.
136924084f9bSBrian Somers  */
137059a7c613SBrian Somers 	ptr = strtok (buf, " \t");
13710fc81af1SPhilippe Charnier 	if (!ptr)
137259a7c613SBrian Somers 		errx(1, "pptpalias: missing src address");
137324084f9bSBrian Somers 
137459a7c613SBrian Somers 	StrToAddr (ptr, &srcAddr);
137559a7c613SBrian Somers 	PacketAliasPptp (srcAddr);
137624084f9bSBrian Somers }
137724084f9bSBrian Somers 
1378902cb50aSBrian Somers void SetupPortRedirect (const char* parms)
137924084f9bSBrian Somers {
138024084f9bSBrian Somers 	char		buf[128];
138124084f9bSBrian Somers 	char*		ptr;
1382bd690510SRuslan Ermilov 	char*		serverPool;
138324084f9bSBrian Somers 	struct in_addr	localAddr;
138424084f9bSBrian Somers 	struct in_addr	publicAddr;
138524084f9bSBrian Somers 	struct in_addr	remoteAddr;
13865d8ee958SBrian Somers 	port_range      portRange;
13875d8ee958SBrian Somers 	u_short         localPort      = 0;
13885d8ee958SBrian Somers 	u_short         publicPort     = 0;
13895d8ee958SBrian Somers 	u_short         remotePort     = 0;
13905d8ee958SBrian Somers 	u_short         numLocalPorts  = 0;
13915d8ee958SBrian Somers 	u_short         numPublicPorts = 0;
13925d8ee958SBrian Somers 	u_short         numRemotePorts = 0;
139324084f9bSBrian Somers 	int		proto;
139424084f9bSBrian Somers 	char*		protoName;
139524084f9bSBrian Somers 	char*		separator;
13965d8ee958SBrian Somers 	int             i;
1397bd690510SRuslan Ermilov 	struct alias_link *link = NULL;
139824084f9bSBrian Somers 
139924084f9bSBrian Somers 	strcpy (buf, parms);
140024084f9bSBrian Somers /*
140124084f9bSBrian Somers  * Extract protocol.
140224084f9bSBrian Somers  */
140324084f9bSBrian Somers 	protoName = strtok (buf, " \t");
14040fc81af1SPhilippe Charnier 	if (!protoName)
14050fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing protocol");
140624084f9bSBrian Somers 
140724084f9bSBrian Somers 	proto = StrToProto (protoName);
140824084f9bSBrian Somers /*
140924084f9bSBrian Somers  * Extract local address.
141024084f9bSBrian Somers  */
141124084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
14120fc81af1SPhilippe Charnier 	if (!ptr)
14130fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing local address");
141424084f9bSBrian Somers 
1415bd690510SRuslan Ermilov 	separator = strchr(ptr, ',');
1416bd690510SRuslan Ermilov 	if (separator) {		/* LSNAT redirection syntax. */
1417bd690510SRuslan Ermilov 		localAddr.s_addr = INADDR_NONE;
1418bd690510SRuslan Ermilov 		localPort = ~0;
1419bd690510SRuslan Ermilov 		numLocalPorts = 1;
1420bd690510SRuslan Ermilov 		serverPool = ptr;
1421bd690510SRuslan Ermilov 	} else {
14225d8ee958SBrian Somers 		if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 )
14235d8ee958SBrian Somers 			errx (1, "redirect_port: invalid local port range");
14245d8ee958SBrian Somers 
14255d8ee958SBrian Somers 		localPort     = GETLOPORT(portRange);
14265d8ee958SBrian Somers 		numLocalPorts = GETNUMPORTS(portRange);
1427bd690510SRuslan Ermilov 		serverPool = NULL;
1428bd690510SRuslan Ermilov 	}
14295d8ee958SBrian Somers 
143024084f9bSBrian Somers /*
14319c501140SBrian Somers  * Extract public port and optionally address.
143224084f9bSBrian Somers  */
143324084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
14340fc81af1SPhilippe Charnier 	if (!ptr)
14350fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing public port");
143624084f9bSBrian Somers 
143724084f9bSBrian Somers 	separator = strchr (ptr, ':');
14385d8ee958SBrian Somers 	if (separator) {
14395d8ee958SBrian Somers 	        if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 )
14405d8ee958SBrian Somers 		        errx (1, "redirect_port: invalid public port range");
144124084f9bSBrian Somers 	}
14425d8ee958SBrian Somers 	else {
14435d8ee958SBrian Somers 		publicAddr.s_addr = INADDR_ANY;
14445d8ee958SBrian Somers 		if (StrToPortRange (ptr, protoName, &portRange) != 0)
14455d8ee958SBrian Somers 		        errx (1, "redirect_port: invalid public port range");
14465d8ee958SBrian Somers 	}
14475d8ee958SBrian Somers 
14485d8ee958SBrian Somers 	publicPort     = GETLOPORT(portRange);
14495d8ee958SBrian Somers 	numPublicPorts = GETNUMPORTS(portRange);
145024084f9bSBrian Somers 
145124084f9bSBrian Somers /*
145224084f9bSBrian Somers  * Extract remote address and optionally port.
145324084f9bSBrian Somers  */
145424084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
145524084f9bSBrian Somers 	if (ptr) {
145624084f9bSBrian Somers 		separator = strchr (ptr, ':');
1457ebe70c8fSWarner Losh 		if (separator) {
14585d8ee958SBrian Somers 		        if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0)
14595d8ee958SBrian Somers 			        errx (1, "redirect_port: invalid remote port range");
1460ebe70c8fSWarner Losh 		} else {
14615d8ee958SBrian Somers 		        SETLOPORT(portRange, 0);
14625d8ee958SBrian Somers 			SETNUMPORTS(portRange, 1);
146324084f9bSBrian Somers 			StrToAddr (ptr, &remoteAddr);
146424084f9bSBrian Somers 		}
146524084f9bSBrian Somers 	}
146624084f9bSBrian Somers 	else {
14675d8ee958SBrian Somers 	        SETLOPORT(portRange, 0);
14685d8ee958SBrian Somers 		SETNUMPORTS(portRange, 1);
146924084f9bSBrian Somers 		remoteAddr.s_addr = INADDR_ANY;
147024084f9bSBrian Somers 	}
147124084f9bSBrian Somers 
14725d8ee958SBrian Somers 	remotePort     = GETLOPORT(portRange);
14735d8ee958SBrian Somers 	numRemotePorts = GETNUMPORTS(portRange);
14745d8ee958SBrian Somers 
14755d8ee958SBrian Somers /*
14765d8ee958SBrian Somers  * Make sure port ranges match up, then add the redirect ports.
14775d8ee958SBrian Somers  */
14785d8ee958SBrian Somers 	if (numLocalPorts != numPublicPorts)
14795d8ee958SBrian Somers 	        errx (1, "redirect_port: port ranges must be equal in size");
14805d8ee958SBrian Somers 
14815d8ee958SBrian Somers 	/* Remote port range is allowed to be '0' which means all ports. */
148229d97436SBrian Somers 	if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0))
14835d8ee958SBrian Somers 	        errx (1, "redirect_port: remote port must be 0 or equal to local port range in size");
14845d8ee958SBrian Somers 
14855d8ee958SBrian Somers 	for (i = 0 ; i < numPublicPorts ; ++i) {
14865d8ee958SBrian Somers 	        /* If remotePort is all ports, set it to 0. */
14875d8ee958SBrian Somers 	        u_short remotePortCopy = remotePort + i;
14885d8ee958SBrian Somers 	        if (numRemotePorts == 1 && remotePort == 0)
14895d8ee958SBrian Somers 		        remotePortCopy = 0;
14905d8ee958SBrian Somers 
1491bd690510SRuslan Ermilov 		link = PacketAliasRedirectPort (localAddr,
14925d8ee958SBrian Somers 						htons(localPort + i),
149324084f9bSBrian Somers 						remoteAddr,
14945d8ee958SBrian Somers 						htons(remotePortCopy),
149524084f9bSBrian Somers 						publicAddr,
14965d8ee958SBrian Somers 						htons(publicPort + i),
149724084f9bSBrian Somers 						proto);
149824084f9bSBrian Somers 	}
1499bd690510SRuslan Ermilov 
1500bd690510SRuslan Ermilov /*
1501bd690510SRuslan Ermilov  * Setup LSNAT server pool.
1502bd690510SRuslan Ermilov  */
1503bd690510SRuslan Ermilov 	if (serverPool != NULL && link != NULL) {
1504bd690510SRuslan Ermilov 		ptr = strtok(serverPool, ",");
1505bd690510SRuslan Ermilov 		while (ptr != NULL) {
1506bd690510SRuslan Ermilov 			if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0)
1507bd690510SRuslan Ermilov 				errx(1, "redirect_port: invalid local port range");
1508bd690510SRuslan Ermilov 
1509bd690510SRuslan Ermilov 			localPort = GETLOPORT(portRange);
1510bd690510SRuslan Ermilov 			if (GETNUMPORTS(portRange) != 1)
1511bd690510SRuslan Ermilov 				errx(1, "redirect_port: local port must be single in this context");
1512bd690510SRuslan Ermilov 			PacketAliasAddServer(link, localAddr, htons(localPort));
1513bd690510SRuslan Ermilov 			ptr = strtok(NULL, ",");
1514bd690510SRuslan Ermilov 		}
1515bd690510SRuslan Ermilov 	}
15165d8ee958SBrian Somers }
151724084f9bSBrian Somers 
15184330006dSRuslan Ermilov void
15194330006dSRuslan Ermilov SetupProtoRedirect(const char* parms)
15204330006dSRuslan Ermilov {
15214330006dSRuslan Ermilov 	char		buf[128];
15224330006dSRuslan Ermilov 	char*		ptr;
15234330006dSRuslan Ermilov 	struct in_addr	localAddr;
15244330006dSRuslan Ermilov 	struct in_addr	publicAddr;
15254330006dSRuslan Ermilov 	struct in_addr	remoteAddr;
15264330006dSRuslan Ermilov 	int		proto;
15274330006dSRuslan Ermilov 	char*		protoName;
15284330006dSRuslan Ermilov 	struct protoent *protoent;
15294330006dSRuslan Ermilov 
15304330006dSRuslan Ermilov 	strcpy (buf, parms);
15314330006dSRuslan Ermilov /*
15324330006dSRuslan Ermilov  * Extract protocol.
15334330006dSRuslan Ermilov  */
15344330006dSRuslan Ermilov 	protoName = strtok(buf, " \t");
15354330006dSRuslan Ermilov 	if (!protoName)
15364330006dSRuslan Ermilov 		errx(1, "redirect_proto: missing protocol");
15374330006dSRuslan Ermilov 
15384330006dSRuslan Ermilov 	protoent = getprotobyname(protoName);
15394330006dSRuslan Ermilov 	if (protoent == NULL)
15404330006dSRuslan Ermilov 		errx(1, "redirect_proto: unknown protocol %s", protoName);
15414330006dSRuslan Ermilov 	else
15424330006dSRuslan Ermilov 		proto = protoent->p_proto;
15434330006dSRuslan Ermilov /*
15444330006dSRuslan Ermilov  * Extract local address.
15454330006dSRuslan Ermilov  */
15464330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
15474330006dSRuslan Ermilov 	if (!ptr)
15484330006dSRuslan Ermilov 		errx(1, "redirect_proto: missing local address");
15494330006dSRuslan Ermilov 	else
15504330006dSRuslan Ermilov 		StrToAddr(ptr, &localAddr);
15514330006dSRuslan Ermilov /*
15524330006dSRuslan Ermilov  * Extract optional public address.
15534330006dSRuslan Ermilov  */
15544330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
15554330006dSRuslan Ermilov 	if (ptr)
15564330006dSRuslan Ermilov 		StrToAddr(ptr, &publicAddr);
15574330006dSRuslan Ermilov 	else
15584330006dSRuslan Ermilov 		publicAddr.s_addr = INADDR_ANY;
15594330006dSRuslan Ermilov /*
15604330006dSRuslan Ermilov  * Extract optional remote address.
15614330006dSRuslan Ermilov  */
15624330006dSRuslan Ermilov 	ptr = strtok(NULL, " \t");
15634330006dSRuslan Ermilov 	if (ptr)
15644330006dSRuslan Ermilov 		StrToAddr(ptr, &remoteAddr);
15654330006dSRuslan Ermilov 	else
15664330006dSRuslan Ermilov 		remoteAddr.s_addr = INADDR_ANY;
15674330006dSRuslan Ermilov /*
15684330006dSRuslan Ermilov  * Create aliasing link.
15694330006dSRuslan Ermilov  */
15704330006dSRuslan Ermilov 	(void)PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr,
15714330006dSRuslan Ermilov 				       proto);
15724330006dSRuslan Ermilov }
15734330006dSRuslan Ermilov 
1574902cb50aSBrian Somers void SetupAddressRedirect (const char* parms)
157524084f9bSBrian Somers {
157624084f9bSBrian Somers 	char		buf[128];
157724084f9bSBrian Somers 	char*		ptr;
1578bd690510SRuslan Ermilov 	char*		separator;
157924084f9bSBrian Somers 	struct in_addr	localAddr;
158024084f9bSBrian Somers 	struct in_addr	publicAddr;
1581bd690510SRuslan Ermilov 	char*		serverPool;
1582bd690510SRuslan Ermilov 	struct alias_link *link;
158324084f9bSBrian Somers 
158424084f9bSBrian Somers 	strcpy (buf, parms);
158524084f9bSBrian Somers /*
158624084f9bSBrian Somers  * Extract local address.
158724084f9bSBrian Somers  */
158824084f9bSBrian Somers 	ptr = strtok (buf, " \t");
15890fc81af1SPhilippe Charnier 	if (!ptr)
15900fc81af1SPhilippe Charnier 		errx (1, "redirect_address: missing local address");
159124084f9bSBrian Somers 
1592bd690510SRuslan Ermilov 	separator = strchr(ptr, ',');
1593bd690510SRuslan Ermilov 	if (separator) {		/* LSNAT redirection syntax. */
1594bd690510SRuslan Ermilov 		localAddr.s_addr = INADDR_NONE;
1595bd690510SRuslan Ermilov 		serverPool = ptr;
1596bd690510SRuslan Ermilov 	} else {
159724084f9bSBrian Somers 		StrToAddr (ptr, &localAddr);
1598bd690510SRuslan Ermilov 		serverPool = NULL;
1599bd690510SRuslan Ermilov 	}
160024084f9bSBrian Somers /*
160124084f9bSBrian Somers  * Extract public address.
160224084f9bSBrian Somers  */
160324084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
16040fc81af1SPhilippe Charnier 	if (!ptr)
16050fc81af1SPhilippe Charnier 		errx (1, "redirect_address: missing public address");
160624084f9bSBrian Somers 
160724084f9bSBrian Somers 	StrToAddr (ptr, &publicAddr);
1608bd690510SRuslan Ermilov 	link = PacketAliasRedirectAddr(localAddr, publicAddr);
1609bd690510SRuslan Ermilov 
1610bd690510SRuslan Ermilov /*
1611bd690510SRuslan Ermilov  * Setup LSNAT server pool.
1612bd690510SRuslan Ermilov  */
1613bd690510SRuslan Ermilov 	if (serverPool != NULL && link != NULL) {
1614bd690510SRuslan Ermilov 		ptr = strtok(serverPool, ",");
1615bd690510SRuslan Ermilov 		while (ptr != NULL) {
1616bd690510SRuslan Ermilov 			StrToAddr(ptr, &localAddr);
1617bd690510SRuslan Ermilov 			PacketAliasAddServer(link, localAddr, htons(~0));
1618bd690510SRuslan Ermilov 			ptr = strtok(NULL, ",");
1619bd690510SRuslan Ermilov 		}
1620bd690510SRuslan Ermilov 	}
162124084f9bSBrian Somers }
162224084f9bSBrian Somers 
1623902cb50aSBrian Somers void StrToAddr (const char* str, struct in_addr* addr)
162424084f9bSBrian Somers {
162524084f9bSBrian Somers 	struct hostent* hp;
162624084f9bSBrian Somers 
162724084f9bSBrian Somers 	if (inet_aton (str, addr))
162824084f9bSBrian Somers 		return;
162924084f9bSBrian Somers 
163024084f9bSBrian Somers 	hp = gethostbyname (str);
16310fc81af1SPhilippe Charnier 	if (!hp)
16320fc81af1SPhilippe Charnier 		errx (1, "unknown host %s", str);
163324084f9bSBrian Somers 
163424084f9bSBrian Somers 	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
163524084f9bSBrian Somers }
163624084f9bSBrian Somers 
1637902cb50aSBrian Somers u_short StrToPort (const char* str, const char* proto)
163824084f9bSBrian Somers {
163967a886fbSBrian Somers 	u_short		port;
164024084f9bSBrian Somers 	struct servent*	sp;
164124084f9bSBrian Somers 	char*		end;
164224084f9bSBrian Somers 
164324084f9bSBrian Somers 	port = strtol (str, &end, 10);
164424084f9bSBrian Somers 	if (end != str)
164527c20503SBrian Somers 		return htons (port);
164624084f9bSBrian Somers 
164724084f9bSBrian Somers 	sp = getservbyname (str, proto);
16480fc81af1SPhilippe Charnier 	if (!sp)
16490fc81af1SPhilippe Charnier 		errx (1, "unknown service %s/%s", str, proto);
165024084f9bSBrian Somers 
165124084f9bSBrian Somers 	return sp->s_port;
165224084f9bSBrian Somers }
165324084f9bSBrian Somers 
1654902cb50aSBrian Somers int StrToPortRange (const char* str, const char* proto, port_range *portRange)
16555d8ee958SBrian Somers {
16565d8ee958SBrian Somers 	char*           sep;
16575d8ee958SBrian Somers 	struct servent*	sp;
16585d8ee958SBrian Somers 	char*		end;
16595d8ee958SBrian Somers 	u_short         loPort;
16605d8ee958SBrian Somers 	u_short         hiPort;
16615d8ee958SBrian Somers 
16625d8ee958SBrian Somers 	/* First see if this is a service, return corresponding port if so. */
16635d8ee958SBrian Somers 	sp = getservbyname (str,proto);
16645d8ee958SBrian Somers 	if (sp) {
16655d8ee958SBrian Somers 	        SETLOPORT(*portRange, ntohs(sp->s_port));
16665d8ee958SBrian Somers 		SETNUMPORTS(*portRange, 1);
16675d8ee958SBrian Somers 		return 0;
16685d8ee958SBrian Somers 	}
16695d8ee958SBrian Somers 
16705d8ee958SBrian Somers 	/* Not a service, see if it's a single port or port range. */
16715d8ee958SBrian Somers 	sep = strchr (str, '-');
16725d8ee958SBrian Somers 	if (sep == NULL) {
16735d8ee958SBrian Somers 	        SETLOPORT(*portRange, strtol(str, &end, 10));
16745d8ee958SBrian Somers 		if (end != str) {
16755d8ee958SBrian Somers 		        /* Single port. */
16765d8ee958SBrian Somers 		        SETNUMPORTS(*portRange, 1);
16775d8ee958SBrian Somers 			return 0;
16785d8ee958SBrian Somers 		}
16795d8ee958SBrian Somers 
16805d8ee958SBrian Somers 		/* Error in port range field. */
16815d8ee958SBrian Somers 		errx (1, "unknown service %s/%s", str, proto);
16825d8ee958SBrian Somers 	}
16835d8ee958SBrian Somers 
16845d8ee958SBrian Somers 	/* Port range, get the values and sanity check. */
16855d8ee958SBrian Somers 	sscanf (str, "%hu-%hu", &loPort, &hiPort);
16865d8ee958SBrian Somers 	SETLOPORT(*portRange, loPort);
16875d8ee958SBrian Somers 	SETNUMPORTS(*portRange, 0);	/* Error by default */
16885d8ee958SBrian Somers 	if (loPort <= hiPort)
16895d8ee958SBrian Somers 	        SETNUMPORTS(*portRange, hiPort - loPort + 1);
16905d8ee958SBrian Somers 
16915d8ee958SBrian Somers 	if (GETNUMPORTS(*portRange) == 0)
16925d8ee958SBrian Somers 	        errx (1, "invalid port range %s", str);
16935d8ee958SBrian Somers 
16945d8ee958SBrian Somers 	return 0;
16955d8ee958SBrian Somers }
16965d8ee958SBrian Somers 
16975d8ee958SBrian Somers 
1698902cb50aSBrian Somers int StrToProto (const char* str)
169924084f9bSBrian Somers {
170024084f9bSBrian Somers 	if (!strcmp (str, "tcp"))
170124084f9bSBrian Somers 		return IPPROTO_TCP;
170224084f9bSBrian Somers 
170324084f9bSBrian Somers 	if (!strcmp (str, "udp"))
170424084f9bSBrian Somers 		return IPPROTO_UDP;
170524084f9bSBrian Somers 
17060fc81af1SPhilippe Charnier 	errx (1, "unknown protocol %s. Expected tcp or udp", str);
170724084f9bSBrian Somers }
170824084f9bSBrian Somers 
1709902cb50aSBrian Somers int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange)
171024084f9bSBrian Somers {
171124084f9bSBrian Somers 	char*	ptr;
171224084f9bSBrian Somers 
171324084f9bSBrian Somers 	ptr = strchr (str, ':');
17140fc81af1SPhilippe Charnier 	if (!ptr)
17150fc81af1SPhilippe Charnier 		errx (1, "%s is missing port number", str);
171624084f9bSBrian Somers 
171724084f9bSBrian Somers 	*ptr = '\0';
171824084f9bSBrian Somers 	++ptr;
171924084f9bSBrian Somers 
172024084f9bSBrian Somers 	StrToAddr (str, addr);
17215d8ee958SBrian Somers 	return StrToPortRange (ptr, proto, portRange);
172224084f9bSBrian Somers }
1723