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