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