141edb306SCy Schubert 
241edb306SCy Schubert /*
341edb306SCy Schubert  * (C)Copyright (C) 2012 by Darren Reed.
441edb306SCy Schubert  */
541edb306SCy Schubert #include <sys/types.h>
641edb306SCy Schubert #include <sys/stat.h>
741edb306SCy Schubert #include <sys/mman.h>
841edb306SCy Schubert #include <sys/socket.h>
941edb306SCy Schubert #include <sys/time.h>
1041edb306SCy Schubert #include <sys/ioctl.h>
1141edb306SCy Schubert 
1241edb306SCy Schubert #include <netinet/in.h>
1341edb306SCy Schubert #include <netinet/in_systm.h>
1441edb306SCy Schubert #include <netinet/ip.h>
1541edb306SCy Schubert 
1641edb306SCy Schubert #include <net/if.h>
1741edb306SCy Schubert 
1841edb306SCy Schubert #include <stdio.h>
1941edb306SCy Schubert #include <netdb.h>
2041edb306SCy Schubert #include <string.h>
2141edb306SCy Schubert #include <ctype.h>
2241edb306SCy Schubert #include <fcntl.h>
2341edb306SCy Schubert #include <errno.h>
2441edb306SCy Schubert #include <stdlib.h>
2541edb306SCy Schubert 
2641edb306SCy Schubert #include "ip_compat.h"
2741edb306SCy Schubert #include "ip_fil.h"
2841edb306SCy Schubert #include "ip_nat.h"
2941edb306SCy Schubert 
3041edb306SCy Schubert #include "ipf.h"
3141edb306SCy Schubert 
3241edb306SCy Schubert extern	char	*optarg;
3341edb306SCy Schubert 
3441edb306SCy Schubert 
3541edb306SCy Schubert typedef	struct	l4cfg	{
3641edb306SCy Schubert 	struct	l4cfg		*l4_next;
3741edb306SCy Schubert 	struct	ipnat		l4_nat;		/* NAT rule */
3841edb306SCy Schubert 	struct	sockaddr_in	l4_sin;		/* remote socket to connect */
3941edb306SCy Schubert 	time_t			l4_last;	/* when we last connected */
4041edb306SCy Schubert 	int			l4_alive;	/* 1 = remote alive */
4141edb306SCy Schubert 	int			l4_fd;
4241edb306SCy Schubert 	int			l4_rw;		/* 0 = reading, 1 = writing */
4341edb306SCy Schubert 	char			*l4_rbuf;	/* read buffer */
4441edb306SCy Schubert 	int			l4_rsize;	/* size of buffer */
4541edb306SCy Schubert 	int			l4_rlen;	/* how much used */
4641edb306SCy Schubert 	char			*l4_wptr;	/* next byte to write */
4741edb306SCy Schubert 	int			l4_wlen;	/* length yet to be written */
4841edb306SCy Schubert } l4cfg_t;
4941edb306SCy Schubert 
5041edb306SCy Schubert 
5141edb306SCy Schubert l4cfg_t *l4list = NULL;
5241edb306SCy Schubert char *response = NULL;
5341edb306SCy Schubert char *probe = NULL;
5441edb306SCy Schubert l4cfg_t template;
5541edb306SCy Schubert int frequency = 20;
5641edb306SCy Schubert int ctimeout = 1;
5741edb306SCy Schubert int rtimeout = 1;
5841edb306SCy Schubert size_t plen = 0;
5941edb306SCy Schubert size_t rlen = 0;
6041edb306SCy Schubert int natfd = -1;
6141edb306SCy Schubert int opts = 0;
6241edb306SCy Schubert 
6341edb306SCy Schubert #if defined(sun) && !defined(__svr4__) && !defined(__SVR4)
6441edb306SCy Schubert # define	strerror(x)	sys_errlist[x]
6541edb306SCy Schubert #endif
6641edb306SCy Schubert 
6741edb306SCy Schubert 
68efeb8bffSCy Schubert char *
copystr(char * dst,char * src)69efeb8bffSCy Schubert copystr(char *dst, char *src)
7041edb306SCy Schubert {
7141edb306SCy Schubert 	register char *s, *t, c;
7241edb306SCy Schubert 	register int esc = 0;
7341edb306SCy Schubert 
7441edb306SCy Schubert 	for (s = src, t = dst; s && t && (c = *s++); )
7541edb306SCy Schubert 		if (esc) {
7641edb306SCy Schubert 			esc = 0;
7741edb306SCy Schubert 			switch (c)
7841edb306SCy Schubert 			{
7941edb306SCy Schubert 			case 'n' :
8041edb306SCy Schubert 				*t++ = '\n';
8141edb306SCy Schubert 				break;
8241edb306SCy Schubert 			case 'r' :
8341edb306SCy Schubert 				*t++ = '\r';
8441edb306SCy Schubert 				break;
8541edb306SCy Schubert 			case 't' :
8641edb306SCy Schubert 				*t++ = '\t';
8741edb306SCy Schubert 				break;
8841edb306SCy Schubert 			}
8941edb306SCy Schubert 		} else if (c != '\\')
9041edb306SCy Schubert 			*t++ = c;
9141edb306SCy Schubert 		else
9241edb306SCy Schubert 			esc = 1;
9341edb306SCy Schubert 	*t = '\0';
9464e8b270SCy Schubert 	return(dst);
9541edb306SCy Schubert }
9641edb306SCy Schubert 
97efeb8bffSCy Schubert void
addnat(l4cfg_t * l4)98efeb8bffSCy Schubert addnat(l4cfg_t *l4)
9941edb306SCy Schubert {
10041edb306SCy Schubert 	ipnat_t *ipn = &l4->l4_nat;
10141edb306SCy Schubert 
10241edb306SCy Schubert 	printf("Add NAT rule for %s/%#x,%u -> ", inet_ntoa(ipn->in_out[0]),
10341edb306SCy Schubert 		ipn->in_outmsk, ntohs(ipn->in_pmin));
10441edb306SCy Schubert 	printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ntohs(ipn->in_pnext));
10541edb306SCy Schubert 	if (!(opts & OPT_DONOTHING)) {
10641edb306SCy Schubert 		if (ioctl(natfd, SIOCADNAT, &ipn) == -1)
10741edb306SCy Schubert 			perror("ioctl(SIOCADNAT)");
10841edb306SCy Schubert 	}
10941edb306SCy Schubert }
11041edb306SCy Schubert 
11141edb306SCy Schubert 
112efeb8bffSCy Schubert void
delnat(l4cfg_t * l4)113efeb8bffSCy Schubert delnat(l4cfg_t *l4)
11441edb306SCy Schubert {
11541edb306SCy Schubert 	ipnat_t *ipn = &l4->l4_nat;
11641edb306SCy Schubert 
11741edb306SCy Schubert 	printf("Remove NAT rule for %s/%#x,%u -> ",
11841edb306SCy Schubert 		inet_ntoa(ipn->in_out[0]), ipn->in_outmsk, ipn->in_pmin);
11941edb306SCy Schubert 	printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ipn->in_pnext);
12041edb306SCy Schubert 	if (!(opts & OPT_DONOTHING)) {
12141edb306SCy Schubert 		if (ioctl(natfd, SIOCRMNAT, &ipn) == -1)
12241edb306SCy Schubert 			perror("ioctl(SIOCRMNAT)");
12341edb306SCy Schubert 	}
12441edb306SCy Schubert }
12541edb306SCy Schubert 
12641edb306SCy Schubert 
127efeb8bffSCy Schubert void
connectl4(l4cfg_t * l4)128efeb8bffSCy Schubert connectl4(l4cfg_t *l4)
12941edb306SCy Schubert {
13041edb306SCy Schubert 	l4->l4_rw = 1;
13141edb306SCy Schubert 	l4->l4_rlen = 0;
13241edb306SCy Schubert 	l4->l4_wlen = plen;
13341edb306SCy Schubert 	if (!l4->l4_wlen) {
13441edb306SCy Schubert 		l4->l4_alive = 1;
13541edb306SCy Schubert 		addnat(l4);
13641edb306SCy Schubert 	} else
13741edb306SCy Schubert 		l4->l4_wptr = probe;
13841edb306SCy Schubert }
13941edb306SCy Schubert 
14041edb306SCy Schubert 
141efeb8bffSCy Schubert void
closel4(l4cfg_t * l4,int dead)142efeb8bffSCy Schubert closel4(l4cfg_t *l4, int dead)
14341edb306SCy Schubert {
14441edb306SCy Schubert 	close(l4->l4_fd);
14541edb306SCy Schubert 	l4->l4_fd = -1;
14641edb306SCy Schubert 	l4->l4_rw = -1;
14741edb306SCy Schubert 	if (dead && l4->l4_alive) {
14841edb306SCy Schubert 		l4->l4_alive = 0;
14941edb306SCy Schubert 		delnat(l4);
15041edb306SCy Schubert 	}
15141edb306SCy Schubert }
15241edb306SCy Schubert 
15341edb306SCy Schubert 
154efeb8bffSCy Schubert void
connectfd(l4cfg_t * l4)155efeb8bffSCy Schubert connectfd(l4cfg_t *l4)
15641edb306SCy Schubert {
15741edb306SCy Schubert 	if (connect(l4->l4_fd, (struct sockaddr *)&l4->l4_sin,
15841edb306SCy Schubert 		    sizeof(l4->l4_sin)) == -1) {
15941edb306SCy Schubert 		if (errno == EISCONN) {
16041edb306SCy Schubert 			if (opts & OPT_VERBOSE)
16141edb306SCy Schubert 				fprintf(stderr, "Connected fd %d\n",
16241edb306SCy Schubert 					l4->l4_fd);
16341edb306SCy Schubert 			connectl4(l4);
16441edb306SCy Schubert 			return;
16541edb306SCy Schubert 		}
16641edb306SCy Schubert 		if (opts & OPT_VERBOSE)
16741edb306SCy Schubert 			fprintf(stderr, "Connect failed fd %d: %s\n",
16841edb306SCy Schubert 				l4->l4_fd, strerror(errno));
16941edb306SCy Schubert 		closel4(l4, 1);
17041edb306SCy Schubert 		return;
17141edb306SCy Schubert 	}
17241edb306SCy Schubert 	l4->l4_rw = 1;
17341edb306SCy Schubert }
17441edb306SCy Schubert 
17541edb306SCy Schubert 
176efeb8bffSCy Schubert void
writefd(l4cfg_t * l4)177efeb8bffSCy Schubert writefd(l4cfg_t *l4)
17841edb306SCy Schubert {
17941edb306SCy Schubert 	char buf[80], *ptr;
18041edb306SCy Schubert 	int n, i, fd;
18141edb306SCy Schubert 
18241edb306SCy Schubert 	fd = l4->l4_fd;
18341edb306SCy Schubert 
18441edb306SCy Schubert 	if (l4->l4_rw == -2) {
18541edb306SCy Schubert 		connectfd(l4);
18641edb306SCy Schubert 		return;
18741edb306SCy Schubert 	}
18841edb306SCy Schubert 
18941edb306SCy Schubert 	n = l4->l4_wlen;
19041edb306SCy Schubert 
19141edb306SCy Schubert 	i = send(fd, l4->l4_wptr, n, 0);
19241edb306SCy Schubert 	if (i == 0 || i == -1) {
19341edb306SCy Schubert 		if (opts & OPT_VERBOSE)
19441edb306SCy Schubert 			fprintf(stderr, "Send on fd %d failed: %s\n",
19541edb306SCy Schubert 				fd, strerror(errno));
19641edb306SCy Schubert 		closel4(l4, 1);
19741edb306SCy Schubert 	} else {
19841edb306SCy Schubert 		l4->l4_wptr += i;
19941edb306SCy Schubert 		l4->l4_wlen -= i;
20041edb306SCy Schubert 		if (l4->l4_wlen == 0)
20141edb306SCy Schubert 			l4->l4_rw = 0;
20241edb306SCy Schubert 		if (opts & OPT_VERBOSE)
20341edb306SCy Schubert 			fprintf(stderr, "Sent %d bytes to fd %d\n", i, fd);
20441edb306SCy Schubert 	}
20541edb306SCy Schubert }
20641edb306SCy Schubert 
20741edb306SCy Schubert 
readfd(l4cfg_t * l4)208efeb8bffSCy Schubert void readfd(l4cfg_t *l4)
20941edb306SCy Schubert {
21041edb306SCy Schubert 	char buf[80], *ptr;
21141edb306SCy Schubert 	int n, i, fd;
21241edb306SCy Schubert 
21341edb306SCy Schubert 	fd = l4->l4_fd;
21441edb306SCy Schubert 
21541edb306SCy Schubert 	if (l4->l4_rw == -2) {
21641edb306SCy Schubert 		connectfd(l4);
21741edb306SCy Schubert 		return;
21841edb306SCy Schubert 	}
21941edb306SCy Schubert 
22041edb306SCy Schubert 	if (l4->l4_rsize) {
22141edb306SCy Schubert 		n = l4->l4_rsize - l4->l4_rlen;
22241edb306SCy Schubert 		ptr = l4->l4_rbuf + l4->l4_rlen;
22341edb306SCy Schubert 	} else {
22441edb306SCy Schubert 		n = sizeof(buf) - 1;
22541edb306SCy Schubert 		ptr = buf;
22641edb306SCy Schubert 	}
22741edb306SCy Schubert 
22841edb306SCy Schubert 	if (opts & OPT_VERBOSE)
22941edb306SCy Schubert 		fprintf(stderr, "Read %d bytes on fd %d to %p\n",
23041edb306SCy Schubert 			n, fd, ptr);
23141edb306SCy Schubert 	i = recv(fd, ptr, n, 0);
23241edb306SCy Schubert 	if (i == 0 || i == -1) {
23341edb306SCy Schubert 		if (opts & OPT_VERBOSE)
23441edb306SCy Schubert 			fprintf(stderr, "Read error on fd %d: %s\n",
23541edb306SCy Schubert 				fd, (i == 0) ? "EOF" : strerror(errno));
23641edb306SCy Schubert 		closel4(l4, 1);
23741edb306SCy Schubert 	} else {
23841edb306SCy Schubert 		if (ptr == buf)
23941edb306SCy Schubert 			ptr[i] = '\0';
24041edb306SCy Schubert 		if (opts & OPT_VERBOSE)
24141edb306SCy Schubert 			fprintf(stderr, "%d: Read %d bytes [%*.*s]\n",
24241edb306SCy Schubert 				fd, i, i, i, ptr);
24341edb306SCy Schubert 		if (ptr != buf) {
24441edb306SCy Schubert 			l4->l4_rlen += i;
24541edb306SCy Schubert 			if (l4->l4_rlen >= l4->l4_rsize) {
24641edb306SCy Schubert 				if (!strncmp(response, l4->l4_rbuf,
24741edb306SCy Schubert 					     l4->l4_rsize)) {
24841edb306SCy Schubert 					printf("%d: Good response\n",
24941edb306SCy Schubert 						fd);
25041edb306SCy Schubert 					if (!l4->l4_alive) {
25141edb306SCy Schubert 						l4->l4_alive = 1;
25241edb306SCy Schubert 						addnat(l4);
25341edb306SCy Schubert 					}
25441edb306SCy Schubert 					closel4(l4, 0);
25541edb306SCy Schubert 				} else {
25641edb306SCy Schubert 					if (opts & OPT_VERBOSE)
25741edb306SCy Schubert 						printf("%d: Bad response\n",
25841edb306SCy Schubert 							fd);
25941edb306SCy Schubert 					closel4(l4, 1);
26041edb306SCy Schubert 				}
26141edb306SCy Schubert 			}
26241edb306SCy Schubert 		} else if (!l4->l4_alive) {
26341edb306SCy Schubert 			l4->l4_alive = 1;
26441edb306SCy Schubert 			addnat(l4);
26541edb306SCy Schubert 			closel4(l4, 0);
26641edb306SCy Schubert 		}
26741edb306SCy Schubert 	}
26841edb306SCy Schubert }
26941edb306SCy Schubert 
27041edb306SCy Schubert 
271efeb8bffSCy Schubert int
runconfig(void)272efeb8bffSCy Schubert runconfig(void)
27341edb306SCy Schubert {
27441edb306SCy Schubert 	int fd, opt, res, mfd, i;
27541edb306SCy Schubert 	struct timeval tv;
27641edb306SCy Schubert 	time_t now, now1;
27741edb306SCy Schubert 	fd_set rfd, wfd;
27841edb306SCy Schubert 	l4cfg_t *l4;
27941edb306SCy Schubert 
28041edb306SCy Schubert 	mfd = 0;
28141edb306SCy Schubert 	opt = 1;
28241edb306SCy Schubert 	now = time(NULL);
28341edb306SCy Schubert 
28441edb306SCy Schubert 	/*
28541edb306SCy Schubert 	 * First, initiate connections that are closed, as required.
28641edb306SCy Schubert 	 */
28741edb306SCy Schubert 	for (l4 = l4list; l4; l4 = l4->l4_next) {
28841edb306SCy Schubert 		if ((l4->l4_last + frequency < now) && (l4->l4_fd == -1)) {
28941edb306SCy Schubert 			l4->l4_last = now;
29041edb306SCy Schubert 			fd = socket(AF_INET, SOCK_STREAM, 0);
29141edb306SCy Schubert 			if (fd == -1)
29241edb306SCy Schubert 				continue;
29341edb306SCy Schubert 			setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt,
29441edb306SCy Schubert 				   sizeof(opt));
29541edb306SCy Schubert #ifdef	O_NONBLOCK
29641edb306SCy Schubert 			if ((res = fcntl(fd, F_GETFL, 0)) != -1)
29741edb306SCy Schubert 				fcntl(fd, F_SETFL, res | O_NONBLOCK);
29841edb306SCy Schubert #endif
29941edb306SCy Schubert 			if (opts & OPT_VERBOSE)
30041edb306SCy Schubert 				fprintf(stderr,
30141edb306SCy Schubert 					"Connecting to %s,%d (fd %d)...",
30241edb306SCy Schubert 					inet_ntoa(l4->l4_sin.sin_addr),
30341edb306SCy Schubert 					ntohs(l4->l4_sin.sin_port), fd);
30441edb306SCy Schubert 			if (connect(fd, (struct sockaddr *)&l4->l4_sin,
30541edb306SCy Schubert 				    sizeof(l4->l4_sin)) == -1) {
30641edb306SCy Schubert 				if (errno != EINPROGRESS) {
30741edb306SCy Schubert 					if (opts & OPT_VERBOSE)
30841edb306SCy Schubert 						fprintf(stderr, "failed\n");
30941edb306SCy Schubert 					perror("connect");
31041edb306SCy Schubert 					close(fd);
31141edb306SCy Schubert 					fd = -1;
31241edb306SCy Schubert 				} else {
31341edb306SCy Schubert 					if (opts & OPT_VERBOSE)
31441edb306SCy Schubert 						fprintf(stderr, "waiting\n");
31541edb306SCy Schubert 					l4->l4_rw = -2;
31641edb306SCy Schubert 				}
31741edb306SCy Schubert 			} else {
31841edb306SCy Schubert 				if (opts & OPT_VERBOSE)
31941edb306SCy Schubert 					fprintf(stderr, "connected\n");
32041edb306SCy Schubert 				connectl4(l4);
32141edb306SCy Schubert 			}
32241edb306SCy Schubert 			l4->l4_fd = fd;
32341edb306SCy Schubert 		}
32441edb306SCy Schubert 	}
32541edb306SCy Schubert 
32641edb306SCy Schubert 	/*
32741edb306SCy Schubert 	 * Now look for fd's which we're expecting to read/write from.
32841edb306SCy Schubert 	 */
32941edb306SCy Schubert 	FD_ZERO(&rfd);
33041edb306SCy Schubert 	FD_ZERO(&wfd);
33141edb306SCy Schubert 	tv.tv_sec = MIN(rtimeout, ctimeout);
33241edb306SCy Schubert 	tv.tv_usec = 0;
33341edb306SCy Schubert 
33441edb306SCy Schubert 	for (l4 = l4list; l4; l4 = l4->l4_next)
33541edb306SCy Schubert 		if (l4->l4_rw == 0) {
33641edb306SCy Schubert 			if (now - l4->l4_last > rtimeout) {
33741edb306SCy Schubert 				if (opts & OPT_VERBOSE)
33841edb306SCy Schubert 					fprintf(stderr, "%d: Read timeout\n",
33941edb306SCy Schubert 						l4->l4_fd);
34041edb306SCy Schubert 				closel4(l4, 1);
34141edb306SCy Schubert 				continue;
34241edb306SCy Schubert 			}
34341edb306SCy Schubert 			if (opts & OPT_VERBOSE)
34441edb306SCy Schubert 				fprintf(stderr, "Wait for read on fd %d\n",
34541edb306SCy Schubert 					l4->l4_fd);
34641edb306SCy Schubert 			FD_SET(l4->l4_fd, &rfd);
34741edb306SCy Schubert 			if (l4->l4_fd > mfd)
34841edb306SCy Schubert 				mfd = l4->l4_fd;
34941edb306SCy Schubert 		} else if ((l4->l4_rw == 1 && l4->l4_wlen) ||
35041edb306SCy Schubert 			   l4->l4_rw == -2) {
35141edb306SCy Schubert 			if ((l4->l4_rw == -2) &&
35241edb306SCy Schubert 			    (now - l4->l4_last > ctimeout)) {
35341edb306SCy Schubert 				if (opts & OPT_VERBOSE)
35441edb306SCy Schubert 					fprintf(stderr,
35541edb306SCy Schubert 						"%d: connect timeout\n",
35641edb306SCy Schubert 						l4->l4_fd);
35741edb306SCy Schubert 				closel4(l4);
35841edb306SCy Schubert 				continue;
35941edb306SCy Schubert 			}
36041edb306SCy Schubert 			if (opts & OPT_VERBOSE)
36141edb306SCy Schubert 				fprintf(stderr, "Wait for write on fd %d\n",
36241edb306SCy Schubert 					l4->l4_fd);
36341edb306SCy Schubert 			FD_SET(l4->l4_fd, &wfd);
36441edb306SCy Schubert 			if (l4->l4_fd > mfd)
36541edb306SCy Schubert 				mfd = l4->l4_fd;
36641edb306SCy Schubert 		}
36741edb306SCy Schubert 
36841edb306SCy Schubert 	if (opts & OPT_VERBOSE)
36941edb306SCy Schubert 		fprintf(stderr, "Select: max fd %d wait %d\n", mfd + 1,
37041edb306SCy Schubert 			tv.tv_sec);
37141edb306SCy Schubert 	i = select(mfd + 1, &rfd, &wfd, NULL, &tv);
37241edb306SCy Schubert 	if (i == -1) {
37341edb306SCy Schubert 		perror("select");
37464e8b270SCy Schubert 		return(-1);
37541edb306SCy Schubert 	}
37641edb306SCy Schubert 
37741edb306SCy Schubert 	now1 = time(NULL);
37841edb306SCy Schubert 
37941edb306SCy Schubert 	for (l4 = l4list; (i > 0) && l4; l4 = l4->l4_next) {
38041edb306SCy Schubert 		if (l4->l4_fd < 0)
38141edb306SCy Schubert 			continue;
38241edb306SCy Schubert 		if (FD_ISSET(l4->l4_fd, &rfd)) {
38341edb306SCy Schubert 			if (opts & OPT_VERBOSE)
38441edb306SCy Schubert 				fprintf(stderr, "Ready to read on fd %d\n",
38541edb306SCy Schubert 					l4->l4_fd);
38641edb306SCy Schubert 			readfd(l4);
38741edb306SCy Schubert 			i--;
38841edb306SCy Schubert 		}
38941edb306SCy Schubert 
39041edb306SCy Schubert 		if ((l4->l4_fd >= 0) && FD_ISSET(l4->l4_fd, &wfd)) {
39141edb306SCy Schubert 			if (opts & OPT_VERBOSE)
39241edb306SCy Schubert 				fprintf(stderr, "Ready to write on fd %d\n",
39341edb306SCy Schubert 					l4->l4_fd);
39441edb306SCy Schubert 			writefd(l4);
39541edb306SCy Schubert 			i--;
39641edb306SCy Schubert 		}
39741edb306SCy Schubert 	}
39864e8b270SCy Schubert 	return(0);
39941edb306SCy Schubert }
40041edb306SCy Schubert 
40141edb306SCy Schubert 
402efeb8bffSCy Schubert int
gethostport(char * str,int lnum,u_32_t * ipp,u_short * portp)403efeb8bffSCy Schubert gethostport(char *str, int lnum, u_32_t *ipp, u_short *portp)
40441edb306SCy Schubert {
40541edb306SCy Schubert 	struct servent *sp;
40641edb306SCy Schubert 	struct hostent *hp;
40741edb306SCy Schubert 	char *host, *port;
40841edb306SCy Schubert 	struct in_addr ip;
40941edb306SCy Schubert 
41041edb306SCy Schubert 	host = str;
41141edb306SCy Schubert 	port = strchr(host, ',');
41241edb306SCy Schubert 	if (port)
41341edb306SCy Schubert 		*port++ = '\0';
41441edb306SCy Schubert 
41541edb306SCy Schubert #ifdef	HAVE_INET_ATON
41641edb306SCy Schubert 	if (ISDIGIT(*host) && inet_aton(host, &ip))
41741edb306SCy Schubert 		*ipp = ip.s_addr;
41841edb306SCy Schubert #else
41941edb306SCy Schubert 	if (ISDIGIT(*host))
42041edb306SCy Schubert 		*ipp = inet_addr(host);
42141edb306SCy Schubert #endif
42241edb306SCy Schubert 	else {
42341edb306SCy Schubert 		if (!(hp = gethostbyname(host))) {
42441edb306SCy Schubert 			fprintf(stderr, "%d: can't resolve hostname: %s\n",
42541edb306SCy Schubert 				lnum, host);
42664e8b270SCy Schubert 			return(0);
42741edb306SCy Schubert 		}
42841edb306SCy Schubert 		*ipp = *(u_32_t *)hp->h_addr;
42941edb306SCy Schubert 	}
43041edb306SCy Schubert 
43141edb306SCy Schubert 	if (port) {
43241edb306SCy Schubert 		if (ISDIGIT(*port))
43341edb306SCy Schubert 			*portp = htons(atoi(port));
43441edb306SCy Schubert 		else {
43541edb306SCy Schubert 			sp = getservbyname(port, "tcp");
43641edb306SCy Schubert 			if (sp)
43741edb306SCy Schubert 				*portp = sp->s_port;
43841edb306SCy Schubert 			else {
43941edb306SCy Schubert 				fprintf(stderr, "%d: unknown service %s\n",
44041edb306SCy Schubert 					lnum, port);
44164e8b270SCy Schubert 				return(0);
44241edb306SCy Schubert 			}
44341edb306SCy Schubert 		}
44441edb306SCy Schubert 	} else
44541edb306SCy Schubert 		*portp = 0;
44664e8b270SCy Schubert 	return(1);
44741edb306SCy Schubert }
44841edb306SCy Schubert 
44941edb306SCy Schubert 
450efeb8bffSCy Schubert char *
mapfile(char * file,size_t * sizep)451efeb8bffSCy Schubert mapfile(char *file, size_t *sizep)
45241edb306SCy Schubert {
45341edb306SCy Schubert 	struct stat sb;
45441edb306SCy Schubert 	caddr_t addr;
45541edb306SCy Schubert 	int fd;
45641edb306SCy Schubert 
45741edb306SCy Schubert 	fd = open(file, O_RDONLY);
45841edb306SCy Schubert 	if (fd == -1) {
45941edb306SCy Schubert 		perror("open(mapfile)");
46064e8b270SCy Schubert 		return(NULL);
46141edb306SCy Schubert 	}
46241edb306SCy Schubert 
46341edb306SCy Schubert 	if (fstat(fd, &sb) == -1) {
46441edb306SCy Schubert 		perror("fstat(mapfile)");
46541edb306SCy Schubert 		close(fd);
46664e8b270SCy Schubert 		return(NULL);
46741edb306SCy Schubert 	}
46841edb306SCy Schubert 
46941edb306SCy Schubert 	addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
47041edb306SCy Schubert 	if (addr == (caddr_t)-1) {
47141edb306SCy Schubert 		perror("mmap(mapfile)");
47241edb306SCy Schubert 		close(fd);
47364e8b270SCy Schubert 		return(NULL);
47441edb306SCy Schubert 	}
47541edb306SCy Schubert 	close(fd);
47641edb306SCy Schubert 	*sizep = sb.st_size;
47741edb306SCy Schubert 	return(char *)addr;
47841edb306SCy Schubert }
47941edb306SCy Schubert 
48041edb306SCy Schubert 
481efeb8bffSCy Schubert int
readconfig(char * filename)482efeb8bffSCy Schubert readconfig(char *filename)
48341edb306SCy Schubert {
48441edb306SCy Schubert 	char c, buf[512], *s, *t, *errtxt = NULL, *line;
48541edb306SCy Schubert 	int num, err = 0;
48641edb306SCy Schubert 	ipnat_t *ipn;
48741edb306SCy Schubert 	l4cfg_t *l4;
48841edb306SCy Schubert 	FILE *fp;
48941edb306SCy Schubert 
49041edb306SCy Schubert 	fp = fopen(filename, "r");
49141edb306SCy Schubert 	if (!fp) {
49241edb306SCy Schubert 		perror("open(configfile)");
49364e8b270SCy Schubert 		return(-1);
49441edb306SCy Schubert 	}
49541edb306SCy Schubert 
49641edb306SCy Schubert 	bzero((char *)&template, sizeof(template));
49741edb306SCy Schubert 	template.l4_fd = -1;
49841edb306SCy Schubert 	template.l4_rw = -1;
49941edb306SCy Schubert 	template.l4_sin.sin_family = AF_INET;
50041edb306SCy Schubert 	ipn = &template.l4_nat;
50141edb306SCy Schubert 	ipn->in_flags = IPN_TCP|IPN_ROUNDR;
50241edb306SCy Schubert 	ipn->in_redir = NAT_REDIRECT;
50341edb306SCy Schubert 
50441edb306SCy Schubert 	for (num = 1; fgets(buf, sizeof(buf), fp); num++) {
50541edb306SCy Schubert 		s = strchr(buf, '\n');
50641edb306SCy Schubert 		if  (!s) {
50741edb306SCy Schubert 			fprintf(stderr, "%d: line too long\n", num);
50841edb306SCy Schubert 			fclose(fp);
50964e8b270SCy Schubert 			return(-1);
51041edb306SCy Schubert 		}
51141edb306SCy Schubert 
51241edb306SCy Schubert 		*s = '\0';
51341edb306SCy Schubert 
51441edb306SCy Schubert 		/*
51541edb306SCy Schubert 		 * lines which are comments
51641edb306SCy Schubert 		 */
51741edb306SCy Schubert 		s = strchr(buf, '#');
51841edb306SCy Schubert 		if (s)
51941edb306SCy Schubert 			*s = '\0';
52041edb306SCy Schubert 
52141edb306SCy Schubert 		/*
52241edb306SCy Schubert 		 * Skip leading whitespace
52341edb306SCy Schubert 		 */
52441edb306SCy Schubert 		for (line = buf; (c = *line) && ISSPACE(c); line++)
52541edb306SCy Schubert 			;
52641edb306SCy Schubert 		if (!*line)
52741edb306SCy Schubert 			continue;
52841edb306SCy Schubert 
52941edb306SCy Schubert 		if (opts & OPT_VERBOSE)
53041edb306SCy Schubert 			fprintf(stderr, "Parsing: [%s]\n", line);
53141edb306SCy Schubert 		t = strtok(line, " \t");
53241edb306SCy Schubert 		if (!t)
53341edb306SCy Schubert 			continue;
53441edb306SCy Schubert 		if (!strcasecmp(t, "interface")) {
53541edb306SCy Schubert 			s = strtok(NULL, " \t");
53641edb306SCy Schubert 			if (s)
53741edb306SCy Schubert 				t = strtok(NULL, "\t");
53841edb306SCy Schubert 			if (!s || !t) {
53941edb306SCy Schubert 				errtxt = line;
54041edb306SCy Schubert 				err = -1;
54141edb306SCy Schubert 				break;
54241edb306SCy Schubert 			}
54341edb306SCy Schubert 
54441edb306SCy Schubert 			if (!strchr(t, ',')) {
54541edb306SCy Schubert 				fprintf(stderr,
54641edb306SCy Schubert 					"%d: local address,port missing\n",
54741edb306SCy Schubert 					num);
54841edb306SCy Schubert 				err = -1;
54941edb306SCy Schubert 				break;
55041edb306SCy Schubert 			}
55141edb306SCy Schubert 
55241edb306SCy Schubert 			strncpy(ipn->in_ifname, s, sizeof(ipn->in_ifname));
55341edb306SCy Schubert 			if (!gethostport(t, num, &ipn->in_outip,
55441edb306SCy Schubert 					 &ipn->in_pmin)) {
55541edb306SCy Schubert 				errtxt = line;
55641edb306SCy Schubert 				err = -1;
55741edb306SCy Schubert 				break;
55841edb306SCy Schubert 			}
55941edb306SCy Schubert 			ipn->in_outmsk = 0xffffffff;
56041edb306SCy Schubert 			ipn->in_pmax = ipn->in_pmin;
56141edb306SCy Schubert 			if (opts & OPT_VERBOSE)
56241edb306SCy Schubert 				fprintf(stderr,
56341edb306SCy Schubert 					"Interface %s %s/%#x port %u\n",
56441edb306SCy Schubert 					ipn->in_ifname,
56541edb306SCy Schubert 					inet_ntoa(ipn->in_out[0]),
56641edb306SCy Schubert 					ipn->in_outmsk, ipn->in_pmin);
56741edb306SCy Schubert 		} else if (!strcasecmp(t, "remote")) {
56841edb306SCy Schubert 			if (!*ipn->in_ifname) {
56941edb306SCy Schubert 				fprintf(stderr,
57041edb306SCy Schubert 					"%d: ifname not set prior to remote\n",
57141edb306SCy Schubert 					num);
57241edb306SCy Schubert 				err = -1;
57341edb306SCy Schubert 				break;
57441edb306SCy Schubert 			}
57541edb306SCy Schubert 			s = strtok(NULL, " \t");
57641edb306SCy Schubert 			if (s)
57741edb306SCy Schubert 				t = strtok(NULL, "");
57841edb306SCy Schubert 			if (!s || !t || strcasecmp(s, "server")) {
57941edb306SCy Schubert 				errtxt = line;
58041edb306SCy Schubert 				err = -1;
58141edb306SCy Schubert 				break;
58241edb306SCy Schubert 			}
58341edb306SCy Schubert 
58441edb306SCy Schubert 			ipn->in_pnext = 0;
58541edb306SCy Schubert 			if (!gethostport(t, num, &ipn->in_inip,
58641edb306SCy Schubert 					 &ipn->in_pnext)) {
58741edb306SCy Schubert 				errtxt = line;
58841edb306SCy Schubert 				err = -1;
58941edb306SCy Schubert 				break;
59041edb306SCy Schubert 			}
59141edb306SCy Schubert 			ipn->in_inmsk = 0xffffffff;
59241edb306SCy Schubert 			if (ipn->in_pnext == 0)
59341edb306SCy Schubert 				ipn->in_pnext = ipn->in_pmin;
59441edb306SCy Schubert 
59541edb306SCy Schubert 			l4 = (l4cfg_t *)malloc(sizeof(*l4));
59641edb306SCy Schubert 			if (!l4) {
59741edb306SCy Schubert 				fprintf(stderr, "%d: out of memory (%d)\n",
59841edb306SCy Schubert 					num, sizeof(*l4));
59941edb306SCy Schubert 				err = -1;
60041edb306SCy Schubert 				break;
60141edb306SCy Schubert 			}
60241edb306SCy Schubert 			bcopy((char *)&template, (char *)l4, sizeof(*l4));
60341edb306SCy Schubert 			l4->l4_sin.sin_addr = ipn->in_in[0];
60441edb306SCy Schubert 			l4->l4_sin.sin_port = ipn->in_pnext;
60541edb306SCy Schubert 			l4->l4_next = l4list;
60641edb306SCy Schubert 			l4list = l4;
60741edb306SCy Schubert 		} else if (!strcasecmp(t, "connect")) {
60841edb306SCy Schubert 			s = strtok(NULL, " \t");
60941edb306SCy Schubert 			if (s)
61041edb306SCy Schubert 				t = strtok(NULL, "\t");
61141edb306SCy Schubert 			if (!s || !t) {
61241edb306SCy Schubert 				errtxt = line;
61341edb306SCy Schubert 				err = -1;
61441edb306SCy Schubert 				break;
61541edb306SCy Schubert 			} else if (!strcasecmp(s, "timeout")) {
61641edb306SCy Schubert 				ctimeout = atoi(t);
61741edb306SCy Schubert 				if (opts & OPT_VERBOSE)
61841edb306SCy Schubert 					fprintf(stderr, "connect timeout %d\n",
61941edb306SCy Schubert 						ctimeout);
62041edb306SCy Schubert 			} else if (!strcasecmp(s, "frequency")) {
62141edb306SCy Schubert 				frequency = atoi(t);
62241edb306SCy Schubert 				if (opts & OPT_VERBOSE)
62341edb306SCy Schubert 					fprintf(stderr,
62441edb306SCy Schubert 						"connect frequency %d\n",
62541edb306SCy Schubert 						frequency);
62641edb306SCy Schubert 			} else {
62741edb306SCy Schubert 				errtxt = line;
62841edb306SCy Schubert 				err = -1;
62941edb306SCy Schubert 				break;
63041edb306SCy Schubert 			}
63141edb306SCy Schubert 		} else if (!strcasecmp(t, "probe")) {
63241edb306SCy Schubert 			s = strtok(NULL, " \t");
63341edb306SCy Schubert 			if (!s) {
63441edb306SCy Schubert 				errtxt = line;
63541edb306SCy Schubert 				err = -1;
63641edb306SCy Schubert 				break;
63741edb306SCy Schubert 			} else if (!strcasecmp(s, "string")) {
63841edb306SCy Schubert 				if (probe) {
63941edb306SCy Schubert 					fprintf(stderr,
64041edb306SCy Schubert 						"%d: probe already set\n",
64141edb306SCy Schubert 						num);
64241edb306SCy Schubert 					err = -1;
64341edb306SCy Schubert 					break;
64441edb306SCy Schubert 				}
64541edb306SCy Schubert 				t = strtok(NULL, "");
64641edb306SCy Schubert 				if (!t) {
64741edb306SCy Schubert 					fprintf(stderr,
64841edb306SCy Schubert 						"%d: No probe string\n", num);
64941edb306SCy Schubert 					err = -1;
65041edb306SCy Schubert 					break;
65141edb306SCy Schubert 				}
65241edb306SCy Schubert 
65341edb306SCy Schubert 				probe = malloc(strlen(t));
65441edb306SCy Schubert 				copystr(probe, t);
65541edb306SCy Schubert 				plen = strlen(probe);
65641edb306SCy Schubert 				if (opts & OPT_VERBOSE)
65741edb306SCy Schubert 					fprintf(stderr, "Probe string [%s]\n",
65841edb306SCy Schubert 						probe);
65941edb306SCy Schubert 			} else if (!strcasecmp(s, "file")) {
66041edb306SCy Schubert 				t = strtok(NULL, " \t");
66141edb306SCy Schubert 				if (!t) {
66241edb306SCy Schubert 					errtxt = line;
66341edb306SCy Schubert 					err = -1;
66441edb306SCy Schubert 					break;
66541edb306SCy Schubert 				}
66641edb306SCy Schubert 				if (probe) {
66741edb306SCy Schubert 					fprintf(stderr,
66841edb306SCy Schubert 						"%d: probe already set\n",
66941edb306SCy Schubert 						num);
67041edb306SCy Schubert 					err = -1;
67141edb306SCy Schubert 					break;
67241edb306SCy Schubert 				}
67341edb306SCy Schubert 				probe = mapfile(t, &plen);
67441edb306SCy Schubert 				if (opts & OPT_VERBOSE)
67541edb306SCy Schubert 					fprintf(stderr,
67641edb306SCy Schubert 						"Probe file %s len %u@%p\n",
67741edb306SCy Schubert 						t, plen, probe);
67841edb306SCy Schubert 			}
67941edb306SCy Schubert 		} else if (!strcasecmp(t, "response")) {
68041edb306SCy Schubert 			s = strtok(NULL, " \t");
68141edb306SCy Schubert 			if (!s) {
68241edb306SCy Schubert 				errtxt = line;
68341edb306SCy Schubert 				err = -1;
68441edb306SCy Schubert 				break;
68541edb306SCy Schubert 			} else if (!strcasecmp(s, "timeout")) {
68641edb306SCy Schubert 				t = strtok(NULL, " \t");
68741edb306SCy Schubert 				if (!t) {
68841edb306SCy Schubert 					errtxt = line;
68941edb306SCy Schubert 					err = -1;
69041edb306SCy Schubert 					break;
69141edb306SCy Schubert 				}
69241edb306SCy Schubert 				rtimeout = atoi(t);
69341edb306SCy Schubert 				if (opts & OPT_VERBOSE)
69441edb306SCy Schubert 					fprintf(stderr,
69541edb306SCy Schubert 						"response timeout %d\n",
69641edb306SCy Schubert 						rtimeout);
69741edb306SCy Schubert 			} else if (!strcasecmp(s, "string")) {
69841edb306SCy Schubert 				if (response) {
69941edb306SCy Schubert 					fprintf(stderr,
70041edb306SCy Schubert 						"%d: response already set\n",
70141edb306SCy Schubert 						num);
70241edb306SCy Schubert 					err = -1;
70341edb306SCy Schubert 					break;
70441edb306SCy Schubert 				}
70541edb306SCy Schubert 				response = strdup(strtok(NULL, ""));
70641edb306SCy Schubert 				rlen = strlen(response);
70741edb306SCy Schubert 				template.l4_rsize = rlen;
70841edb306SCy Schubert 				template.l4_rbuf = malloc(rlen);
70941edb306SCy Schubert 				if (opts & OPT_VERBOSE)
71041edb306SCy Schubert 					fprintf(stderr,
71141edb306SCy Schubert 						"Response string [%s]\n",
71241edb306SCy Schubert 						response);
71341edb306SCy Schubert 			} else if (!strcasecmp(s, "file")) {
71441edb306SCy Schubert 				t = strtok(NULL, " \t");
71541edb306SCy Schubert 				if (!t) {
71641edb306SCy Schubert 					errtxt = line;
71741edb306SCy Schubert 					err = -1;
71841edb306SCy Schubert 					break;
71941edb306SCy Schubert 				}
72041edb306SCy Schubert 				if (response) {
72141edb306SCy Schubert 					fprintf(stderr,
72241edb306SCy Schubert 						"%d: response already set\n",
72341edb306SCy Schubert 						num);
72441edb306SCy Schubert 					err = -1;
72541edb306SCy Schubert 					break;
72641edb306SCy Schubert 				}
72741edb306SCy Schubert 				response = mapfile(t, &rlen);
72841edb306SCy Schubert 				template.l4_rsize = rlen;
72941edb306SCy Schubert 				template.l4_rbuf = malloc(rlen);
73041edb306SCy Schubert 				if (opts & OPT_VERBOSE)
73141edb306SCy Schubert 					fprintf(stderr,
73241edb306SCy Schubert 						"Response file %s len %u@%p\n",
73341edb306SCy Schubert 						t, rlen, response);
73441edb306SCy Schubert 			}
73541edb306SCy Schubert 		} else {
73641edb306SCy Schubert 			errtxt = line;
73741edb306SCy Schubert 			err = -1;
73841edb306SCy Schubert 			break;
73941edb306SCy Schubert 		}
74041edb306SCy Schubert 	}
74141edb306SCy Schubert 
74241edb306SCy Schubert 	if (errtxt)
74341edb306SCy Schubert 		fprintf(stderr, "%d: syntax error at \"%s\"\n", num, errtxt);
74441edb306SCy Schubert 	fclose(fp);
74564e8b270SCy Schubert 	return(err);
74641edb306SCy Schubert }
74741edb306SCy Schubert 
74841edb306SCy Schubert 
749efeb8bffSCy Schubert void
usage(char * prog)750efeb8bffSCy Schubert usage(char *prog)
75141edb306SCy Schubert {
75241edb306SCy Schubert 	fprintf(stderr, "Usage: %s -f <configfile>\n", prog);
75341edb306SCy Schubert 	exit(1);
75441edb306SCy Schubert }
75541edb306SCy Schubert 
75641edb306SCy Schubert 
757efeb8bffSCy Schubert int
main(int argc,char * argv[])758efeb8bffSCy Schubert main(int argc, char *argv[])
75941edb306SCy Schubert {
76041edb306SCy Schubert 	char *config = NULL;
76141edb306SCy Schubert 	int c;
76241edb306SCy Schubert 
76341edb306SCy Schubert 	while ((c = getopt(argc, argv, "f:nv")) != -1)
76441edb306SCy Schubert 		switch (c)
76541edb306SCy Schubert 		{
76641edb306SCy Schubert 		case 'f' :
76741edb306SCy Schubert 			config = optarg;
76841edb306SCy Schubert 			break;
76941edb306SCy Schubert 		case 'n' :
77041edb306SCy Schubert 			opts |= OPT_DONOTHING;
77141edb306SCy Schubert 			break;
77241edb306SCy Schubert 		case 'v' :
77341edb306SCy Schubert 			opts |= OPT_VERBOSE;
77441edb306SCy Schubert 			break;
77541edb306SCy Schubert 		}
77641edb306SCy Schubert 
77741edb306SCy Schubert 	if (config == NULL)
77841edb306SCy Schubert 		usage(argv[0]);
77941edb306SCy Schubert 
78041edb306SCy Schubert 	if (readconfig(config))
78141edb306SCy Schubert 		exit(1);
78241edb306SCy Schubert 
78341edb306SCy Schubert 	if (!l4list) {
78441edb306SCy Schubert 		fprintf(stderr, "No remote servers, exiting.");
78541edb306SCy Schubert 		exit(1);
78641edb306SCy Schubert 	}
78741edb306SCy Schubert 
78841edb306SCy Schubert 	if (!(opts & OPT_DONOTHING)) {
78941edb306SCy Schubert 		natfd = open(IPL_NAT, O_RDWR);
79041edb306SCy Schubert 		if (natfd == -1) {
79141edb306SCy Schubert 			perror("open(IPL_NAT)");
79241edb306SCy Schubert 			exit(1);
79341edb306SCy Schubert 		}
79441edb306SCy Schubert 	}
79541edb306SCy Schubert 
79641edb306SCy Schubert 	if (opts & OPT_VERBOSE)
79741edb306SCy Schubert 		fprintf(stderr, "Starting...\n");
79841edb306SCy Schubert 	while (runconfig() == 0)
79941edb306SCy Schubert 		;
80041edb306SCy Schubert }
801