xref: /freebsd/sbin/natd/natd.c (revision f13f9fada747ab4c953b849aadf4d155e671279f)
124084f9bSBrian Somers /*
224084f9bSBrian Somers  * natd - Network Address Translation Daemon for FreeBSD.
324084f9bSBrian Somers  *
4f13f9fadSAlexander Langer  * This software is provided free of charge, with no
524084f9bSBrian Somers  * warranty of any kind, either expressed or implied.
624084f9bSBrian Somers  * Use at your own risk.
724084f9bSBrian Somers  *
824084f9bSBrian Somers  * You may copy, modify and distribute this software (natd.c) freely.
924084f9bSBrian Somers  *
10fb994b07SBrian Somers  * Ari Suutari <suutari@iki.fi>
1124084f9bSBrian Somers  *
12f13f9fadSAlexander Langer  * $Id$
1324084f9bSBrian Somers  */
1424084f9bSBrian Somers 
1524084f9bSBrian Somers #include <sys/types.h>
1624084f9bSBrian Somers #include <sys/socket.h>
1724084f9bSBrian Somers #include <sys/time.h>
1824084f9bSBrian Somers 
1924084f9bSBrian Somers #include <netinet/in.h>
2024084f9bSBrian Somers #include <netinet/in_systm.h>
2124084f9bSBrian Somers #include <netinet/ip.h>
2224084f9bSBrian Somers #include <machine/in_cksum.h>
2324084f9bSBrian Somers #include <netinet/tcp.h>
2424084f9bSBrian Somers #include <sys/ioctl.h>
2524084f9bSBrian Somers #include <net/if.h>
2624084f9bSBrian Somers #include <net/route.h>
2724084f9bSBrian Somers #include <arpa/inet.h>
2824084f9bSBrian Somers 
2924084f9bSBrian Somers #include <alias.h>
300fc81af1SPhilippe Charnier #include <ctype.h>
310fc81af1SPhilippe Charnier #include <err.h>
320fc81af1SPhilippe Charnier #include <errno.h>
330fc81af1SPhilippe Charnier #include <netdb.h>
340fc81af1SPhilippe Charnier #include <signal.h>
350fc81af1SPhilippe Charnier #include <stdio.h>
360fc81af1SPhilippe Charnier #include <stdlib.h>
370fc81af1SPhilippe Charnier #include <string.h>
380fc81af1SPhilippe Charnier #include <syslog.h>
390fc81af1SPhilippe Charnier #include <unistd.h>
4067a886fbSBrian 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);
6967a886fbSBrian Somers static u_short  StrToPort (char* str, char* proto);
7024084f9bSBrian Somers static int 	StrToProto (char* str);
7167a886fbSBrian Somers static u_short  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;
8567a886fbSBrian Somers static	u_short			inPort;
8667a886fbSBrian Somers static	u_short			outPort;
8767a886fbSBrian Somers static	u_short			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  */
1390fc81af1SPhilippe Charnier 	if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL)
1400fc81af1SPhilippe Charnier 		errx (1, "aliasing address not given");
14124084f9bSBrian Somers 
1420fc81af1SPhilippe Charnier 	if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL)
14367a886fbSBrian Somers 		errx (1, "both alias address and interface "
14467a886fbSBrian Somers 			 "name are not allowed");
14524084f9bSBrian Somers /*
14624084f9bSBrian Somers  * Check that valid port number is known.
14724084f9bSBrian Somers  */
14824084f9bSBrian Somers 	if (inPort != 0 || outPort != 0)
1490fc81af1SPhilippe Charnier 		if (inPort == 0 || outPort == 0)
1500fc81af1SPhilippe Charnier 			errx (1, "both input and output ports are required");
15124084f9bSBrian Somers 
15224084f9bSBrian Somers 	if (inPort == 0 && outPort == 0 && inOutPort == 0)
15324084f9bSBrian Somers 		ParseOption ("port", DEFAULT_SERVICE, 0);
15424084f9bSBrian Somers 
15524084f9bSBrian Somers /*
156f9b06d5cSBrian Somers  * Check if ignored packets should be dropped.
157f9b06d5cSBrian Somers  */
158f9b06d5cSBrian Somers 	dropIgnoredIncoming = PacketAliasSetMode (0, 0);
159f9b06d5cSBrian Somers 	dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING;
160f9b06d5cSBrian Somers /*
16124084f9bSBrian Somers  * Create divert sockets. Use only one socket if -p was specified
16224084f9bSBrian Somers  * on command line. Otherwise, create separate sockets for
16324084f9bSBrian Somers  * outgoing and incoming connnections.
16424084f9bSBrian Somers  */
16524084f9bSBrian Somers 	if (inOutPort) {
16624084f9bSBrian Somers 
16724084f9bSBrian Somers 		divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
16824084f9bSBrian Somers 		if (divertInOut == -1)
16924084f9bSBrian Somers 			Quit ("Unable to create divert socket.");
17024084f9bSBrian Somers 
17124084f9bSBrian Somers 		divertIn  = -1;
17224084f9bSBrian Somers 		divertOut = -1;
17324084f9bSBrian Somers /*
17424084f9bSBrian Somers  * Bind socket.
17524084f9bSBrian Somers  */
17624084f9bSBrian Somers 
17724084f9bSBrian Somers 		addr.sin_family		= AF_INET;
17824084f9bSBrian Somers 		addr.sin_addr.s_addr	= INADDR_ANY;
17924084f9bSBrian Somers 		addr.sin_port		= inOutPort;
18024084f9bSBrian Somers 
18124084f9bSBrian Somers 		if (bind (divertInOut,
18224084f9bSBrian Somers 			  (struct sockaddr*) &addr,
18324084f9bSBrian Somers 			  sizeof addr) == -1)
18424084f9bSBrian Somers 			Quit ("Unable to bind divert socket.");
18524084f9bSBrian Somers 	}
18624084f9bSBrian Somers 	else {
18724084f9bSBrian Somers 
18824084f9bSBrian Somers 		divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
18924084f9bSBrian Somers 		if (divertIn == -1)
19024084f9bSBrian Somers 			Quit ("Unable to create incoming divert socket.");
19124084f9bSBrian Somers 
19224084f9bSBrian Somers 		divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT);
19324084f9bSBrian Somers 		if (divertOut == -1)
19424084f9bSBrian Somers 			Quit ("Unable to create outgoing divert socket.");
19524084f9bSBrian Somers 
19624084f9bSBrian Somers 		divertInOut = -1;
19724084f9bSBrian Somers 
19824084f9bSBrian Somers /*
19924084f9bSBrian Somers  * Bind divert sockets.
20024084f9bSBrian Somers  */
20124084f9bSBrian Somers 
20224084f9bSBrian Somers 		addr.sin_family		= AF_INET;
20324084f9bSBrian Somers 		addr.sin_addr.s_addr	= INADDR_ANY;
20424084f9bSBrian Somers 		addr.sin_port		= inPort;
20524084f9bSBrian Somers 
20624084f9bSBrian Somers 		if (bind (divertIn,
20724084f9bSBrian Somers 			  (struct sockaddr*) &addr,
20824084f9bSBrian Somers 			  sizeof addr) == -1)
20924084f9bSBrian Somers 			Quit ("Unable to bind incoming divert socket.");
21024084f9bSBrian Somers 
21124084f9bSBrian Somers 		addr.sin_family		= AF_INET;
21224084f9bSBrian Somers 		addr.sin_addr.s_addr	= INADDR_ANY;
21324084f9bSBrian Somers 		addr.sin_port		= outPort;
21424084f9bSBrian Somers 
21524084f9bSBrian Somers 		if (bind (divertOut,
21624084f9bSBrian Somers 			  (struct sockaddr*) &addr,
21724084f9bSBrian Somers 			  sizeof addr) == -1)
21824084f9bSBrian Somers 			Quit ("Unable to bind outgoing divert socket.");
21924084f9bSBrian Somers 	}
22024084f9bSBrian Somers /*
22124084f9bSBrian Somers  * Create routing socket if interface name specified.
22224084f9bSBrian Somers  */
22324084f9bSBrian Somers 	if (ifName && dynamicMode) {
22424084f9bSBrian Somers 
22524084f9bSBrian Somers 		routeSock = socket (PF_ROUTE, SOCK_RAW, 0);
22624084f9bSBrian Somers 		if (routeSock == -1)
22724084f9bSBrian Somers 			Quit ("Unable to create routing info socket.");
22824084f9bSBrian Somers 	}
22924084f9bSBrian Somers 	else
23024084f9bSBrian Somers 		routeSock = -1;
23124084f9bSBrian Somers /*
23224084f9bSBrian Somers  * Create socket for sending ICMP messages.
23324084f9bSBrian Somers  */
23424084f9bSBrian Somers 	icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
23524084f9bSBrian Somers 	if (icmpSock == -1)
23624084f9bSBrian Somers 		Quit ("Unable to create ICMP socket.");
23724084f9bSBrian Somers /*
23824084f9bSBrian Somers  * Become a daemon unless verbose mode was requested.
23924084f9bSBrian Somers  */
24024084f9bSBrian Somers 	if (!verbose)
24124084f9bSBrian Somers 		DaemonMode ();
24224084f9bSBrian Somers /*
24324084f9bSBrian Somers  * Catch signals to manage shutdown and
24424084f9bSBrian Somers  * refresh of interface address.
24524084f9bSBrian Somers  */
24624084f9bSBrian Somers 	signal (SIGTERM, InitiateShutdown);
24724084f9bSBrian Somers 	signal (SIGHUP, RefreshAddr);
24824084f9bSBrian Somers /*
24924084f9bSBrian Somers  * Set alias address if it has been given.
25024084f9bSBrian Somers  */
25124084f9bSBrian Somers 	if (aliasAddr.s_addr != INADDR_NONE)
252fb994b07SBrian Somers 		PacketAliasSetAddress (aliasAddr);
25324084f9bSBrian Somers /*
25424084f9bSBrian Somers  * We need largest descriptor number for select.
25524084f9bSBrian Somers  */
25624084f9bSBrian Somers 
25724084f9bSBrian Somers 	fdMax = -1;
25824084f9bSBrian Somers 
25924084f9bSBrian Somers 	if (divertIn > fdMax)
26024084f9bSBrian Somers 		fdMax = divertIn;
26124084f9bSBrian Somers 
26224084f9bSBrian Somers 	if (divertOut > fdMax)
26324084f9bSBrian Somers 		fdMax = divertOut;
26424084f9bSBrian Somers 
26524084f9bSBrian Somers 	if (divertInOut > fdMax)
26624084f9bSBrian Somers 		fdMax = divertInOut;
26724084f9bSBrian Somers 
26824084f9bSBrian Somers 	if (routeSock > fdMax)
26924084f9bSBrian Somers 		fdMax = routeSock;
27024084f9bSBrian Somers 
27124084f9bSBrian Somers 	while (running) {
272fb994b07SBrian Somers 
273fb994b07SBrian Somers 		if (divertInOut != -1 && !ifName && packetSock == -1) {
274fb994b07SBrian Somers /*
275fb994b07SBrian Somers  * When using only one socket, just call
276fb994b07SBrian Somers  * DoAliasing repeatedly to process packets.
277fb994b07SBrian Somers  */
278fb994b07SBrian Somers 			DoAliasing (divertInOut);
279fb994b07SBrian Somers 			continue;
280fb994b07SBrian Somers 		}
28124084f9bSBrian Somers /*
28224084f9bSBrian Somers  * Build read mask from socket descriptors to select.
28324084f9bSBrian Somers  */
28424084f9bSBrian Somers 		FD_ZERO (&readMask);
285fb994b07SBrian Somers 		FD_ZERO (&writeMask);
28624084f9bSBrian Somers 
287fb994b07SBrian Somers /*
288fb994b07SBrian Somers  * If there is unsent packet in buffer, use select
289fb994b07SBrian Somers  * to check when socket comes writable again.
290fb994b07SBrian Somers  */
291fb994b07SBrian Somers 		if (packetSock != -1) {
292fb994b07SBrian Somers 
293fb994b07SBrian Somers 			FD_SET (packetSock, &writeMask);
294fb994b07SBrian Somers 		}
295fb994b07SBrian Somers 		else {
296fb994b07SBrian Somers /*
297fb994b07SBrian Somers  * No unsent packet exists - safe to check if
298fb994b07SBrian Somers  * new ones are available.
299fb994b07SBrian Somers  */
30024084f9bSBrian Somers 			if (divertIn != -1)
30124084f9bSBrian Somers 				FD_SET (divertIn, &readMask);
30224084f9bSBrian Somers 
30324084f9bSBrian Somers 			if (divertOut != -1)
30424084f9bSBrian Somers 				FD_SET (divertOut, &readMask);
30524084f9bSBrian Somers 
30624084f9bSBrian Somers 			if (divertInOut != -1)
30724084f9bSBrian Somers 				FD_SET (divertInOut, &readMask);
308fb994b07SBrian Somers 		}
309fb994b07SBrian Somers /*
310fb994b07SBrian Somers  * Routing info is processed always.
311fb994b07SBrian Somers  */
31224084f9bSBrian Somers 		if (routeSock != -1)
31324084f9bSBrian Somers 			FD_SET (routeSock, &readMask);
31424084f9bSBrian Somers 
31524084f9bSBrian Somers 		if (select (fdMax + 1,
31624084f9bSBrian Somers 			    &readMask,
317fb994b07SBrian Somers 			    &writeMask,
31824084f9bSBrian Somers 			    NULL,
31924084f9bSBrian Somers 			    NULL) == -1) {
32024084f9bSBrian Somers 
32124084f9bSBrian Somers 			if (errno == EINTR)
32224084f9bSBrian Somers 				continue;
32324084f9bSBrian Somers 
32424084f9bSBrian Somers 			Quit ("Select failed.");
32524084f9bSBrian Somers 		}
32624084f9bSBrian Somers 
327fb994b07SBrian Somers 		if (packetSock != -1)
328fb994b07SBrian Somers 			if (FD_ISSET (packetSock, &writeMask))
329fb994b07SBrian Somers 				FlushPacketBuffer (packetSock);
330fb994b07SBrian Somers 
33124084f9bSBrian Somers 		if (divertIn != -1)
33224084f9bSBrian Somers 			if (FD_ISSET (divertIn, &readMask))
33324084f9bSBrian Somers 				DoAliasing (divertIn);
33424084f9bSBrian Somers 
33524084f9bSBrian Somers 		if (divertOut != -1)
33624084f9bSBrian Somers 			if (FD_ISSET (divertOut, &readMask))
33724084f9bSBrian Somers 				DoAliasing (divertOut);
33824084f9bSBrian Somers 
33924084f9bSBrian Somers 		if (divertInOut != -1)
34024084f9bSBrian Somers 			if (FD_ISSET (divertInOut, &readMask))
34124084f9bSBrian Somers 				DoAliasing (divertInOut);
34224084f9bSBrian Somers 
34324084f9bSBrian Somers 		if (routeSock != -1)
34424084f9bSBrian Somers 			if (FD_ISSET (routeSock, &readMask))
34524084f9bSBrian Somers 				HandleRoutingInfo (routeSock);
34624084f9bSBrian Somers 	}
34724084f9bSBrian Somers 
34824084f9bSBrian Somers 	if (background)
34924084f9bSBrian Somers 		unlink (PIDFILE);
35024084f9bSBrian Somers 
35124084f9bSBrian Somers 	return 0;
35224084f9bSBrian Somers }
35324084f9bSBrian Somers 
35424084f9bSBrian Somers static void DaemonMode ()
35524084f9bSBrian Somers {
35624084f9bSBrian Somers 	FILE*	pidFile;
35724084f9bSBrian Somers 
35824084f9bSBrian Somers 	daemon (0, 0);
35924084f9bSBrian Somers 	background = 1;
36024084f9bSBrian Somers 
36124084f9bSBrian Somers 	pidFile = fopen (PIDFILE, "w");
36224084f9bSBrian Somers 	if (pidFile) {
36324084f9bSBrian Somers 
36424084f9bSBrian Somers 		fprintf (pidFile, "%d\n", getpid ());
36524084f9bSBrian Somers 		fclose (pidFile);
36624084f9bSBrian Somers 	}
36724084f9bSBrian Somers }
36824084f9bSBrian Somers 
36924084f9bSBrian Somers static void ParseArgs (int argc, char** argv)
37024084f9bSBrian Somers {
37124084f9bSBrian Somers 	int		arg;
37224084f9bSBrian Somers 	char*		parm;
37324084f9bSBrian Somers 	char*		opt;
37424084f9bSBrian Somers 	char		parmBuf[256];
37524084f9bSBrian Somers 
37624084f9bSBrian Somers 	for (arg = 1; arg < argc; arg++) {
37724084f9bSBrian Somers 
37824084f9bSBrian Somers 		opt  = argv[arg];
37924084f9bSBrian Somers 		if (*opt != '-') {
38024084f9bSBrian Somers 
3810fc81af1SPhilippe Charnier 			warnx ("invalid option %s", opt);
38224084f9bSBrian Somers 			Usage ();
38324084f9bSBrian Somers 		}
38424084f9bSBrian Somers 
38524084f9bSBrian Somers 		parm = NULL;
38624084f9bSBrian Somers 		parmBuf[0] = '\0';
38724084f9bSBrian Somers 
38824084f9bSBrian Somers 		while (arg < argc - 1) {
38924084f9bSBrian Somers 
39024084f9bSBrian Somers 			if (argv[arg + 1][0] == '-')
39124084f9bSBrian Somers 				break;
39224084f9bSBrian Somers 
39324084f9bSBrian Somers 			if (parm)
39424084f9bSBrian Somers 				strcat (parmBuf, " ");
39524084f9bSBrian Somers 
39624084f9bSBrian Somers 			++arg;
39724084f9bSBrian Somers 			parm = parmBuf;
39824084f9bSBrian Somers 			strcat (parmBuf, argv[arg]);
39924084f9bSBrian Somers 		}
40024084f9bSBrian Somers 
40124084f9bSBrian Somers 		ParseOption (opt + 1, parm, 1);
40224084f9bSBrian Somers 	}
40324084f9bSBrian Somers }
40424084f9bSBrian Somers 
40524084f9bSBrian Somers static void DoAliasing (int fd)
40624084f9bSBrian Somers {
40724084f9bSBrian Somers 	int			bytes;
40824084f9bSBrian Somers 	int			origBytes;
409f9b06d5cSBrian Somers 	int			status;
41024084f9bSBrian Somers 	int			addrSize;
41124084f9bSBrian Somers 	struct ip*		ip;
41224084f9bSBrian Somers 
41324084f9bSBrian Somers 	if (assignAliasAddr) {
41424084f9bSBrian Somers 
41524084f9bSBrian Somers 		SetAliasAddressFromIfName (ifName);
41624084f9bSBrian Somers 		assignAliasAddr = 0;
41724084f9bSBrian Somers 	}
41824084f9bSBrian Somers /*
41924084f9bSBrian Somers  * Get packet from socket.
42024084f9bSBrian Somers  */
421fb994b07SBrian Somers 	addrSize  = sizeof packetAddr;
42224084f9bSBrian Somers 	origBytes = recvfrom (fd,
423fb994b07SBrian Somers 			      packetBuf,
424fb994b07SBrian Somers 			      sizeof packetBuf,
42524084f9bSBrian Somers 			      0,
426fb994b07SBrian Somers 			      (struct sockaddr*) &packetAddr,
42724084f9bSBrian Somers 			      &addrSize);
42824084f9bSBrian Somers 
42924084f9bSBrian Somers 	if (origBytes == -1) {
43024084f9bSBrian Somers 
43124084f9bSBrian Somers 		if (errno != EINTR)
4320fc81af1SPhilippe Charnier 			Warn ("read from divert socket failed");
43324084f9bSBrian Somers 
43424084f9bSBrian Somers 		return;
43524084f9bSBrian Somers 	}
43624084f9bSBrian Somers /*
43724084f9bSBrian Somers  * This is a IP packet.
43824084f9bSBrian Somers  */
439fb994b07SBrian Somers 	ip = (struct ip*) packetBuf;
44024084f9bSBrian Somers 
44124084f9bSBrian Somers 	if (verbose) {
44224084f9bSBrian Somers 
44324084f9bSBrian Somers /*
44424084f9bSBrian Somers  * Print packet direction and protocol type.
44524084f9bSBrian Somers  */
44624084f9bSBrian Somers 
447fb994b07SBrian Somers 		if (packetAddr.sin_addr.s_addr == INADDR_ANY)
44824084f9bSBrian Somers 			printf ("Out ");
44924084f9bSBrian Somers 		else
45024084f9bSBrian Somers 			printf ("In  ");
45124084f9bSBrian Somers 
45224084f9bSBrian Somers 		switch (ip->ip_p) {
45324084f9bSBrian Somers 		case IPPROTO_TCP:
45424084f9bSBrian Somers 			printf ("[TCP]  ");
45524084f9bSBrian Somers 			break;
45624084f9bSBrian Somers 
45724084f9bSBrian Somers 		case IPPROTO_UDP:
45824084f9bSBrian Somers 			printf ("[UDP]  ");
45924084f9bSBrian Somers 			break;
46024084f9bSBrian Somers 
46124084f9bSBrian Somers 		case IPPROTO_ICMP:
46224084f9bSBrian Somers 			printf ("[ICMP] ");
46324084f9bSBrian Somers 			break;
46424084f9bSBrian Somers 
46524084f9bSBrian Somers 		default:
46624084f9bSBrian Somers 			printf ("[?]    ");
46724084f9bSBrian Somers 			break;
46824084f9bSBrian Somers 		}
46924084f9bSBrian Somers /*
47024084f9bSBrian Somers  * Print addresses.
47124084f9bSBrian Somers  */
47224084f9bSBrian Somers 		PrintPacket (ip);
47324084f9bSBrian Somers 	}
47424084f9bSBrian Somers 
475fb994b07SBrian Somers 	if (packetAddr.sin_addr.s_addr == INADDR_ANY) {
47624084f9bSBrian Somers /*
47724084f9bSBrian Somers  * Outgoing packets. Do aliasing.
47824084f9bSBrian Somers  */
479fb994b07SBrian Somers 		PacketAliasOut (packetBuf, IP_MAXPACKET);
48024084f9bSBrian Somers 	}
48124084f9bSBrian Somers 	else {
48224084f9bSBrian Somers /*
48324084f9bSBrian Somers  * Do aliasing.
48424084f9bSBrian Somers  */
485f9b06d5cSBrian Somers 		status = PacketAliasIn (packetBuf, IP_MAXPACKET);
486f9b06d5cSBrian Somers 		if (status == PKT_ALIAS_IGNORED &&
487f9b06d5cSBrian Somers 		    dropIgnoredIncoming) {
488f9b06d5cSBrian Somers 
489f9b06d5cSBrian Somers 			printf (" dropped.\n");
490f9b06d5cSBrian Somers 			return;
491f9b06d5cSBrian Somers 		}
49224084f9bSBrian Somers 	}
49324084f9bSBrian Somers /*
49424084f9bSBrian Somers  * Length might have changed during aliasing.
49524084f9bSBrian Somers  */
49624084f9bSBrian Somers 	bytes = ntohs (ip->ip_len);
49724084f9bSBrian Somers /*
49824084f9bSBrian Somers  * Update alias overhead size for outgoing packets.
49924084f9bSBrian Somers  */
500fb994b07SBrian Somers 	if (packetAddr.sin_addr.s_addr == INADDR_ANY &&
50124084f9bSBrian Somers 	    bytes - origBytes > aliasOverhead)
50224084f9bSBrian Somers 		aliasOverhead = bytes - origBytes;
50324084f9bSBrian Somers 
50424084f9bSBrian Somers 	if (verbose) {
50524084f9bSBrian Somers 
50624084f9bSBrian Somers /*
50724084f9bSBrian Somers  * Print addresses after aliasing.
50824084f9bSBrian Somers  */
50924084f9bSBrian Somers 		printf (" aliased to\n");
51024084f9bSBrian Somers 		printf ("           ");
51124084f9bSBrian Somers 		PrintPacket (ip);
51224084f9bSBrian Somers 		printf ("\n");
51324084f9bSBrian Somers 	}
514fb994b07SBrian Somers 
515fb994b07SBrian Somers 	packetLen  = bytes;
516fb994b07SBrian Somers 	packetSock = fd;
517fb994b07SBrian Somers 	FlushPacketBuffer (fd);
518fb994b07SBrian Somers }
519fb994b07SBrian Somers 
520fb994b07SBrian Somers static void FlushPacketBuffer (int fd)
521fb994b07SBrian Somers {
522fb994b07SBrian Somers 	int			wrote;
523fb994b07SBrian Somers 	char			msgBuf[80];
52424084f9bSBrian Somers /*
52524084f9bSBrian Somers  * Put packet back for processing.
52624084f9bSBrian Somers  */
52724084f9bSBrian Somers 	wrote = sendto (fd,
528fb994b07SBrian Somers 		        packetBuf,
529fb994b07SBrian Somers 	    		packetLen,
53024084f9bSBrian Somers 	    		0,
531fb994b07SBrian Somers 	    		(struct sockaddr*) &packetAddr,
532fb994b07SBrian Somers 	    		sizeof packetAddr);
53324084f9bSBrian Somers 
534fb994b07SBrian Somers 	if (wrote != packetLen) {
535fb994b07SBrian Somers /*
536fb994b07SBrian Somers  * If buffer space is not available,
537fb994b07SBrian Somers  * just return. Main loop will take care of
538fb994b07SBrian Somers  * retrying send when space becomes available.
539fb994b07SBrian Somers  */
540fb994b07SBrian Somers 		if (errno == ENOBUFS)
541fb994b07SBrian Somers 			return;
54224084f9bSBrian Somers 
54324084f9bSBrian Somers 		if (errno == EMSGSIZE) {
54424084f9bSBrian Somers 
545fb994b07SBrian Somers 			if (packetAddr.sin_addr.s_addr == INADDR_ANY &&
54624084f9bSBrian Somers 			    ifMTU != -1)
54724084f9bSBrian Somers 				SendNeedFragIcmp (icmpSock,
548fb994b07SBrian Somers 						  (struct ip*) packetBuf,
54924084f9bSBrian Somers 						  ifMTU - aliasOverhead);
55024084f9bSBrian Somers 		}
55124084f9bSBrian Somers 		else {
55224084f9bSBrian Somers 
5530fc81af1SPhilippe Charnier 			sprintf (msgBuf, "failed to write packet back");
55424084f9bSBrian Somers 			Warn (msgBuf);
55524084f9bSBrian Somers 		}
55624084f9bSBrian Somers 	}
557fb994b07SBrian Somers 
558fb994b07SBrian Somers 	packetSock = -1;
55924084f9bSBrian Somers }
56024084f9bSBrian Somers 
56124084f9bSBrian Somers static void HandleRoutingInfo (int fd)
56224084f9bSBrian Somers {
56324084f9bSBrian Somers 	int			bytes;
56424084f9bSBrian Somers 	struct if_msghdr	ifMsg;
56524084f9bSBrian Somers /*
56624084f9bSBrian Somers  * Get packet from socket.
56724084f9bSBrian Somers  */
56824084f9bSBrian Somers 	bytes = read (fd, &ifMsg, sizeof ifMsg);
56924084f9bSBrian Somers 	if (bytes == -1) {
57024084f9bSBrian Somers 
5710fc81af1SPhilippe Charnier 		Warn ("read from routing socket failed");
57224084f9bSBrian Somers 		return;
57324084f9bSBrian Somers 	}
57424084f9bSBrian Somers 
57524084f9bSBrian Somers 	if (ifMsg.ifm_version != RTM_VERSION) {
57624084f9bSBrian Somers 
5770fc81af1SPhilippe Charnier 		Warn ("unexpected packet read from routing socket");
57824084f9bSBrian Somers 		return;
57924084f9bSBrian Somers 	}
58024084f9bSBrian Somers 
58124084f9bSBrian Somers 	if (verbose)
58224084f9bSBrian Somers 		printf ("Routing message %X received.\n", ifMsg.ifm_type);
58324084f9bSBrian Somers 
58424084f9bSBrian Somers 	if (ifMsg.ifm_type != RTM_NEWADDR)
58524084f9bSBrian Somers 		return;
58624084f9bSBrian Somers 
58724084f9bSBrian Somers 	if (verbose && ifMsg.ifm_index == ifIndex)
58824084f9bSBrian Somers 		printf ("Interface address has changed.\n");
58924084f9bSBrian Somers 
59024084f9bSBrian Somers 	if (ifMsg.ifm_index == ifIndex)
59124084f9bSBrian Somers 		assignAliasAddr = 1;
59224084f9bSBrian Somers }
59324084f9bSBrian Somers 
59424084f9bSBrian Somers static void PrintPacket (struct ip* ip)
59524084f9bSBrian Somers {
59624084f9bSBrian Somers 	struct tcphdr*	tcphdr;
59724084f9bSBrian Somers 
59824084f9bSBrian Somers 	if (ip->ip_p == IPPROTO_TCP)
59924084f9bSBrian Somers 		tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2));
60024084f9bSBrian Somers 	else
60124084f9bSBrian Somers 		tcphdr = NULL;
60224084f9bSBrian Somers 
60324084f9bSBrian Somers 	printf ("%s", inet_ntoa (ip->ip_src));
60424084f9bSBrian Somers 	if (tcphdr)
60524084f9bSBrian Somers 		printf (":%d", ntohs (tcphdr->th_sport));
60624084f9bSBrian Somers 
60724084f9bSBrian Somers 	printf (" -> ");
60824084f9bSBrian Somers 	printf ("%s", inet_ntoa (ip->ip_dst));
60924084f9bSBrian Somers 	if (tcphdr)
61024084f9bSBrian Somers 		printf (":%d", ntohs (tcphdr->th_dport));
61124084f9bSBrian Somers }
61224084f9bSBrian Somers 
61324084f9bSBrian Somers static void SetAliasAddressFromIfName (char* ifName)
61424084f9bSBrian Somers {
61524084f9bSBrian Somers 	struct ifconf		cf;
61624084f9bSBrian Somers 	struct ifreq		buf[32];
61724084f9bSBrian Somers 	char			msg[80];
61824084f9bSBrian Somers 	struct ifreq*		ifPtr;
61924084f9bSBrian Somers 	int			extra;
62024084f9bSBrian Somers 	int			helperSock;
62124084f9bSBrian Somers 	int			bytes;
62224084f9bSBrian Somers 	struct sockaddr_in*	addr;
62324084f9bSBrian Somers 	int			found;
62424084f9bSBrian Somers 	struct ifreq		req;
62524084f9bSBrian Somers 	char			last[10];
62624084f9bSBrian Somers /*
62724084f9bSBrian Somers  * Create a dummy socket to access interface information.
62824084f9bSBrian Somers  */
62924084f9bSBrian Somers 	helperSock = socket (AF_INET, SOCK_DGRAM, 0);
63024084f9bSBrian Somers 	if (helperSock == -1) {
63124084f9bSBrian Somers 
63224084f9bSBrian Somers 		Quit ("Failed to create helper socket.");
63324084f9bSBrian Somers 		exit (1);
63424084f9bSBrian Somers 	}
63524084f9bSBrian Somers 
63624084f9bSBrian Somers 	cf.ifc_len = sizeof (buf);
63724084f9bSBrian Somers 	cf.ifc_req = buf;
63824084f9bSBrian Somers /*
63924084f9bSBrian Somers  * Get interface data.
64024084f9bSBrian Somers  */
64124084f9bSBrian Somers 	if (ioctl (helperSock, SIOCGIFCONF, &cf) == -1) {
64224084f9bSBrian Somers 
64324084f9bSBrian Somers 		Quit ("Ioctl SIOCGIFCONF failed.");
64424084f9bSBrian Somers 		exit (1);
64524084f9bSBrian Somers 	}
64624084f9bSBrian Somers 
64724084f9bSBrian Somers 	ifIndex	= 0;
64824084f9bSBrian Somers 	ifPtr	= buf;
64924084f9bSBrian Somers 	bytes	= cf.ifc_len;
65024084f9bSBrian Somers 	found   = 0;
65124084f9bSBrian Somers 	last[0] = '\0';
65224084f9bSBrian Somers /*
65324084f9bSBrian Somers  * Loop through interfaces until one with
65424084f9bSBrian Somers  * given name is found. This is done to
65524084f9bSBrian Somers  * find correct interface index for routing
65624084f9bSBrian Somers  * message processing.
65724084f9bSBrian Somers  */
65824084f9bSBrian Somers 	while (bytes) {
65924084f9bSBrian Somers 
66024084f9bSBrian Somers 		if (ifPtr->ifr_addr.sa_family == AF_INET &&
66124084f9bSBrian Somers                     !strcmp (ifPtr->ifr_name, ifName)) {
66224084f9bSBrian Somers 
66324084f9bSBrian Somers 			found = 1;
66424084f9bSBrian Somers 			break;
66524084f9bSBrian Somers 		}
66624084f9bSBrian Somers 
66724084f9bSBrian Somers 		if (strcmp (last, ifPtr->ifr_name)) {
66824084f9bSBrian Somers 
66924084f9bSBrian Somers 			strcpy (last, ifPtr->ifr_name);
67024084f9bSBrian Somers 			++ifIndex;
67124084f9bSBrian Somers 		}
67224084f9bSBrian Somers 
67324084f9bSBrian Somers 		extra = ifPtr->ifr_addr.sa_len - sizeof (struct sockaddr);
67424084f9bSBrian Somers 
67524084f9bSBrian Somers 		ifPtr++;
67624084f9bSBrian Somers 		ifPtr = (struct ifreq*) ((char*) ifPtr + extra);
67724084f9bSBrian Somers 		bytes -= sizeof (struct ifreq) + extra;
67824084f9bSBrian Somers 	}
67924084f9bSBrian Somers 
68024084f9bSBrian Somers 	if (!found) {
68124084f9bSBrian Somers 
68224084f9bSBrian Somers 		close (helperSock);
68324084f9bSBrian Somers 		sprintf (msg, "Unknown interface name %s.\n", ifName);
68424084f9bSBrian Somers 		Quit (msg);
68524084f9bSBrian Somers 	}
68624084f9bSBrian Somers /*
68724084f9bSBrian Somers  * Get MTU size.
68824084f9bSBrian Somers  */
68924084f9bSBrian Somers 	strcpy (req.ifr_name, ifName);
69024084f9bSBrian Somers 
69124084f9bSBrian Somers 	if (ioctl (helperSock, SIOCGIFMTU, &req) == -1)
69224084f9bSBrian Somers 		Quit ("Cannot get interface mtu size.");
69324084f9bSBrian Somers 
69424084f9bSBrian Somers 	ifMTU = req.ifr_mtu;
69524084f9bSBrian Somers /*
69624084f9bSBrian Somers  * Get interface address.
69724084f9bSBrian Somers  */
69824084f9bSBrian Somers 	if (ioctl (helperSock, SIOCGIFADDR, &req) == -1)
69924084f9bSBrian Somers 		Quit ("Cannot get interface address.");
70024084f9bSBrian Somers 
70124084f9bSBrian Somers 	addr = (struct sockaddr_in*) &req.ifr_addr;
70224084f9bSBrian Somers 	SetPacketAliasAddress (addr->sin_addr);
70324084f9bSBrian Somers 	syslog (LOG_INFO, "Aliasing to %s, mtu %d bytes",
70424084f9bSBrian Somers 			  inet_ntoa (addr->sin_addr),
70524084f9bSBrian Somers 			  ifMTU);
70624084f9bSBrian Somers 
70724084f9bSBrian Somers 	close (helperSock);
70824084f9bSBrian Somers }
70924084f9bSBrian Somers 
71024084f9bSBrian Somers void Quit (char* msg)
71124084f9bSBrian Somers {
71224084f9bSBrian Somers 	Warn (msg);
71324084f9bSBrian Somers 	exit (1);
71424084f9bSBrian Somers }
71524084f9bSBrian Somers 
71624084f9bSBrian Somers void Warn (char* msg)
71724084f9bSBrian Somers {
71824084f9bSBrian Somers 	if (background)
71924084f9bSBrian Somers 		syslog (LOG_ALERT, "%s (%m)", msg);
72024084f9bSBrian Somers 	else
7210fc81af1SPhilippe Charnier 		warn (msg);
72224084f9bSBrian Somers }
72324084f9bSBrian Somers 
72424084f9bSBrian Somers static void RefreshAddr ()
72524084f9bSBrian Somers {
72624084f9bSBrian Somers 	signal (SIGHUP, RefreshAddr);
72724084f9bSBrian Somers 	if (ifName)
72824084f9bSBrian Somers 		assignAliasAddr = 1;
72924084f9bSBrian Somers }
73024084f9bSBrian Somers 
73124084f9bSBrian Somers static void InitiateShutdown ()
73224084f9bSBrian Somers {
73324084f9bSBrian Somers /*
73424084f9bSBrian Somers  * Start timer to allow kernel gracefully
73524084f9bSBrian Somers  * shutdown existing connections when system
73624084f9bSBrian Somers  * is shut down.
73724084f9bSBrian Somers  */
73824084f9bSBrian Somers 	signal (SIGALRM, Shutdown);
73924084f9bSBrian Somers 	alarm (10);
74024084f9bSBrian Somers }
74124084f9bSBrian Somers 
74224084f9bSBrian Somers static void Shutdown ()
74324084f9bSBrian Somers {
74424084f9bSBrian Somers 	running = 0;
74524084f9bSBrian Somers }
74624084f9bSBrian Somers 
74724084f9bSBrian Somers /*
74824084f9bSBrian Somers  * Different options recognized by this program.
74924084f9bSBrian Somers  */
75024084f9bSBrian Somers 
75124084f9bSBrian Somers enum Option {
75224084f9bSBrian Somers 
75324084f9bSBrian Somers 	PacketAliasOption,
75424084f9bSBrian Somers 	Verbose,
75524084f9bSBrian Somers 	InPort,
75624084f9bSBrian Somers 	OutPort,
75724084f9bSBrian Somers 	Port,
75824084f9bSBrian Somers 	AliasAddress,
75924084f9bSBrian Somers 	InterfaceName,
76024084f9bSBrian Somers 	PermanentLink,
76124084f9bSBrian Somers 	RedirectPort,
76224084f9bSBrian Somers 	RedirectAddress,
76324084f9bSBrian Somers 	ConfigFile,
76424084f9bSBrian Somers 	DynamicMode
76524084f9bSBrian Somers };
76624084f9bSBrian Somers 
76724084f9bSBrian Somers enum Param {
76824084f9bSBrian Somers 
76924084f9bSBrian Somers 	YesNo,
77024084f9bSBrian Somers 	Numeric,
77124084f9bSBrian Somers 	String,
77224084f9bSBrian Somers 	None,
77324084f9bSBrian Somers 	Address,
77424084f9bSBrian Somers 	Service
77524084f9bSBrian Somers };
77624084f9bSBrian Somers 
77724084f9bSBrian Somers /*
77824084f9bSBrian Somers  * Option information structure (used by ParseOption).
77924084f9bSBrian Somers  */
78024084f9bSBrian Somers 
78124084f9bSBrian Somers struct OptionInfo {
78224084f9bSBrian Somers 
78324084f9bSBrian Somers 	enum Option		type;
78424084f9bSBrian Somers 	int			packetAliasOpt;
78524084f9bSBrian Somers 	enum Param		parm;
78624084f9bSBrian Somers 	char*			parmDescription;
78724084f9bSBrian Somers 	char*			description;
78824084f9bSBrian Somers 	char*			name;
78924084f9bSBrian Somers 	char*			shortName;
79024084f9bSBrian Somers };
79124084f9bSBrian Somers 
79224084f9bSBrian Somers /*
79324084f9bSBrian Somers  * Table of known options.
79424084f9bSBrian Somers  */
79524084f9bSBrian Somers 
79624084f9bSBrian Somers static struct OptionInfo optionTable[] = {
79724084f9bSBrian Somers 
79824084f9bSBrian Somers 	{ PacketAliasOption,
79924084f9bSBrian Somers 		PKT_ALIAS_UNREGISTERED_ONLY,
80024084f9bSBrian Somers 		YesNo,
80124084f9bSBrian Somers 		"[yes|no]",
80224084f9bSBrian Somers 		"alias only unregistered addresses",
80324084f9bSBrian Somers 		"unregistered_only",
80424084f9bSBrian Somers 		"u" },
80524084f9bSBrian Somers 
80624084f9bSBrian Somers 	{ PacketAliasOption,
80724084f9bSBrian Somers 		PKT_ALIAS_LOG,
80824084f9bSBrian Somers 		YesNo,
80924084f9bSBrian Somers 		"[yes|no]",
81024084f9bSBrian Somers 		"enable logging",
81124084f9bSBrian Somers 		"log",
81224084f9bSBrian Somers 		"l" },
81324084f9bSBrian Somers 
81424084f9bSBrian Somers 	{ PacketAliasOption,
81524084f9bSBrian Somers 		PKT_ALIAS_DENY_INCOMING,
81624084f9bSBrian Somers 		YesNo,
81724084f9bSBrian Somers 		"[yes|no]",
81824084f9bSBrian Somers 		"allow incoming connections",
81924084f9bSBrian Somers 		"deny_incoming",
82024084f9bSBrian Somers 		"d" },
82124084f9bSBrian Somers 
82224084f9bSBrian Somers 	{ PacketAliasOption,
82324084f9bSBrian Somers 		PKT_ALIAS_USE_SOCKETS,
82424084f9bSBrian Somers 		YesNo,
82524084f9bSBrian Somers 		"[yes|no]",
82624084f9bSBrian Somers 		"use sockets to inhibit port conflict",
82724084f9bSBrian Somers 		"use_sockets",
82824084f9bSBrian Somers 		"s" },
82924084f9bSBrian Somers 
83024084f9bSBrian Somers 	{ PacketAliasOption,
83124084f9bSBrian Somers 		PKT_ALIAS_SAME_PORTS,
83224084f9bSBrian Somers 		YesNo,
83324084f9bSBrian Somers 		"[yes|no]",
83424084f9bSBrian Somers 		"try to keep original port numbers for connections",
83524084f9bSBrian Somers 		"same_ports",
83624084f9bSBrian Somers 		"m" },
83724084f9bSBrian Somers 
83824084f9bSBrian Somers 	{ Verbose,
83924084f9bSBrian Somers 		0,
84024084f9bSBrian Somers 		YesNo,
84124084f9bSBrian Somers 		"[yes|no]",
84224084f9bSBrian Somers 		"verbose mode, dump packet information",
84324084f9bSBrian Somers 		"verbose",
84424084f9bSBrian Somers 		"v" },
84524084f9bSBrian Somers 
84624084f9bSBrian Somers 	{ DynamicMode,
84724084f9bSBrian Somers 		0,
84824084f9bSBrian Somers 		YesNo,
84924084f9bSBrian Somers 		"[yes|no]",
85024084f9bSBrian Somers 		"dynamic mode, automatically detect interface address changes",
85124084f9bSBrian Somers 		"dynamic",
85224084f9bSBrian Somers 		NULL },
85324084f9bSBrian Somers 
85424084f9bSBrian Somers 	{ InPort,
85524084f9bSBrian Somers 		0,
85624084f9bSBrian Somers 		Service,
85724084f9bSBrian Somers 		"number|service_name",
85824084f9bSBrian Somers 		"set port for incoming packets",
85924084f9bSBrian Somers 		"in_port",
86024084f9bSBrian Somers 		"i" },
86124084f9bSBrian Somers 
86224084f9bSBrian Somers 	{ OutPort,
86324084f9bSBrian Somers 		0,
86424084f9bSBrian Somers 		Service,
86524084f9bSBrian Somers 		"number|service_name",
86624084f9bSBrian Somers 		"set port for outgoing packets",
86724084f9bSBrian Somers 		"out_port",
86824084f9bSBrian Somers 		"o" },
86924084f9bSBrian Somers 
87024084f9bSBrian Somers 	{ Port,
87124084f9bSBrian Somers 		0,
87224084f9bSBrian Somers 		Service,
87324084f9bSBrian Somers 		"number|service_name",
87424084f9bSBrian Somers 		"set port (defaults to natd/divert)",
87524084f9bSBrian Somers 		"port",
87624084f9bSBrian Somers 		"p" },
87724084f9bSBrian Somers 
87824084f9bSBrian Somers 	{ AliasAddress,
87924084f9bSBrian Somers 		0,
88024084f9bSBrian Somers 		Address,
88124084f9bSBrian Somers 		"x.x.x.x",
88224084f9bSBrian Somers 		"address to use for aliasing",
88324084f9bSBrian Somers 		"alias_address",
88424084f9bSBrian Somers 		"a" },
88524084f9bSBrian Somers 
88624084f9bSBrian Somers 	{ InterfaceName,
88724084f9bSBrian Somers 		0,
88824084f9bSBrian Somers 		String,
88924084f9bSBrian Somers 	        "network_if_name",
89024084f9bSBrian Somers 		"take aliasing address from interface",
89124084f9bSBrian Somers 		"interface",
89224084f9bSBrian Somers 		"n" },
89324084f9bSBrian Somers 
89424084f9bSBrian Somers 	{ PermanentLink,
89524084f9bSBrian Somers 		0,
89624084f9bSBrian Somers 		String,
89724084f9bSBrian Somers 	        "tcp|udp src:port dst:port alias",
89824084f9bSBrian Somers 		"define permanent link for incoming connection",
89924084f9bSBrian Somers 		"permanent_link",
90024084f9bSBrian Somers 		NULL },
90124084f9bSBrian Somers 
90224084f9bSBrian Somers 	{ RedirectPort,
90324084f9bSBrian Somers 		0,
90424084f9bSBrian Somers 		String,
90524084f9bSBrian Somers 	        "tcp|udp local_addr:local_port [public_addr:]public_port"
90624084f9bSBrian Somers 	 	" [remote_addr[:remote_port]]",
90724084f9bSBrian Somers 		"redirect a port for incoming traffic",
90824084f9bSBrian Somers 		"redirect_port",
90924084f9bSBrian Somers 		NULL },
91024084f9bSBrian Somers 
91124084f9bSBrian Somers 	{ RedirectAddress,
91224084f9bSBrian Somers 		0,
91324084f9bSBrian Somers 		String,
91424084f9bSBrian Somers 	        "local_addr public_addr",
91524084f9bSBrian Somers 		"define mapping between local and public addresses",
91624084f9bSBrian Somers 		"redirect_address",
91724084f9bSBrian Somers 		NULL },
91824084f9bSBrian Somers 
91924084f9bSBrian Somers 	{ ConfigFile,
92024084f9bSBrian Somers 		0,
92124084f9bSBrian Somers 		String,
92224084f9bSBrian Somers 		"file_name",
92324084f9bSBrian Somers 		"read options from configuration file",
92424084f9bSBrian Somers 		"config",
92524084f9bSBrian Somers 		"f" }
92624084f9bSBrian Somers };
92724084f9bSBrian Somers 
92824084f9bSBrian Somers static void ParseOption (char* option, char* parms, int cmdLine)
92924084f9bSBrian Somers {
93024084f9bSBrian Somers 	int			i;
93124084f9bSBrian Somers 	struct OptionInfo*	info;
93224084f9bSBrian Somers 	int			yesNoValue;
93324084f9bSBrian Somers 	int			aliasValue;
93424084f9bSBrian Somers 	int			numValue;
93567a886fbSBrian Somers 	u_short			uNumValue;
93624084f9bSBrian Somers 	char*			strValue;
93724084f9bSBrian Somers 	struct in_addr		addrValue;
93824084f9bSBrian Somers 	int			max;
93924084f9bSBrian Somers 	char*			end;
94024084f9bSBrian Somers /*
94124084f9bSBrian Somers  * Find option from table.
94224084f9bSBrian Somers  */
94324084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
94424084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
94524084f9bSBrian Somers 
94624084f9bSBrian Somers 		if (!strcmp (info->name, option))
94724084f9bSBrian Somers 			break;
94824084f9bSBrian Somers 
94924084f9bSBrian Somers 		if (info->shortName)
95024084f9bSBrian Somers 			if (!strcmp (info->shortName, option))
95124084f9bSBrian Somers 				break;
95224084f9bSBrian Somers 	}
95324084f9bSBrian Somers 
95424084f9bSBrian Somers 	if (i >= max) {
95524084f9bSBrian Somers 
9560fc81af1SPhilippe Charnier 		warnx ("unknown option %s", option);
95724084f9bSBrian Somers 		Usage ();
95824084f9bSBrian Somers 	}
95924084f9bSBrian Somers 
96067a886fbSBrian Somers 	uNumValue	= 0;
96124084f9bSBrian Somers 	yesNoValue	= 0;
96224084f9bSBrian Somers 	numValue	= 0;
96324084f9bSBrian Somers 	strValue	= NULL;
96424084f9bSBrian Somers /*
96524084f9bSBrian Somers  * Check parameters.
96624084f9bSBrian Somers  */
96724084f9bSBrian Somers 	switch (info->parm) {
96824084f9bSBrian Somers 	case YesNo:
96924084f9bSBrian Somers 		if (!parms)
97024084f9bSBrian Somers 			parms = "yes";
97124084f9bSBrian Somers 
97224084f9bSBrian Somers 		if (!strcmp (parms, "yes"))
97324084f9bSBrian Somers 			yesNoValue = 1;
97424084f9bSBrian Somers 		else
97524084f9bSBrian Somers 			if (!strcmp (parms, "no"))
97624084f9bSBrian Somers 				yesNoValue = 0;
9770fc81af1SPhilippe Charnier 			else
9780fc81af1SPhilippe Charnier 				errx (1, "%s needs yes/no parameter", option);
97924084f9bSBrian Somers 		break;
98024084f9bSBrian Somers 
98124084f9bSBrian Somers 	case Service:
9820fc81af1SPhilippe Charnier 		if (!parms)
98367a886fbSBrian Somers 			errx (1, "%s needs service name or "
98467a886fbSBrian Somers 				 "port number parameter",
98567a886fbSBrian Somers 				 option);
98624084f9bSBrian Somers 
98767a886fbSBrian Somers 		uNumValue = StrToPort (parms, "divert");
98824084f9bSBrian Somers 		break;
98924084f9bSBrian Somers 
99024084f9bSBrian Somers 	case Numeric:
99124084f9bSBrian Somers 		if (parms)
99224084f9bSBrian Somers 			numValue = strtol (parms, &end, 10);
99324084f9bSBrian Somers 		else
99424084f9bSBrian Somers 			end = parms;
99524084f9bSBrian Somers 
9960fc81af1SPhilippe Charnier 		if (end == parms)
9970fc81af1SPhilippe Charnier 			errx (1, "%s needs numeric parameter", option);
99824084f9bSBrian Somers 		break;
99924084f9bSBrian Somers 
100024084f9bSBrian Somers 	case String:
100124084f9bSBrian Somers 		strValue = parms;
10020fc81af1SPhilippe Charnier 		if (!strValue)
10030fc81af1SPhilippe Charnier 			errx (1, "%s needs parameter", option);
100424084f9bSBrian Somers 		break;
100524084f9bSBrian Somers 
100624084f9bSBrian Somers 	case None:
10070fc81af1SPhilippe Charnier 		if (parms)
10080fc81af1SPhilippe Charnier 			errx (1, "%s does not take parameters", option);
100924084f9bSBrian Somers 		break;
101024084f9bSBrian Somers 
101124084f9bSBrian Somers 	case Address:
10120fc81af1SPhilippe Charnier 		if (!parms)
10130fc81af1SPhilippe Charnier 			errx (1, "%s needs address/host parameter", option);
101424084f9bSBrian Somers 
101524084f9bSBrian Somers 		StrToAddr (parms, &addrValue);
101624084f9bSBrian Somers 		break;
101724084f9bSBrian Somers 	}
101824084f9bSBrian Somers 
101924084f9bSBrian Somers 	switch (info->type) {
102024084f9bSBrian Somers 	case PacketAliasOption:
102124084f9bSBrian Somers 
102224084f9bSBrian Somers 		aliasValue = yesNoValue ? info->packetAliasOpt : 0;
1023fb994b07SBrian Somers 		PacketAliasSetMode (aliasValue, info->packetAliasOpt);
102424084f9bSBrian Somers 		break;
102524084f9bSBrian Somers 
102624084f9bSBrian Somers 	case Verbose:
102724084f9bSBrian Somers 		verbose = yesNoValue;
102824084f9bSBrian Somers 		break;
102924084f9bSBrian Somers 
103024084f9bSBrian Somers 	case DynamicMode:
103124084f9bSBrian Somers 		dynamicMode = yesNoValue;
103224084f9bSBrian Somers 		break;
103324084f9bSBrian Somers 
103424084f9bSBrian Somers 	case InPort:
103567a886fbSBrian Somers 		inPort = uNumValue;
103624084f9bSBrian Somers 		break;
103724084f9bSBrian Somers 
103824084f9bSBrian Somers 	case OutPort:
103967a886fbSBrian Somers 		outPort = uNumValue;
104024084f9bSBrian Somers 		break;
104124084f9bSBrian Somers 
104224084f9bSBrian Somers 	case Port:
104367a886fbSBrian Somers 		inOutPort = uNumValue;
104424084f9bSBrian Somers 		break;
104524084f9bSBrian Somers 
104624084f9bSBrian Somers 	case AliasAddress:
104724084f9bSBrian Somers 		memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr));
104824084f9bSBrian Somers 		break;
104924084f9bSBrian Somers 
105024084f9bSBrian Somers 	case PermanentLink:
105124084f9bSBrian Somers 		SetupPermanentLink (strValue);
105224084f9bSBrian Somers 		break;
105324084f9bSBrian Somers 
105424084f9bSBrian Somers 	case RedirectPort:
105524084f9bSBrian Somers 		SetupPortRedirect (strValue);
105624084f9bSBrian Somers 		break;
105724084f9bSBrian Somers 
105824084f9bSBrian Somers 	case RedirectAddress:
105924084f9bSBrian Somers 		SetupAddressRedirect (strValue);
106024084f9bSBrian Somers 		break;
106124084f9bSBrian Somers 
106224084f9bSBrian Somers 	case InterfaceName:
106324084f9bSBrian Somers 		if (ifName)
106424084f9bSBrian Somers 			free (ifName);
106524084f9bSBrian Somers 
106624084f9bSBrian Somers 		ifName = strdup (strValue);
106724084f9bSBrian Somers 		assignAliasAddr = 1;
106824084f9bSBrian Somers 		break;
106924084f9bSBrian Somers 
107024084f9bSBrian Somers 	case ConfigFile:
107124084f9bSBrian Somers 		ReadConfigFile (strValue);
107224084f9bSBrian Somers 		break;
107324084f9bSBrian Somers 	}
107424084f9bSBrian Somers }
107524084f9bSBrian Somers 
107624084f9bSBrian Somers void ReadConfigFile (char* fileName)
107724084f9bSBrian Somers {
107824084f9bSBrian Somers 	FILE*	file;
107924084f9bSBrian Somers 	char	buf[128];
108024084f9bSBrian Somers 	char*	ptr;
108124084f9bSBrian Somers 	char*	option;
108224084f9bSBrian Somers 
108324084f9bSBrian Somers 	file = fopen (fileName, "r");
108424084f9bSBrian Somers 	if (!file) {
108524084f9bSBrian Somers 
108624084f9bSBrian Somers 		sprintf (buf, "Cannot open config file %s.\n", fileName);
108724084f9bSBrian Somers 		Quit (buf);
108824084f9bSBrian Somers 	}
108924084f9bSBrian Somers 
109024084f9bSBrian Somers 	while (fgets (buf, sizeof (buf), file)) {
109124084f9bSBrian Somers 
109224084f9bSBrian Somers 		ptr = strchr (buf, '\n');
10930fc81af1SPhilippe Charnier 		if (!ptr)
109467a886fbSBrian Somers 			errx (1, "config line too long: %s", buf);
109524084f9bSBrian Somers 
109624084f9bSBrian Somers 		*ptr = '\0';
109724084f9bSBrian Somers 		if (buf[0] == '#')
109824084f9bSBrian Somers 			continue;
109924084f9bSBrian Somers 
110024084f9bSBrian Somers 		ptr = buf;
110124084f9bSBrian Somers /*
110224084f9bSBrian Somers  * Skip white space at beginning of line.
110324084f9bSBrian Somers  */
110424084f9bSBrian Somers 		while (*ptr && isspace (*ptr))
110524084f9bSBrian Somers 			++ptr;
110624084f9bSBrian Somers 
110724084f9bSBrian Somers 		if (*ptr == '\0')
110824084f9bSBrian Somers 			continue;
110924084f9bSBrian Somers /*
111024084f9bSBrian Somers  * Extract option name.
111124084f9bSBrian Somers  */
111224084f9bSBrian Somers 		option = ptr;
111324084f9bSBrian Somers 		while (*ptr && !isspace (*ptr))
111424084f9bSBrian Somers 			++ptr;
111524084f9bSBrian Somers 
111624084f9bSBrian Somers 		if (*ptr != '\0') {
111724084f9bSBrian Somers 
111824084f9bSBrian Somers 			*ptr = '\0';
111924084f9bSBrian Somers 			++ptr;
112024084f9bSBrian Somers 		}
112124084f9bSBrian Somers /*
112224084f9bSBrian Somers  * Skip white space between name and parms.
112324084f9bSBrian Somers  */
112424084f9bSBrian Somers 		while (*ptr && isspace (*ptr))
112524084f9bSBrian Somers 			++ptr;
112624084f9bSBrian Somers 
112724084f9bSBrian Somers 		ParseOption (option, *ptr ? ptr : NULL, 0);
112824084f9bSBrian Somers 	}
112924084f9bSBrian Somers 
113024084f9bSBrian Somers 	fclose (file);
113124084f9bSBrian Somers }
113224084f9bSBrian Somers 
113324084f9bSBrian Somers static void Usage ()
113424084f9bSBrian Somers {
113524084f9bSBrian Somers 	int			i;
113624084f9bSBrian Somers 	int			max;
113724084f9bSBrian Somers 	struct OptionInfo*	info;
113824084f9bSBrian Somers 
113924084f9bSBrian Somers 	fprintf (stderr, "Recognized options:\n\n");
114024084f9bSBrian Somers 
114124084f9bSBrian Somers 	max = sizeof (optionTable) / sizeof (struct OptionInfo);
114224084f9bSBrian Somers 	for (i = 0, info = optionTable; i < max; i++, info++) {
114324084f9bSBrian Somers 
114424084f9bSBrian Somers 		fprintf (stderr, "-%-20s %s\n", info->name,
114524084f9bSBrian Somers 						info->parmDescription);
114624084f9bSBrian Somers 
114724084f9bSBrian Somers 		if (info->shortName)
114824084f9bSBrian Somers 			fprintf (stderr, "-%-20s %s\n", info->shortName,
114924084f9bSBrian Somers 							info->parmDescription);
115024084f9bSBrian Somers 
115124084f9bSBrian Somers 		fprintf (stderr, "      %s\n\n", info->description);
115224084f9bSBrian Somers 	}
115324084f9bSBrian Somers 
115424084f9bSBrian Somers 	exit (1);
115524084f9bSBrian Somers }
115624084f9bSBrian Somers 
115724084f9bSBrian Somers void SetupPermanentLink (char* parms)
115824084f9bSBrian Somers {
115924084f9bSBrian Somers 	char		buf[128];
116024084f9bSBrian Somers 	char*		ptr;
116124084f9bSBrian Somers 	struct in_addr	srcAddr;
116224084f9bSBrian Somers 	struct in_addr	dstAddr;
116367a886fbSBrian Somers 	u_short		srcPort;
116467a886fbSBrian Somers 	u_short		dstPort;
116567a886fbSBrian Somers 	u_short		aliasPort;
116624084f9bSBrian Somers 	int		proto;
116724084f9bSBrian Somers 	char*		protoName;
116824084f9bSBrian Somers 
116924084f9bSBrian Somers 	strcpy (buf, parms);
117024084f9bSBrian Somers /*
117124084f9bSBrian Somers  * Extract protocol.
117224084f9bSBrian Somers  */
117324084f9bSBrian Somers 	protoName = strtok (buf, " \t");
11740fc81af1SPhilippe Charnier 	if (!protoName)
11750fc81af1SPhilippe Charnier 		errx (1, "permanent_link: missing protocol");
117624084f9bSBrian Somers 
117724084f9bSBrian Somers 	proto = StrToProto (protoName);
117824084f9bSBrian Somers /*
117924084f9bSBrian Somers  * Extract source address.
118024084f9bSBrian Somers  */
118124084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
11820fc81af1SPhilippe Charnier 	if (!ptr)
11830fc81af1SPhilippe Charnier 		errx (1, "permanent_link: missing src address");
118424084f9bSBrian Somers 
118524084f9bSBrian Somers 	srcPort = StrToAddrAndPort (ptr, &srcAddr, protoName);
118624084f9bSBrian Somers /*
118724084f9bSBrian Somers  * Extract destination address.
118824084f9bSBrian Somers  */
118924084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
11900fc81af1SPhilippe Charnier 	if (!ptr)
11910fc81af1SPhilippe Charnier 		errx (1, "permanent_link: missing dst address");
119224084f9bSBrian Somers 
119324084f9bSBrian Somers 	dstPort = StrToAddrAndPort (ptr, &dstAddr, protoName);
119424084f9bSBrian Somers /*
119524084f9bSBrian Somers  * Export alias port.
119624084f9bSBrian Somers  */
119724084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
11980fc81af1SPhilippe Charnier 	if (!ptr)
11990fc81af1SPhilippe Charnier 		errx (1, "permanent_link: missing alias port");
120024084f9bSBrian Somers 
120124084f9bSBrian Somers 	aliasPort = StrToPort (ptr, protoName);
120224084f9bSBrian Somers 
120324084f9bSBrian Somers 	PacketAliasPermanentLink (srcAddr,
120424084f9bSBrian Somers 				  srcPort,
120524084f9bSBrian Somers 				  dstAddr,
120624084f9bSBrian Somers 				  dstPort,
120724084f9bSBrian Somers 				  aliasPort,
120824084f9bSBrian Somers 				  proto);
120924084f9bSBrian Somers }
121024084f9bSBrian Somers 
121124084f9bSBrian Somers void SetupPortRedirect (char* parms)
121224084f9bSBrian Somers {
121324084f9bSBrian Somers 	char		buf[128];
121424084f9bSBrian Somers 	char*		ptr;
121524084f9bSBrian Somers 	struct in_addr	localAddr;
121624084f9bSBrian Somers 	struct in_addr	publicAddr;
121724084f9bSBrian Somers 	struct in_addr	remoteAddr;
121867a886fbSBrian Somers 	u_short		localPort;
121967a886fbSBrian Somers 	u_short		publicPort;
122067a886fbSBrian Somers 	u_short		remotePort;
122124084f9bSBrian Somers 	int		proto;
122224084f9bSBrian Somers 	char*		protoName;
122324084f9bSBrian Somers 	char*		separator;
122424084f9bSBrian Somers 
122524084f9bSBrian Somers 	strcpy (buf, parms);
122624084f9bSBrian Somers /*
122724084f9bSBrian Somers  * Extract protocol.
122824084f9bSBrian Somers  */
122924084f9bSBrian Somers 	protoName = strtok (buf, " \t");
12300fc81af1SPhilippe Charnier 	if (!protoName)
12310fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing protocol");
123224084f9bSBrian Somers 
123324084f9bSBrian Somers 	proto = StrToProto (protoName);
123424084f9bSBrian Somers /*
123524084f9bSBrian Somers  * Extract local address.
123624084f9bSBrian Somers  */
123724084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
12380fc81af1SPhilippe Charnier 	if (!ptr)
12390fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing local address");
124024084f9bSBrian Somers 
124124084f9bSBrian Somers 	localPort = StrToAddrAndPort (ptr, &localAddr, protoName);
124224084f9bSBrian Somers /*
124324084f9bSBrian Somers  * Extract public port and optinally address.
124424084f9bSBrian Somers  */
124524084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
12460fc81af1SPhilippe Charnier 	if (!ptr)
12470fc81af1SPhilippe Charnier 		errx (1, "redirect_port: missing public port");
124824084f9bSBrian Somers 
124924084f9bSBrian Somers 	separator = strchr (ptr, ':');
125024084f9bSBrian Somers 	if (separator)
125124084f9bSBrian Somers 		publicPort = StrToAddrAndPort (ptr, &publicAddr, protoName);
125224084f9bSBrian Somers 	else {
125324084f9bSBrian Somers 
125424084f9bSBrian Somers 		publicAddr.s_addr = INADDR_ANY;
125524084f9bSBrian Somers 		publicPort = StrToPort (ptr, protoName);
125624084f9bSBrian Somers 	}
125724084f9bSBrian Somers 
125824084f9bSBrian Somers /*
125924084f9bSBrian Somers  * Extract remote address and optionally port.
126024084f9bSBrian Somers  */
126124084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
126224084f9bSBrian Somers 	if (ptr) {
126324084f9bSBrian Somers 
126424084f9bSBrian Somers 
126524084f9bSBrian Somers 		separator = strchr (ptr, ':');
126624084f9bSBrian Somers 		if (separator)
126724084f9bSBrian Somers 			remotePort = StrToAddrAndPort (ptr,
126824084f9bSBrian Somers 						       &remoteAddr,
126924084f9bSBrian Somers 						       protoName);
127024084f9bSBrian Somers 		else {
127124084f9bSBrian Somers 
127224084f9bSBrian Somers 			remotePort = 0;
127324084f9bSBrian Somers 			StrToAddr (ptr, &remoteAddr);
127424084f9bSBrian Somers 		}
127524084f9bSBrian Somers 	}
127624084f9bSBrian Somers 	else {
127724084f9bSBrian Somers 
127824084f9bSBrian Somers 		remotePort = 0;
127924084f9bSBrian Somers 		remoteAddr.s_addr = INADDR_ANY;
128024084f9bSBrian Somers 	}
128124084f9bSBrian Somers 
128224084f9bSBrian Somers 	PacketAliasRedirectPort (localAddr,
128324084f9bSBrian Somers 				 localPort,
128424084f9bSBrian Somers 				 remoteAddr,
128524084f9bSBrian Somers 				 remotePort,
128624084f9bSBrian Somers 				 publicAddr,
128724084f9bSBrian Somers 				 publicPort,
128824084f9bSBrian Somers 				 proto);
128924084f9bSBrian Somers }
129024084f9bSBrian Somers 
129124084f9bSBrian Somers void SetupAddressRedirect (char* parms)
129224084f9bSBrian Somers {
129324084f9bSBrian Somers 	char		buf[128];
129424084f9bSBrian Somers 	char*		ptr;
129524084f9bSBrian Somers 	struct in_addr	localAddr;
129624084f9bSBrian Somers 	struct in_addr	publicAddr;
129724084f9bSBrian Somers 
129824084f9bSBrian Somers 	strcpy (buf, parms);
129924084f9bSBrian Somers /*
130024084f9bSBrian Somers  * Extract local address.
130124084f9bSBrian Somers  */
130224084f9bSBrian Somers 	ptr = strtok (buf, " \t");
13030fc81af1SPhilippe Charnier 	if (!ptr)
13040fc81af1SPhilippe Charnier 		errx (1, "redirect_address: missing local address");
130524084f9bSBrian Somers 
130624084f9bSBrian Somers 	StrToAddr (ptr, &localAddr);
130724084f9bSBrian Somers /*
130824084f9bSBrian Somers  * Extract public address.
130924084f9bSBrian Somers  */
131024084f9bSBrian Somers 	ptr = strtok (NULL, " \t");
13110fc81af1SPhilippe Charnier 	if (!ptr)
13120fc81af1SPhilippe Charnier 		errx (1, "redirect_address: missing public address");
131324084f9bSBrian Somers 
131424084f9bSBrian Somers 	StrToAddr (ptr, &publicAddr);
131524084f9bSBrian Somers 	PacketAliasRedirectAddr (localAddr, publicAddr);
131624084f9bSBrian Somers }
131724084f9bSBrian Somers 
131824084f9bSBrian Somers void StrToAddr (char* str, struct in_addr* addr)
131924084f9bSBrian Somers {
132024084f9bSBrian Somers 	struct hostent* hp;
132124084f9bSBrian Somers 
132224084f9bSBrian Somers 	if (inet_aton (str, addr))
132324084f9bSBrian Somers 		return;
132424084f9bSBrian Somers 
132524084f9bSBrian Somers 	hp = gethostbyname (str);
13260fc81af1SPhilippe Charnier 	if (!hp)
13270fc81af1SPhilippe Charnier 		errx (1, "unknown host %s", str);
132824084f9bSBrian Somers 
132924084f9bSBrian Somers 	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
133024084f9bSBrian Somers }
133124084f9bSBrian Somers 
133267a886fbSBrian Somers u_short StrToPort (char* str, char* proto)
133324084f9bSBrian Somers {
133467a886fbSBrian Somers 	u_short		port;
133524084f9bSBrian Somers 	struct servent*	sp;
133624084f9bSBrian Somers 	char*		end;
133724084f9bSBrian Somers 
133824084f9bSBrian Somers 	port = strtol (str, &end, 10);
133924084f9bSBrian Somers 	if (end != str)
134027c20503SBrian Somers 		return htons (port);
134124084f9bSBrian Somers 
134224084f9bSBrian Somers 	sp = getservbyname (str, proto);
13430fc81af1SPhilippe Charnier 	if (!sp)
13440fc81af1SPhilippe Charnier 		errx (1, "unknown service %s/%s", str, proto);
134524084f9bSBrian Somers 
134624084f9bSBrian Somers 	return sp->s_port;
134724084f9bSBrian Somers }
134824084f9bSBrian Somers 
134924084f9bSBrian Somers int StrToProto (char* str)
135024084f9bSBrian Somers {
135124084f9bSBrian Somers 	if (!strcmp (str, "tcp"))
135224084f9bSBrian Somers 		return IPPROTO_TCP;
135324084f9bSBrian Somers 
135424084f9bSBrian Somers 	if (!strcmp (str, "udp"))
135524084f9bSBrian Somers 		return IPPROTO_UDP;
135624084f9bSBrian Somers 
13570fc81af1SPhilippe Charnier 	errx (1, "unknown protocol %s. Expected tcp or udp", str);
135824084f9bSBrian Somers }
135924084f9bSBrian Somers 
136067a886fbSBrian Somers u_short StrToAddrAndPort (char* str, struct in_addr* addr, char* proto)
136124084f9bSBrian Somers {
136224084f9bSBrian Somers 	char*	ptr;
136324084f9bSBrian Somers 
136424084f9bSBrian Somers 	ptr = strchr (str, ':');
13650fc81af1SPhilippe Charnier 	if (!ptr)
13660fc81af1SPhilippe Charnier 		errx (1, "%s is missing port number", str);
136724084f9bSBrian Somers 
136824084f9bSBrian Somers 	*ptr = '\0';
136924084f9bSBrian Somers 	++ptr;
137024084f9bSBrian Somers 
137124084f9bSBrian Somers 	StrToAddr (str, addr);
137224084f9bSBrian Somers 	return StrToPort (ptr, proto);
137324084f9bSBrian Somers }
137424084f9bSBrian Somers 
1375