xref: /freebsd/sbin/natd/natd.c (revision 27c20503c61a661921e8c226868df0f6399854f7)
124084f9bSBrian Somers /*
224084f9bSBrian Somers  * natd - Network Address Translation Daemon for FreeBSD.
324084f9bSBrian Somers  *
424084f9bSBrian Somers  * This software ois 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  *
1224084f9bSBrian Somers  */
1324084f9bSBrian Somers 
1424084f9bSBrian Somers #include <sys/types.h>
1524084f9bSBrian Somers #include <sys/socket.h>
1624084f9bSBrian Somers #include <sys/time.h>
1724084f9bSBrian Somers 
1824084f9bSBrian Somers #include <netinet/in.h>
1924084f9bSBrian Somers #include <netinet/in_systm.h>
2024084f9bSBrian Somers #include <netinet/ip.h>
2124084f9bSBrian Somers #include <machine/in_cksum.h>
2224084f9bSBrian Somers #include <netinet/tcp.h>
2324084f9bSBrian Somers #include <sys/ioctl.h>
2424084f9bSBrian Somers #include <net/if.h>
2524084f9bSBrian Somers #include <net/route.h>
2624084f9bSBrian Somers #include <arpa/inet.h>
2724084f9bSBrian Somers 
2824084f9bSBrian Somers #include <alias.h>
290fc81af1SPhilippe Charnier #include <ctype.h>
300fc81af1SPhilippe Charnier #include <err.h>
310fc81af1SPhilippe Charnier #include <errno.h>
320fc81af1SPhilippe Charnier #include <netdb.h>
330fc81af1SPhilippe Charnier #include <signal.h>
340fc81af1SPhilippe Charnier #include <stdio.h>
350fc81af1SPhilippe Charnier #include <stdlib.h>
360fc81af1SPhilippe Charnier #include <string.h>
370fc81af1SPhilippe Charnier #include <syslog.h>
380fc81af1SPhilippe Charnier #include <unistd.h>
3924084f9bSBrian Somers #include "natd.h"
4024084f9bSBrian Somers 
4124084f9bSBrian Somers /*
4224084f9bSBrian Somers  * Default values for input and output
4324084f9bSBrian Somers  * divert socket ports.
4424084f9bSBrian Somers  */
4524084f9bSBrian Somers 
4624084f9bSBrian Somers #define	DEFAULT_SERVICE	"natd"
4724084f9bSBrian Somers 
4824084f9bSBrian Somers /*
4924084f9bSBrian Somers  * Function prototypes.
5024084f9bSBrian Somers  */
5124084f9bSBrian Somers 
5224084f9bSBrian Somers static void DoAliasing (int fd);
5324084f9bSBrian Somers static void DaemonMode ();
5424084f9bSBrian Somers static void HandleRoutingInfo (int fd);
5524084f9bSBrian Somers static void Usage ();
5624084f9bSBrian Somers static void PrintPacket (struct ip*);
5724084f9bSBrian Somers static void SetAliasAddressFromIfName (char* ifName);
5824084f9bSBrian Somers static void InitiateShutdown ();
5924084f9bSBrian Somers static void Shutdown ();
6024084f9bSBrian Somers static void RefreshAddr ();
6124084f9bSBrian Somers static void ParseOption (char* option, char* parms, int cmdLine);
6224084f9bSBrian Somers static void ReadConfigFile (char* fileName);
6324084f9bSBrian Somers static void SetupPermanentLink (char* parms);
6424084f9bSBrian Somers static void SetupPortRedirect (char* parms);
6524084f9bSBrian Somers static void SetupAddressRedirect (char* parms);
6624084f9bSBrian Somers static void StrToAddr (char* str, struct in_addr* addr);
6724084f9bSBrian Somers static int  StrToPort (char* str, char* proto);
6824084f9bSBrian Somers static int  StrToProto (char* str);
6924084f9bSBrian Somers static int  StrToAddrAndPort (char* str, struct in_addr* addr, char* proto);
7024084f9bSBrian Somers static void ParseArgs (int argc, char** argv);
71fb994b07SBrian Somers static void FlushPacketBuffer (int fd);
7224084f9bSBrian Somers 
7324084f9bSBrian Somers /*
7424084f9bSBrian Somers  * Globals.
7524084f9bSBrian Somers  */
7624084f9bSBrian Somers 
7724084f9bSBrian Somers static	int			verbose;
7824084f9bSBrian Somers static 	int			background;
7924084f9bSBrian Somers static	int			running;
8024084f9bSBrian Somers static	int			assignAliasAddr;
8124084f9bSBrian Somers static	char*			ifName;
8224084f9bSBrian Somers static  int			ifIndex;
8324084f9bSBrian Somers static	int			inPort;
8424084f9bSBrian Somers static	int			outPort;
8524084f9bSBrian Somers static	int			inOutPort;
8624084f9bSBrian Somers static	struct in_addr		aliasAddr;
8724084f9bSBrian Somers static 	int			dynamicMode;
8824084f9bSBrian Somers static  int			ifMTU;
8924084f9bSBrian Somers static	int			aliasOverhead;
9024084f9bSBrian Somers static 	int			icmpSock;
91fb994b07SBrian Somers static	char			packetBuf[IP_MAXPACKET];
92fb994b07SBrian Somers static 	int			packetLen;
93fb994b07SBrian Somers static	struct sockaddr_in	packetAddr;
94fb994b07SBrian Somers static 	int			packetSock;
95f9b06d5cSBrian Somers static  int			dropIgnoredIncoming;
9624084f9bSBrian Somers 
9724084f9bSBrian Somers int main (int argc, char** argv)
9824084f9bSBrian Somers {
9924084f9bSBrian Somers 	int			divertIn;
10024084f9bSBrian Somers 	int			divertOut;
10124084f9bSBrian Somers 	int			divertInOut;
10224084f9bSBrian Somers 	int			routeSock;
10324084f9bSBrian Somers 	struct sockaddr_in	addr;
10424084f9bSBrian Somers 	fd_set			readMask;
105fb994b07SBrian Somers 	fd_set			writeMask;
10624084f9bSBrian Somers 	int			fdMax;
10724084f9bSBrian Somers /*
10824084f9bSBrian Somers  * Initialize packet aliasing software.
10924084f9bSBrian Somers  * Done already here to be able to alter option bits
11024084f9bSBrian Somers  * during command line and configuration file processing.
11124084f9bSBrian Somers  */
112fb994b07SBrian Somers 	PacketAliasInit ();
11324084f9bSBrian Somers /*
11424084f9bSBrian Somers  * Parse options.
11524084f9bSBrian Somers  */
11624084f9bSBrian Somers 	inPort			= 0;
11724084f9bSBrian Somers 	outPort			= 0;
11824084f9bSBrian Somers 	verbose 		= 0;
11924084f9bSBrian Somers 	inOutPort		= 0;
12024084f9bSBrian Somers 	ifName			= NULL;
12124084f9bSBrian Somers 	ifMTU			= -1;
12224084f9bSBrian Somers 	background		= 0;
12324084f9bSBrian Somers 	running			= 1;
12424084f9bSBrian Somers 	assignAliasAddr		= 0;
12524084f9bSBrian Somers 	aliasAddr.s_addr	= INADDR_NONE;
12624084f9bSBrian Somers 	aliasOverhead		= 12;
12724084f9bSBrian Somers 	dynamicMode		= 0;
128fb994b07SBrian Somers /*
129fb994b07SBrian Somers  * Mark packet buffer empty.
130fb994b07SBrian Somers  */
131fb994b07SBrian Somers 	packetSock		= -1;
13224084f9bSBrian Somers 
13324084f9bSBrian Somers 	ParseArgs (argc, argv);
13424084f9bSBrian Somers /*
13524084f9bSBrian Somers  * Check that valid aliasing address has been given.
13624084f9bSBrian Somers  */
1370fc81af1SPhilippe Charnier 	if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL)
1380fc81af1SPhilippe Charnier 		errx(1, "aliasing address not given");
13924084f9bSBrian Somers 
1400fc81af1SPhilippe Charnier 	if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL)
1410fc81af1SPhilippe Charnier 		errx(1,
1420fc81af1SPhilippe Charnier 		"both alias address and interface name are not allowed");
14324084f9bSBrian Somers /*
14424084f9bSBrian Somers  * Check that valid port number is known.
14524084f9bSBrian Somers  */
14624084f9bSBrian Somers 	if (inPort != 0 || outPort != 0)
1470fc81af1SPhilippe Charnier 		if (inPort == 0 || outPort == 0)
1480fc81af1SPhilippe Charnier 			errx(1, "both input and output ports are required");
14924084f9bSBrian Somers 
15024084f9bSBrian Somers 	if (inPort == 0 && outPort == 0 && inOutPort == 0)
15124084f9bSBrian Somers 		ParseOption ("port", DEFAULT_SERVICE, 0);
15224084f9bSBrian Somers 
15324084f9bSBrian Somers /*
154f9b06d5cSBrian Somers  * Check if ignored packets should be dropped.
155f9b06d5cSBrian Somers  */
156f9b06d5cSBrian Somers 	dropIgnoredIncoming = PacketAliasSetMode (0, 0);
157f9b06d5cSBrian Somers 	dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
158f9b06d5cSBrian Somers /*
15924084f9bSBrian Somers  * Create divert sockets. Use only one socket if -p was specified
16024084f9bSBrian Somers  * on command line. Otherwise, create separate sockets for
16124084f9bSBrian Somers  * outgoing and incoming connnections.
16224084f9bSBrian Somers  */
16324084f9bSBrian Somers 	if (inOutPort) {
16424084f9bSBrian Somers 
16524084f9bSBrian Somers 		divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
16624084f9bSBrian Somers 		if (divertInOut == -1)
16724084f9bSBrian Somers 			Quit ("Unable to create divert socket.");
16824084f9bSBrian Somers 
16924084f9bSBrian Somers 		divertIn  = -1;
17024084f9bSBrian Somers 		divertOut = -1;
17124084f9bSBrian Somers /*
17224084f9bSBrian Somers  * Bind socket.
17324084f9bSBrian Somers  */
17424084f9bSBrian Somers 
17524084f9bSBrian Somers 		addr.sin_family		= AF_INET;
17624084f9bSBrian Somers 		addr.sin_addr.s_addr	= INADDR_ANY;
17724084f9bSBrian Somers 		addr.sin_port		= inOutPort;
17824084f9bSBrian Somers 
17924084f9bSBrian Somers 		if (bind (divertInOut,
18024084f9bSBrian Somers 			  (struct sockaddr*) &addr,
18124084f9bSBrian Somers 			  sizeof addr) == -1)
18224084f9bSBrian Somers 			Quit ("Unable to bind divert socket.");
18324084f9bSBrian Somers 	}
18424084f9bSBrian Somers 	else {
18524084f9bSBrian Somers 
18624084f9bSBrian Somers 		divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
18724084f9bSBrian Somers 		if (divertIn == -1)
18824084f9bSBrian Somers 			Quit ("Unable to create incoming divert socket.");
18924084f9bSBrian Somers 
19024084f9bSBrian Somers 		divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
19124084f9bSBrian Somers 		if (divertOut == -1)
19224084f9bSBrian Somers 			Quit ("Unable to create outgoing divert socket.");
19324084f9bSBrian Somers 
19424084f9bSBrian Somers 		divertInOut = -1;
19524084f9bSBrian Somers 
19624084f9bSBrian Somers /*
19724084f9bSBrian Somers  * Bind divert sockets.
19824084f9bSBrian Somers  */
19924084f9bSBrian Somers 
20024084f9bSBrian Somers 		addr.sin_family		= AF_INET;
20124084f9bSBrian Somers 		addr.sin_addr.s_addr	= INADDR_ANY;
20224084f9bSBrian Somers 		addr.sin_port		= inPort;
20324084f9bSBrian Somers 
20424084f9bSBrian Somers 		if (bind (divertIn,
20524084f9bSBrian Somers 			  (struct sockaddr*) &addr,
20624084f9bSBrian Somers 			  sizeof addr) == -1)
20724084f9bSBrian Somers 			Quit ("Unable to bind incoming divert socket.");
20824084f9bSBrian Somers 
20924084f9bSBrian Somers 		addr.sin_family		= AF_INET;
21024084f9bSBrian Somers 		addr.sin_addr.s_addr	= INADDR_ANY;
21124084f9bSBrian Somers 		addr.sin_port		= outPort;
21224084f9bSBrian Somers 
21324084f9bSBrian Somers 		if (bind (divertOut,
21424084f9bSBrian Somers 			  (struct sockaddr*) &addr,
21524084f9bSBrian Somers 			  sizeof addr) == -1)
21624084f9bSBrian Somers 			Quit ("Unable to bind outgoing divert socket.");
21724084f9bSBrian Somers 	}
21824084f9bSBrian Somers /*
21924084f9bSBrian Somers  * Create routing socket if interface name specified.
22024084f9bSBrian Somers  */
22124084f9bSBrian Somers 	if (ifName && dynamicMode) {
22224084f9bSBrian Somers 
22324084f9bSBrian Somers 		routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
22424084f9bSBrian Somers 		if (routeSock == -1)
22524084f9bSBrian Somers 			Quit ("Unable to create routing info socket.");
22624084f9bSBrian Somers 	}
22724084f9bSBrian Somers 	else
22824084f9bSBrian Somers 		routeSock = -1;
22924084f9bSBrian Somers /*
23024084f9bSBrian Somers  * Create socket for sending ICMP messages.
23124084f9bSBrian Somers  */
23224084f9bSBrian Somers 	icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
23324084f9bSBrian Somers 	if (icmpSock == -1)
23424084f9bSBrian Somers 		Quit ("Unable to create ICMP socket.");
23524084f9bSBrian Somers /*
23624084f9bSBrian Somers  * Become a daemon unless verbose mode was requested.
23724084f9bSBrian Somers  */
23824084f9bSBrian Somers 	if (!verbose)
23924084f9bSBrian Somers 		DaemonMode ();
24024084f9bSBrian Somers /*
24124084f9bSBrian Somers  * Catch signals to manage shutdown and
24224084f9bSBrian Somers  * refresh of interface address.
24324084f9bSBrian Somers  */
24424084f9bSBrian Somers 	signal (SIGTERM, InitiateShutdown);
24524084f9bSBrian Somers 	signal (SIGHUP, RefreshAddr);
24624084f9bSBrian Somers /*
24724084f9bSBrian Somers  * Set alias address if it has been given.
24824084f9bSBrian Somers  */
24924084f9bSBrian Somers 	if (aliasAddr.s_addr != INADDR_NONE)
250fb994b07SBrian Somers 		PacketAliasSetAddress (aliasAddr);
25124084f9bSBrian Somers /*
25224084f9bSBrian Somers  * We need largest descriptor number for select.
25324084f9bSBrian Somers  */
25424084f9bSBrian Somers 
25524084f9bSBrian Somers 	fdMax = -1;
25624084f9bSBrian Somers 
25724084f9bSBrian Somers 	if (divertIn > fdMax)
25824084f9bSBrian Somers 		fdMax = divertIn;
25924084f9bSBrian Somers 
26024084f9bSBrian Somers 	if (divertOut > fdMax)
26124084f9bSBrian Somers 		fdMax = divertOut;
26224084f9bSBrian Somers 
26324084f9bSBrian Somers 	if (divertInOut > fdMax)
26424084f9bSBrian Somers 		fdMax = divertInOut;
26524084f9bSBrian Somers 
26624084f9bSBrian Somers 	if (routeSock > fdMax)
26724084f9bSBrian Somers 		fdMax = routeSock;
26824084f9bSBrian Somers 
26924084f9bSBrian Somers 	while (running) {
270fb994b07SBrian Somers 
271fb994b07SBrian Somers 		if (divertInOut != -1 && !ifName && packetSock == -1) {
272fb994b07SBrian Somers /*
273fb994b07SBrian Somers  * When using only one socket, just call
274fb994b07SBrian Somers  * DoAliasing repeatedly to process packets.
275fb994b07SBrian Somers  */
276fb994b07SBrian Somers 			DoAliasing (divertInOut);
277fb994b07SBrian Somers 			continue;
278fb994b07SBrian Somers 		}
27924084f9bSBrian Somers /*
28024084f9bSBrian Somers  * Build read mask from socket descriptors to select.
28124084f9bSBrian Somers  */
28224084f9bSBrian Somers 		FD_ZERO (&readMask);
283fb994b07SBrian Somers 		FD_ZERO (&writeMask);
28424084f9bSBrian Somers 
285fb994b07SBrian Somers /*
286fb994b07SBrian Somers  * If there is unsent packet in buffer, use select
287fb994b07SBrian Somers  * to check when socket comes writable again.
288fb994b07SBrian Somers  */
289fb994b07SBrian Somers 		if (packetSock != -1) {
290fb994b07SBrian Somers 
291fb994b07SBrian Somers 			FD_SET (packetSock, &writeMask);
292fb994b07SBrian Somers 		}
293fb994b07SBrian Somers 		else {
294fb994b07SBrian Somers /*
295fb994b07SBrian Somers  * No unsent packet exists - safe to check if
296fb994b07SBrian Somers  * new ones are available.
297fb994b07SBrian Somers  */
29824084f9bSBrian Somers 			if (divertIn != -1)
29924084f9bSBrian Somers 				FD_SET (divertIn, &readMask);
30024084f9bSBrian Somers 
30124084f9bSBrian Somers 			if (divertOut != -1)
30224084f9bSBrian Somers 				FD_SET (divertOut, &readMask);
30324084f9bSBrian Somers 
30424084f9bSBrian Somers 			if (divertInOut != -1)
30524084f9bSBrian Somers 				FD_SET (divertInOut, &readMask);
306fb994b07SBrian Somers 		}
307fb994b07SBrian Somers /*
308fb994b07SBrian Somers  * Routing info is processed always.
309fb994b07SBrian Somers  */
31024084f9bSBrian Somers 		if (routeSock != -1)
31124084f9bSBrian Somers 			FD_SET (routeSock, &readMask);
31224084f9bSBrian Somers 
31324084f9bSBrian Somers 		if (select (fdMax + 1,
31424084f9bSBrian Somers 			    &readMask,
315fb994b07SBrian Somers 			    &writeMask,
31624084f9bSBrian Somers 			    NULL,
31724084f9bSBrian Somers 			    NULL) == -1) {
31824084f9bSBrian Somers 
31924084f9bSBrian Somers 			if (errno == EINTR)
32024084f9bSBrian Somers 				continue;
32124084f9bSBrian Somers 
32224084f9bSBrian Somers 			Quit ("Select failed.");
32324084f9bSBrian Somers 		}
32424084f9bSBrian Somers 
325fb994b07SBrian Somers 		if (packetSock != -1)
326fb994b07SBrian Somers 			if (FD_ISSET (packetSock, &writeMask))
327fb994b07SBrian Somers 				FlushPacketBuffer (packetSock);
328fb994b07SBrian Somers 
32924084f9bSBrian Somers 		if (divertIn != -1)
33024084f9bSBrian Somers 			if (FD_ISSET (divertIn, &readMask))
33124084f9bSBrian Somers 				DoAliasing (divertIn);
33224084f9bSBrian Somers 
33324084f9bSBrian Somers 		if (divertOut != -1)
33424084f9bSBrian Somers 			if (FD_ISSET (divertOut, &readMask))
33524084f9bSBrian Somers 				DoAliasing (divertOut);
33624084f9bSBrian Somers 
33724084f9bSBrian Somers 		if (divertInOut != -1)
33824084f9bSBrian Somers 			if (FD_ISSET (divertInOut, &readMask))
33924084f9bSBrian Somers 				DoAliasing (divertInOut);
34024084f9bSBrian Somers 
34124084f9bSBrian Somers 		if (routeSock != -1)
34224084f9bSBrian Somers 			if (FD_ISSET (routeSock, &readMask))
34324084f9bSBrian Somers 				HandleRoutingInfo (routeSock);
34424084f9bSBrian Somers 	}
34524084f9bSBrian Somers 
34624084f9bSBrian Somers 	if (background)
34724084f9bSBrian Somers 		unlink (PIDFILE);
34824084f9bSBrian Somers 
34924084f9bSBrian Somers 	return 0;
35024084f9bSBrian Somers }
35124084f9bSBrian Somers 
35224084f9bSBrian Somers static void DaemonMode ()
35324084f9bSBrian Somers {
35424084f9bSBrian Somers 	FILE*	pidFile;
35524084f9bSBrian Somers 
35624084f9bSBrian Somers 	daemon (0, 0);
35724084f9bSBrian Somers 	background = 1;
35824084f9bSBrian Somers 
35924084f9bSBrian Somers 	pidFile = fopen (PIDFILE, "w");
36024084f9bSBrian Somers 	if (pidFile) {
36124084f9bSBrian Somers 
36224084f9bSBrian Somers 		fprintf (pidFile, "%d\n", getpid ());
36324084f9bSBrian Somers 		fclose (pidFile);
36424084f9bSBrian Somers 	}
36524084f9bSBrian Somers }
36624084f9bSBrian Somers 
36724084f9bSBrian Somers static void ParseArgs (int argc, char** argv)
36824084f9bSBrian Somers {
36924084f9bSBrian Somers 	int		arg;
37024084f9bSBrian Somers 	char*		parm;
37124084f9bSBrian Somers 	char*		opt;
37224084f9bSBrian Somers 	char		parmBuf[256];
37324084f9bSBrian Somers 
37424084f9bSBrian Somers 	for (arg = 1; arg < argc; arg++) {
37524084f9bSBrian Somers 
37624084f9bSBrian Somers 		opt  = argv[arg];
37724084f9bSBrian Somers 		if (*opt != '-') {
37824084f9bSBrian Somers 
3790fc81af1SPhilippe Charnier 			warnx ("invalid option %s", opt);
38024084f9bSBrian Somers 			Usage ();
38124084f9bSBrian Somers 		}
38224084f9bSBrian Somers 
38324084f9bSBrian Somers 		parm = NULL;
38424084f9bSBrian Somers 		parmBuf[0] = '\0';
38524084f9bSBrian Somers 
38624084f9bSBrian Somers 		while (arg < argc - 1) {
38724084f9bSBrian Somers 
38824084f9bSBrian Somers 			if (argv[arg + 1][0] == '-')
38924084f9bSBrian Somers 				break;
39024084f9bSBrian Somers 
39124084f9bSBrian Somers 			if (parm)
39224084f9bSBrian Somers 				strcat (parmBuf, " ");
39324084f9bSBrian Somers 
39424084f9bSBrian Somers 			++arg;
39524084f9bSBrian Somers 			parm = parmBuf;
39624084f9bSBrian Somers 			strcat (parmBuf, argv[arg]);
39724084f9bSBrian Somers 		}
39824084f9bSBrian Somers 
39924084f9bSBrian Somers 		ParseOption (opt + 1, parm, 1);
40024084f9bSBrian Somers 	}
40124084f9bSBrian Somers }
40224084f9bSBrian Somers 
40324084f9bSBrian Somers static void DoAliasing (int fd)
40424084f9bSBrian Somers {
40524084f9bSBrian Somers 	int			bytes;
40624084f9bSBrian Somers 	int			origBytes;
407f9b06d5cSBrian Somers 	int			status;
40824084f9bSBrian Somers 	int			addrSize;
40924084f9bSBrian Somers 	struct ip*		ip;
41024084f9bSBrian Somers 
41124084f9bSBrian Somers 	if (assignAliasAddr) {
41224084f9bSBrian Somers 
41324084f9bSBrian Somers 		SetAliasAddressFromIfName (ifName);
41424084f9bSBrian Somers 		assignAliasAddr = 0;
41524084f9bSBrian Somers 	}
41624084f9bSBrian Somers /*
41724084f9bSBrian Somers  * Get packet from socket.
41824084f9bSBrian Somers  */
419fb994b07SBrian Somers 	addrSize  = sizeof packetAddr;
42024084f9bSBrian Somers 	origBytes = recvfrom (fd,
421fb994b07SBrian Somers 			      packetBuf,
422fb994b07SBrian Somers 			      sizeof packetBuf,
42324084f9bSBrian Somers 			      0,
424fb994b07SBrian Somers 			      (struct sockaddr*) &packetAddr,
42524084f9bSBrian Somers 			      &addrSize);
42624084f9bSBrian Somers 
42724084f9bSBrian Somers 	if (origBytes == -1) {
42824084f9bSBrian Somers 
42924084f9bSBrian Somers 		if (errno != EINTR)
4300fc81af1SPhilippe Charnier 			Warn ("read from divert socket failed");
43124084f9bSBrian Somers 
43224084f9bSBrian Somers 		return;
43324084f9bSBrian Somers 	}
43424084f9bSBrian Somers /*
43524084f9bSBrian Somers  * This is a IP packet.
43624084f9bSBrian Somers  */
437fb994b07SBrian Somers 	ip = (struct ip*) packetBuf;
43824084f9bSBrian Somers 
43924084f9bSBrian Somers 	if (verbose) {
44024084f9bSBrian Somers 
44124084f9bSBrian Somers /*
44224084f9bSBrian Somers  * Print packet direction and protocol type.
44324084f9bSBrian Somers  */
44424084f9bSBrian Somers 
445fb994b07SBrian Somers 		if (packetAddr.sin_addr.s_addr == INADDR_ANY)
44624084f9bSBrian Somers 			printf ("Out ");
44724084f9bSBrian Somers 		else
44824084f9bSBrian Somers 			printf ("In  ");
44924084f9bSBrian Somers 
45024084f9bSBrian Somers 		switch (ip->ip_p) {
45124084f9bSBrian Somers 		case IPPROTO_TCP:
45224084f9bSBrian Somers 			printf ("[TCP]  ");
45324084f9bSBrian Somers 			break;
45424084f9bSBrian Somers 
45524084f9bSBrian Somers 		case IPPROTO_UDP:
45624084f9bSBrian Somers 			printf ("[UDP]  ");
45724084f9bSBrian Somers 			break;
45824084f9bSBrian Somers 
45924084f9bSBrian Somers 		case IPPROTO_ICMP:
46024084f9bSBrian Somers 			printf ("[ICMP] ");
46124084f9bSBrian Somers 			break;
46224084f9bSBrian Somers 
46324084f9bSBrian Somers 		default:
46424084f9bSBrian Somers 			printf ("[?]    ");
46524084f9bSBrian Somers 			break;
46624084f9bSBrian Somers 		}
46724084f9bSBrian Somers /*
46824084f9bSBrian Somers  * Print addresses.
46924084f9bSBrian Somers  */
47024084f9bSBrian Somers 		PrintPacket (ip);
47124084f9bSBrian Somers 	}
47224084f9bSBrian Somers 
473fb994b07SBrian Somers 	if (packetAddr.sin_addr.s_addr == INADDR_ANY) {
47424084f9bSBrian Somers /*
47524084f9bSBrian Somers  * Outgoing packets. Do aliasing.
47624084f9bSBrian Somers  */
477fb994b07SBrian Somers 		PacketAliasOut (packetBuf, IP_MAXPACKET);
47824084f9bSBrian Somers 	}
47924084f9bSBrian Somers 	else {
48024084f9bSBrian Somers /*
48124084f9bSBrian Somers  * Do aliasing.
48224084f9bSBrian Somers  */
483f9b06d5cSBrian Somers 		status = PacketAliasIn (packetBuf, IP_MAXPACKET);
484f9b06d5cSBrian Somers 		if (status == PKT_ALIAS_IGNORED &&
485f9b06d5cSBrian Somers 		    dropIgnoredIncoming) {
486f9b06d5cSBrian Somers 
487f9b06d5cSBrian Somers 			printf (" dropped.\n");
488f9b06d5cSBrian Somers 			return;
489f9b06d5cSBrian Somers 		}
49024084f9bSBrian Somers 	}
49124084f9bSBrian Somers /*
49224084f9bSBrian Somers  * Length might have changed during aliasing.
49324084f9bSBrian Somers  */
49424084f9bSBrian Somers 	bytes = ntohs (ip->ip_len);
49524084f9bSBrian Somers /*
49624084f9bSBrian Somers  * Update alias overhead size for outgoing packets.
49724084f9bSBrian Somers  */
498fb994b07SBrian Somers 	if (packetAddr.sin_addr.s_addr == INADDR_ANY &&
49924084f9bSBrian Somers 	    bytes - origBytes > aliasOverhead)
50024084f9bSBrian Somers 		aliasOverhead = bytes - origBytes;
50124084f9bSBrian Somers 
50224084f9bSBrian Somers 	if (verbose) {
50324084f9bSBrian Somers 
50424084f9bSBrian Somers /*
50524084f9bSBrian Somers  * Print addresses after aliasing.
50624084f9bSBrian Somers  */
50724084f9bSBrian Somers 		printf (" aliased to\n");
50824084f9bSBrian Somers 		printf ("           ");
50924084f9bSBrian Somers 		PrintPacket (ip);
51024084f9bSBrian Somers 		printf ("\n");
51124084f9bSBrian Somers 	}
512fb994b07SBrian Somers 
513fb994b07SBrian Somers 	packetLen  = bytes;
514fb994b07SBrian Somers 	packetSock = fd;
515fb994b07SBrian Somers 	FlushPacketBuffer (fd);
516fb994b07SBrian Somers }
517fb994b07SBrian Somers 
518fb994b07SBrian Somers static void FlushPacketBuffer (int fd)
519fb994b07SBrian Somers {
520fb994b07SBrian Somers 	int			wrote;
521fb994b07SBrian Somers 	char			msgBuf[80];
52224084f9bSBrian Somers /*
52324084f9bSBrian Somers  * Put packet back for processing.
52424084f9bSBrian Somers  */
52524084f9bSBrian Somers 	wrote = sendto (fd,
526fb994b07SBrian Somers 		        packetBuf,
527fb994b07SBrian Somers 	    		packetLen,
52824084f9bSBrian Somers 	    		0,
529fb994b07SBrian Somers 	    		(struct sockaddr*) &packetAddr,
530fb994b07SBrian Somers 	    		sizeof packetAddr);
53124084f9bSBrian Somers 
532fb994b07SBrian Somers 	if (wrote != packetLen) {
533fb994b07SBrian Somers /*
534fb994b07SBrian Somers  * If buffer space is not available,
535fb994b07SBrian Somers  * just return. Main loop will take care of
536fb994b07SBrian Somers  * retrying send when space becomes available.
537fb994b07SBrian Somers  */
538fb994b07SBrian Somers 		if (errno == ENOBUFS)
539fb994b07SBrian Somers 			return;
54024084f9bSBrian Somers 
54124084f9bSBrian Somers 		if (errno == EMSGSIZE) {
54224084f9bSBrian Somers 
543fb994b07SBrian Somers 			if (packetAddr.sin_addr.s_addr == INADDR_ANY &&
54424084f9bSBrian Somers 			    ifMTU != -1)
54524084f9bSBrian Somers 				SendNeedFragIcmp (icmpSock,
546fb994b07SBrian Somers 						  (struct ip*) packetBuf,
54724084f9bSBrian Somers 						  ifMTU - aliasOverhead);
54824084f9bSBrian Somers 		}
54924084f9bSBrian Somers 		else {
55024084f9bSBrian Somers 
5510fc81af1SPhilippe Charnier 			sprintf (msgBuf, "failed to write packet back");
55224084f9bSBrian Somers 			Warn (msgBuf);
55324084f9bSBrian Somers 		}
55424084f9bSBrian Somers 	}
555fb994b07SBrian Somers 
556fb994b07SBrian Somers 	packetSock = -1;
55724084f9bSBrian Somers }
55824084f9bSBrian Somers 
55924084f9bSBrian Somers static void HandleRoutingInfo (int fd)
56024084f9bSBrian Somers {
56124084f9bSBrian Somers 	int			bytes;
56224084f9bSBrian Somers 	struct if_msghdr	ifMsg;
56324084f9bSBrian Somers /*
56424084f9bSBrian Somers  * Get packet from socket.
56524084f9bSBrian Somers  */
56624084f9bSBrian Somers 	bytes = read (fd, &ifMsg, sizeof ifMsg);
56724084f9bSBrian Somers 	if (bytes == -1) {
56824084f9bSBrian Somers 
5690fc81af1SPhilippe Charnier 		Warn ("read from routing socket failed");
57024084f9bSBrian Somers 		return;
57124084f9bSBrian Somers 	}
57224084f9bSBrian Somers 
57324084f9bSBrian Somers 	if (ifMsg.ifm_version != RTM_VERSION) {
57424084f9bSBrian Somers 
5750fc81af1SPhilippe Charnier 		Warn ("unexpected packet read from routing socket");
57624084f9bSBrian Somers 		return;
57724084f9bSBrian Somers 	}
57824084f9bSBrian Somers 
57924084f9bSBrian Somers 	if (verbose)
58024084f9bSBrian Somers 		printf ("Routing message %X received.\n", ifMsg.ifm_type);
58124084f9bSBrian Somers 
58224084f9bSBrian Somers 	if (ifMsg.ifm_type != RTM_NEWADDR)
58324084f9bSBrian Somers 		return;
58424084f9bSBrian Somers 
58524084f9bSBrian Somers 	if (verbose && ifMsg.ifm_index == ifIndex)
58624084f9bSBrian Somers 		printf ("Interface address has changed.\n");
58724084f9bSBrian Somers 
58824084f9bSBrian Somers 	if (ifMsg.ifm_index == ifIndex)
58924084f9bSBrian Somers 		assignAliasAddr = 1;
59024084f9bSBrian Somers }
59124084f9bSBrian Somers 
59224084f9bSBrian Somers static void PrintPacket (struct ip* ip)
59324084f9bSBrian Somers {
59424084f9bSBrian Somers 	struct tcphdr*	tcphdr;
59524084f9bSBrian Somers 
59624084f9bSBrian Somers 	if (ip->ip_p == IPPROTO_TCP)
59724084f9bSBrian Somers 		tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
59824084f9bSBrian Somers 	else
59924084f9bSBrian Somers 		tcphdr = NULL;
60024084f9bSBrian Somers 
60124084f9bSBrian Somers 	printf ("%s", inet_ntoa (ip->ip_src));
60224084f9bSBrian Somers 	if (tcphdr)
60324084f9bSBrian Somers 		printf (":%d", ntohs (tcphdr->th_sport));
60424084f9bSBrian Somers 
60524084f9bSBrian Somers 	printf (" -> ");
60624084f9bSBrian Somers 	printf ("%s", inet_ntoa (ip->ip_dst));
60724084f9bSBrian Somers 	if (tcphdr)
60824084f9bSBrian Somers 		printf (":%d", ntohs (tcphdr->th_dport));
60924084f9bSBrian Somers }
61024084f9bSBrian Somers 
61124084f9bSBrian Somers static void SetAliasAddressFromIfName (char* ifName)
61224084f9bSBrian Somers {
61324084f9bSBrian Somers 	struct ifconf		cf;
61424084f9bSBrian Somers 	struct ifreq		buf[32];
61524084f9bSBrian Somers 	char			msg[80];
61624084f9bSBrian Somers 	struct ifreq*		ifPtr;
61724084f9bSBrian Somers 	int			extra;
61824084f9bSBrian Somers 	int			helperSock;
61924084f9bSBrian Somers 	int			bytes;
62024084f9bSBrian Somers 	struct sockaddr_in*	addr;
62124084f9bSBrian Somers 	int			found;
62224084f9bSBrian Somers 	struct ifreq		req;
62324084f9bSBrian Somers 	char			last[10];
62424084f9bSBrian Somers /*
62524084f9bSBrian Somers  * Create a dummy socket to access interface information.
62624084f9bSBrian Somers  */
62724084f9bSBrian Somers 	helperSock = socket (AF_INET, SOCK_DGRAM, 0);
62824084f9bSBrian Somers 	if (helperSock == -1) {
62924084f9bSBrian Somers 
63024084f9bSBrian Somers 		Quit ("Failed to create helper socket.");
63124084f9bSBrian Somers 		exit (1);
63224084f9bSBrian Somers 	}
63324084f9bSBrian Somers 
63424084f9bSBrian Somers 	cf.ifc_len = sizeof (buf);
63524084f9bSBrian Somers 	cf.ifc_req = buf;
63624084f9bSBrian Somers /*
63724084f9bSBrian Somers  * Get interface data.
63824084f9bSBrian Somers  */
63924084f9bSBrian Somers 	if (ioctl (helperSock, SIOCGIFCONF, &cf) == -1) {
64024084f9bSBrian Somers 
64124084f9bSBrian Somers 		Quit ("Ioctl SIOCGIFCONF failed.");
64224084f9bSBrian Somers 		exit (1);
64324084f9bSBrian Somers 	}
64424084f9bSBrian Somers 
64524084f9bSBrian Somers 	ifIndex	= 0;
64624084f9bSBrian Somers 	ifPtr	= buf;
64724084f9bSBrian Somers 	bytes	= cf.ifc_len;
64824084f9bSBrian Somers 	found   = 0;
64924084f9bSBrian Somers 	last[0] = '\0';
65024084f9bSBrian Somers /*
65124084f9bSBrian Somers  * Loop through interfaces until one with
65224084f9bSBrian Somers  * given name is found. This is done to
65324084f9bSBrian Somers  * find correct interface index for routing
65424084f9bSBrian Somers  * message processing.
65524084f9bSBrian Somers  */
65624084f9bSBrian Somers 	while (bytes) {
65724084f9bSBrian Somers 
65824084f9bSBrian Somers 		if (ifPtr->ifr_addr.sa_family == AF_INET &&
65924084f9bSBrian Somers                     !strcmp (ifPtr->ifr_name, ifName)) {
66024084f9bSBrian Somers 
66124084f9bSBrian Somers 			found = 1;
66224084f9bSBrian Somers 			break;
66324084f9bSBrian Somers 		}
66424084f9bSBrian Somers 
66524084f9bSBrian Somers 		if (strcmp (last, ifPtr->ifr_name)) {
66624084f9bSBrian Somers 
66724084f9bSBrian Somers 			strcpy (last, ifPtr->ifr_name);
66824084f9bSBrian Somers 			++ifIndex;
66924084f9bSBrian Somers 		}
67024084f9bSBrian Somers 
67124084f9bSBrian Somers 		extra = ifPtr->ifr_addr.sa_len - sizeof (struct sockaddr);
67224084f9bSBrian Somers 
67324084f9bSBrian Somers 		ifPtr++;
67424084f9bSBrian Somers 		ifPtr = (struct ifreq*) ((char*) ifPtr + extra);
67524084f9bSBrian Somers 		bytes -= sizeof (struct ifreq) + extra;
67624084f9bSBrian Somers 	}
67724084f9bSBrian Somers 
67824084f9bSBrian Somers 	if (!found) {
67924084f9bSBrian Somers 
68024084f9bSBrian Somers 		close (helperSock);
68124084f9bSBrian Somers 		sprintf (msg, "Unknown interface name %s.\n", ifName);
68224084f9bSBrian Somers 		Quit (msg);
68324084f9bSBrian Somers 	}
68424084f9bSBrian Somers /*
68524084f9bSBrian Somers  * Get MTU size.
68624084f9bSBrian Somers  */
68724084f9bSBrian Somers 	strcpy (req.ifr_name, ifName);
68824084f9bSBrian Somers 
68924084f9bSBrian Somers 	if (ioctl (helperSock, SIOCGIFMTU, &req) == -1)
69024084f9bSBrian Somers 		Quit ("Cannot get interface mtu size.");
69124084f9bSBrian Somers 
69224084f9bSBrian Somers 	ifMTU = req.ifr_mtu;
69324084f9bSBrian Somers /*
69424084f9bSBrian Somers  * Get interface address.
69524084f9bSBrian Somers  */
69624084f9bSBrian Somers 	if (ioctl (helperSock, SIOCGIFADDR, &req) == -1)
69724084f9bSBrian Somers 		Quit ("Cannot get interface address.");
69824084f9bSBrian Somers 
69924084f9bSBrian Somers 	addr = (struct sockaddr_in*) &req.ifr_addr;
70024084f9bSBrian Somers 	SetPacketAliasAddress (addr->sin_addr);
70124084f9bSBrian Somers 	syslog (LOG_INFO, "Aliasing to %s, mtu %d bytes",
70224084f9bSBrian Somers 			  inet_ntoa (addr->sin_addr),
70324084f9bSBrian Somers 			  ifMTU);
70424084f9bSBrian Somers 
70524084f9bSBrian Somers 	close (helperSock);
70624084f9bSBrian Somers }
70724084f9bSBrian Somers 
70824084f9bSBrian Somers void Quit (char* msg)
70924084f9bSBrian Somers {
71024084f9bSBrian Somers 	Warn (msg);
71124084f9bSBrian Somers 	exit (1);
71224084f9bSBrian Somers }
71324084f9bSBrian Somers 
71424084f9bSBrian Somers void Warn (char* msg)
71524084f9bSBrian Somers {
71624084f9bSBrian Somers 	if (background)
71724084f9bSBrian Somers 		syslog (LOG_ALERT, "%s (%m)", msg);
71824084f9bSBrian Somers 	else
7190fc81af1SPhilippe Charnier 		warn (msg);
72024084f9bSBrian Somers }
72124084f9bSBrian Somers 
72224084f9bSBrian Somers static void RefreshAddr ()
72324084f9bSBrian Somers {
72424084f9bSBrian Somers 	signal (SIGHUP, RefreshAddr);
72524084f9bSBrian Somers 	if (ifName)
72624084f9bSBrian Somers 		assignAliasAddr = 1;
72724084f9bSBrian Somers }
72824084f9bSBrian Somers 
72924084f9bSBrian Somers static void InitiateShutdown ()
73024084f9bSBrian Somers {
73124084f9bSBrian Somers /*
73224084f9bSBrian Somers  * Start timer to allow kernel gracefully
73324084f9bSBrian Somers  * shutdown existing connections when system
73424084f9bSBrian Somers  * is shut down.
73524084f9bSBrian Somers  */
73624084f9bSBrian Somers 	signal (SIGALRM, Shutdown);
73724084f9bSBrian Somers 	alarm (10);
73824084f9bSBrian Somers }
73924084f9bSBrian Somers 
74024084f9bSBrian Somers static void Shutdown ()
74124084f9bSBrian Somers {
74224084f9bSBrian Somers 	running = 0;
74324084f9bSBrian Somers }
74424084f9bSBrian Somers 
74524084f9bSBrian Somers /*
74624084f9bSBrian Somers  * Different options recognized by this program.
74724084f9bSBrian Somers  */
74824084f9bSBrian Somers 
74924084f9bSBrian Somers enum Option {
75024084f9bSBrian Somers 
75124084f9bSBrian Somers 	PacketAliasOption,
75224084f9bSBrian Somers 	Verbose,
75324084f9bSBrian Somers 	InPort,
75424084f9bSBrian Somers 	OutPort,
75524084f9bSBrian Somers 	Port,
75624084f9bSBrian Somers 	AliasAddress,
75724084f9bSBrian Somers 	InterfaceName,
75824084f9bSBrian Somers 	PermanentLink,
75924084f9bSBrian Somers 	RedirectPort,
76024084f9bSBrian Somers 	RedirectAddress,
76124084f9bSBrian Somers 	ConfigFile,
76224084f9bSBrian Somers 	DynamicMode
76324084f9bSBrian Somers };
76424084f9bSBrian Somers 
76524084f9bSBrian Somers enum Param {
76624084f9bSBrian Somers 
76724084f9bSBrian Somers 	YesNo,
76824084f9bSBrian Somers 	Numeric,
76924084f9bSBrian Somers 	String,
77024084f9bSBrian Somers 	None,
77124084f9bSBrian Somers 	Address,
77224084f9bSBrian Somers 	Service
77324084f9bSBrian Somers };
77424084f9bSBrian Somers 
77524084f9bSBrian Somers /*
77624084f9bSBrian Somers  * Option information structure (used by ParseOption).
77724084f9bSBrian Somers  */
77824084f9bSBrian Somers 
77924084f9bSBrian Somers struct OptionInfo {
78024084f9bSBrian Somers 
78124084f9bSBrian Somers 	enum Option		type;
78224084f9bSBrian Somers 	int			packetAliasOpt;
78324084f9bSBrian Somers 	enum Param		parm;
78424084f9bSBrian Somers 	char*			parmDescription;
78524084f9bSBrian Somers 	char*			description;
78624084f9bSBrian Somers 	char*			name;
78724084f9bSBrian Somers 	char*			shortName;
78824084f9bSBrian Somers };
78924084f9bSBrian Somers 
79024084f9bSBrian Somers /*
79124084f9bSBrian Somers  * Table of known options.
79224084f9bSBrian Somers  */
79324084f9bSBrian Somers 
79424084f9bSBrian Somers static struct OptionInfo optionTable[] = {
79524084f9bSBrian Somers 
79624084f9bSBrian Somers 	{ PacketAliasOption,
79724084f9bSBrian Somers 		PKT_ALIAS_UNREGISTERED_ONLY,
79824084f9bSBrian Somers 		YesNo,
79924084f9bSBrian Somers 		"[yes|no]",
80024084f9bSBrian Somers 		"alias only unregistered addresses",
80124084f9bSBrian Somers 		"unregistered_only",
80224084f9bSBrian Somers 		"u" },
80324084f9bSBrian Somers 
80424084f9bSBrian Somers 	{ PacketAliasOption,
80524084f9bSBrian Somers 		PKT_ALIAS_LOG,
80624084f9bSBrian Somers 		YesNo,
80724084f9bSBrian Somers 		"[yes|no]",
80824084f9bSBrian Somers 		"enable logging",
80924084f9bSBrian Somers 		"log",
81024084f9bSBrian Somers 		"l" },
81124084f9bSBrian Somers 
81224084f9bSBrian Somers 	{ PacketAliasOption,
81324084f9bSBrian Somers 		PKT_ALIAS_DENY_INCOMING,
81424084f9bSBrian Somers 		YesNo,
81524084f9bSBrian Somers 		"[yes|no]",
81624084f9bSBrian Somers 		"allow incoming connections",
81724084f9bSBrian Somers 		"deny_incoming",
81824084f9bSBrian Somers 		"d" },
81924084f9bSBrian Somers 
82024084f9bSBrian Somers 	{ PacketAliasOption,
82124084f9bSBrian Somers 		PKT_ALIAS_USE_SOCKETS,
82224084f9bSBrian Somers 		YesNo,
82324084f9bSBrian Somers 		"[yes|no]",
82424084f9bSBrian Somers 		"use sockets to inhibit port conflict",
82524084f9bSBrian Somers 		"use_sockets",
82624084f9bSBrian Somers 		"s" },
82724084f9bSBrian Somers 
82824084f9bSBrian Somers 	{ PacketAliasOption,
82924084f9bSBrian Somers 		PKT_ALIAS_SAME_PORTS,
83024084f9bSBrian Somers 		YesNo,
83124084f9bSBrian Somers 		"[yes|no]",
83224084f9bSBrian Somers 		"try to keep original port numbers for connections",
83324084f9bSBrian Somers 		"same_ports",
83424084f9bSBrian Somers 		"m" },
83524084f9bSBrian Somers 
83624084f9bSBrian Somers 	{ Verbose,
83724084f9bSBrian Somers 		0,
83824084f9bSBrian Somers 		YesNo,
83924084f9bSBrian Somers 		"[yes|no]",
84024084f9bSBrian Somers 		"verbose mode, dump packet information",
84124084f9bSBrian Somers 		"verbose",
84224084f9bSBrian Somers 		"v" },
84324084f9bSBrian Somers 
84424084f9bSBrian Somers 	{ DynamicMode,
84524084f9bSBrian Somers 		0,
84624084f9bSBrian Somers 		YesNo,
84724084f9bSBrian Somers 		"[yes|no]",
84824084f9bSBrian Somers 		"dynamic mode, automatically detect interface address changes",
84924084f9bSBrian Somers 		"dynamic",
85024084f9bSBrian Somers 		NULL },
85124084f9bSBrian Somers 
85224084f9bSBrian Somers 	{ InPort,
85324084f9bSBrian Somers 		0,
85424084f9bSBrian Somers 		Service,
85524084f9bSBrian Somers 		"number|service_name",
85624084f9bSBrian Somers 		"set port for incoming packets",
85724084f9bSBrian Somers 		"in_port",
85824084f9bSBrian Somers 		"i" },
85924084f9bSBrian Somers 
86024084f9bSBrian Somers 	{ OutPort,
86124084f9bSBrian Somers 		0,
86224084f9bSBrian Somers 		Service,
86324084f9bSBrian Somers 		"number|service_name",
86424084f9bSBrian Somers 		"set port for outgoing packets",
86524084f9bSBrian Somers 		"out_port",
86624084f9bSBrian Somers 		"o" },
86724084f9bSBrian Somers 
86824084f9bSBrian Somers 	{ Port,
86924084f9bSBrian Somers 		0,
87024084f9bSBrian Somers 		Service,
87124084f9bSBrian Somers 		"number|service_name",
87224084f9bSBrian Somers 		"set port (defaults to natd/divert)",
87324084f9bSBrian Somers 		"port",
87424084f9bSBrian Somers 		"p" },
87524084f9bSBrian Somers 
87624084f9bSBrian Somers 	{ AliasAddress,
87724084f9bSBrian Somers 		0,
87824084f9bSBrian Somers 		Address,
87924084f9bSBrian Somers 		"x.x.x.x",
88024084f9bSBrian Somers 		"address to use for aliasing",
88124084f9bSBrian Somers 		"alias_address",
88224084f9bSBrian Somers 		"a" },
88324084f9bSBrian Somers 
88424084f9bSBrian Somers 	{ InterfaceName,
88524084f9bSBrian Somers 		0,
88624084f9bSBrian Somers 		String,
88724084f9bSBrian Somers 	        "network_if_name",
88824084f9bSBrian Somers 		"take aliasing address from interface",
88924084f9bSBrian Somers 		"interface",
89024084f9bSBrian Somers 		"n" },
89124084f9bSBrian Somers 
89224084f9bSBrian Somers 	{ PermanentLink,
89324084f9bSBrian Somers 		0,
89424084f9bSBrian Somers 		String,
89524084f9bSBrian Somers 	        "tcp|udp src:port dst:port alias",
89624084f9bSBrian Somers 		"define permanent link for incoming connection",
89724084f9bSBrian Somers 		"permanent_link",
89824084f9bSBrian Somers 		NULL },
89924084f9bSBrian Somers 
90024084f9bSBrian Somers 	{ RedirectPort,
90124084f9bSBrian Somers 		0,
90224084f9bSBrian Somers 		String,
90324084f9bSBrian Somers 	        "tcp|udp local_addr:local_port [public_addr:]public_port"
90424084f9bSBrian Somers 	 	" [remote_addr[:remote_port]]",
90524084f9bSBrian Somers 		"redirect a port for incoming traffic",
90624084f9bSBrian Somers 		"redirect_port",
90724084f9bSBrian Somers 		NULL },
90824084f9bSBrian Somers 
90924084f9bSBrian Somers 	{ RedirectAddress,
91024084f9bSBrian Somers 		0,
91124084f9bSBrian Somers 		String,
91224084f9bSBrian Somers 	        "local_addr public_addr",
91324084f9bSBrian Somers 		"define mapping between local and public addresses",
91424084f9bSBrian Somers 		"redirect_address",
91524084f9bSBrian Somers 		NULL },
91624084f9bSBrian Somers 
91724084f9bSBrian Somers 	{ ConfigFile,
91824084f9bSBrian Somers 		0,
91924084f9bSBrian Somers 		String,
92024084f9bSBrian Somers 		"file_name",
92124084f9bSBrian Somers 		"read options from configuration file",
92224084f9bSBrian Somers 		"config",
92324084f9bSBrian Somers 		"f" }
92424084f9bSBrian Somers };
92524084f9bSBrian Somers 
92624084f9bSBrian Somers static void ParseOption (char* option, char* parms, int cmdLine)
92724084f9bSBrian Somers {
92824084f9bSBrian Somers 	int			i;
92924084f9bSBrian Somers 	struct OptionInfo*	info;
93024084f9bSBrian Somers 	int			yesNoValue;
93124084f9bSBrian Somers 	int			aliasValue;
93224084f9bSBrian Somers 	int			numValue;
93324084f9bSBrian Somers 	char*			strValue;
93424084f9bSBrian Somers 	struct in_addr		addrValue;
93524084f9bSBrian Somers 	int			max;
93624084f9bSBrian Somers 	char*			end;
93724084f9bSBrian Somers /*
93824084f9bSBrian Somers  * Find option from table.
93924084f9bSBrian Somers  */
94024084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
94124084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
94224084f9bSBrian Somers 
94324084f9bSBrian Somers 		if (!strcmp (info->name, option))
94424084f9bSBrian Somers 			break;
94524084f9bSBrian Somers 
94624084f9bSBrian Somers 		if (info->shortName)
94724084f9bSBrian Somers 			if (!strcmp (info->shortName, option))
94824084f9bSBrian Somers 				break;
94924084f9bSBrian Somers 	}
95024084f9bSBrian Somers 
95124084f9bSBrian Somers 	if (i >= max) {
95224084f9bSBrian Somers 
9530fc81af1SPhilippe Charnier 		warnx ("unknown option %s", option);
95424084f9bSBrian Somers 		Usage ();
95524084f9bSBrian Somers 	}
95624084f9bSBrian Somers 
95724084f9bSBrian Somers 	yesNoValue	= 0;
95824084f9bSBrian Somers 	numValue	= 0;
95924084f9bSBrian Somers 	strValue	= NULL;
96024084f9bSBrian Somers /*
96124084f9bSBrian Somers  * Check parameters.
96224084f9bSBrian Somers  */
96324084f9bSBrian Somers 	switch (info->parm) {
96424084f9bSBrian Somers 	case YesNo:
96524084f9bSBrian Somers 		if (!parms)
96624084f9bSBrian Somers 			parms = "yes";
96724084f9bSBrian Somers 
96824084f9bSBrian Somers 		if (!strcmp (parms, "yes"))
96924084f9bSBrian Somers 			yesNoValue = 1;
97024084f9bSBrian Somers 		else
97124084f9bSBrian Somers 			if (!strcmp (parms, "no"))
97224084f9bSBrian Somers 				yesNoValue = 0;
9730fc81af1SPhilippe Charnier 			else
9740fc81af1SPhilippe Charnier 				errx(1, "%s needs yes/no parameter", option);
97524084f9bSBrian Somers 		break;
97624084f9bSBrian Somers 
97724084f9bSBrian Somers 	case Service:
9780fc81af1SPhilippe Charnier 		if (!parms)
9790fc81af1SPhilippe Charnier 			errx(1,
9800fc81af1SPhilippe Charnier 		"%s needs service name or port number parameter", option);
98124084f9bSBrian Somers 
98224084f9bSBrian Somers 		numValue = StrToPort (parms, "divert");
98324084f9bSBrian Somers 		break;
98424084f9bSBrian Somers 
98524084f9bSBrian Somers 	case Numeric:
98624084f9bSBrian Somers 		if (parms)
98724084f9bSBrian Somers 			numValue = strtol (parms, &end, 10);
98824084f9bSBrian Somers 		else
98924084f9bSBrian Somers 			end = parms;
99024084f9bSBrian Somers 
9910fc81af1SPhilippe Charnier 		if (end == parms)
9920fc81af1SPhilippe Charnier 			errx(1, "%s needs numeric parameter", option);
99324084f9bSBrian Somers 		break;
99424084f9bSBrian Somers 
99524084f9bSBrian Somers 	case String:
99624084f9bSBrian Somers 		strValue = parms;
9970fc81af1SPhilippe Charnier 		if (!strValue)
9980fc81af1SPhilippe Charnier 			errx(1, "%s needs parameter", option);
99924084f9bSBrian Somers 		break;
100024084f9bSBrian Somers 
100124084f9bSBrian Somers 	case None:
10020fc81af1SPhilippe Charnier 		if (parms)
10030fc81af1SPhilippe Charnier 			errx(1, "%s does not take parameters", option);
100424084f9bSBrian Somers 		break;
100524084f9bSBrian Somers 
100624084f9bSBrian Somers 	case Address:
10070fc81af1SPhilippe Charnier 		if (!parms)
10080fc81af1SPhilippe Charnier 			errx(1, "%s needs address/host parameter", option);
100924084f9bSBrian Somers 
101024084f9bSBrian Somers 		StrToAddr (parms, &addrValue);
101124084f9bSBrian Somers 		break;
101224084f9bSBrian Somers 	}
101324084f9bSBrian Somers 
101424084f9bSBrian Somers 	switch (info->type) {
101524084f9bSBrian Somers 	case PacketAliasOption:
101624084f9bSBrian Somers 
101724084f9bSBrian Somers 		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1018fb994b07SBrian Somers 		PacketAliasSetMode (aliasValue, info->packetAliasOpt);
101924084f9bSBrian Somers 		break;
102024084f9bSBrian Somers 
102124084f9bSBrian Somers 	case Verbose:
102224084f9bSBrian Somers 		verbose = yesNoValue;
102324084f9bSBrian Somers 		break;
102424084f9bSBrian Somers 
102524084f9bSBrian Somers 	case DynamicMode:
102624084f9bSBrian Somers 		dynamicMode = yesNoValue;
102724084f9bSBrian Somers 		break;
102824084f9bSBrian Somers 
102924084f9bSBrian Somers 	case InPort:
103024084f9bSBrian Somers 		inPort = numValue;
103124084f9bSBrian Somers 		break;
103224084f9bSBrian Somers 
103324084f9bSBrian Somers 	case OutPort:
103424084f9bSBrian Somers 		outPort = numValue;
103524084f9bSBrian Somers 		break;
103624084f9bSBrian Somers 
103724084f9bSBrian Somers 	case Port:
103824084f9bSBrian Somers 		inOutPort = numValue;
103924084f9bSBrian Somers 		break;
104024084f9bSBrian Somers 
104124084f9bSBrian Somers 	case AliasAddress:
104224084f9bSBrian Somers 		memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
104324084f9bSBrian Somers 		break;
104424084f9bSBrian Somers 
104524084f9bSBrian Somers 	case PermanentLink:
104624084f9bSBrian Somers 		SetupPermanentLink (strValue);
104724084f9bSBrian Somers 		break;
104824084f9bSBrian Somers 
104924084f9bSBrian Somers 	case RedirectPort:
105024084f9bSBrian Somers 		SetupPortRedirect (strValue);
105124084f9bSBrian Somers 		break;
105224084f9bSBrian Somers 
105324084f9bSBrian Somers 	case RedirectAddress:
105424084f9bSBrian Somers 		SetupAddressRedirect (strValue);
105524084f9bSBrian Somers 		break;
105624084f9bSBrian Somers 
105724084f9bSBrian Somers 	case InterfaceName:
105824084f9bSBrian Somers 		if (ifName)
105924084f9bSBrian Somers 			free (ifName);
106024084f9bSBrian Somers 
106124084f9bSBrian Somers 		ifName = strdup (strValue);
106224084f9bSBrian Somers 		assignAliasAddr = 1;
106324084f9bSBrian Somers 		break;
106424084f9bSBrian Somers 
106524084f9bSBrian Somers 	case ConfigFile:
106624084f9bSBrian Somers 		ReadConfigFile (strValue);
106724084f9bSBrian Somers 		break;
106824084f9bSBrian Somers 	}
106924084f9bSBrian Somers }
107024084f9bSBrian Somers 
107124084f9bSBrian Somers void ReadConfigFile (char* fileName)
107224084f9bSBrian Somers {
107324084f9bSBrian Somers 	FILE*	file;
107424084f9bSBrian Somers 	char	buf[128];
107524084f9bSBrian Somers 	char*	ptr;
107624084f9bSBrian Somers 	char*	option;
107724084f9bSBrian Somers 
107824084f9bSBrian Somers 	file = fopen (fileName, "r");
107924084f9bSBrian Somers 	if (!file) {
108024084f9bSBrian Somers 
108124084f9bSBrian Somers 		sprintf (buf, "Cannot open config file %s.\n", fileName);
108224084f9bSBrian Somers 		Quit (buf);
108324084f9bSBrian Somers 	}
108424084f9bSBrian Somers 
108524084f9bSBrian Somers 	while (fgets (buf, sizeof (buf), file)) {
108624084f9bSBrian Somers 
108724084f9bSBrian Somers 		ptr = strchr (buf, '\n');
10880fc81af1SPhilippe Charnier 		if (!ptr)
10890fc81af1SPhilippe Charnier 			errx(1, "config line too link: %s", buf);
109024084f9bSBrian Somers 
109124084f9bSBrian Somers 		*ptr = '\0';
109224084f9bSBrian Somers 		if (buf[0] == '#')
109324084f9bSBrian Somers 			continue;
109424084f9bSBrian Somers 
109524084f9bSBrian Somers 		ptr = buf;
109624084f9bSBrian Somers /*
109724084f9bSBrian Somers  * Skip white space at beginning of line.
109824084f9bSBrian Somers  */
109924084f9bSBrian Somers 		while (*ptr && isspace (*ptr))
110024084f9bSBrian Somers 			++ptr;
110124084f9bSBrian Somers 
110224084f9bSBrian Somers 		if (*ptr == '\0')
110324084f9bSBrian Somers 			continue;
110424084f9bSBrian Somers /*
110524084f9bSBrian Somers  * Extract option name.
110624084f9bSBrian Somers  */
110724084f9bSBrian Somers 		option = ptr;
110824084f9bSBrian Somers 		while (*ptr && !isspace (*ptr))
110924084f9bSBrian Somers 			++ptr;
111024084f9bSBrian Somers 
111124084f9bSBrian Somers 		if (*ptr != '\0') {
111224084f9bSBrian Somers 
111324084f9bSBrian Somers 			*ptr = '\0';
111424084f9bSBrian Somers 			++ptr;
111524084f9bSBrian Somers 		}
111624084f9bSBrian Somers /*
111724084f9bSBrian Somers  * Skip white space between name and parms.
111824084f9bSBrian Somers  */
111924084f9bSBrian Somers 		while (*ptr && isspace (*ptr))
112024084f9bSBrian Somers 			++ptr;
112124084f9bSBrian Somers 
112224084f9bSBrian Somers 		ParseOption (option, *ptr ? ptr : NULL, 0);
112324084f9bSBrian Somers 	}
112424084f9bSBrian Somers 
112524084f9bSBrian Somers 	fclose (file);
112624084f9bSBrian Somers }
112724084f9bSBrian Somers 
112824084f9bSBrian Somers static void Usage ()
112924084f9bSBrian Somers {
113024084f9bSBrian Somers 	int			i;
113124084f9bSBrian Somers 	int			max;
113224084f9bSBrian Somers 	struct OptionInfo*	info;
113324084f9bSBrian Somers 
113424084f9bSBrian Somers 	fprintf (stderr, "Recognized options:\n\n");
113524084f9bSBrian Somers 
113624084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
113724084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
113824084f9bSBrian Somers 
113924084f9bSBrian Somers 		fprintf (stderr, "-%-20s %s\n", info->name,
114024084f9bSBrian Somers 						info->parmDescription);
114124084f9bSBrian Somers 
114224084f9bSBrian Somers 		if (info->shortName)
114324084f9bSBrian Somers 			fprintf (stderr, "-%-20s %s\n", info->shortName,
114424084f9bSBrian Somers 							info->parmDescription);
114524084f9bSBrian Somers 
114624084f9bSBrian Somers 		fprintf (stderr, "      %s\n\n", info->description);
114724084f9bSBrian Somers 	}
114824084f9bSBrian Somers 
114924084f9bSBrian Somers 	exit (1);
115024084f9bSBrian Somers }
115124084f9bSBrian Somers 
115224084f9bSBrian Somers void SetupPermanentLink (char* parms)
115324084f9bSBrian Somers {
115424084f9bSBrian Somers 	char		buf[128];
115524084f9bSBrian Somers 	char*		ptr;
115624084f9bSBrian Somers 	struct in_addr	srcAddr;
115724084f9bSBrian Somers 	struct in_addr	dstAddr;
115824084f9bSBrian Somers 	int		srcPort;
115924084f9bSBrian Somers 	int		dstPort;
116024084f9bSBrian Somers 	int		aliasPort;
116124084f9bSBrian Somers 	int		proto;
116224084f9bSBrian Somers 	char*		protoName;
116324084f9bSBrian Somers 
116424084f9bSBrian Somers 	strcpy (buf, parms);
116524084f9bSBrian Somers /*
116624084f9bSBrian Somers  * Extract protocol.
116724084f9bSBrian Somers  */
116824084f9bSBrian Somers 	protoName = strtok (buf, " \t");
11690fc81af1SPhilippe Charnier 	if (!protoName)
11700fc81af1SPhilippe Charnier 		errx(1, "permanent_link: missing protocol");
117124084f9bSBrian Somers 
117224084f9bSBrian Somers 	proto = StrToProto (protoName);
117324084f9bSBrian Somers /*
117424084f9bSBrian Somers  * Extract source address.
117524084f9bSBrian Somers  */
117624084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
11770fc81af1SPhilippe Charnier 	if (!ptr)
11780fc81af1SPhilippe Charnier 		errx(1, "permanent_link: missing src address");
117924084f9bSBrian Somers 
118024084f9bSBrian Somers 	srcPort = StrToAddrAndPort (ptr, &srcAddr, protoName);
118124084f9bSBrian Somers /*
118224084f9bSBrian Somers  * Extract destination address.
118324084f9bSBrian Somers  */
118424084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
11850fc81af1SPhilippe Charnier 	if (!ptr)
11860fc81af1SPhilippe Charnier 		errx(1, "permanent_link: missing dst address");
118724084f9bSBrian Somers 
118824084f9bSBrian Somers 	dstPort = StrToAddrAndPort (ptr, &dstAddr, protoName);
118924084f9bSBrian Somers /*
119024084f9bSBrian Somers  * Export alias port.
119124084f9bSBrian Somers  */
119224084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
11930fc81af1SPhilippe Charnier 	if (!ptr)
11940fc81af1SPhilippe Charnier 		errx(1, "permanent_link: missing alias port");
119524084f9bSBrian Somers 
119624084f9bSBrian Somers 	aliasPort = StrToPort (ptr, protoName);
119724084f9bSBrian Somers 
119824084f9bSBrian Somers 	PacketAliasPermanentLink (srcAddr,
119924084f9bSBrian Somers 				  srcPort,
120024084f9bSBrian Somers 				  dstAddr,
120124084f9bSBrian Somers 				  dstPort,
120224084f9bSBrian Somers 				  aliasPort,
120324084f9bSBrian Somers 				  proto);
120424084f9bSBrian Somers }
120524084f9bSBrian Somers 
120624084f9bSBrian Somers void SetupPortRedirect (char* parms)
120724084f9bSBrian Somers {
120824084f9bSBrian Somers 	char		buf[128];
120924084f9bSBrian Somers 	char*		ptr;
121024084f9bSBrian Somers 	struct in_addr	localAddr;
121124084f9bSBrian Somers 	struct in_addr	publicAddr;
121224084f9bSBrian Somers 	struct in_addr	remoteAddr;
121324084f9bSBrian Somers 	int		localPort;
121424084f9bSBrian Somers 	int		publicPort;
121524084f9bSBrian Somers 	int		remotePort;
121624084f9bSBrian Somers 	int		proto;
121724084f9bSBrian Somers 	char*		protoName;
121824084f9bSBrian Somers 	char*		separator;
121924084f9bSBrian Somers 
122024084f9bSBrian Somers 	strcpy (buf, parms);
122124084f9bSBrian Somers /*
122224084f9bSBrian Somers  * Extract protocol.
122324084f9bSBrian Somers  */
122424084f9bSBrian Somers 	protoName = strtok (buf, " \t");
12250fc81af1SPhilippe Charnier 	if (!protoName)
12260fc81af1SPhilippe Charnier 		errx(1, "redirect_port: missing protocol");
122724084f9bSBrian Somers 
122824084f9bSBrian Somers 	proto = StrToProto (protoName);
122924084f9bSBrian Somers /*
123024084f9bSBrian Somers  * Extract local address.
123124084f9bSBrian Somers  */
123224084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
12330fc81af1SPhilippe Charnier 	if (!ptr)
12340fc81af1SPhilippe Charnier 		errx(1, "redirect_port: missing local address");
123524084f9bSBrian Somers 
123624084f9bSBrian Somers 	localPort = StrToAddrAndPort (ptr, &localAddr, protoName);
123724084f9bSBrian Somers /*
123824084f9bSBrian Somers  * Extract public port and optinally address.
123924084f9bSBrian Somers  */
124024084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
12410fc81af1SPhilippe Charnier 	if (!ptr)
12420fc81af1SPhilippe Charnier 		errx(1, "redirect_port: missing public port");
124324084f9bSBrian Somers 
124424084f9bSBrian Somers 	separator = strchr (ptr, ':');
124524084f9bSBrian Somers 	if (separator)
124624084f9bSBrian Somers 		publicPort = StrToAddrAndPort (ptr, &publicAddr, protoName);
124724084f9bSBrian Somers 	else {
124824084f9bSBrian Somers 
124924084f9bSBrian Somers 		publicAddr.s_addr = INADDR_ANY;
125024084f9bSBrian Somers 		publicPort = StrToPort (ptr, protoName);
125124084f9bSBrian Somers 	}
125224084f9bSBrian Somers 
125324084f9bSBrian Somers /*
125424084f9bSBrian Somers  * Extract remote address and optionally port.
125524084f9bSBrian Somers  */
125624084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
125724084f9bSBrian Somers 	if (ptr) {
125824084f9bSBrian Somers 
125924084f9bSBrian Somers 
126024084f9bSBrian Somers 		separator = strchr (ptr, ':');
126124084f9bSBrian Somers 		if (separator)
126224084f9bSBrian Somers 			remotePort = StrToAddrAndPort (ptr,
126324084f9bSBrian Somers 						       &remoteAddr,
126424084f9bSBrian Somers 						       protoName);
126524084f9bSBrian Somers 		else {
126624084f9bSBrian Somers 
126724084f9bSBrian Somers 			remotePort = 0;
126824084f9bSBrian Somers 			StrToAddr (ptr, &remoteAddr);
126924084f9bSBrian Somers 		}
127024084f9bSBrian Somers 	}
127124084f9bSBrian Somers 	else {
127224084f9bSBrian Somers 
127324084f9bSBrian Somers 		remotePort = 0;
127424084f9bSBrian Somers 		remoteAddr.s_addr = INADDR_ANY;
127524084f9bSBrian Somers 	}
127624084f9bSBrian Somers 
127724084f9bSBrian Somers 	PacketAliasRedirectPort (localAddr,
127824084f9bSBrian Somers 				 localPort,
127924084f9bSBrian Somers 				 remoteAddr,
128024084f9bSBrian Somers 				 remotePort,
128124084f9bSBrian Somers 				 publicAddr,
128224084f9bSBrian Somers 				 publicPort,
128324084f9bSBrian Somers 				 proto);
128424084f9bSBrian Somers }
128524084f9bSBrian Somers 
128624084f9bSBrian Somers void SetupAddressRedirect (char* parms)
128724084f9bSBrian Somers {
128824084f9bSBrian Somers 	char		buf[128];
128924084f9bSBrian Somers 	char*		ptr;
129024084f9bSBrian Somers 	struct in_addr	localAddr;
129124084f9bSBrian Somers 	struct in_addr	publicAddr;
129224084f9bSBrian Somers 
129324084f9bSBrian Somers 	strcpy (buf, parms);
129424084f9bSBrian Somers /*
129524084f9bSBrian Somers  * Extract local address.
129624084f9bSBrian Somers  */
129724084f9bSBrian Somers 	ptr = strtok (buf, " \t");
12980fc81af1SPhilippe Charnier 	if (!ptr)
12990fc81af1SPhilippe Charnier 		errx(1, "redirect_address: missing local address");
130024084f9bSBrian Somers 
130124084f9bSBrian Somers 	StrToAddr (ptr, &localAddr);
130224084f9bSBrian Somers /*
130324084f9bSBrian Somers  * Extract public address.
130424084f9bSBrian Somers  */
130524084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
13060fc81af1SPhilippe Charnier 	if (!ptr)
13070fc81af1SPhilippe Charnier 		errx(1, "redirect_address: missing public address");
130824084f9bSBrian Somers 
130924084f9bSBrian Somers 	StrToAddr (ptr, &publicAddr);
131024084f9bSBrian Somers 	PacketAliasRedirectAddr (localAddr, publicAddr);
131124084f9bSBrian Somers }
131224084f9bSBrian Somers 
131324084f9bSBrian Somers void StrToAddr (char* str, struct in_addr* addr)
131424084f9bSBrian Somers {
131524084f9bSBrian Somers 	struct hostent* hp;
131624084f9bSBrian Somers 
131724084f9bSBrian Somers 	if (inet_aton (str, addr))
131824084f9bSBrian Somers 		return;
131924084f9bSBrian Somers 
132024084f9bSBrian Somers 	hp = gethostbyname (str);
13210fc81af1SPhilippe Charnier 	if (!hp)
13220fc81af1SPhilippe Charnier 		errx(1, "unknown host %s", str);
132324084f9bSBrian Somers 
132424084f9bSBrian Somers 	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
132524084f9bSBrian Somers }
132624084f9bSBrian Somers 
132724084f9bSBrian Somers int StrToPort (char* str, char* proto)
132824084f9bSBrian Somers {
132924084f9bSBrian Somers 	int		port;
133024084f9bSBrian Somers 	struct servent*	sp;
133124084f9bSBrian Somers 	char*		end;
133224084f9bSBrian Somers 
133324084f9bSBrian Somers 	port = strtol (str, &end, 10);
133424084f9bSBrian Somers 	if (end != str)
133527c20503SBrian Somers 		return htons (port);
133624084f9bSBrian Somers 
133724084f9bSBrian Somers 	sp = getservbyname (str, proto);
13380fc81af1SPhilippe Charnier 	if (!sp)
13390fc81af1SPhilippe Charnier 		errx(1, "unknown service %s/%s", str, proto);
134024084f9bSBrian Somers 
134124084f9bSBrian Somers 	return sp->s_port;
134224084f9bSBrian Somers }
134324084f9bSBrian Somers 
134424084f9bSBrian Somers int StrToProto (char* str)
134524084f9bSBrian Somers {
134624084f9bSBrian Somers 	if (!strcmp (str, "tcp"))
134724084f9bSBrian Somers 		return IPPROTO_TCP;
134824084f9bSBrian Somers 
134924084f9bSBrian Somers 	if (!strcmp (str, "udp"))
135024084f9bSBrian Somers 		return IPPROTO_UDP;
135124084f9bSBrian Somers 
13520fc81af1SPhilippe Charnier 	errx(1, "unknown protocol %s. Expected tcp or udp", str);
135324084f9bSBrian Somers }
135424084f9bSBrian Somers 
135524084f9bSBrian Somers int StrToAddrAndPort (char* str, struct in_addr* addr, char* proto)
135624084f9bSBrian Somers {
135724084f9bSBrian Somers 	char*	ptr;
135824084f9bSBrian Somers 
135924084f9bSBrian Somers 	ptr = strchr (str, ':');
13600fc81af1SPhilippe Charnier 	if (!ptr)
13610fc81af1SPhilippe Charnier 		errx(1, "%s is missing port number", str);
136224084f9bSBrian Somers 
136324084f9bSBrian Somers 	*ptr = '\0';
136424084f9bSBrian Somers 	++ptr;
136524084f9bSBrian Somers 
136624084f9bSBrian Somers 	StrToAddr (str, addr);
136724084f9bSBrian Somers 	return StrToPort (ptr, proto);
136824084f9bSBrian Somers }
136924084f9bSBrian Somers 
1370