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