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