xref: /freebsd/sbin/natd/natd.c (revision f9b06d5cbee5e16afde99bc0fad5fafd1d119c8a)
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 <stdlib.h>
1524084f9bSBrian Somers #include <stdio.h>
1624084f9bSBrian Somers #include <unistd.h>
1724084f9bSBrian Somers #include <string.h>
1824084f9bSBrian Somers #include <ctype.h>
1924084f9bSBrian Somers 
2024084f9bSBrian Somers #include <sys/types.h>
2124084f9bSBrian Somers #include <sys/socket.h>
2224084f9bSBrian Somers #include <sys/time.h>
2324084f9bSBrian Somers #include <errno.h>
2424084f9bSBrian Somers #include <signal.h>
2524084f9bSBrian Somers 
2624084f9bSBrian Somers #include <netdb.h>
2724084f9bSBrian Somers 
2824084f9bSBrian Somers #include <netinet/in.h>
2924084f9bSBrian Somers #include <netinet/in_systm.h>
3024084f9bSBrian Somers #include <netinet/ip.h>
3124084f9bSBrian Somers #include <machine/in_cksum.h>
3224084f9bSBrian Somers #include <netinet/tcp.h>
3324084f9bSBrian Somers #include <sys/ioctl.h>
3424084f9bSBrian Somers #include <net/if.h>
3524084f9bSBrian Somers #include <net/route.h>
3624084f9bSBrian Somers #include <arpa/inet.h>
3724084f9bSBrian Somers 
3824084f9bSBrian Somers #include <syslog.h>
3924084f9bSBrian Somers #include <alias.h>
4024084f9bSBrian Somers 
4124084f9bSBrian Somers #include "natd.h"
4224084f9bSBrian Somers 
4324084f9bSBrian Somers /*
4424084f9bSBrian Somers  * Default values for input and output
4524084f9bSBrian Somers  * divert socket ports.
4624084f9bSBrian Somers  */
4724084f9bSBrian Somers 
4824084f9bSBrian Somers #define	DEFAULT_SERVICE	"natd"
4924084f9bSBrian Somers 
5024084f9bSBrian Somers /*
5124084f9bSBrian Somers  * Function prototypes.
5224084f9bSBrian Somers  */
5324084f9bSBrian Somers 
5424084f9bSBrian Somers static void DoAliasing (int fd);
5524084f9bSBrian Somers static void DaemonMode ();
5624084f9bSBrian Somers static void HandleRoutingInfo (int fd);
5724084f9bSBrian Somers static void Usage ();
5824084f9bSBrian Somers static void PrintPacket (struct ip*);
5924084f9bSBrian Somers static void SetAliasAddressFromIfName (char* ifName);
6024084f9bSBrian Somers static void InitiateShutdown ();
6124084f9bSBrian Somers static void Shutdown ();
6224084f9bSBrian Somers static void RefreshAddr ();
6324084f9bSBrian Somers static void ParseOption (char* option, char* parms, int cmdLine);
6424084f9bSBrian Somers static void ReadConfigFile (char* fileName);
6524084f9bSBrian Somers static void SetupPermanentLink (char* parms);
6624084f9bSBrian Somers static void SetupPortRedirect (char* parms);
6724084f9bSBrian Somers static void SetupAddressRedirect (char* parms);
6824084f9bSBrian Somers static void StrToAddr (char* str, struct in_addr* addr);
6924084f9bSBrian Somers static int  StrToPort (char* str, char* proto);
7024084f9bSBrian Somers static int  StrToProto (char* str);
7124084f9bSBrian Somers static int  StrToAddrAndPort (char* str, struct in_addr* addr, char* proto);
7224084f9bSBrian Somers static void ParseArgs (int argc, char** argv);
73fb994b07SBrian Somers static void FlushPacketBuffer (int fd);
7424084f9bSBrian Somers 
7524084f9bSBrian Somers /*
7624084f9bSBrian Somers  * Globals.
7724084f9bSBrian Somers  */
7824084f9bSBrian Somers 
7924084f9bSBrian Somers static	int			verbose;
8024084f9bSBrian Somers static 	int			background;
8124084f9bSBrian Somers static	int			running;
8224084f9bSBrian Somers static	int			assignAliasAddr;
8324084f9bSBrian Somers static	char*			ifName;
8424084f9bSBrian Somers static  int			ifIndex;
8524084f9bSBrian Somers static	int			inPort;
8624084f9bSBrian Somers static	int			outPort;
8724084f9bSBrian Somers static	int			inOutPort;
8824084f9bSBrian Somers static	struct in_addr		aliasAddr;
8924084f9bSBrian Somers static 	int			dynamicMode;
9024084f9bSBrian Somers static  int			ifMTU;
9124084f9bSBrian Somers static	int			aliasOverhead;
9224084f9bSBrian Somers static 	int			icmpSock;
93fb994b07SBrian Somers static	char			packetBuf[IP_MAXPACKET];
94fb994b07SBrian Somers static 	int			packetLen;
95fb994b07SBrian Somers static	struct sockaddr_in	packetAddr;
96fb994b07SBrian Somers static 	int			packetSock;
97f9b06d5cSBrian Somers static  int			dropIgnoredIncoming;
9824084f9bSBrian Somers 
9924084f9bSBrian Somers int main (int argc, char** argv)
10024084f9bSBrian Somers {
10124084f9bSBrian Somers 	int			divertIn;
10224084f9bSBrian Somers 	int			divertOut;
10324084f9bSBrian Somers 	int			divertInOut;
10424084f9bSBrian Somers 	int			routeSock;
10524084f9bSBrian Somers 	struct sockaddr_in	addr;
10624084f9bSBrian Somers 	fd_set			readMask;
107fb994b07SBrian Somers 	fd_set			writeMask;
10824084f9bSBrian Somers 	int			fdMax;
10924084f9bSBrian Somers /*
11024084f9bSBrian Somers  * Initialize packet aliasing software.
11124084f9bSBrian Somers  * Done already here to be able to alter option bits
11224084f9bSBrian Somers  * during command line and configuration file processing.
11324084f9bSBrian Somers  */
114fb994b07SBrian Somers 	PacketAliasInit ();
11524084f9bSBrian Somers /*
11624084f9bSBrian Somers  * Parse options.
11724084f9bSBrian Somers  */
11824084f9bSBrian Somers 	inPort			= 0;
11924084f9bSBrian Somers 	outPort			= 0;
12024084f9bSBrian Somers 	verbose 		= 0;
12124084f9bSBrian Somers 	inOutPort		= 0;
12224084f9bSBrian Somers 	ifName			= NULL;
12324084f9bSBrian Somers 	ifMTU			= -1;
12424084f9bSBrian Somers 	background		= 0;
12524084f9bSBrian Somers 	running			= 1;
12624084f9bSBrian Somers 	assignAliasAddr		= 0;
12724084f9bSBrian Somers 	aliasAddr.s_addr	= INADDR_NONE;
12824084f9bSBrian Somers 	aliasOverhead		= 12;
12924084f9bSBrian Somers 	dynamicMode		= 0;
130fb994b07SBrian Somers /*
131fb994b07SBrian Somers  * Mark packet buffer empty.
132fb994b07SBrian Somers  */
133fb994b07SBrian Somers 	packetSock		= -1;
13424084f9bSBrian Somers 
13524084f9bSBrian Somers 	ParseArgs (argc, argv);
13624084f9bSBrian Somers /*
13724084f9bSBrian Somers  * Check that valid aliasing address has been given.
13824084f9bSBrian Somers  */
13924084f9bSBrian Somers 	if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL) {
14024084f9bSBrian Somers 
14124084f9bSBrian Somers 		fprintf (stderr, "Aliasing address not given.\n");
14224084f9bSBrian Somers 		exit (1);
14324084f9bSBrian Somers 	}
14424084f9bSBrian Somers 
14524084f9bSBrian Somers 	if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL) {
14624084f9bSBrian Somers 
14724084f9bSBrian Somers 		fprintf (stderr, "Both alias address and interface name "
14824084f9bSBrian Somers 				 "are not allowed.\n");
14924084f9bSBrian Somers 		exit (1);
15024084f9bSBrian Somers 	}
15124084f9bSBrian Somers /*
15224084f9bSBrian Somers  * Check that valid port number is known.
15324084f9bSBrian Somers  */
15424084f9bSBrian Somers 	if (inPort != 0 || outPort != 0)
15524084f9bSBrian Somers 		if (inPort == 0 || outPort == 0) {
15624084f9bSBrian Somers 
15724084f9bSBrian Somers 			fprintf (stderr, "Both input and output ports"
15824084f9bSBrian Somers 					 " are required.\n");
15924084f9bSBrian Somers 			exit (1);
16024084f9bSBrian Somers 		}
16124084f9bSBrian Somers 
16224084f9bSBrian Somers 	if (inPort == 0 && outPort == 0 && inOutPort == 0)
16324084f9bSBrian Somers 		ParseOption ("port", DEFAULT_SERVICE, 0);
16424084f9bSBrian Somers 
16524084f9bSBrian Somers /*
166f9b06d5cSBrian Somers  * Check if ignored packets should be dropped.
167f9b06d5cSBrian Somers  */
168f9b06d5cSBrian Somers 	dropIgnoredIncoming = PacketAliasSetMode (0, 0);
169f9b06d5cSBrian Somers 	dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
170f9b06d5cSBrian Somers /*
17124084f9bSBrian Somers  * Create divert sockets. Use only one socket if -p was specified
17224084f9bSBrian Somers  * on command line. Otherwise, create separate sockets for
17324084f9bSBrian Somers  * outgoing and incoming connnections.
17424084f9bSBrian Somers  */
17524084f9bSBrian Somers 	if (inOutPort) {
17624084f9bSBrian Somers 
17724084f9bSBrian Somers 		divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
17824084f9bSBrian Somers 		if (divertInOut == -1)
17924084f9bSBrian Somers 			Quit ("Unable to create divert socket.");
18024084f9bSBrian Somers 
18124084f9bSBrian Somers 		divertIn  = -1;
18224084f9bSBrian Somers 		divertOut = -1;
18324084f9bSBrian Somers /*
18424084f9bSBrian Somers  * Bind socket.
18524084f9bSBrian Somers  */
18624084f9bSBrian Somers 
18724084f9bSBrian Somers 		addr.sin_family		= AF_INET;
18824084f9bSBrian Somers 		addr.sin_addr.s_addr	= INADDR_ANY;
18924084f9bSBrian Somers 		addr.sin_port		= inOutPort;
19024084f9bSBrian Somers 
19124084f9bSBrian Somers 		if (bind (divertInOut,
19224084f9bSBrian Somers 			  (struct sockaddr*) &addr,
19324084f9bSBrian Somers 			  sizeof addr) == -1)
19424084f9bSBrian Somers 			Quit ("Unable to bind divert socket.");
19524084f9bSBrian Somers 	}
19624084f9bSBrian Somers 	else {
19724084f9bSBrian Somers 
19824084f9bSBrian Somers 		divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
19924084f9bSBrian Somers 		if (divertIn == -1)
20024084f9bSBrian Somers 			Quit ("Unable to create incoming divert socket.");
20124084f9bSBrian Somers 
20224084f9bSBrian Somers 		divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
20324084f9bSBrian Somers 		if (divertOut == -1)
20424084f9bSBrian Somers 			Quit ("Unable to create outgoing divert socket.");
20524084f9bSBrian Somers 
20624084f9bSBrian Somers 		divertInOut = -1;
20724084f9bSBrian Somers 
20824084f9bSBrian Somers /*
20924084f9bSBrian Somers  * Bind divert sockets.
21024084f9bSBrian Somers  */
21124084f9bSBrian Somers 
21224084f9bSBrian Somers 		addr.sin_family		= AF_INET;
21324084f9bSBrian Somers 		addr.sin_addr.s_addr	= INADDR_ANY;
21424084f9bSBrian Somers 		addr.sin_port		= inPort;
21524084f9bSBrian Somers 
21624084f9bSBrian Somers 		if (bind (divertIn,
21724084f9bSBrian Somers 			  (struct sockaddr*) &addr,
21824084f9bSBrian Somers 			  sizeof addr) == -1)
21924084f9bSBrian Somers 			Quit ("Unable to bind incoming divert socket.");
22024084f9bSBrian Somers 
22124084f9bSBrian Somers 		addr.sin_family		= AF_INET;
22224084f9bSBrian Somers 		addr.sin_addr.s_addr	= INADDR_ANY;
22324084f9bSBrian Somers 		addr.sin_port		= outPort;
22424084f9bSBrian Somers 
22524084f9bSBrian Somers 		if (bind (divertOut,
22624084f9bSBrian Somers 			  (struct sockaddr*) &addr,
22724084f9bSBrian Somers 			  sizeof addr) == -1)
22824084f9bSBrian Somers 			Quit ("Unable to bind outgoing divert socket.");
22924084f9bSBrian Somers 	}
23024084f9bSBrian Somers /*
23124084f9bSBrian Somers  * Create routing socket if interface name specified.
23224084f9bSBrian Somers  */
23324084f9bSBrian Somers 	if (ifName && dynamicMode) {
23424084f9bSBrian Somers 
23524084f9bSBrian Somers 		routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
23624084f9bSBrian Somers 		if (routeSock == -1)
23724084f9bSBrian Somers 			Quit ("Unable to create routing info socket.");
23824084f9bSBrian Somers 	}
23924084f9bSBrian Somers 	else
24024084f9bSBrian Somers 		routeSock = -1;
24124084f9bSBrian Somers /*
24224084f9bSBrian Somers  * Create socket for sending ICMP messages.
24324084f9bSBrian Somers  */
24424084f9bSBrian Somers 	icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
24524084f9bSBrian Somers 	if (icmpSock == -1)
24624084f9bSBrian Somers 		Quit ("Unable to create ICMP socket.");
24724084f9bSBrian Somers /*
24824084f9bSBrian Somers  * Become a daemon unless verbose mode was requested.
24924084f9bSBrian Somers  */
25024084f9bSBrian Somers 	if (!verbose)
25124084f9bSBrian Somers 		DaemonMode ();
25224084f9bSBrian Somers /*
25324084f9bSBrian Somers  * Catch signals to manage shutdown and
25424084f9bSBrian Somers  * refresh of interface address.
25524084f9bSBrian Somers  */
25624084f9bSBrian Somers 	signal (SIGTERM, InitiateShutdown);
25724084f9bSBrian Somers 	signal (SIGHUP, RefreshAddr);
25824084f9bSBrian Somers /*
25924084f9bSBrian Somers  * Set alias address if it has been given.
26024084f9bSBrian Somers  */
26124084f9bSBrian Somers 	if (aliasAddr.s_addr != INADDR_NONE)
262fb994b07SBrian Somers 		PacketAliasSetAddress (aliasAddr);
26324084f9bSBrian Somers /*
26424084f9bSBrian Somers  * We need largest descriptor number for select.
26524084f9bSBrian Somers  */
26624084f9bSBrian Somers 
26724084f9bSBrian Somers 	fdMax = -1;
26824084f9bSBrian Somers 
26924084f9bSBrian Somers 	if (divertIn > fdMax)
27024084f9bSBrian Somers 		fdMax = divertIn;
27124084f9bSBrian Somers 
27224084f9bSBrian Somers 	if (divertOut > fdMax)
27324084f9bSBrian Somers 		fdMax = divertOut;
27424084f9bSBrian Somers 
27524084f9bSBrian Somers 	if (divertInOut > fdMax)
27624084f9bSBrian Somers 		fdMax = divertInOut;
27724084f9bSBrian Somers 
27824084f9bSBrian Somers 	if (routeSock > fdMax)
27924084f9bSBrian Somers 		fdMax = routeSock;
28024084f9bSBrian Somers 
28124084f9bSBrian Somers 	while (running) {
282fb994b07SBrian Somers 
283fb994b07SBrian Somers 		if (divertInOut != -1 && !ifName && packetSock == -1) {
284fb994b07SBrian Somers /*
285fb994b07SBrian Somers  * When using only one socket, just call
286fb994b07SBrian Somers  * DoAliasing repeatedly to process packets.
287fb994b07SBrian Somers  */
288fb994b07SBrian Somers 			DoAliasing (divertInOut);
289fb994b07SBrian Somers 			continue;
290fb994b07SBrian Somers 		}
29124084f9bSBrian Somers /*
29224084f9bSBrian Somers  * Build read mask from socket descriptors to select.
29324084f9bSBrian Somers  */
29424084f9bSBrian Somers 		FD_ZERO (&readMask);
295fb994b07SBrian Somers 		FD_ZERO (&writeMask);
29624084f9bSBrian Somers 
297fb994b07SBrian Somers /*
298fb994b07SBrian Somers  * If there is unsent packet in buffer, use select
299fb994b07SBrian Somers  * to check when socket comes writable again.
300fb994b07SBrian Somers  */
301fb994b07SBrian Somers 		if (packetSock != -1) {
302fb994b07SBrian Somers 
303fb994b07SBrian Somers 			FD_SET (packetSock, &writeMask);
304fb994b07SBrian Somers 		}
305fb994b07SBrian Somers 		else {
306fb994b07SBrian Somers /*
307fb994b07SBrian Somers  * No unsent packet exists - safe to check if
308fb994b07SBrian Somers  * new ones are available.
309fb994b07SBrian Somers  */
31024084f9bSBrian Somers 			if (divertIn != -1)
31124084f9bSBrian Somers 				FD_SET (divertIn, &readMask);
31224084f9bSBrian Somers 
31324084f9bSBrian Somers 			if (divertOut != -1)
31424084f9bSBrian Somers 				FD_SET (divertOut, &readMask);
31524084f9bSBrian Somers 
31624084f9bSBrian Somers 			if (divertInOut != -1)
31724084f9bSBrian Somers 				FD_SET (divertInOut, &readMask);
318fb994b07SBrian Somers 		}
319fb994b07SBrian Somers /*
320fb994b07SBrian Somers  * Routing info is processed always.
321fb994b07SBrian Somers  */
32224084f9bSBrian Somers 		if (routeSock != -1)
32324084f9bSBrian Somers 			FD_SET (routeSock, &readMask);
32424084f9bSBrian Somers 
32524084f9bSBrian Somers 		if (select (fdMax + 1,
32624084f9bSBrian Somers 			    &readMask,
327fb994b07SBrian Somers 			    &writeMask,
32824084f9bSBrian Somers 			    NULL,
32924084f9bSBrian Somers 			    NULL) == -1) {
33024084f9bSBrian Somers 
33124084f9bSBrian Somers 			if (errno == EINTR)
33224084f9bSBrian Somers 				continue;
33324084f9bSBrian Somers 
33424084f9bSBrian Somers 			Quit ("Select failed.");
33524084f9bSBrian Somers 		}
33624084f9bSBrian Somers 
337fb994b07SBrian Somers 		if (packetSock != -1)
338fb994b07SBrian Somers 			if (FD_ISSET (packetSock, &writeMask))
339fb994b07SBrian Somers 				FlushPacketBuffer (packetSock);
340fb994b07SBrian Somers 
34124084f9bSBrian Somers 		if (divertIn != -1)
34224084f9bSBrian Somers 			if (FD_ISSET (divertIn, &readMask))
34324084f9bSBrian Somers 				DoAliasing (divertIn);
34424084f9bSBrian Somers 
34524084f9bSBrian Somers 		if (divertOut != -1)
34624084f9bSBrian Somers 			if (FD_ISSET (divertOut, &readMask))
34724084f9bSBrian Somers 				DoAliasing (divertOut);
34824084f9bSBrian Somers 
34924084f9bSBrian Somers 		if (divertInOut != -1)
35024084f9bSBrian Somers 			if (FD_ISSET (divertInOut, &readMask))
35124084f9bSBrian Somers 				DoAliasing (divertInOut);
35224084f9bSBrian Somers 
35324084f9bSBrian Somers 		if (routeSock != -1)
35424084f9bSBrian Somers 			if (FD_ISSET (routeSock, &readMask))
35524084f9bSBrian Somers 				HandleRoutingInfo (routeSock);
35624084f9bSBrian Somers 	}
35724084f9bSBrian Somers 
35824084f9bSBrian Somers 	if (background)
35924084f9bSBrian Somers 		unlink (PIDFILE);
36024084f9bSBrian Somers 
36124084f9bSBrian Somers 	return 0;
36224084f9bSBrian Somers }
36324084f9bSBrian Somers 
36424084f9bSBrian Somers static void DaemonMode ()
36524084f9bSBrian Somers {
36624084f9bSBrian Somers 	FILE*	pidFile;
36724084f9bSBrian Somers 
36824084f9bSBrian Somers 	daemon (0, 0);
36924084f9bSBrian Somers 	background = 1;
37024084f9bSBrian Somers 
37124084f9bSBrian Somers 	pidFile = fopen (PIDFILE, "w");
37224084f9bSBrian Somers 	if (pidFile) {
37324084f9bSBrian Somers 
37424084f9bSBrian Somers 		fprintf (pidFile, "%d\n", getpid ());
37524084f9bSBrian Somers 		fclose (pidFile);
37624084f9bSBrian Somers 	}
37724084f9bSBrian Somers }
37824084f9bSBrian Somers 
37924084f9bSBrian Somers static void ParseArgs (int argc, char** argv)
38024084f9bSBrian Somers {
38124084f9bSBrian Somers 	int		arg;
38224084f9bSBrian Somers 	char*		parm;
38324084f9bSBrian Somers 	char*		opt;
38424084f9bSBrian Somers 	char		parmBuf[256];
38524084f9bSBrian Somers 
38624084f9bSBrian Somers 	for (arg = 1; arg < argc; arg++) {
38724084f9bSBrian Somers 
38824084f9bSBrian Somers 		opt  = argv[arg];
38924084f9bSBrian Somers 		if (*opt != '-') {
39024084f9bSBrian Somers 
39124084f9bSBrian Somers 			fprintf (stderr, "Invalid option %s.\n", opt);
39224084f9bSBrian Somers 			Usage ();
39324084f9bSBrian Somers 		}
39424084f9bSBrian Somers 
39524084f9bSBrian Somers 		parm = NULL;
39624084f9bSBrian Somers 		parmBuf[0] = '\0';
39724084f9bSBrian Somers 
39824084f9bSBrian Somers 		while (arg < argc - 1) {
39924084f9bSBrian Somers 
40024084f9bSBrian Somers 			if (argv[arg + 1][0] == '-')
40124084f9bSBrian Somers 				break;
40224084f9bSBrian Somers 
40324084f9bSBrian Somers 			if (parm)
40424084f9bSBrian Somers 				strcat (parmBuf, " ");
40524084f9bSBrian Somers 
40624084f9bSBrian Somers 			++arg;
40724084f9bSBrian Somers 			parm = parmBuf;
40824084f9bSBrian Somers 			strcat (parmBuf, argv[arg]);
40924084f9bSBrian Somers 		}
41024084f9bSBrian Somers 
41124084f9bSBrian Somers 		ParseOption (opt + 1, parm, 1);
41224084f9bSBrian Somers 	}
41324084f9bSBrian Somers }
41424084f9bSBrian Somers 
41524084f9bSBrian Somers static void DoAliasing (int fd)
41624084f9bSBrian Somers {
41724084f9bSBrian Somers 	int			bytes;
41824084f9bSBrian Somers 	int			origBytes;
419f9b06d5cSBrian Somers 	int			status;
42024084f9bSBrian Somers 	int			addrSize;
42124084f9bSBrian Somers 	struct ip*		ip;
42224084f9bSBrian Somers 
42324084f9bSBrian Somers 	if (assignAliasAddr) {
42424084f9bSBrian Somers 
42524084f9bSBrian Somers 		SetAliasAddressFromIfName (ifName);
42624084f9bSBrian Somers 		assignAliasAddr = 0;
42724084f9bSBrian Somers 	}
42824084f9bSBrian Somers /*
42924084f9bSBrian Somers  * Get packet from socket.
43024084f9bSBrian Somers  */
431fb994b07SBrian Somers 	addrSize  = sizeof packetAddr;
43224084f9bSBrian Somers 	origBytes = recvfrom (fd,
433fb994b07SBrian Somers 			      packetBuf,
434fb994b07SBrian Somers 			      sizeof packetBuf,
43524084f9bSBrian Somers 			      0,
436fb994b07SBrian Somers 			      (struct sockaddr*) &packetAddr,
43724084f9bSBrian Somers 			      &addrSize);
43824084f9bSBrian Somers 
43924084f9bSBrian Somers 	if (origBytes == -1) {
44024084f9bSBrian Somers 
44124084f9bSBrian Somers 		if (errno != EINTR)
44224084f9bSBrian Somers 			Warn ("Read from divert socket failed.");
44324084f9bSBrian Somers 
44424084f9bSBrian Somers 		return;
44524084f9bSBrian Somers 	}
44624084f9bSBrian Somers /*
44724084f9bSBrian Somers  * This is a IP packet.
44824084f9bSBrian Somers  */
449fb994b07SBrian Somers 	ip = (struct ip*) packetBuf;
45024084f9bSBrian Somers 
45124084f9bSBrian Somers 	if (verbose) {
45224084f9bSBrian Somers 
45324084f9bSBrian Somers /*
45424084f9bSBrian Somers  * Print packet direction and protocol type.
45524084f9bSBrian Somers  */
45624084f9bSBrian Somers 
457fb994b07SBrian Somers 		if (packetAddr.sin_addr.s_addr == INADDR_ANY)
45824084f9bSBrian Somers 			printf ("Out ");
45924084f9bSBrian Somers 		else
46024084f9bSBrian Somers 			printf ("In  ");
46124084f9bSBrian Somers 
46224084f9bSBrian Somers 		switch (ip->ip_p) {
46324084f9bSBrian Somers 		case IPPROTO_TCP:
46424084f9bSBrian Somers 			printf ("[TCP]  ");
46524084f9bSBrian Somers 			break;
46624084f9bSBrian Somers 
46724084f9bSBrian Somers 		case IPPROTO_UDP:
46824084f9bSBrian Somers 			printf ("[UDP]  ");
46924084f9bSBrian Somers 			break;
47024084f9bSBrian Somers 
47124084f9bSBrian Somers 		case IPPROTO_ICMP:
47224084f9bSBrian Somers 			printf ("[ICMP] ");
47324084f9bSBrian Somers 			break;
47424084f9bSBrian Somers 
47524084f9bSBrian Somers 		default:
47624084f9bSBrian Somers 			printf ("[?]    ");
47724084f9bSBrian Somers 			break;
47824084f9bSBrian Somers 		}
47924084f9bSBrian Somers /*
48024084f9bSBrian Somers  * Print addresses.
48124084f9bSBrian Somers  */
48224084f9bSBrian Somers 		PrintPacket (ip);
48324084f9bSBrian Somers 	}
48424084f9bSBrian Somers 
485fb994b07SBrian Somers 	if (packetAddr.sin_addr.s_addr == INADDR_ANY) {
48624084f9bSBrian Somers /*
48724084f9bSBrian Somers  * Outgoing packets. Do aliasing.
48824084f9bSBrian Somers  */
489fb994b07SBrian Somers 		PacketAliasOut (packetBuf, IP_MAXPACKET);
49024084f9bSBrian Somers 	}
49124084f9bSBrian Somers 	else {
49224084f9bSBrian Somers /*
49324084f9bSBrian Somers  * Do aliasing.
49424084f9bSBrian Somers  */
495f9b06d5cSBrian Somers 		status = PacketAliasIn (packetBuf, IP_MAXPACKET);
496f9b06d5cSBrian Somers 		if (status == PKT_ALIAS_IGNORED &&
497f9b06d5cSBrian Somers 		    dropIgnoredIncoming) {
498f9b06d5cSBrian Somers 
499f9b06d5cSBrian Somers 			printf (" dropped.\n");
500f9b06d5cSBrian Somers 			return;
501f9b06d5cSBrian Somers 		}
50224084f9bSBrian Somers 	}
50324084f9bSBrian Somers /*
50424084f9bSBrian Somers  * Length might have changed during aliasing.
50524084f9bSBrian Somers  */
50624084f9bSBrian Somers 	bytes = ntohs (ip->ip_len);
50724084f9bSBrian Somers /*
50824084f9bSBrian Somers  * Update alias overhead size for outgoing packets.
50924084f9bSBrian Somers  */
510fb994b07SBrian Somers 	if (packetAddr.sin_addr.s_addr == INADDR_ANY &&
51124084f9bSBrian Somers 	    bytes - origBytes > aliasOverhead)
51224084f9bSBrian Somers 		aliasOverhead = bytes - origBytes;
51324084f9bSBrian Somers 
51424084f9bSBrian Somers 	if (verbose) {
51524084f9bSBrian Somers 
51624084f9bSBrian Somers /*
51724084f9bSBrian Somers  * Print addresses after aliasing.
51824084f9bSBrian Somers  */
51924084f9bSBrian Somers 		printf (" aliased to\n");
52024084f9bSBrian Somers 		printf ("           ");
52124084f9bSBrian Somers 		PrintPacket (ip);
52224084f9bSBrian Somers 		printf ("\n");
52324084f9bSBrian Somers 	}
524fb994b07SBrian Somers 
525fb994b07SBrian Somers 	packetLen  = bytes;
526fb994b07SBrian Somers 	packetSock = fd;
527fb994b07SBrian Somers 	FlushPacketBuffer (fd);
528fb994b07SBrian Somers }
529fb994b07SBrian Somers 
530fb994b07SBrian Somers static void FlushPacketBuffer (int fd)
531fb994b07SBrian Somers {
532fb994b07SBrian Somers 	int			wrote;
533fb994b07SBrian Somers 	char			msgBuf[80];
53424084f9bSBrian Somers /*
53524084f9bSBrian Somers  * Put packet back for processing.
53624084f9bSBrian Somers  */
53724084f9bSBrian Somers 	wrote = sendto (fd,
538fb994b07SBrian Somers 		        packetBuf,
539fb994b07SBrian Somers 	    		packetLen,
54024084f9bSBrian Somers 	    		0,
541fb994b07SBrian Somers 	    		(struct sockaddr*) &packetAddr,
542fb994b07SBrian Somers 	    		sizeof packetAddr);
54324084f9bSBrian Somers 
544fb994b07SBrian Somers 	if (wrote != packetLen) {
545fb994b07SBrian Somers /*
546fb994b07SBrian Somers  * If buffer space is not available,
547fb994b07SBrian Somers  * just return. Main loop will take care of
548fb994b07SBrian Somers  * retrying send when space becomes available.
549fb994b07SBrian Somers  */
550fb994b07SBrian Somers 		if (errno == ENOBUFS)
551fb994b07SBrian Somers 			return;
55224084f9bSBrian Somers 
55324084f9bSBrian Somers 		if (errno == EMSGSIZE) {
55424084f9bSBrian Somers 
555fb994b07SBrian Somers 			if (packetAddr.sin_addr.s_addr == INADDR_ANY &&
55624084f9bSBrian Somers 			    ifMTU != -1)
55724084f9bSBrian Somers 				SendNeedFragIcmp (icmpSock,
558fb994b07SBrian Somers 						  (struct ip*) packetBuf,
55924084f9bSBrian Somers 						  ifMTU - aliasOverhead);
56024084f9bSBrian Somers 		}
56124084f9bSBrian Somers 		else {
56224084f9bSBrian Somers 
56324084f9bSBrian Somers 			sprintf (msgBuf, "Failed to write packet back.");
56424084f9bSBrian Somers 			Warn (msgBuf);
56524084f9bSBrian Somers 		}
56624084f9bSBrian Somers 	}
567fb994b07SBrian Somers 
568fb994b07SBrian Somers 	packetSock = -1;
56924084f9bSBrian Somers }
57024084f9bSBrian Somers 
57124084f9bSBrian Somers static void HandleRoutingInfo (int fd)
57224084f9bSBrian Somers {
57324084f9bSBrian Somers 	int			bytes;
57424084f9bSBrian Somers 	struct if_msghdr	ifMsg;
57524084f9bSBrian Somers /*
57624084f9bSBrian Somers  * Get packet from socket.
57724084f9bSBrian Somers  */
57824084f9bSBrian Somers 	bytes = read (fd, &ifMsg, sizeof ifMsg);
57924084f9bSBrian Somers 	if (bytes == -1) {
58024084f9bSBrian Somers 
58124084f9bSBrian Somers 		Warn ("Read from routing socket failed.");
58224084f9bSBrian Somers 		return;
58324084f9bSBrian Somers 	}
58424084f9bSBrian Somers 
58524084f9bSBrian Somers 	if (ifMsg.ifm_version != RTM_VERSION) {
58624084f9bSBrian Somers 
58724084f9bSBrian Somers 		Warn ("Unexpected packet read from routing socket.");
58824084f9bSBrian Somers 		return;
58924084f9bSBrian Somers 	}
59024084f9bSBrian Somers 
59124084f9bSBrian Somers 	if (verbose)
59224084f9bSBrian Somers 		printf ("Routing message %X received.\n", ifMsg.ifm_type);
59324084f9bSBrian Somers 
59424084f9bSBrian Somers 	if (ifMsg.ifm_type != RTM_NEWADDR)
59524084f9bSBrian Somers 		return;
59624084f9bSBrian Somers 
59724084f9bSBrian Somers 	if (verbose && ifMsg.ifm_index == ifIndex)
59824084f9bSBrian Somers 		printf ("Interface address has changed.\n");
59924084f9bSBrian Somers 
60024084f9bSBrian Somers 	if (ifMsg.ifm_index == ifIndex)
60124084f9bSBrian Somers 		assignAliasAddr = 1;
60224084f9bSBrian Somers }
60324084f9bSBrian Somers 
60424084f9bSBrian Somers static void PrintPacket (struct ip* ip)
60524084f9bSBrian Somers {
60624084f9bSBrian Somers 	struct tcphdr*	tcphdr;
60724084f9bSBrian Somers 
60824084f9bSBrian Somers 	if (ip->ip_p == IPPROTO_TCP)
60924084f9bSBrian Somers 		tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
61024084f9bSBrian Somers 	else
61124084f9bSBrian Somers 		tcphdr = NULL;
61224084f9bSBrian Somers 
61324084f9bSBrian Somers 	printf ("%s", inet_ntoa (ip->ip_src));
61424084f9bSBrian Somers 	if (tcphdr)
61524084f9bSBrian Somers 		printf (":%d", ntohs (tcphdr->th_sport));
61624084f9bSBrian Somers 
61724084f9bSBrian Somers 	printf (" -> ");
61824084f9bSBrian Somers 	printf ("%s", inet_ntoa (ip->ip_dst));
61924084f9bSBrian Somers 	if (tcphdr)
62024084f9bSBrian Somers 		printf (":%d", ntohs (tcphdr->th_dport));
62124084f9bSBrian Somers }
62224084f9bSBrian Somers 
62324084f9bSBrian Somers static void SetAliasAddressFromIfName (char* ifName)
62424084f9bSBrian Somers {
62524084f9bSBrian Somers 	struct ifconf		cf;
62624084f9bSBrian Somers 	struct ifreq		buf[32];
62724084f9bSBrian Somers 	char			msg[80];
62824084f9bSBrian Somers 	struct ifreq*		ifPtr;
62924084f9bSBrian Somers 	int			extra;
63024084f9bSBrian Somers 	int			helperSock;
63124084f9bSBrian Somers 	int			bytes;
63224084f9bSBrian Somers 	struct sockaddr_in*	addr;
63324084f9bSBrian Somers 	int			found;
63424084f9bSBrian Somers 	struct ifreq		req;
63524084f9bSBrian Somers 	char			last[10];
63624084f9bSBrian Somers /*
63724084f9bSBrian Somers  * Create a dummy socket to access interface information.
63824084f9bSBrian Somers  */
63924084f9bSBrian Somers 	helperSock = socket (AF_INET, SOCK_DGRAM, 0);
64024084f9bSBrian Somers 	if (helperSock == -1) {
64124084f9bSBrian Somers 
64224084f9bSBrian Somers 		Quit ("Failed to create helper socket.");
64324084f9bSBrian Somers 		exit (1);
64424084f9bSBrian Somers 	}
64524084f9bSBrian Somers 
64624084f9bSBrian Somers 	cf.ifc_len = sizeof (buf);
64724084f9bSBrian Somers 	cf.ifc_req = buf;
64824084f9bSBrian Somers /*
64924084f9bSBrian Somers  * Get interface data.
65024084f9bSBrian Somers  */
65124084f9bSBrian Somers 	if (ioctl (helperSock, SIOCGIFCONF, &cf) == -1) {
65224084f9bSBrian Somers 
65324084f9bSBrian Somers 		Quit ("Ioctl SIOCGIFCONF failed.");
65424084f9bSBrian Somers 		exit (1);
65524084f9bSBrian Somers 	}
65624084f9bSBrian Somers 
65724084f9bSBrian Somers 	ifIndex	= 0;
65824084f9bSBrian Somers 	ifPtr	= buf;
65924084f9bSBrian Somers 	bytes	= cf.ifc_len;
66024084f9bSBrian Somers 	found   = 0;
66124084f9bSBrian Somers 	last[0] = '\0';
66224084f9bSBrian Somers /*
66324084f9bSBrian Somers  * Loop through interfaces until one with
66424084f9bSBrian Somers  * given name is found. This is done to
66524084f9bSBrian Somers  * find correct interface index for routing
66624084f9bSBrian Somers  * message processing.
66724084f9bSBrian Somers  */
66824084f9bSBrian Somers 	while (bytes) {
66924084f9bSBrian Somers 
67024084f9bSBrian Somers 		if (ifPtr->ifr_addr.sa_family == AF_INET &&
67124084f9bSBrian Somers                     !strcmp (ifPtr->ifr_name, ifName)) {
67224084f9bSBrian Somers 
67324084f9bSBrian Somers 			found = 1;
67424084f9bSBrian Somers 			break;
67524084f9bSBrian Somers 		}
67624084f9bSBrian Somers 
67724084f9bSBrian Somers 		if (strcmp (last, ifPtr->ifr_name)) {
67824084f9bSBrian Somers 
67924084f9bSBrian Somers 			strcpy (last, ifPtr->ifr_name);
68024084f9bSBrian Somers 			++ifIndex;
68124084f9bSBrian Somers 		}
68224084f9bSBrian Somers 
68324084f9bSBrian Somers 		extra = ifPtr->ifr_addr.sa_len - sizeof (struct sockaddr);
68424084f9bSBrian Somers 
68524084f9bSBrian Somers 		ifPtr++;
68624084f9bSBrian Somers 		ifPtr = (struct ifreq*) ((char*) ifPtr + extra);
68724084f9bSBrian Somers 		bytes -= sizeof (struct ifreq) + extra;
68824084f9bSBrian Somers 	}
68924084f9bSBrian Somers 
69024084f9bSBrian Somers 	if (!found) {
69124084f9bSBrian Somers 
69224084f9bSBrian Somers 		close (helperSock);
69324084f9bSBrian Somers 		sprintf (msg, "Unknown interface name %s.\n", ifName);
69424084f9bSBrian Somers 		Quit (msg);
69524084f9bSBrian Somers 	}
69624084f9bSBrian Somers /*
69724084f9bSBrian Somers  * Get MTU size.
69824084f9bSBrian Somers  */
69924084f9bSBrian Somers 	strcpy (req.ifr_name, ifName);
70024084f9bSBrian Somers 
70124084f9bSBrian Somers 	if (ioctl (helperSock, SIOCGIFMTU, &req) == -1)
70224084f9bSBrian Somers 		Quit ("Cannot get interface mtu size.");
70324084f9bSBrian Somers 
70424084f9bSBrian Somers 	ifMTU = req.ifr_mtu;
70524084f9bSBrian Somers /*
70624084f9bSBrian Somers  * Get interface address.
70724084f9bSBrian Somers  */
70824084f9bSBrian Somers 	if (ioctl (helperSock, SIOCGIFADDR, &req) == -1)
70924084f9bSBrian Somers 		Quit ("Cannot get interface address.");
71024084f9bSBrian Somers 
71124084f9bSBrian Somers 	addr = (struct sockaddr_in*) &req.ifr_addr;
71224084f9bSBrian Somers 	SetPacketAliasAddress (addr->sin_addr);
71324084f9bSBrian Somers 	syslog (LOG_INFO, "Aliasing to %s, mtu %d bytes",
71424084f9bSBrian Somers 			  inet_ntoa (addr->sin_addr),
71524084f9bSBrian Somers 			  ifMTU);
71624084f9bSBrian Somers 
71724084f9bSBrian Somers 	close (helperSock);
71824084f9bSBrian Somers }
71924084f9bSBrian Somers 
72024084f9bSBrian Somers void Quit (char* msg)
72124084f9bSBrian Somers {
72224084f9bSBrian Somers 	Warn (msg);
72324084f9bSBrian Somers 	exit (1);
72424084f9bSBrian Somers }
72524084f9bSBrian Somers 
72624084f9bSBrian Somers void Warn (char* msg)
72724084f9bSBrian Somers {
72824084f9bSBrian Somers 	if (background)
72924084f9bSBrian Somers 		syslog (LOG_ALERT, "%s (%m)", msg);
73024084f9bSBrian Somers 	else
73124084f9bSBrian Somers 		perror (msg);
73224084f9bSBrian Somers }
73324084f9bSBrian Somers 
73424084f9bSBrian Somers static void RefreshAddr ()
73524084f9bSBrian Somers {
73624084f9bSBrian Somers 	signal (SIGHUP, RefreshAddr);
73724084f9bSBrian Somers 	if (ifName)
73824084f9bSBrian Somers 		assignAliasAddr = 1;
73924084f9bSBrian Somers }
74024084f9bSBrian Somers 
74124084f9bSBrian Somers static void InitiateShutdown ()
74224084f9bSBrian Somers {
74324084f9bSBrian Somers /*
74424084f9bSBrian Somers  * Start timer to allow kernel gracefully
74524084f9bSBrian Somers  * shutdown existing connections when system
74624084f9bSBrian Somers  * is shut down.
74724084f9bSBrian Somers  */
74824084f9bSBrian Somers 	signal (SIGALRM, Shutdown);
74924084f9bSBrian Somers 	alarm (10);
75024084f9bSBrian Somers }
75124084f9bSBrian Somers 
75224084f9bSBrian Somers static void Shutdown ()
75324084f9bSBrian Somers {
75424084f9bSBrian Somers 	running = 0;
75524084f9bSBrian Somers }
75624084f9bSBrian Somers 
75724084f9bSBrian Somers /*
75824084f9bSBrian Somers  * Different options recognized by this program.
75924084f9bSBrian Somers  */
76024084f9bSBrian Somers 
76124084f9bSBrian Somers enum Option {
76224084f9bSBrian Somers 
76324084f9bSBrian Somers 	PacketAliasOption,
76424084f9bSBrian Somers 	Verbose,
76524084f9bSBrian Somers 	InPort,
76624084f9bSBrian Somers 	OutPort,
76724084f9bSBrian Somers 	Port,
76824084f9bSBrian Somers 	AliasAddress,
76924084f9bSBrian Somers 	InterfaceName,
77024084f9bSBrian Somers 	PermanentLink,
77124084f9bSBrian Somers 	RedirectPort,
77224084f9bSBrian Somers 	RedirectAddress,
77324084f9bSBrian Somers 	ConfigFile,
77424084f9bSBrian Somers 	DynamicMode
77524084f9bSBrian Somers };
77624084f9bSBrian Somers 
77724084f9bSBrian Somers enum Param {
77824084f9bSBrian Somers 
77924084f9bSBrian Somers 	YesNo,
78024084f9bSBrian Somers 	Numeric,
78124084f9bSBrian Somers 	String,
78224084f9bSBrian Somers 	None,
78324084f9bSBrian Somers 	Address,
78424084f9bSBrian Somers 	Service
78524084f9bSBrian Somers };
78624084f9bSBrian Somers 
78724084f9bSBrian Somers /*
78824084f9bSBrian Somers  * Option information structure (used by ParseOption).
78924084f9bSBrian Somers  */
79024084f9bSBrian Somers 
79124084f9bSBrian Somers struct OptionInfo {
79224084f9bSBrian Somers 
79324084f9bSBrian Somers 	enum Option		type;
79424084f9bSBrian Somers 	int			packetAliasOpt;
79524084f9bSBrian Somers 	enum Param		parm;
79624084f9bSBrian Somers 	char*			parmDescription;
79724084f9bSBrian Somers 	char*			description;
79824084f9bSBrian Somers 	char*			name;
79924084f9bSBrian Somers 	char*			shortName;
80024084f9bSBrian Somers };
80124084f9bSBrian Somers 
80224084f9bSBrian Somers /*
80324084f9bSBrian Somers  * Table of known options.
80424084f9bSBrian Somers  */
80524084f9bSBrian Somers 
80624084f9bSBrian Somers static struct OptionInfo optionTable[] = {
80724084f9bSBrian Somers 
80824084f9bSBrian Somers 	{ PacketAliasOption,
80924084f9bSBrian Somers 		PKT_ALIAS_UNREGISTERED_ONLY,
81024084f9bSBrian Somers 		YesNo,
81124084f9bSBrian Somers 		"[yes|no]",
81224084f9bSBrian Somers 		"alias only unregistered addresses",
81324084f9bSBrian Somers 		"unregistered_only",
81424084f9bSBrian Somers 		"u" },
81524084f9bSBrian Somers 
81624084f9bSBrian Somers 	{ PacketAliasOption,
81724084f9bSBrian Somers 		PKT_ALIAS_LOG,
81824084f9bSBrian Somers 		YesNo,
81924084f9bSBrian Somers 		"[yes|no]",
82024084f9bSBrian Somers 		"enable logging",
82124084f9bSBrian Somers 		"log",
82224084f9bSBrian Somers 		"l" },
82324084f9bSBrian Somers 
82424084f9bSBrian Somers 	{ PacketAliasOption,
82524084f9bSBrian Somers 		PKT_ALIAS_DENY_INCOMING,
82624084f9bSBrian Somers 		YesNo,
82724084f9bSBrian Somers 		"[yes|no]",
82824084f9bSBrian Somers 		"allow incoming connections",
82924084f9bSBrian Somers 		"deny_incoming",
83024084f9bSBrian Somers 		"d" },
83124084f9bSBrian Somers 
83224084f9bSBrian Somers 	{ PacketAliasOption,
83324084f9bSBrian Somers 		PKT_ALIAS_USE_SOCKETS,
83424084f9bSBrian Somers 		YesNo,
83524084f9bSBrian Somers 		"[yes|no]",
83624084f9bSBrian Somers 		"use sockets to inhibit port conflict",
83724084f9bSBrian Somers 		"use_sockets",
83824084f9bSBrian Somers 		"s" },
83924084f9bSBrian Somers 
84024084f9bSBrian Somers 	{ PacketAliasOption,
84124084f9bSBrian Somers 		PKT_ALIAS_SAME_PORTS,
84224084f9bSBrian Somers 		YesNo,
84324084f9bSBrian Somers 		"[yes|no]",
84424084f9bSBrian Somers 		"try to keep original port numbers for connections",
84524084f9bSBrian Somers 		"same_ports",
84624084f9bSBrian Somers 		"m" },
84724084f9bSBrian Somers 
84824084f9bSBrian Somers 	{ Verbose,
84924084f9bSBrian Somers 		0,
85024084f9bSBrian Somers 		YesNo,
85124084f9bSBrian Somers 		"[yes|no]",
85224084f9bSBrian Somers 		"verbose mode, dump packet information",
85324084f9bSBrian Somers 		"verbose",
85424084f9bSBrian Somers 		"v" },
85524084f9bSBrian Somers 
85624084f9bSBrian Somers 	{ DynamicMode,
85724084f9bSBrian Somers 		0,
85824084f9bSBrian Somers 		YesNo,
85924084f9bSBrian Somers 		"[yes|no]",
86024084f9bSBrian Somers 		"dynamic mode, automatically detect interface address changes",
86124084f9bSBrian Somers 		"dynamic",
86224084f9bSBrian Somers 		NULL },
86324084f9bSBrian Somers 
86424084f9bSBrian Somers 	{ InPort,
86524084f9bSBrian Somers 		0,
86624084f9bSBrian Somers 		Service,
86724084f9bSBrian Somers 		"number|service_name",
86824084f9bSBrian Somers 		"set port for incoming packets",
86924084f9bSBrian Somers 		"in_port",
87024084f9bSBrian Somers 		"i" },
87124084f9bSBrian Somers 
87224084f9bSBrian Somers 	{ OutPort,
87324084f9bSBrian Somers 		0,
87424084f9bSBrian Somers 		Service,
87524084f9bSBrian Somers 		"number|service_name",
87624084f9bSBrian Somers 		"set port for outgoing packets",
87724084f9bSBrian Somers 		"out_port",
87824084f9bSBrian Somers 		"o" },
87924084f9bSBrian Somers 
88024084f9bSBrian Somers 	{ Port,
88124084f9bSBrian Somers 		0,
88224084f9bSBrian Somers 		Service,
88324084f9bSBrian Somers 		"number|service_name",
88424084f9bSBrian Somers 		"set port (defaults to natd/divert)",
88524084f9bSBrian Somers 		"port",
88624084f9bSBrian Somers 		"p" },
88724084f9bSBrian Somers 
88824084f9bSBrian Somers 	{ AliasAddress,
88924084f9bSBrian Somers 		0,
89024084f9bSBrian Somers 		Address,
89124084f9bSBrian Somers 		"x.x.x.x",
89224084f9bSBrian Somers 		"address to use for aliasing",
89324084f9bSBrian Somers 		"alias_address",
89424084f9bSBrian Somers 		"a" },
89524084f9bSBrian Somers 
89624084f9bSBrian Somers 	{ InterfaceName,
89724084f9bSBrian Somers 		0,
89824084f9bSBrian Somers 		String,
89924084f9bSBrian Somers 	        "network_if_name",
90024084f9bSBrian Somers 		"take aliasing address from interface",
90124084f9bSBrian Somers 		"interface",
90224084f9bSBrian Somers 		"n" },
90324084f9bSBrian Somers 
90424084f9bSBrian Somers 	{ PermanentLink,
90524084f9bSBrian Somers 		0,
90624084f9bSBrian Somers 		String,
90724084f9bSBrian Somers 	        "tcp|udp src:port dst:port alias",
90824084f9bSBrian Somers 		"define permanent link for incoming connection",
90924084f9bSBrian Somers 		"permanent_link",
91024084f9bSBrian Somers 		NULL },
91124084f9bSBrian Somers 
91224084f9bSBrian Somers 	{ RedirectPort,
91324084f9bSBrian Somers 		0,
91424084f9bSBrian Somers 		String,
91524084f9bSBrian Somers 	        "tcp|udp local_addr:local_port [public_addr:]public_port"
91624084f9bSBrian Somers 	 	" [remote_addr[:remote_port]]",
91724084f9bSBrian Somers 		"redirect a port for incoming traffic",
91824084f9bSBrian Somers 		"redirect_port",
91924084f9bSBrian Somers 		NULL },
92024084f9bSBrian Somers 
92124084f9bSBrian Somers 	{ RedirectAddress,
92224084f9bSBrian Somers 		0,
92324084f9bSBrian Somers 		String,
92424084f9bSBrian Somers 	        "local_addr public_addr",
92524084f9bSBrian Somers 		"define mapping between local and public addresses",
92624084f9bSBrian Somers 		"redirect_address",
92724084f9bSBrian Somers 		NULL },
92824084f9bSBrian Somers 
92924084f9bSBrian Somers 	{ ConfigFile,
93024084f9bSBrian Somers 		0,
93124084f9bSBrian Somers 		String,
93224084f9bSBrian Somers 		"file_name",
93324084f9bSBrian Somers 		"read options from configuration file",
93424084f9bSBrian Somers 		"config",
93524084f9bSBrian Somers 		"f" }
93624084f9bSBrian Somers };
93724084f9bSBrian Somers 
93824084f9bSBrian Somers static void ParseOption (char* option, char* parms, int cmdLine)
93924084f9bSBrian Somers {
94024084f9bSBrian Somers 	int			i;
94124084f9bSBrian Somers 	struct OptionInfo*	info;
94224084f9bSBrian Somers 	int			yesNoValue;
94324084f9bSBrian Somers 	int			aliasValue;
94424084f9bSBrian Somers 	int			numValue;
94524084f9bSBrian Somers 	char*			strValue;
94624084f9bSBrian Somers 	struct in_addr		addrValue;
94724084f9bSBrian Somers 	int			max;
94824084f9bSBrian Somers 	char*			end;
94924084f9bSBrian Somers /*
95024084f9bSBrian Somers  * Find option from table.
95124084f9bSBrian Somers  */
95224084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
95324084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
95424084f9bSBrian Somers 
95524084f9bSBrian Somers 		if (!strcmp (info->name, option))
95624084f9bSBrian Somers 			break;
95724084f9bSBrian Somers 
95824084f9bSBrian Somers 		if (info->shortName)
95924084f9bSBrian Somers 			if (!strcmp (info->shortName, option))
96024084f9bSBrian Somers 				break;
96124084f9bSBrian Somers 	}
96224084f9bSBrian Somers 
96324084f9bSBrian Somers 	if (i >= max) {
96424084f9bSBrian Somers 
96524084f9bSBrian Somers 		fprintf (stderr, "Unknown option %s.\n", option);
96624084f9bSBrian Somers 		Usage ();
96724084f9bSBrian Somers 	}
96824084f9bSBrian Somers 
96924084f9bSBrian Somers 	yesNoValue	= 0;
97024084f9bSBrian Somers 	numValue	= 0;
97124084f9bSBrian Somers 	strValue	= NULL;
97224084f9bSBrian Somers /*
97324084f9bSBrian Somers  * Check parameters.
97424084f9bSBrian Somers  */
97524084f9bSBrian Somers 	switch (info->parm) {
97624084f9bSBrian Somers 	case YesNo:
97724084f9bSBrian Somers 		if (!parms)
97824084f9bSBrian Somers 			parms = "yes";
97924084f9bSBrian Somers 
98024084f9bSBrian Somers 		if (!strcmp (parms, "yes"))
98124084f9bSBrian Somers 			yesNoValue = 1;
98224084f9bSBrian Somers 		else
98324084f9bSBrian Somers 			if (!strcmp (parms, "no"))
98424084f9bSBrian Somers 				yesNoValue = 0;
98524084f9bSBrian Somers 			else {
98624084f9bSBrian Somers 
98724084f9bSBrian Somers 				fprintf (stderr, "%s needs yes/no parameter.\n",
98824084f9bSBrian Somers 						 option);
98924084f9bSBrian Somers 				exit (1);
99024084f9bSBrian Somers 			}
99124084f9bSBrian Somers 		break;
99224084f9bSBrian Somers 
99324084f9bSBrian Somers 	case Service:
99424084f9bSBrian Somers 		if (!parms) {
99524084f9bSBrian Somers 
99624084f9bSBrian Somers 			fprintf (stderr, "%s needs service name or "
99724084f9bSBrian Somers 					 "port number  parameter.\n",
99824084f9bSBrian Somers 					 option);
99924084f9bSBrian Somers 			exit (1);
100024084f9bSBrian Somers 		}
100124084f9bSBrian Somers 
100224084f9bSBrian Somers 		numValue = StrToPort (parms, "divert");
100324084f9bSBrian Somers 		break;
100424084f9bSBrian Somers 
100524084f9bSBrian Somers 	case Numeric:
100624084f9bSBrian Somers 		if (parms)
100724084f9bSBrian Somers 			numValue = strtol (parms, &end, 10);
100824084f9bSBrian Somers 		else
100924084f9bSBrian Somers 			end = parms;
101024084f9bSBrian Somers 
101124084f9bSBrian Somers 		if (end == parms) {
101224084f9bSBrian Somers 
101324084f9bSBrian Somers 			fprintf (stderr, "%s needs numeric parameter.\n",
101424084f9bSBrian Somers 					 option);
101524084f9bSBrian Somers 			exit (1);
101624084f9bSBrian Somers 		}
101724084f9bSBrian Somers 		break;
101824084f9bSBrian Somers 
101924084f9bSBrian Somers 	case String:
102024084f9bSBrian Somers 		strValue = parms;
102124084f9bSBrian Somers 		if (!strValue) {
102224084f9bSBrian Somers 
102324084f9bSBrian Somers 			fprintf (stderr, "%s needs parameter.\n",
102424084f9bSBrian Somers 					 option);
102524084f9bSBrian Somers 			exit (1);
102624084f9bSBrian Somers 		}
102724084f9bSBrian Somers 		break;
102824084f9bSBrian Somers 
102924084f9bSBrian Somers 	case None:
103024084f9bSBrian Somers 		if (parms) {
103124084f9bSBrian Somers 
103224084f9bSBrian Somers 			fprintf (stderr, "%s does not take parameters.\n",
103324084f9bSBrian Somers 					 option);
103424084f9bSBrian Somers 			exit (1);
103524084f9bSBrian Somers 		}
103624084f9bSBrian Somers 		break;
103724084f9bSBrian Somers 
103824084f9bSBrian Somers 	case Address:
103924084f9bSBrian Somers 		if (!parms) {
104024084f9bSBrian Somers 
104124084f9bSBrian Somers 			fprintf (stderr, "%s needs address/host parameter.\n",
104224084f9bSBrian Somers 					 option);
104324084f9bSBrian Somers 			exit (1);
104424084f9bSBrian Somers 		}
104524084f9bSBrian Somers 
104624084f9bSBrian Somers 		StrToAddr (parms, &addrValue);
104724084f9bSBrian Somers 		break;
104824084f9bSBrian Somers 	}
104924084f9bSBrian Somers 
105024084f9bSBrian Somers 	switch (info->type) {
105124084f9bSBrian Somers 	case PacketAliasOption:
105224084f9bSBrian Somers 
105324084f9bSBrian Somers 		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1054fb994b07SBrian Somers 		PacketAliasSetMode (aliasValue, info->packetAliasOpt);
105524084f9bSBrian Somers 		break;
105624084f9bSBrian Somers 
105724084f9bSBrian Somers 	case Verbose:
105824084f9bSBrian Somers 		verbose = yesNoValue;
105924084f9bSBrian Somers 		break;
106024084f9bSBrian Somers 
106124084f9bSBrian Somers 	case DynamicMode:
106224084f9bSBrian Somers 		dynamicMode = yesNoValue;
106324084f9bSBrian Somers 		break;
106424084f9bSBrian Somers 
106524084f9bSBrian Somers 	case InPort:
106624084f9bSBrian Somers 		inPort = numValue;
106724084f9bSBrian Somers 		break;
106824084f9bSBrian Somers 
106924084f9bSBrian Somers 	case OutPort:
107024084f9bSBrian Somers 		outPort = numValue;
107124084f9bSBrian Somers 		break;
107224084f9bSBrian Somers 
107324084f9bSBrian Somers 	case Port:
107424084f9bSBrian Somers 		inOutPort = numValue;
107524084f9bSBrian Somers 		break;
107624084f9bSBrian Somers 
107724084f9bSBrian Somers 	case AliasAddress:
107824084f9bSBrian Somers 		memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
107924084f9bSBrian Somers 		break;
108024084f9bSBrian Somers 
108124084f9bSBrian Somers 	case PermanentLink:
108224084f9bSBrian Somers 		SetupPermanentLink (strValue);
108324084f9bSBrian Somers 		break;
108424084f9bSBrian Somers 
108524084f9bSBrian Somers 	case RedirectPort:
108624084f9bSBrian Somers 		SetupPortRedirect (strValue);
108724084f9bSBrian Somers 		break;
108824084f9bSBrian Somers 
108924084f9bSBrian Somers 	case RedirectAddress:
109024084f9bSBrian Somers 		SetupAddressRedirect (strValue);
109124084f9bSBrian Somers 		break;
109224084f9bSBrian Somers 
109324084f9bSBrian Somers 	case InterfaceName:
109424084f9bSBrian Somers 		if (ifName)
109524084f9bSBrian Somers 			free (ifName);
109624084f9bSBrian Somers 
109724084f9bSBrian Somers 		ifName = strdup (strValue);
109824084f9bSBrian Somers 		assignAliasAddr = 1;
109924084f9bSBrian Somers 		break;
110024084f9bSBrian Somers 
110124084f9bSBrian Somers 	case ConfigFile:
110224084f9bSBrian Somers 		ReadConfigFile (strValue);
110324084f9bSBrian Somers 		break;
110424084f9bSBrian Somers 	}
110524084f9bSBrian Somers }
110624084f9bSBrian Somers 
110724084f9bSBrian Somers void ReadConfigFile (char* fileName)
110824084f9bSBrian Somers {
110924084f9bSBrian Somers 	FILE*	file;
111024084f9bSBrian Somers 	char	buf[128];
111124084f9bSBrian Somers 	char*	ptr;
111224084f9bSBrian Somers 	char*	option;
111324084f9bSBrian Somers 
111424084f9bSBrian Somers 	file = fopen (fileName, "r");
111524084f9bSBrian Somers 	if (!file) {
111624084f9bSBrian Somers 
111724084f9bSBrian Somers 		sprintf (buf, "Cannot open config file %s.\n", fileName);
111824084f9bSBrian Somers 		Quit (buf);
111924084f9bSBrian Somers 	}
112024084f9bSBrian Somers 
112124084f9bSBrian Somers 	while (fgets (buf, sizeof (buf), file)) {
112224084f9bSBrian Somers 
112324084f9bSBrian Somers 		ptr = strchr (buf, '\n');
112424084f9bSBrian Somers 		if (!ptr) {
112524084f9bSBrian Somers 
112624084f9bSBrian Somers 			fprintf (stderr, "config line too link: %s\n", buf);
112724084f9bSBrian Somers 			exit (1);
112824084f9bSBrian Somers 		}
112924084f9bSBrian Somers 
113024084f9bSBrian Somers 		*ptr = '\0';
113124084f9bSBrian Somers 		if (buf[0] == '#')
113224084f9bSBrian Somers 			continue;
113324084f9bSBrian Somers 
113424084f9bSBrian Somers 		ptr = buf;
113524084f9bSBrian Somers /*
113624084f9bSBrian Somers  * Skip white space at beginning of line.
113724084f9bSBrian Somers  */
113824084f9bSBrian Somers 		while (*ptr && isspace (*ptr))
113924084f9bSBrian Somers 			++ptr;
114024084f9bSBrian Somers 
114124084f9bSBrian Somers 		if (*ptr == '\0')
114224084f9bSBrian Somers 			continue;
114324084f9bSBrian Somers /*
114424084f9bSBrian Somers  * Extract option name.
114524084f9bSBrian Somers  */
114624084f9bSBrian Somers 		option = ptr;
114724084f9bSBrian Somers 		while (*ptr && !isspace (*ptr))
114824084f9bSBrian Somers 			++ptr;
114924084f9bSBrian Somers 
115024084f9bSBrian Somers 		if (*ptr != '\0') {
115124084f9bSBrian Somers 
115224084f9bSBrian Somers 			*ptr = '\0';
115324084f9bSBrian Somers 			++ptr;
115424084f9bSBrian Somers 		}
115524084f9bSBrian Somers /*
115624084f9bSBrian Somers  * Skip white space between name and parms.
115724084f9bSBrian Somers  */
115824084f9bSBrian Somers 		while (*ptr && isspace (*ptr))
115924084f9bSBrian Somers 			++ptr;
116024084f9bSBrian Somers 
116124084f9bSBrian Somers 		ParseOption (option, *ptr ? ptr : NULL, 0);
116224084f9bSBrian Somers 	}
116324084f9bSBrian Somers 
116424084f9bSBrian Somers 	fclose (file);
116524084f9bSBrian Somers }
116624084f9bSBrian Somers 
116724084f9bSBrian Somers static void Usage ()
116824084f9bSBrian Somers {
116924084f9bSBrian Somers 	int			i;
117024084f9bSBrian Somers 	int			max;
117124084f9bSBrian Somers 	struct OptionInfo*	info;
117224084f9bSBrian Somers 
117324084f9bSBrian Somers 	fprintf (stderr, "Recognized options:\n\n");
117424084f9bSBrian Somers 
117524084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
117624084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
117724084f9bSBrian Somers 
117824084f9bSBrian Somers 		fprintf (stderr, "-%-20s %s\n", info->name,
117924084f9bSBrian Somers 						info->parmDescription);
118024084f9bSBrian Somers 
118124084f9bSBrian Somers 		if (info->shortName)
118224084f9bSBrian Somers 			fprintf (stderr, "-%-20s %s\n", info->shortName,
118324084f9bSBrian Somers 							info->parmDescription);
118424084f9bSBrian Somers 
118524084f9bSBrian Somers 		fprintf (stderr, "      %s\n\n", info->description);
118624084f9bSBrian Somers 	}
118724084f9bSBrian Somers 
118824084f9bSBrian Somers 	exit (1);
118924084f9bSBrian Somers }
119024084f9bSBrian Somers 
119124084f9bSBrian Somers void SetupPermanentLink (char* parms)
119224084f9bSBrian Somers {
119324084f9bSBrian Somers 	char		buf[128];
119424084f9bSBrian Somers 	char*		ptr;
119524084f9bSBrian Somers 	struct in_addr	srcAddr;
119624084f9bSBrian Somers 	struct in_addr	dstAddr;
119724084f9bSBrian Somers 	int		srcPort;
119824084f9bSBrian Somers 	int		dstPort;
119924084f9bSBrian Somers 	int		aliasPort;
120024084f9bSBrian Somers 	int		proto;
120124084f9bSBrian Somers 	char*		protoName;
120224084f9bSBrian Somers 
120324084f9bSBrian Somers 	strcpy (buf, parms);
120424084f9bSBrian Somers /*
120524084f9bSBrian Somers  * Extract protocol.
120624084f9bSBrian Somers  */
120724084f9bSBrian Somers 	protoName = strtok (buf, " \t");
120824084f9bSBrian Somers 	if (!protoName) {
120924084f9bSBrian Somers 
121024084f9bSBrian Somers 		fprintf (stderr, "permanent_link: missing protocol.\n");
121124084f9bSBrian Somers 		exit (1);
121224084f9bSBrian Somers 	}
121324084f9bSBrian Somers 
121424084f9bSBrian Somers 	proto = StrToProto (protoName);
121524084f9bSBrian Somers /*
121624084f9bSBrian Somers  * Extract source address.
121724084f9bSBrian Somers  */
121824084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
121924084f9bSBrian Somers 	if (!ptr) {
122024084f9bSBrian Somers 
122124084f9bSBrian Somers 		fprintf (stderr, "permanent_link: missing src address.\n");
122224084f9bSBrian Somers 		exit (1);
122324084f9bSBrian Somers 	}
122424084f9bSBrian Somers 
122524084f9bSBrian Somers 	srcPort = StrToAddrAndPort (ptr, &srcAddr, protoName);
122624084f9bSBrian Somers /*
122724084f9bSBrian Somers  * Extract destination address.
122824084f9bSBrian Somers  */
122924084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
123024084f9bSBrian Somers 	if (!ptr) {
123124084f9bSBrian Somers 
123224084f9bSBrian Somers 		fprintf (stderr, "permanent_link: missing dst address.\n");
123324084f9bSBrian Somers 		exit (1);
123424084f9bSBrian Somers 	}
123524084f9bSBrian Somers 
123624084f9bSBrian Somers 	dstPort = StrToAddrAndPort (ptr, &dstAddr, protoName);
123724084f9bSBrian Somers /*
123824084f9bSBrian Somers  * Export alias port.
123924084f9bSBrian Somers  */
124024084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
124124084f9bSBrian Somers 	if (!ptr) {
124224084f9bSBrian Somers 
124324084f9bSBrian Somers 		fprintf (stderr, "permanent_link: missing alias port.\n");
124424084f9bSBrian Somers 		exit (1);
124524084f9bSBrian Somers 	}
124624084f9bSBrian Somers 
124724084f9bSBrian Somers 	aliasPort = StrToPort (ptr, protoName);
124824084f9bSBrian Somers 
124924084f9bSBrian Somers 	PacketAliasPermanentLink (srcAddr,
125024084f9bSBrian Somers 				  srcPort,
125124084f9bSBrian Somers 				  dstAddr,
125224084f9bSBrian Somers 				  dstPort,
125324084f9bSBrian Somers 				  aliasPort,
125424084f9bSBrian Somers 				  proto);
125524084f9bSBrian Somers }
125624084f9bSBrian Somers 
125724084f9bSBrian Somers void SetupPortRedirect (char* parms)
125824084f9bSBrian Somers {
125924084f9bSBrian Somers 	char		buf[128];
126024084f9bSBrian Somers 	char*		ptr;
126124084f9bSBrian Somers 	struct in_addr	localAddr;
126224084f9bSBrian Somers 	struct in_addr	publicAddr;
126324084f9bSBrian Somers 	struct in_addr	remoteAddr;
126424084f9bSBrian Somers 	int		localPort;
126524084f9bSBrian Somers 	int		publicPort;
126624084f9bSBrian Somers 	int		remotePort;
126724084f9bSBrian Somers 	int		proto;
126824084f9bSBrian Somers 	char*		protoName;
126924084f9bSBrian Somers 	char*		separator;
127024084f9bSBrian Somers 
127124084f9bSBrian Somers 	strcpy (buf, parms);
127224084f9bSBrian Somers /*
127324084f9bSBrian Somers  * Extract protocol.
127424084f9bSBrian Somers  */
127524084f9bSBrian Somers 	protoName = strtok (buf, " \t");
127624084f9bSBrian Somers 	if (!protoName) {
127724084f9bSBrian Somers 
127824084f9bSBrian Somers 		fprintf (stderr, "redirect_port: missing protocol.\n");
127924084f9bSBrian Somers 		exit (1);
128024084f9bSBrian Somers 	}
128124084f9bSBrian Somers 
128224084f9bSBrian Somers 	proto = StrToProto (protoName);
128324084f9bSBrian Somers /*
128424084f9bSBrian Somers  * Extract local address.
128524084f9bSBrian Somers  */
128624084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
128724084f9bSBrian Somers 	if (!ptr) {
128824084f9bSBrian Somers 
128924084f9bSBrian Somers 		fprintf (stderr, "redirect_port: missing local address.\n");
129024084f9bSBrian Somers 		exit (1);
129124084f9bSBrian Somers 	}
129224084f9bSBrian Somers 
129324084f9bSBrian Somers 	localPort = StrToAddrAndPort (ptr, &localAddr, protoName);
129424084f9bSBrian Somers /*
129524084f9bSBrian Somers  * Extract public port and optinally address.
129624084f9bSBrian Somers  */
129724084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
129824084f9bSBrian Somers 	if (!ptr) {
129924084f9bSBrian Somers 
130024084f9bSBrian Somers 		fprintf (stderr, "redirect_port: missing public port.\n");
130124084f9bSBrian Somers 		exit (1);
130224084f9bSBrian Somers 	}
130324084f9bSBrian Somers 
130424084f9bSBrian Somers 	separator = strchr (ptr, ':');
130524084f9bSBrian Somers 	if (separator)
130624084f9bSBrian Somers 		publicPort = StrToAddrAndPort (ptr, &publicAddr, protoName);
130724084f9bSBrian Somers 	else {
130824084f9bSBrian Somers 
130924084f9bSBrian Somers 		publicAddr.s_addr = INADDR_ANY;
131024084f9bSBrian Somers 		publicPort = StrToPort (ptr, protoName);
131124084f9bSBrian Somers 	}
131224084f9bSBrian Somers 
131324084f9bSBrian Somers /*
131424084f9bSBrian Somers  * Extract remote address and optionally port.
131524084f9bSBrian Somers  */
131624084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
131724084f9bSBrian Somers 	if (ptr) {
131824084f9bSBrian Somers 
131924084f9bSBrian Somers 
132024084f9bSBrian Somers 		separator = strchr (ptr, ':');
132124084f9bSBrian Somers 		if (separator)
132224084f9bSBrian Somers 			remotePort = StrToAddrAndPort (ptr,
132324084f9bSBrian Somers 						       &remoteAddr,
132424084f9bSBrian Somers 						       protoName);
132524084f9bSBrian Somers 		else {
132624084f9bSBrian Somers 
132724084f9bSBrian Somers 			remotePort = 0;
132824084f9bSBrian Somers 			StrToAddr (ptr, &remoteAddr);
132924084f9bSBrian Somers 		}
133024084f9bSBrian Somers 	}
133124084f9bSBrian Somers 	else {
133224084f9bSBrian Somers 
133324084f9bSBrian Somers 		remotePort = 0;
133424084f9bSBrian Somers 		remoteAddr.s_addr = INADDR_ANY;
133524084f9bSBrian Somers 	}
133624084f9bSBrian Somers 
133724084f9bSBrian Somers 	PacketAliasRedirectPort (localAddr,
133824084f9bSBrian Somers 				 localPort,
133924084f9bSBrian Somers 				 remoteAddr,
134024084f9bSBrian Somers 				 remotePort,
134124084f9bSBrian Somers 				 publicAddr,
134224084f9bSBrian Somers 				 publicPort,
134324084f9bSBrian Somers 				 proto);
134424084f9bSBrian Somers }
134524084f9bSBrian Somers 
134624084f9bSBrian Somers void SetupAddressRedirect (char* parms)
134724084f9bSBrian Somers {
134824084f9bSBrian Somers 	char		buf[128];
134924084f9bSBrian Somers 	char*		ptr;
135024084f9bSBrian Somers 	struct in_addr	localAddr;
135124084f9bSBrian Somers 	struct in_addr	publicAddr;
135224084f9bSBrian Somers 
135324084f9bSBrian Somers 	strcpy (buf, parms);
135424084f9bSBrian Somers /*
135524084f9bSBrian Somers  * Extract local address.
135624084f9bSBrian Somers  */
135724084f9bSBrian Somers 	ptr = strtok (buf, " \t");
135824084f9bSBrian Somers 	if (!ptr) {
135924084f9bSBrian Somers 
136024084f9bSBrian Somers 		fprintf (stderr, "redirect_address: missing local address.\n");
136124084f9bSBrian Somers 		exit (1);
136224084f9bSBrian Somers 	}
136324084f9bSBrian Somers 
136424084f9bSBrian Somers 	StrToAddr (ptr, &localAddr);
136524084f9bSBrian Somers /*
136624084f9bSBrian Somers  * Extract public address.
136724084f9bSBrian Somers  */
136824084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
136924084f9bSBrian Somers 	if (!ptr) {
137024084f9bSBrian Somers 
137124084f9bSBrian Somers 		fprintf (stderr, "redirect_address: missing public address.\n");
137224084f9bSBrian Somers 		exit (1);
137324084f9bSBrian Somers 	}
137424084f9bSBrian Somers 
137524084f9bSBrian Somers 	StrToAddr (ptr, &publicAddr);
137624084f9bSBrian Somers 	PacketAliasRedirectAddr (localAddr, publicAddr);
137724084f9bSBrian Somers }
137824084f9bSBrian Somers 
137924084f9bSBrian Somers void StrToAddr (char* str, struct in_addr* addr)
138024084f9bSBrian Somers {
138124084f9bSBrian Somers 	struct hostent* hp;
138224084f9bSBrian Somers 
138324084f9bSBrian Somers 	if (inet_aton (str, addr))
138424084f9bSBrian Somers 		return;
138524084f9bSBrian Somers 
138624084f9bSBrian Somers 	hp = gethostbyname (str);
138724084f9bSBrian Somers 	if (!hp) {
138824084f9bSBrian Somers 
138924084f9bSBrian Somers 		fprintf (stderr, "Unknown host %s.\n", str);
139024084f9bSBrian Somers 		exit (1);
139124084f9bSBrian Somers 	}
139224084f9bSBrian Somers 
139324084f9bSBrian Somers 	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
139424084f9bSBrian Somers }
139524084f9bSBrian Somers 
139624084f9bSBrian Somers int StrToPort (char* str, char* proto)
139724084f9bSBrian Somers {
139824084f9bSBrian Somers 	int		port;
139924084f9bSBrian Somers 	struct servent*	sp;
140024084f9bSBrian Somers 	char*		end;
140124084f9bSBrian Somers 
140224084f9bSBrian Somers 	port = strtol (str, &end, 10);
140324084f9bSBrian Somers 	if (end != str)
140424084f9bSBrian Somers 		return htons (port);
140524084f9bSBrian Somers 
140624084f9bSBrian Somers 	sp = getservbyname (str, proto);
140724084f9bSBrian Somers 	if (!sp) {
140824084f9bSBrian Somers 
140924084f9bSBrian Somers 		fprintf (stderr, "Unknown service %s/%s.\n",
141024084f9bSBrian Somers 				 str, proto);
141124084f9bSBrian Somers 		exit (1);
141224084f9bSBrian Somers 	}
141324084f9bSBrian Somers 
141424084f9bSBrian Somers 	return sp->s_port;
141524084f9bSBrian Somers }
141624084f9bSBrian Somers 
141724084f9bSBrian Somers int StrToProto (char* str)
141824084f9bSBrian Somers {
141924084f9bSBrian Somers 	if (!strcmp (str, "tcp"))
142024084f9bSBrian Somers 		return IPPROTO_TCP;
142124084f9bSBrian Somers 
142224084f9bSBrian Somers 	if (!strcmp (str, "udp"))
142324084f9bSBrian Somers 		return IPPROTO_UDP;
142424084f9bSBrian Somers 
142524084f9bSBrian Somers 	fprintf (stderr, "Unknown protocol %s. Expected tcp or udp.\n", str);
142624084f9bSBrian Somers 	exit (1);
142724084f9bSBrian Somers }
142824084f9bSBrian Somers 
142924084f9bSBrian Somers int StrToAddrAndPort (char* str, struct in_addr* addr, char* proto)
143024084f9bSBrian Somers {
143124084f9bSBrian Somers 	char*	ptr;
143224084f9bSBrian Somers 
143324084f9bSBrian Somers 	ptr = strchr (str, ':');
143424084f9bSBrian Somers 	if (!ptr) {
143524084f9bSBrian Somers 
143624084f9bSBrian Somers 		fprintf (stderr, "%s is missing port number.\n", str);
143724084f9bSBrian Somers 		exit (1);
143824084f9bSBrian Somers 	}
143924084f9bSBrian Somers 
144024084f9bSBrian Somers 	*ptr = '\0';
144124084f9bSBrian Somers 	++ptr;
144224084f9bSBrian Somers 
144324084f9bSBrian Somers 	StrToAddr (str, addr);
144424084f9bSBrian Somers 	return StrToPort (ptr, proto);
144524084f9bSBrian Somers }
144624084f9bSBrian Somers 
1447