]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ipfilter/natparse.c
This commit was generated by cvs2svn to compensate for changes in r93982,
[FreeBSD/FreeBSD.git] / contrib / ipfilter / natparse.c
1 /*
2  * Copyright (C) 1993-2002 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  */
6 #ifdef __sgi
7 # include <sys/ptimers.h>
8 #endif
9 #include <stdio.h>
10 #include <string.h>
11 #include <fcntl.h>
12 #include <errno.h>
13 #include <sys/types.h>
14 #if !defined(__SVR4) && !defined(__svr4__)
15 #include <strings.h>
16 #else
17 #include <sys/byteorder.h>
18 #endif
19 #include <sys/time.h>
20 #include <sys/param.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <stddef.h>
24 #include <sys/socket.h>
25 #include <sys/ioctl.h>
26 #if defined(sun) && (defined(__svr4__) || defined(__SVR4))
27 # include <sys/ioccom.h>
28 # include <sys/sysmacros.h>
29 #endif
30 #include <netinet/in.h>
31 #include <netinet/in_systm.h>
32 #include <netinet/ip.h>
33 #include <netinet/tcp.h>
34 #include <net/if.h>
35 #if __FreeBSD_version >= 300000
36 # include <net/if_var.h>
37 #endif
38 #include <netdb.h>
39 #include <arpa/nameser.h>
40 #include <arpa/inet.h>
41 #include <resolv.h>
42 #include <ctype.h>
43 #include "netinet/ip_compat.h"
44 #include "netinet/ip_fil.h"
45 #include "netinet/ip_nat.h"
46 #include "netinet/ip_state.h"
47 #include "netinet/ip_proxy.h"
48 #include "ipf.h"
49
50 #if     defined(sun) && !SOLARIS2
51 # define        STRERROR(x)     sys_errlist[x]
52 extern  char    *sys_errlist[];
53 #else
54 # define        STRERROR(x)     strerror(x)
55 #endif
56
57 #if !defined(lint)
58 static const char sccsid[] ="@(#)ipnat.c        1.9 6/5/96 (C) 1993 Darren Reed";
59 static const char rcsid[] = "@(#)$Id: natparse.c,v 1.17.2.23 2002/02/22 15:32:55 darrenr Exp $";
60 #endif
61
62
63 #if     SOLARIS
64 #define bzero(a,b)      memset(a,0,b)
65 #endif
66
67 extern  void    printnat __P((ipnat_t *, int));
68 extern  int     countbits __P((u_32_t));
69 extern  char    *proto;
70
71 ipnat_t *natparse __P((char *, int));
72 void    natparsefile __P((int, char *, int));
73 void    nat_setgroupmap __P((struct ipnat *));
74
75
76 void nat_setgroupmap(n)
77 ipnat_t *n;
78 {
79         if (n->in_outmsk == n->in_inmsk)
80                 n->in_ippip = 1;
81         else if (n->in_flags & IPN_AUTOPORTMAP) {
82                 n->in_ippip = ~ntohl(n->in_inmsk);
83                 if (n->in_outmsk != 0xffffffff)
84                         n->in_ippip /= (~ntohl(n->in_outmsk) + 1);
85                 n->in_ippip++;
86                 if (n->in_ippip == 0)
87                         n->in_ippip = 1;
88                 n->in_ppip = USABLE_PORTS / n->in_ippip;
89         } else {
90                 n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk);
91                 n->in_nip = 0;
92                 if (!(n->in_ppip = n->in_pmin))
93                         n->in_ppip = 1;
94                 n->in_ippip = USABLE_PORTS / n->in_ppip;
95         }
96 }
97
98
99 /*
100  * Parse a line of input from the ipnat configuration file
101  */
102 ipnat_t *natparse(line, linenum)
103 char *line;
104 int linenum;
105 {
106         static ipnat_t ipn;
107         struct protoent *pr;
108         char *dnetm = NULL, *dport = NULL;
109         char *s, *t, *cps[31], **cpp;
110         int i, cnt;
111         char *port1a = NULL, *port1b = NULL, *port2a = NULL;
112
113         proto = NULL;
114
115         /*
116          * Search for end of line and comment marker, advance of leading spaces
117          */
118         if ((s = strchr(line, '\n')))
119                 *s = '\0';
120         if ((s = strchr(line, '#')))
121                 *s = '\0';
122         while (*line && isspace(*line))
123                 line++;
124         if (!*line)
125                 return NULL;
126
127         bzero((char *)&ipn, sizeof(ipn));
128         cnt = 0;
129
130         /*
131          * split line upto into segments.
132          */
133         for (i = 0, *cps = strtok(line, " \b\t\r\n"); cps[i] && i < 30; cnt++)
134                 cps[++i] = strtok(NULL, " \b\t\r\n");
135
136         cps[i] = NULL;
137
138         if (cnt < 3) {
139                 fprintf(stderr, "%d: not enough segments in line\n", linenum);
140                 return NULL;
141         }
142
143         cpp = cps;
144
145         /*
146          * Check first word is a recognised keyword and then is the interface
147          */
148         if (!strcasecmp(*cpp, "map"))
149                 ipn.in_redir = NAT_MAP;
150         else if (!strcasecmp(*cpp, "map-block"))
151                 ipn.in_redir = NAT_MAPBLK;
152         else if (!strcasecmp(*cpp, "rdr"))
153                 ipn.in_redir = NAT_REDIRECT;
154         else if (!strcasecmp(*cpp, "bimap"))
155                 ipn.in_redir = NAT_BIMAP;
156         else {
157                 fprintf(stderr, "%d: unknown mapping: \"%s\"\n",
158                         linenum, *cpp);
159                 return NULL;
160         }
161
162         cpp++;
163
164         strncpy(ipn.in_ifname, *cpp, sizeof(ipn.in_ifname) - 1);
165         ipn.in_ifname[sizeof(ipn.in_ifname) - 1] = '\0';
166         cpp++;
167
168         /*
169          * If the first word after the interface is "from" or is a ! then
170          * the expanded syntax is being used so parse it differently.
171          */
172         if (!strcasecmp(*cpp, "from") || (**cpp == '!')) {
173                 if (!strcmp(*cpp, "!")) {
174                         cpp++;
175                         if (strcasecmp(*cpp, "from")) {
176                                 fprintf(stderr, "Missing from after !\n");
177                                 return NULL;
178                         }
179                         ipn.in_flags |= IPN_NOTSRC;
180                 } else if (**cpp == '!') {
181                         if (strcasecmp(*cpp + 1, "from")) {
182                                 fprintf(stderr, "Missing from after !\n");
183                                 return NULL;
184                         }
185                         ipn.in_flags |= IPN_NOTSRC;
186                 }
187                 if ((ipn.in_flags & IPN_NOTSRC) &&
188                     (ipn.in_redir & (NAT_MAP|NAT_MAPBLK))) {
189                         fprintf(stderr, "Cannot use '! from' with map\n");
190                         return NULL;
191                 }
192
193                 ipn.in_flags |= IPN_FILTER;
194                 cpp++;
195                 if (ipn.in_redir == NAT_REDIRECT) {
196                         if (hostmask(&cpp, (u_32_t *)&ipn.in_srcip,
197                                      (u_32_t *)&ipn.in_srcmsk, &ipn.in_sport,
198                                      &ipn.in_scmp, &ipn.in_stop, linenum)) {
199                                 return NULL;
200                         }
201                 } else {
202                         if (hostmask(&cpp, (u_32_t *)&ipn.in_inip,
203                                      (u_32_t *)&ipn.in_inmsk, &ipn.in_sport,
204                                      &ipn.in_scmp, &ipn.in_stop, linenum)) {
205                                 return NULL;
206                         }
207                 }
208
209                 if (!strcmp(*cpp, "!")) {
210                         cpp++;
211                         ipn.in_flags |= IPN_NOTDST;
212                 } else if (**cpp == '!') {
213                         (*cpp)++;
214                         ipn.in_flags |= IPN_NOTDST;
215                 }
216
217                 if (strcasecmp(*cpp, "to")) {
218                         fprintf(stderr, "%d: unexpected keyword (%s) - to\n",
219                                 linenum, *cpp);
220                         return NULL;
221                 }
222                 if ((ipn.in_flags & IPN_NOTDST) &&
223                     (ipn.in_redir & (NAT_REDIRECT))) {
224                         fprintf(stderr, "Cannot use '! to' with rdr\n");
225                         return NULL;
226                 }
227
228                 if (!*++cpp) {
229                         fprintf(stderr, "%d: missing host after to\n", linenum);
230                         return NULL;
231                 }
232                 if (ipn.in_redir == NAT_REDIRECT) {
233                         if (hostmask(&cpp, (u_32_t *)&ipn.in_outip,
234                                      (u_32_t *)&ipn.in_outmsk, &ipn.in_dport,
235                                      &ipn.in_dcmp, &ipn.in_dtop, linenum)) {
236                                 return NULL;
237                         }
238                         ipn.in_pmin = htons(ipn.in_dport);
239                 } else {
240                         if (hostmask(&cpp, (u_32_t *)&ipn.in_srcip,
241                                      (u_32_t *)&ipn.in_srcmsk, &ipn.in_dport,
242                                      &ipn.in_dcmp, &ipn.in_dtop, linenum)) {
243                                 return NULL;
244                         }
245                 }
246         } else {
247                 s = *cpp;
248                 if (!s) {
249                         fprintf(stderr, "%d: short line\n", linenum);
250                         return NULL;
251                 }
252                 t = strchr(s, '/');
253                 if (!t) {
254                         fprintf(stderr, "%d: no netmask on LHS\n", linenum);
255                         return NULL;
256                 }
257                 *t++ = '\0';
258                 if (ipn.in_redir == NAT_REDIRECT) {
259                         if (hostnum((u_32_t *)&ipn.in_outip, s, linenum) == -1)
260                                 return NULL;
261                         if (genmask(t, (u_32_t *)&ipn.in_outmsk) == -1) {
262                                 return NULL;
263                         }
264                 } else {
265                         if (hostnum((u_32_t *)&ipn.in_inip, s, linenum) == -1)
266                                 return NULL;
267                         if (genmask(t, (u_32_t *)&ipn.in_inmsk) == -1) {
268                                 return NULL;
269                         }
270                 }
271                 cpp++;
272                 if (!*cpp) {
273                         fprintf(stderr, "%d: short line\n", linenum);
274                         return NULL;
275                 }
276         }
277
278         /*
279          * If it is a standard redirect then we expect it to have a port
280          * match after the hostmask.
281          */
282         if ((ipn.in_redir == NAT_REDIRECT) && !(ipn.in_flags & IPN_FILTER)) {
283                 if (strcasecmp(*cpp, "port")) {
284                         fprintf(stderr, "%d: missing fields - 1st port\n",
285                                 linenum);
286                         return NULL;
287                 }
288
289                 cpp++;
290
291                 if (!*cpp) {
292                         fprintf(stderr,
293                                 "%d: missing fields (destination port)\n",
294                                 linenum);
295                         return NULL;
296                 }
297
298                 if (isdigit(**cpp) && (s = strchr(*cpp, '-')))
299                         *s++ = '\0';
300                 else
301                         s = NULL;
302
303                 port1a = *cpp++;
304
305                 if (!strcmp(*cpp, "-")) {
306                         cpp++;
307                         s = *cpp++;
308                 }
309
310                 if (s)
311                         port1b = s;
312                 else
313                         ipn.in_pmax = ipn.in_pmin;
314         }
315
316         /*
317          * In the middle of the NAT rule syntax is -> to indicate the
318          * direction of translation.
319          */
320         if (!*cpp) {
321                 fprintf(stderr, "%d: missing fields (->)\n", linenum);
322                 return NULL;
323         }
324         if (strcmp(*cpp, "->")) {
325                 fprintf(stderr, "%d: missing ->\n", linenum);
326                 return NULL;
327         }
328         cpp++;
329
330         if (!*cpp) {
331                 fprintf(stderr, "%d: missing fields (%s)\n",
332                         linenum, ipn.in_redir ? "destination" : "target");
333                 return NULL;
334         }
335
336         if (ipn.in_redir == NAT_MAP) {
337                 if (!strcasecmp(*cpp, "range")) {
338                         cpp++;
339                         ipn.in_flags |= IPN_IPRANGE;
340                         if (!*cpp) {
341                                 fprintf(stderr, "%d: missing fields (%s)\n",
342                                         linenum,
343                                         ipn.in_redir ? "destination":"target");
344                                 return NULL;
345                         }
346                 }
347         }
348
349         if (ipn.in_flags & IPN_IPRANGE) {
350                 dnetm = strrchr(*cpp, '-');
351                 if (dnetm == NULL) {
352                         cpp++;
353                         if (*cpp && !strcmp(*cpp, "-") && *(cpp + 1))
354                                         dnetm = *(cpp + 1);
355                 } else
356                         *dnetm++ = '\0';
357                 if (dnetm == NULL || *dnetm == '\0') {
358                         fprintf(stderr,
359                                 "%d: desination range not specified\n",
360                                 linenum);
361                         return NULL;
362                 }
363         } else if (ipn.in_redir != NAT_REDIRECT) {
364                 dnetm = strrchr(*cpp, '/');
365                 if (dnetm == NULL) {
366                         cpp++;
367                         if (*cpp && !strcasecmp(*cpp, "netmask"))
368                                 dnetm = *++cpp;
369                 }
370                 if (dnetm == NULL) {
371                         fprintf(stderr,
372                                 "%d: missing fields (dest netmask)\n",
373                                 linenum);
374                         return NULL;
375                 }
376                 if (*dnetm == '/')
377                         *dnetm++ = '\0';
378         }
379
380         if (ipn.in_redir == NAT_REDIRECT) {
381                 dnetm = strchr(*cpp, ',');
382                 if (dnetm != NULL) {
383                         ipn.in_flags |= IPN_SPLIT;
384                         *dnetm++ = '\0';
385                 }
386                 if (hostnum((u_32_t *)&ipn.in_inip, *cpp, linenum) == -1)
387                         return NULL;
388         } else {
389                 if (!strcmp(*cpp, ipn.in_ifname))
390                         *cpp = "0";
391                 if (hostnum((u_32_t *)&ipn.in_outip, *cpp, linenum) == -1)
392                         return NULL;
393         }
394         cpp++;
395
396         if (ipn.in_redir & NAT_MAPBLK) {
397                 if (*cpp && strcasecmp(*cpp, "ports")) {
398                         fprintf(stderr,
399                                 "%d: expected \"ports\" - got \"%s\"\n",
400                                 linenum, *cpp);
401                         return NULL;
402                 }
403                 cpp++;
404                 if (*cpp) {
405                         ipn.in_pmin = atoi(*cpp);
406                         cpp++;
407                 } else
408                         ipn.in_pmin = 0;
409         } else if ((ipn.in_redir & NAT_BIMAP) == NAT_REDIRECT) {
410                 if (*cpp && (strrchr(*cpp, '/') != NULL)) {
411                         fprintf(stderr, "%d: No netmask supported in %s\n",
412                                 linenum, "destination host for redirect");
413                         return NULL;
414                 }
415
416                 if (!*cpp) {
417                         fprintf(stderr, "%d: Missing destination port %s\n",
418                                 linenum, "in redirect");
419                         return NULL;
420                 }
421
422                 /* If it's a in_redir, expect target port */
423
424                 if (strcasecmp(*cpp, "port")) {
425                         fprintf(stderr, "%d: missing fields - 2nd port (%s)\n",
426                                 linenum, *cpp);
427                         return NULL;
428                 }
429                 cpp++;
430                 if (!*cpp) {
431                         fprintf(stderr,
432                                 "%d: missing fields (destination port)\n",
433                                 linenum);
434                         return NULL;
435                 }
436
437                 port2a = *cpp++;
438         } 
439         if (dnetm && *dnetm == '/')
440                 *dnetm++ = '\0';
441
442         if (ipn.in_redir & (NAT_MAP|NAT_MAPBLK)) {
443                 if (ipn.in_flags & IPN_IPRANGE) {
444                         if (hostnum((u_32_t *)&ipn.in_outmsk, dnetm,
445                                     linenum) == -1)
446                                 return NULL;
447                 } else if (genmask(dnetm, (u_32_t *)&ipn.in_outmsk))
448                         return NULL;
449         } else {
450                 if (ipn.in_flags & IPN_SPLIT) {
451                         if (hostnum((u_32_t *)&ipn.in_inmsk, dnetm,
452                                     linenum) == -1)
453                                 return NULL;
454                 } else if (genmask("255.255.255.255", (u_32_t *)&ipn.in_inmsk))
455                         return NULL;
456                 if (!*cpp) {
457                         ipn.in_flags |= IPN_TCP; /* XXX- TCP only by default */
458                         proto = "tcp";
459                 } else {
460                         proto = *cpp++;
461                         if (!strcasecmp(proto, "tcp"))
462                                 ipn.in_flags |= IPN_TCP;
463                         else if (!strcasecmp(proto, "udp"))
464                                 ipn.in_flags |= IPN_UDP;
465                         else if (!strcasecmp(proto, "tcp/udp"))
466                                 ipn.in_flags |= IPN_TCPUDP;
467                         else if (!strcasecmp(proto, "tcpudp")) {
468                                 ipn.in_flags |= IPN_TCPUDP;
469                                 proto = "tcp/udp";
470                         } else if (!strcasecmp(proto, "ip"))
471                                 ipn.in_flags |= IPN_ANY;
472                         else {
473                                 ipn.in_flags |= IPN_ANY;
474                                 if ((pr = getprotobyname(proto)))
475                                         ipn.in_p = pr->p_proto;
476                                 else {
477                                         if (!isdigit(*proto)) {
478                                                 fprintf(stderr,
479                                                 "%d: Unknown protocol %s\n",
480                                                         linenum, proto);
481                                                 return NULL;
482                                         } else
483                                                 ipn.in_p = atoi(proto);
484                                 }
485                         }
486
487                         if (*cpp && !strcasecmp(*cpp, "round-robin")) {
488                                 cpp++;
489                                 ipn.in_flags |= IPN_ROUNDR;
490                         }
491
492                         if (*cpp && !strcasecmp(*cpp, "frag")) {
493                                 cpp++;
494                                 ipn.in_flags |= IPN_FRAG;
495                         }
496
497                         if (*cpp && !strcasecmp(*cpp, "age")) {
498                                 cpp++;
499                                 if (!*cpp) {
500                                         fprintf(stderr,
501                                                 "%d: age with no parameters\n",
502                                                 linenum);
503                                         return NULL;
504                                 }
505
506                                 ipn.in_age[0] = atoi(*cpp);
507                                 s = index(*cpp, '/');
508                                 if (s != NULL)
509                                         ipn.in_age[1] = atoi(s + 1);
510                                 else
511                                         ipn.in_age[1] = ipn.in_age[0];
512                                 cpp++;
513                         }
514
515                         if (*cpp) {
516                                 fprintf(stderr,
517                                 "%d: extra junk at the end of the line: %s\n",
518                                         linenum, *cpp);
519                                 return NULL;
520                         }
521                 }
522         }
523
524         if ((ipn.in_redir == NAT_REDIRECT) && !(ipn.in_flags & IPN_FILTER)) {
525                 if (!portnum(port1a, &ipn.in_pmin, linenum))
526                         return NULL;
527                 ipn.in_pmin = htons(ipn.in_pmin);
528                 if (port1b != NULL) {
529                         if (!portnum(port1b, &ipn.in_pmax, linenum))
530                                 return NULL;
531                         ipn.in_pmax = htons(ipn.in_pmax);
532                 } else
533                         ipn.in_pmax = ipn.in_pmin;
534         }
535
536         if ((ipn.in_redir & NAT_BIMAP) == NAT_REDIRECT) {
537                 if (!portnum(port2a, &ipn.in_pnext, linenum))
538                         return NULL;
539                 ipn.in_pnext = htons(ipn.in_pnext);
540         }
541
542         if (!(ipn.in_flags & IPN_SPLIT))
543                 ipn.in_inip &= ipn.in_inmsk;
544         if ((ipn.in_flags & IPN_IPRANGE) == 0)
545                 ipn.in_outip &= ipn.in_outmsk;
546         ipn.in_srcip &= ipn.in_srcmsk;
547
548         if ((ipn.in_redir & NAT_MAPBLK) != 0)
549                 nat_setgroupmap(&ipn);
550
551         if (*cpp && !strcasecmp(*cpp, "frag")) {
552                 cpp++;
553                 ipn.in_flags |= IPN_FRAG;
554         }
555
556         if (!*cpp)
557                 return &ipn;
558
559         if (ipn.in_redir == NAT_BIMAP) {
560                 fprintf(stderr,
561                         "%d: extra words at the end of bimap line: %s\n",
562                         linenum, *cpp);
563                 return NULL;
564         }
565
566         if (!strcasecmp(*cpp, "proxy")) {
567                 if (ipn.in_redir == NAT_BIMAP) {
568                         fprintf(stderr, "%d: cannot use proxy with bimap\n",
569                                 linenum);
570                         return NULL;
571                 }
572                 cpp++;
573                 if (!*cpp) {
574                         fprintf(stderr,
575                                 "%d: missing parameter for \"proxy\"\n",
576                                 linenum);
577                         return NULL;
578                 }
579                 dport = NULL;
580
581                 if (!strcasecmp(*cpp, "port")) {
582                         cpp++;
583                         if (!*cpp) {
584                                 fprintf(stderr,
585                                         "%d: missing parameter for \"port\"\n",
586                                         linenum);
587                                 return NULL;
588                         }
589
590                         dport = *cpp;
591                         cpp++;
592
593                         if (!*cpp) {
594                                 fprintf(stderr,
595                                         "%d: missing parameter for \"proxy\"\n",
596                                         linenum);
597                                 return NULL;
598                         }
599                 } else {
600                         fprintf(stderr,
601                                 "%d: missing keyword \"port\"\n", linenum);
602                         return NULL;
603                 }
604
605                 if ((proto = index(*cpp, '/'))) {
606                         *proto++ = '\0';
607                         if ((pr = getprotobyname(proto)))
608                                 ipn.in_p = pr->p_proto;
609                         else
610                                 ipn.in_p = atoi(proto);
611                 } else
612                         ipn.in_p = 0;
613
614                 if (dport && !portnum(dport, &ipn.in_dport, linenum))
615                         return NULL;
616                 ipn.in_dport = htons(ipn.in_dport);
617
618                 (void) strncpy(ipn.in_plabel, *cpp, sizeof(ipn.in_plabel));
619                 cpp++;
620
621                 if (*cpp) {
622                         fprintf(stderr,
623                                 "%d: too many parameters for \"proxy\"\n",
624                                 linenum);
625                         return NULL;
626                 }
627         } else if (!strcasecmp(*cpp, "portmap")) {
628                 if (ipn.in_redir == NAT_BIMAP) {
629                         fprintf(stderr, "%d: cannot use portmap with bimap\n",
630                                 linenum);
631                         return NULL;
632                 }
633                 cpp++;
634                 if (!*cpp) {
635                         fprintf(stderr,
636                                 "%d: missing expression following portmap\n",
637                                 linenum);
638                         return NULL;
639                 }
640
641                 if (!strcasecmp(*cpp, "tcp"))
642                         ipn.in_flags |= IPN_TCP;
643                 else if (!strcasecmp(*cpp, "udp"))
644                         ipn.in_flags |= IPN_UDP;
645                 else if (!strcasecmp(*cpp, "tcpudp"))
646                         ipn.in_flags |= IPN_TCPUDP;
647                 else if (!strcasecmp(*cpp, "tcp/udp"))
648                         ipn.in_flags |= IPN_TCPUDP;
649                 else {
650                         fprintf(stderr,
651                                 "%d: expected protocol name - got \"%s\"\n",
652                                 linenum, *cpp);
653                         return NULL;
654                 }
655                 proto = *cpp;
656                 cpp++;
657
658                 if (!*cpp) {
659                         fprintf(stderr, "%d: no port range found\n", linenum);
660                         return NULL;
661                 }
662
663                 if (!strcasecmp(*cpp, "auto")) {
664                         ipn.in_flags |= IPN_AUTOPORTMAP;
665                         ipn.in_pmin = htons(1024);
666                         ipn.in_pmax = htons(65535);
667                         nat_setgroupmap(&ipn);
668                         cpp++;
669                 } else {
670                         if (!(t = strchr(*cpp, ':'))) {
671                                 fprintf(stderr,
672                                         "%d: no port range in \"%s\"\n",
673                                         linenum, *cpp);
674                                 return NULL;
675                         }
676                         *t++ = '\0';
677                         if (!portnum(*cpp, &ipn.in_pmin, linenum) ||
678                             !portnum(t, &ipn.in_pmax, linenum))
679                                 return NULL;
680                         ipn.in_pmin = htons(ipn.in_pmin);
681                         ipn.in_pmax = htons(ipn.in_pmax);
682                         cpp++;
683                 }
684         }
685
686         if (*cpp && !strcasecmp(*cpp, "age")) {
687                 cpp++;
688                 if (!*cpp) {
689                         fprintf(stderr, "%d: age with no parameters\n",
690                                 linenum);
691                         return NULL;
692                 }
693                 s = index(*cpp, '/');
694                 if (s != NULL)
695                         ipn.in_age[1] = atoi(s + 1);
696                 else
697                         ipn.in_age[1] = ipn.in_age[0];
698                 cpp++;
699         }
700
701         if (*cpp) {
702                 fprintf(stderr, "%d: extra junk at the end of the line: %s\n",
703                         linenum, *cpp);
704                 return NULL;
705         }
706         return &ipn;
707 }
708
709
710 void natparsefile(fd, file, opts)
711 int fd;
712 char *file;
713 int opts;
714 {
715         char    line[512], *s;
716         ipnat_t *np;
717         FILE    *fp;
718         int     linenum = 0;
719
720         if (strcmp(file, "-")) {
721                 if (!(fp = fopen(file, "r"))) {
722                         fprintf(stderr, "%s: open: %s\n", file,
723                                 STRERROR(errno));
724                         exit(1);
725                 }
726         } else
727                 fp = stdin;
728
729         while (fgets(line, sizeof(line) - 1, fp)) {
730                 linenum++;
731                 line[sizeof(line) - 1] = '\0';
732                 if ((s = strchr(line, '\n')))
733                         *s = '\0';
734
735                 if (!(np = natparse(line, linenum))) {
736                         if (*line)
737                                 fprintf(stderr, "%d: syntax error in \"%s\"\n",
738                                         linenum, line);
739                 } else {
740                         if ((opts & OPT_VERBOSE) && np)
741                                 printnat(np, opts);
742                         if (!(opts & OPT_NODO)) {
743                                 if (!(opts & OPT_REMOVE)) {
744                                         if (ioctl(fd, SIOCADNAT, &np) == -1) {
745                                                 fprintf(stderr, "%d:",
746                                                         linenum);
747                                                 perror("ioctl(SIOCADNAT)");
748                                         }
749                                 } else if (ioctl(fd, SIOCRMNAT, &np) == -1) {
750                                         fprintf(stderr, "%d:", linenum);
751                                         perror("ioctl(SIOCRMNAT)");
752                                 }
753                         }
754                 }
755         }
756         if (fp != stdin)
757                 fclose(fp);
758 }