xref: /netbsd-src/external/bsd/ipf/dist/l4check/l4check.c (revision c9d5dc6c77aa32fd07899a7a63638e95ffa433dd)
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 
copystr(dst,src)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 
addnat(l4)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 
delnat(l4)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 
connectl4(l4)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 
closel4(l4,dead)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 
connectfd(l4)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 
writefd(l4)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 
readfd(l4)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 
runconfig()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 
gethostport(str,lnum,ipp,portp)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 
mapfile(file,sizep)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 
readconfig(filename)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 
usage(prog)755 void usage(prog)
756 	char *prog;
757 {
758 	fprintf(stderr, "Usage: %s -f <configfile>\n", prog);
759 	exit(1);
760 }
761 
762 
main(argc,argv)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