Home | History | Annotate | Line # | Download | only in l4check
      1 /*	$NetBSD: l4check.c,v 1.1.1.2 2012/07/22 13:44:38 darrenr Exp $	*/
      2 
      3 /*
      4  * (C)Copyright (C) 2012 by Darren Reed.
      5  */
      6 #include <sys/types.h>
      7 #include <sys/stat.h>
      8 #include <sys/mman.h>
      9 #include <sys/socket.h>
     10 #include <sys/time.h>
     11 #include <sys/ioctl.h>
     12 
     13 #include <netinet/in.h>
     14 #include <netinet/in_systm.h>
     15 #include <netinet/ip.h>
     16 
     17 #include <net/if.h>
     18 
     19 #include <stdio.h>
     20 #include <netdb.h>
     21 #include <string.h>
     22 #include <ctype.h>
     23 #include <fcntl.h>
     24 #include <errno.h>
     25 #include <stdlib.h>
     26 
     27 #include "ip_compat.h"
     28 #include "ip_fil.h"
     29 #include "ip_nat.h"
     30 
     31 #include "ipf.h"
     32 
     33 extern	char	*optarg;
     34 
     35 
     36 typedef	struct	l4cfg	{
     37 	struct	l4cfg		*l4_next;
     38 	struct	ipnat		l4_nat;		/* NAT rule */
     39 	struct	sockaddr_in	l4_sin;		/* remote socket to connect */
     40 	time_t			l4_last;	/* when we last connected */
     41 	int			l4_alive;	/* 1 = remote alive */
     42 	int			l4_fd;
     43 	int			l4_rw;		/* 0 = reading, 1 = writing */
     44 	char			*l4_rbuf;	/* read buffer */
     45 	int			l4_rsize;	/* size of buffer */
     46 	int			l4_rlen;	/* how much used */
     47 	char			*l4_wptr;	/* next byte to write */
     48 	int			l4_wlen;	/* length yet to be written */
     49 } l4cfg_t;
     50 
     51 
     52 l4cfg_t *l4list = NULL;
     53 char *response = NULL;
     54 char *probe = NULL;
     55 l4cfg_t template;
     56 int frequency = 20;
     57 int ctimeout = 1;
     58 int rtimeout = 1;
     59 size_t plen = 0;
     60 size_t rlen = 0;
     61 int natfd = -1;
     62 int opts = 0;
     63 
     64 #if defined(sun) && !defined(__svr4__) && !defined(__SVR4)
     65 # define	strerror(x)	sys_errlist[x]
     66 #endif
     67 
     68 
     69 char *copystr(dst, src)
     70 	char *dst, *src;
     71 {
     72 	register char *s, *t, c;
     73 	register int esc = 0;
     74 
     75 	for (s = src, t = dst; s && t && (c = *s++); )
     76 		if (esc) {
     77 			esc = 0;
     78 			switch (c)
     79 			{
     80 			case 'n' :
     81 				*t++ = '\n';
     82 				break;
     83 			case 'r' :
     84 				*t++ = '\r';
     85 				break;
     86 			case 't' :
     87 				*t++ = '\t';
     88 				break;
     89 			}
     90 		} else if (c != '\\')
     91 			*t++ = c;
     92 		else
     93 			esc = 1;
     94 	*t = '\0';
     95 	return dst;
     96 }
     97 
     98 void addnat(l4)
     99 	l4cfg_t *l4;
    100 {
    101 	ipnat_t *ipn = &l4->l4_nat;
    102 
    103 	printf("Add NAT rule for %s/%#x,%u -> ", inet_ntoa(ipn->in_out[0]),
    104 		ipn->in_outmsk, ntohs(ipn->in_pmin));
    105 	printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ntohs(ipn->in_pnext));
    106 	if (!(opts & OPT_DONOTHING)) {
    107 		if (ioctl(natfd, SIOCADNAT, &ipn) == -1)
    108 			perror("ioctl(SIOCADNAT)");
    109 	}
    110 }
    111 
    112 
    113 void delnat(l4)
    114 	l4cfg_t *l4;
    115 {
    116 	ipnat_t *ipn = &l4->l4_nat;
    117 
    118 	printf("Remove NAT rule for %s/%#x,%u -> ",
    119 		inet_ntoa(ipn->in_out[0]), ipn->in_outmsk, ipn->in_pmin);
    120 	printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ipn->in_pnext);
    121 	if (!(opts & OPT_DONOTHING)) {
    122 		if (ioctl(natfd, SIOCRMNAT, &ipn) == -1)
    123 			perror("ioctl(SIOCRMNAT)");
    124 	}
    125 }
    126 
    127 
    128 void connectl4(l4)
    129 	l4cfg_t *l4;
    130 {
    131 	l4->l4_rw = 1;
    132 	l4->l4_rlen = 0;
    133 	l4->l4_wlen = plen;
    134 	if (!l4->l4_wlen) {
    135 		l4->l4_alive = 1;
    136 		addnat(l4);
    137 	} else
    138 		l4->l4_wptr = probe;
    139 }
    140 
    141 
    142 void closel4(l4, dead)
    143 	l4cfg_t *l4;
    144 	int dead;
    145 {
    146 	close(l4->l4_fd);
    147 	l4->l4_fd = -1;
    148 	l4->l4_rw = -1;
    149 	if (dead && l4->l4_alive) {
    150 		l4->l4_alive = 0;
    151 		delnat(l4);
    152 	}
    153 }
    154 
    155 
    156 void connectfd(l4)
    157 	l4cfg_t *l4;
    158 {
    159 	if (connect(l4->l4_fd, (struct sockaddr *)&l4->l4_sin,
    160 		    sizeof(l4->l4_sin)) == -1) {
    161 		if (errno == EISCONN) {
    162 			if (opts & OPT_VERBOSE)
    163 				fprintf(stderr, "Connected fd %d\n",
    164 					l4->l4_fd);
    165 			connectl4(l4);
    166 			return;
    167 		}
    168 		if (opts & OPT_VERBOSE)
    169 			fprintf(stderr, "Connect failed fd %d: %s\n",
    170 				l4->l4_fd, strerror(errno));
    171 		closel4(l4, 1);
    172 		return;
    173 	}
    174 	l4->l4_rw = 1;
    175 }
    176 
    177 
    178 void writefd(l4)
    179 	l4cfg_t *l4;
    180 {
    181 	char buf[80], *ptr;
    182 	int n, i, fd;
    183 
    184 	fd = l4->l4_fd;
    185 
    186 	if (l4->l4_rw == -2) {
    187 		connectfd(l4);
    188 		return;
    189 	}
    190 
    191 	n = l4->l4_wlen;
    192 
    193 	i = send(fd, l4->l4_wptr, n, 0);
    194 	if (i == 0 || i == -1) {
    195 		if (opts & OPT_VERBOSE)
    196 			fprintf(stderr, "Send on fd %d failed: %s\n",
    197 				fd, strerror(errno));
    198 		closel4(l4, 1);
    199 	} else {
    200 		l4->l4_wptr += i;
    201 		l4->l4_wlen -= i;
    202 		if (l4->l4_wlen == 0)
    203 			l4->l4_rw = 0;
    204 		if (opts & OPT_VERBOSE)
    205 			fprintf(stderr, "Sent %d bytes to fd %d\n", i, fd);
    206 	}
    207 }
    208 
    209 
    210 void readfd(l4)
    211 	l4cfg_t *l4;
    212 {
    213 	char buf[80], *ptr;
    214 	int n, i, fd;
    215 
    216 	fd = l4->l4_fd;
    217 
    218 	if (l4->l4_rw == -2) {
    219 		connectfd(l4);
    220 		return;
    221 	}
    222 
    223 	if (l4->l4_rsize) {
    224 		n = l4->l4_rsize - l4->l4_rlen;
    225 		ptr = l4->l4_rbuf + l4->l4_rlen;
    226 	} else {
    227 		n = sizeof(buf) - 1;
    228 		ptr = buf;
    229 	}
    230 
    231 	if (opts & OPT_VERBOSE)
    232 		fprintf(stderr, "Read %d bytes on fd %d to %p\n",
    233 			n, fd, ptr);
    234 	i = recv(fd, ptr, n, 0);
    235 	if (i == 0 || i == -1) {
    236 		if (opts & OPT_VERBOSE)
    237 			fprintf(stderr, "Read error on fd %d: %s\n",
    238 				fd, (i == 0) ? "EOF" : strerror(errno));
    239 		closel4(l4, 1);
    240 	} else {
    241 		if (ptr == buf)
    242 			ptr[i] = '\0';
    243 		if (opts & OPT_VERBOSE)
    244 			fprintf(stderr, "%d: Read %d bytes [%*.*s]\n",
    245 				fd, i, i, i, ptr);
    246 		if (ptr != buf) {
    247 			l4->l4_rlen += i;
    248 			if (l4->l4_rlen >= l4->l4_rsize) {
    249 				if (!strncmp(response, l4->l4_rbuf,
    250 					     l4->l4_rsize)) {
    251 					printf("%d: Good response\n",
    252 						fd);
    253 					if (!l4->l4_alive) {
    254 						l4->l4_alive = 1;
    255 						addnat(l4);
    256 					}
    257 					closel4(l4, 0);
    258 				} else {
    259 					if (opts & OPT_VERBOSE)
    260 						printf("%d: Bad response\n",
    261 							fd);
    262 					closel4(l4, 1);
    263 				}
    264 			}
    265 		} else if (!l4->l4_alive) {
    266 			l4->l4_alive = 1;
    267 			addnat(l4);
    268 			closel4(l4, 0);
    269 		}
    270 	}
    271 }
    272 
    273 
    274 int runconfig()
    275 {
    276 	int fd, opt, res, mfd, i;
    277 	struct timeval tv;
    278 	time_t now, now1;
    279 	fd_set rfd, wfd;
    280 	l4cfg_t *l4;
    281 
    282 	mfd = 0;
    283 	opt = 1;
    284 	now = time(NULL);
    285 
    286 	/*
    287 	 * First, initiate connections that are closed, as required.
    288 	 */
    289 	for (l4 = l4list; l4; l4 = l4->l4_next) {
    290 		if ((l4->l4_last + frequency < now) && (l4->l4_fd == -1)) {
    291 			l4->l4_last = now;
    292 			fd = socket(AF_INET, SOCK_STREAM, 0);
    293 			if (fd == -1)
    294 				continue;
    295 			setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt,
    296 				   sizeof(opt));
    297 #ifdef	O_NONBLOCK
    298 			if ((res = fcntl(fd, F_GETFL, 0)) != -1)
    299 				fcntl(fd, F_SETFL, res | O_NONBLOCK);
    300 #endif
    301 			if (opts & OPT_VERBOSE)
    302 				fprintf(stderr,
    303 					"Connecting to %s,%d (fd %d)...",
    304 					inet_ntoa(l4->l4_sin.sin_addr),
    305 					ntohs(l4->l4_sin.sin_port), fd);
    306 			if (connect(fd, (struct sockaddr *)&l4->l4_sin,
    307 				    sizeof(l4->l4_sin)) == -1) {
    308 				if (errno != EINPROGRESS) {
    309 					if (opts & OPT_VERBOSE)
    310 						fprintf(stderr, "failed\n");
    311 					perror("connect");
    312 					close(fd);
    313 					fd = -1;
    314 				} else {
    315 					if (opts & OPT_VERBOSE)
    316 						fprintf(stderr, "waiting\n");
    317 					l4->l4_rw = -2;
    318 				}
    319 			} else {
    320 				if (opts & OPT_VERBOSE)
    321 					fprintf(stderr, "connected\n");
    322 				connectl4(l4);
    323 			}
    324 			l4->l4_fd = fd;
    325 		}
    326 	}
    327 
    328 	/*
    329 	 * Now look for fd's which we're expecting to read/write from.
    330 	 */
    331 	FD_ZERO(&rfd);
    332 	FD_ZERO(&wfd);
    333 	tv.tv_sec = MIN(rtimeout, ctimeout);
    334 	tv.tv_usec = 0;
    335 
    336 	for (l4 = l4list; l4; l4 = l4->l4_next)
    337 		if (l4->l4_rw == 0) {
    338 			if (now - l4->l4_last > rtimeout) {
    339 				if (opts & OPT_VERBOSE)
    340 					fprintf(stderr, "%d: Read timeout\n",
    341 						l4->l4_fd);
    342 				closel4(l4, 1);
    343 				continue;
    344 			}
    345 			if (opts & OPT_VERBOSE)
    346 				fprintf(stderr, "Wait for read on fd %d\n",
    347 					l4->l4_fd);
    348 			FD_SET(l4->l4_fd, &rfd);
    349 			if (l4->l4_fd > mfd)
    350 				mfd = l4->l4_fd;
    351 		} else if ((l4->l4_rw == 1 && l4->l4_wlen) ||
    352 			   l4->l4_rw == -2) {
    353 			if ((l4->l4_rw == -2) &&
    354 			    (now - l4->l4_last > ctimeout)) {
    355 				if (opts & OPT_VERBOSE)
    356 					fprintf(stderr,
    357 						"%d: connect timeout\n",
    358 						l4->l4_fd);
    359 				closel4(l4);
    360 				continue;
    361 			}
    362 			if (opts & OPT_VERBOSE)
    363 				fprintf(stderr, "Wait for write on fd %d\n",
    364 					l4->l4_fd);
    365 			FD_SET(l4->l4_fd, &wfd);
    366 			if (l4->l4_fd > mfd)
    367 				mfd = l4->l4_fd;
    368 		}
    369 
    370 	if (opts & OPT_VERBOSE)
    371 		fprintf(stderr, "Select: max fd %d wait %d\n", mfd + 1,
    372 			tv.tv_sec);
    373 	i = select(mfd + 1, &rfd, &wfd, NULL, &tv);
    374 	if (i == -1) {
    375 		perror("select");
    376 		return -1;
    377 	}
    378 
    379 	now1 = time(NULL);
    380 
    381 	for (l4 = l4list; (i > 0) && l4; l4 = l4->l4_next) {
    382 		if (l4->l4_fd < 0)
    383 			continue;
    384 		if (FD_ISSET(l4->l4_fd, &rfd)) {
    385 			if (opts & OPT_VERBOSE)
    386 				fprintf(stderr, "Ready to read on fd %d\n",
    387 					l4->l4_fd);
    388 			readfd(l4);
    389 			i--;
    390 		}
    391 
    392 		if ((l4->l4_fd >= 0) && FD_ISSET(l4->l4_fd, &wfd)) {
    393 			if (opts & OPT_VERBOSE)
    394 				fprintf(stderr, "Ready to write on fd %d\n",
    395 					l4->l4_fd);
    396 			writefd(l4);
    397 			i--;
    398 		}
    399 	}
    400 	return 0;
    401 }
    402 
    403 
    404 int gethostport(str, lnum, ipp, portp)
    405 	char *str;
    406 	int lnum;
    407 	u_32_t *ipp;
    408 	u_short *portp;
    409 {
    410 	struct servent *sp;
    411 	struct hostent *hp;
    412 	char *host, *port;
    413 	struct in_addr ip;
    414 
    415 	host = str;
    416 	port = strchr(host, ',');
    417 	if (port)
    418 		*port++ = '\0';
    419 
    420 #ifdef	HAVE_INET_ATON
    421 	if (ISDIGIT(*host) && inet_aton(host, &ip))
    422 		*ipp = ip.s_addr;
    423 #else
    424 	if (ISDIGIT(*host))
    425 		*ipp = inet_addr(host);
    426 #endif
    427 	else {
    428 		if (!(hp = gethostbyname(host))) {
    429 			fprintf(stderr, "%d: can't resolve hostname: %s\n",
    430 				lnum, host);
    431 			return 0;
    432 		}
    433 		*ipp = *(u_32_t *)hp->h_addr;
    434 	}
    435 
    436 	if (port) {
    437 		if (ISDIGIT(*port))
    438 			*portp = htons(atoi(port));
    439 		else {
    440 			sp = getservbyname(port, "tcp");
    441 			if (sp)
    442 				*portp = sp->s_port;
    443 			else {
    444 				fprintf(stderr, "%d: unknown service %s\n",
    445 					lnum, port);
    446 				return 0;
    447 			}
    448 		}
    449 	} else
    450 		*portp = 0;
    451 	return 1;
    452 }
    453 
    454 
    455 char *mapfile(file, sizep)
    456 	char *file;
    457 	size_t *sizep;
    458 {
    459 	struct stat sb;
    460 	caddr_t addr;
    461 	int fd;
    462 
    463 	fd = open(file, O_RDONLY);
    464 	if (fd == -1) {
    465 		perror("open(mapfile)");
    466 		return NULL;
    467 	}
    468 
    469 	if (fstat(fd, &sb) == -1) {
    470 		perror("fstat(mapfile)");
    471 		close(fd);
    472 		return NULL;
    473 	}
    474 
    475 	addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
    476 	if (addr == (caddr_t)-1) {
    477 		perror("mmap(mapfile)");
    478 		close(fd);
    479 		return NULL;
    480 	}
    481 	close(fd);
    482 	*sizep = sb.st_size;
    483 	return (char *)addr;
    484 }
    485 
    486 
    487 int readconfig(filename)
    488 	char *filename;
    489 {
    490 	char c, buf[512], *s, *t, *errtxt = NULL, *line;
    491 	int num, err = 0;
    492 	ipnat_t *ipn;
    493 	l4cfg_t *l4;
    494 	FILE *fp;
    495 
    496 	fp = fopen(filename, "r");
    497 	if (!fp) {
    498 		perror("open(configfile)");
    499 		return -1;
    500 	}
    501 
    502 	bzero((char *)&template, sizeof(template));
    503 	template.l4_fd = -1;
    504 	template.l4_rw = -1;
    505 	template.l4_sin.sin_family = AF_INET;
    506 	ipn = &template.l4_nat;
    507 	ipn->in_flags = IPN_TCP|IPN_ROUNDR;
    508 	ipn->in_redir = NAT_REDIRECT;
    509 
    510 	for (num = 1; fgets(buf, sizeof(buf), fp); num++) {
    511 		s = strchr(buf, '\n');
    512 		if  (!s) {
    513 			fprintf(stderr, "%d: line too long\n", num);
    514 			fclose(fp);
    515 			return -1;
    516 		}
    517 
    518 		*s = '\0';
    519 
    520 		/*
    521 		 * lines which are comments
    522 		 */
    523 		s = strchr(buf, '#');
    524 		if (s)
    525 			*s = '\0';
    526 
    527 		/*
    528 		 * Skip leading whitespace
    529 		 */
    530 		for (line = buf; (c = *line) && ISSPACE(c); line++)
    531 			;
    532 		if (!*line)
    533 			continue;
    534 
    535 		if (opts & OPT_VERBOSE)
    536 			fprintf(stderr, "Parsing: [%s]\n", line);
    537 		t = strtok(line, " \t");
    538 		if (!t)
    539 			continue;
    540 		if (!strcasecmp(t, "interface")) {
    541 			s = strtok(NULL, " \t");
    542 			if (s)
    543 				t = strtok(NULL, "\t");
    544 			if (!s || !t) {
    545 				errtxt = line;
    546 				err = -1;
    547 				break;
    548 			}
    549 
    550 			if (!strchr(t, ',')) {
    551 				fprintf(stderr,
    552 					"%d: local address,port missing\n",
    553 					num);
    554 				err = -1;
    555 				break;
    556 			}
    557 
    558 			strncpy(ipn->in_ifname, s, sizeof(ipn->in_ifname));
    559 			if (!gethostport(t, num, &ipn->in_outip,
    560 					 &ipn->in_pmin)) {
    561 				errtxt = line;
    562 				err = -1;
    563 				break;
    564 			}
    565 			ipn->in_outmsk = 0xffffffff;
    566 			ipn->in_pmax = ipn->in_pmin;
    567 			if (opts & OPT_VERBOSE)
    568 				fprintf(stderr,
    569 					"Interface %s %s/%#x port %u\n",
    570 					ipn->in_ifname,
    571 					inet_ntoa(ipn->in_out[0]),
    572 					ipn->in_outmsk, ipn->in_pmin);
    573 		} else if (!strcasecmp(t, "remote")) {
    574 			if (!*ipn->in_ifname) {
    575 				fprintf(stderr,
    576 					"%d: ifname not set prior to remote\n",
    577 					num);
    578 				err = -1;
    579 				break;
    580 			}
    581 			s = strtok(NULL, " \t");
    582 			if (s)
    583 				t = strtok(NULL, "");
    584 			if (!s || !t || strcasecmp(s, "server")) {
    585 				errtxt = line;
    586 				err = -1;
    587 				break;
    588 			}
    589 
    590 			ipn->in_pnext = 0;
    591 			if (!gethostport(t, num, &ipn->in_inip,
    592 					 &ipn->in_pnext)) {
    593 				errtxt = line;
    594 				err = -1;
    595 				break;
    596 			}
    597 			ipn->in_inmsk = 0xffffffff;
    598 			if (ipn->in_pnext == 0)
    599 				ipn->in_pnext = ipn->in_pmin;
    600 
    601 			l4 = (l4cfg_t *)malloc(sizeof(*l4));
    602 			if (!l4) {
    603 				fprintf(stderr, "%d: out of memory (%d)\n",
    604 					num, sizeof(*l4));
    605 				err = -1;
    606 				break;
    607 			}
    608 			bcopy((char *)&template, (char *)l4, sizeof(*l4));
    609 			l4->l4_sin.sin_addr = ipn->in_in[0];
    610 			l4->l4_sin.sin_port = ipn->in_pnext;
    611 			l4->l4_next = l4list;
    612 			l4list = l4;
    613 		} else if (!strcasecmp(t, "connect")) {
    614 			s = strtok(NULL, " \t");
    615 			if (s)
    616 				t = strtok(NULL, "\t");
    617 			if (!s || !t) {
    618 				errtxt = line;
    619 				err = -1;
    620 				break;
    621 			} else if (!strcasecmp(s, "timeout")) {
    622 				ctimeout = atoi(t);
    623 				if (opts & OPT_VERBOSE)
    624 					fprintf(stderr, "connect timeout %d\n",
    625 						ctimeout);
    626 			} else if (!strcasecmp(s, "frequency")) {
    627 				frequency = atoi(t);
    628 				if (opts & OPT_VERBOSE)
    629 					fprintf(stderr,
    630 						"connect frequency %d\n",
    631 						frequency);
    632 			} else {
    633 				errtxt = line;
    634 				err = -1;
    635 				break;
    636 			}
    637 		} else if (!strcasecmp(t, "probe")) {
    638 			s = strtok(NULL, " \t");
    639 			if (!s) {
    640 				errtxt = line;
    641 				err = -1;
    642 				break;
    643 			} else if (!strcasecmp(s, "string")) {
    644 				if (probe) {
    645 					fprintf(stderr,
    646 						"%d: probe already set\n",
    647 						num);
    648 					err = -1;
    649 					break;
    650 				}
    651 				t = strtok(NULL, "");
    652 				if (!t) {
    653 					fprintf(stderr,
    654 						"%d: No probe string\n", num);
    655 					err = -1;
    656 					break;
    657 				}
    658 
    659 				probe = malloc(strlen(t));
    660 				copystr(probe, t);
    661 				plen = strlen(probe);
    662 				if (opts & OPT_VERBOSE)
    663 					fprintf(stderr, "Probe string [%s]\n",
    664 						probe);
    665 			} else if (!strcasecmp(s, "file")) {
    666 				t = strtok(NULL, " \t");
    667 				if (!t) {
    668 					errtxt = line;
    669 					err = -1;
    670 					break;
    671 				}
    672 				if (probe) {
    673 					fprintf(stderr,
    674 						"%d: probe already set\n",
    675 						num);
    676 					err = -1;
    677 					break;
    678 				}
    679 				probe = mapfile(t, &plen);
    680 				if (opts & OPT_VERBOSE)
    681 					fprintf(stderr,
    682 						"Probe file %s len %u@%p\n",
    683 						t, plen, probe);
    684 			}
    685 		} else if (!strcasecmp(t, "response")) {
    686 			s = strtok(NULL, " \t");
    687 			if (!s) {
    688 				errtxt = line;
    689 				err = -1;
    690 				break;
    691 			} else if (!strcasecmp(s, "timeout")) {
    692 				t = strtok(NULL, " \t");
    693 				if (!t) {
    694 					errtxt = line;
    695 					err = -1;
    696 					break;
    697 				}
    698 				rtimeout = atoi(t);
    699 				if (opts & OPT_VERBOSE)
    700 					fprintf(stderr,
    701 						"response timeout %d\n",
    702 						rtimeout);
    703 			} else if (!strcasecmp(s, "string")) {
    704 				if (response) {
    705 					fprintf(stderr,
    706 						"%d: response already set\n",
    707 						num);
    708 					err = -1;
    709 					break;
    710 				}
    711 				response = strdup(strtok(NULL, ""));
    712 				rlen = strlen(response);
    713 				template.l4_rsize = rlen;
    714 				template.l4_rbuf = malloc(rlen);
    715 				if (opts & OPT_VERBOSE)
    716 					fprintf(stderr,
    717 						"Response string [%s]\n",
    718 						response);
    719 			} else if (!strcasecmp(s, "file")) {
    720 				t = strtok(NULL, " \t");
    721 				if (!t) {
    722 					errtxt = line;
    723 					err = -1;
    724 					break;
    725 				}
    726 				if (response) {
    727 					fprintf(stderr,
    728 						"%d: response already set\n",
    729 						num);
    730 					err = -1;
    731 					break;
    732 				}
    733 				response = mapfile(t, &rlen);
    734 				template.l4_rsize = rlen;
    735 				template.l4_rbuf = malloc(rlen);
    736 				if (opts & OPT_VERBOSE)
    737 					fprintf(stderr,
    738 						"Response file %s len %u@%p\n",
    739 						t, rlen, response);
    740 			}
    741 		} else {
    742 			errtxt = line;
    743 			err = -1;
    744 			break;
    745 		}
    746 	}
    747 
    748 	if (errtxt)
    749 		fprintf(stderr, "%d: syntax error at \"%s\"\n", num, errtxt);
    750 	fclose(fp);
    751 	return err;
    752 }
    753 
    754 
    755 void usage(prog)
    756 	char *prog;
    757 {
    758 	fprintf(stderr, "Usage: %s -f <configfile>\n", prog);
    759 	exit(1);
    760 }
    761 
    762 
    763 int main(argc, argv)
    764 	int argc;
    765 	char *argv[];
    766 {
    767 	char *config = NULL;
    768 	int c;
    769 
    770 	while ((c = getopt(argc, argv, "f:nv")) != -1)
    771 		switch (c)
    772 		{
    773 		case 'f' :
    774 			config = optarg;
    775 			break;
    776 		case 'n' :
    777 			opts |= OPT_DONOTHING;
    778 			break;
    779 		case 'v' :
    780 			opts |= OPT_VERBOSE;
    781 			break;
    782 		}
    783 
    784 	if (config == NULL)
    785 		usage(argv[0]);
    786 
    787 	if (readconfig(config))
    788 		exit(1);
    789 
    790 	if (!l4list) {
    791 		fprintf(stderr, "No remote servers, exiting.");
    792 		exit(1);
    793 	}
    794 
    795 	if (!(opts & OPT_DONOTHING)) {
    796 		natfd = open(IPL_NAT, O_RDWR);
    797 		if (natfd == -1) {
    798 			perror("open(IPL_NAT)");
    799 			exit(1);
    800 		}
    801 	}
    802 
    803 	if (opts & OPT_VERBOSE)
    804 		fprintf(stderr, "Starting...\n");
    805 	while (runconfig() == 0)
    806 		;
    807 }
    808