]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ipfilter/parse.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / contrib / ipfilter / parse.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 <sys/types.h>
9 #if !defined(__SVR4) && !defined(__svr4__)
10 #include <strings.h>
11 #else
12 #include <sys/byteorder.h>
13 #endif
14 #include <sys/param.h>
15 #include <sys/time.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <netinet/in_systm.h>
19 #include <netinet/ip.h>
20 #include <netinet/tcp.h>
21 #include <net/if.h>
22 #if __FreeBSD_version >= 300000
23 # include <net/if_var.h>
24 #endif
25 #include <stdio.h>
26 #include <string.h>
27 #include <limits.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <stddef.h>
31 #include <netdb.h>
32 #include <arpa/nameser.h>
33 #include <arpa/inet.h>
34 #include <resolv.h>
35 #include <ctype.h>
36 #include <syslog.h>
37 #include "ip_compat.h"
38 #include "ip_fil.h"
39 #include "ipf.h"
40 #include "facpri.h"
41
42 #if !defined(lint)
43 static const char sccsid[] = "@(#)parse.c       1.44 6/5/96 (C) 1993-1996 Darren Reed";
44 static const char rcsid[] = "@(#)$Id: parse.c,v 2.1.2.8 2000/01/27 08:49:42 darrenr Exp $";
45 #endif
46
47 extern  struct  ipopt_names     ionames[], secclass[];
48 extern  int     opts;
49
50 int     portnum __P((char *, u_short *, int));
51 u_char  tcp_flags __P((char *, u_char *, int));
52 int     addicmp __P((char ***, struct frentry *, int));
53 int     extras __P((char ***, struct frentry *, int));
54 char    ***seg;
55 u_long  *sa, *msk;
56 u_short *pp, *tp;
57 u_char  *cp;
58
59 int     hostmask __P((char ***, u_32_t *, u_32_t *, u_short *, u_char *,
60                       u_short *, int));
61 int     ports __P((char ***, u_short *, u_char *, u_short *, int));
62 int     icmpcode __P((char *)), addkeep __P((char ***, struct frentry *, int));
63 int     to_interface __P((frdest_t *, char *, int));
64 void    print_toif __P((char *, frdest_t *));
65 void    optprint __P((u_short *, u_long, u_long));
66 int     countbits __P((u_32_t));
67 char    *portname __P((int, int));
68 int     ratoi __P((char *, int *, int, int));
69
70
71 char    *proto = NULL;
72 char    flagset[] = "FSRPAU";
73 u_char  flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, TH_ACK, TH_URG };
74
75 static  char    thishost[MAXHOSTNAMELEN];
76
77
78 void initparse()
79 {
80         gethostname(thishost, sizeof(thishost));
81         thishost[sizeof(thishost) - 1] = '\0';
82 }
83
84
85 /* parse()
86  *
87  * parse a line read from the input filter rule file
88  */
89 struct  frentry *parse(line, linenum)
90 char    *line;
91 int     linenum;
92 {
93         static  struct  frentry fil;
94         struct  protoent        *p = NULL;
95         char    *cps[31], **cpp, *endptr;
96         u_char  ch;
97         int     i, cnt = 1, j;
98
99         while (*line && isspace(*line))
100                 line++;
101         if (!*line)
102                 return NULL;
103
104         bzero((char *)&fil, sizeof(fil));
105         fil.fr_mip.fi_v = 0xf;
106         fil.fr_ip.fi_v = 4;
107         fil.fr_loglevel = 0xffff;
108
109         /*
110          * break line up into max of 20 segments
111          */
112         if (opts & OPT_DEBUG)
113                 fprintf(stderr, "parse [%s]\n", line);
114         for (i = 0, *cps = strtok(line, " \b\t\r\n"); cps[i] && i < 30; cnt++)
115                 cps[++i] = strtok(NULL, " \b\t\r\n");
116         cps[i] = NULL;
117
118         if (cnt < 3) {
119                 fprintf(stderr, "%d: not enough segments in line\n", linenum);
120                 return NULL;
121         }
122
123         cpp = cps;
124         if (**cpp == '@')
125                 fil.fr_hits = (U_QUAD_T)atoi(*cpp++ + 1) + 1;
126
127
128         if (!strcasecmp("block", *cpp)) {
129                 fil.fr_flags |= FR_BLOCK;
130                 if (!strncasecmp(*(cpp+1), "return-icmp-as-dest", 19) &&
131                     (i = 19))
132                         fil.fr_flags |= FR_FAKEICMP;
133                 else if (!strncasecmp(*(cpp+1), "return-icmp", 11) && (i = 11))
134                         fil.fr_flags |= FR_RETICMP;
135                 if (fil.fr_flags & FR_RETICMP) {
136                         cpp++;
137                         if (strlen(*cpp) == i) {
138                                 if (*(cpp + 1) && **(cpp +1) == '(') {
139                                         cpp++;
140                                         i = 0;
141                                 } else
142                                         i = -1;
143                         }
144
145                         /*
146                          * The ICMP code is not required to follow in ()'s
147                          */
148                         if ((i >= 0) && (*(*cpp + i) == '(')) {
149                                 i++;
150                                 j = icmpcode(*cpp + i);
151                                 if (j == -1) {
152                                         fprintf(stderr,
153                                         "%d: unrecognised icmp code %s\n",
154                                                 linenum, *cpp + 20);
155                                         return NULL;
156                                 }
157                                 fil.fr_icode = j;
158                         }
159                 } else if (!strncasecmp(*(cpp+1), "return-rst", 10)) {
160                         fil.fr_flags |= FR_RETRST;
161                         cpp++;
162                 }
163         } else if (!strcasecmp("count", *cpp)) {
164                 fil.fr_flags |= FR_ACCOUNT;
165         } else if (!strcasecmp("pass", *cpp)) {
166                 fil.fr_flags |= FR_PASS;
167         } else if (!strcasecmp("auth", *cpp)) {
168                  fil.fr_flags |= FR_AUTH;
169         } else if (!strcasecmp("preauth", *cpp)) {
170                  fil.fr_flags |= FR_PREAUTH;
171         } else if (!strcasecmp("skip", *cpp)) {
172                 cpp++;
173                 if (ratoi(*cpp, &i, 0, USHRT_MAX))
174                         fil.fr_skip = i;
175                 else {
176                         fprintf(stderr, "%d: integer must follow skip\n",
177                                 linenum);
178                         return NULL;
179                 }
180         } else if (!strcasecmp("log", *cpp)) {
181                 fil.fr_flags |= FR_LOG;
182                 if (!strcasecmp(*(cpp+1), "body")) {
183                         fil.fr_flags |= FR_LOGBODY;
184                         cpp++;
185                 }
186                 if (!strcasecmp(*(cpp+1), "first")) {
187                         fil.fr_flags |= FR_LOGFIRST;
188                 }
189                 if (!strcasecmp(*(cpp+1), "level")) {
190                         int fac, pri;
191                         char *s;
192
193                         fac = 0;
194                         pri = 0;
195                         if (!*++cpp) {
196                                 fprintf(stderr, "%d: %s\n", linenum,
197                                         "missing identifier after level");
198                                 return NULL;
199                         }
200                         s = index(*cpp, '.');
201                         if (s) {
202                                 *s++ = '\0';
203                                 fac = fac_findname(*cpp);
204                                 if (fac == -1) {
205                                         fprintf(stderr, "%d: %s %s\n", linenum,
206                                                 "Unknown facility", *cpp);
207                                         return NULL;
208                                 }
209                                 pri = pri_findname(s);
210                                 if (pri == -1) {
211                                         fprintf(stderr, "%d: %s %s\n", linenum,
212                                                 "Unknown priority", s);
213                                         return NULL;
214                                 }
215                         } else {
216                                 pri = pri_findname(*cpp);
217                                 if (pri == -1) {
218                                         fprintf(stderr, "%d: %s %s\n", linenum,
219                                                 "Unknown priority", *cpp);
220                                         return NULL;
221                                 }
222                         }
223                         fil.fr_loglevel = fac|pri;
224                         cpp++;
225                 }
226         } else {
227                 /*
228                  * Doesn't start with one of the action words
229                  */
230                 fprintf(stderr, "%d: unknown keyword (%s)\n", linenum, *cpp);
231                 return NULL;
232         }
233         if (!*++cpp) {
234                 fprintf(stderr, "%d: missing 'in'/'out' keyword\n", linenum);
235                 return NULL;
236         }
237
238         if (!strcasecmp("in", *cpp))
239                 fil.fr_flags |= FR_INQUE;
240         else if (!strcasecmp("out", *cpp)) {
241                 fil.fr_flags |= FR_OUTQUE;
242                 if (fil.fr_flags & FR_RETICMP) {
243                         fprintf(stderr,
244                                 "%d: Can only use return-icmp with 'in'\n",
245                                 linenum);
246                         return NULL;
247                 } else if (fil.fr_flags & FR_RETRST) {
248                         fprintf(stderr,
249                                 "%d: Can only use return-rst with 'in'\n", 
250                                 linenum);
251                         return NULL;
252                 }
253         }
254         if (!*++cpp) {
255                 fprintf(stderr, "%d: missing source specification\n", linenum);
256                 return NULL;
257         }
258
259         if (!strcasecmp("log", *cpp)) {
260                 if (!*++cpp) {
261                         fprintf(stderr, "%d: missing source specification\n",
262                                 linenum);
263                         return NULL;
264                 }
265                 if (fil.fr_flags & FR_PASS)
266                         fil.fr_flags |= FR_LOGP;
267                 else if (fil.fr_flags & FR_BLOCK)
268                         fil.fr_flags |= FR_LOGB;
269                 if (*cpp && !strcasecmp(*cpp, "body")) {
270                         fil.fr_flags |= FR_LOGBODY;
271                         cpp++;
272                 }
273                 if (*cpp && !strcasecmp(*cpp, "first")) {
274                         fil.fr_flags |= FR_LOGFIRST;
275                         cpp++;
276                 }
277                 if (*cpp && !strcasecmp(*cpp, "or-block")) {
278                         if (!(fil.fr_flags & FR_PASS)) {
279                                 fprintf(stderr,
280                                         "%d: or-block must be used with pass\n",
281                                         linenum);
282                                 return NULL;
283                         }
284                         fil.fr_flags |= FR_LOGORBLOCK;
285                         cpp++;
286                 }
287                 if (*cpp && !strcasecmp(*cpp, "level")) {
288                         int fac, pri;
289                         char *s;
290
291                         fac = 0;
292                         pri = 0;
293                         if (!*++cpp) {
294                                 fprintf(stderr, "%d: %s\n", linenum,
295                                         "missing identifier after level");
296                                 return NULL;
297                         }
298                         s = index(*cpp, '.');
299                         if (s) {
300                                 *s++ = '\0';
301                                 fac = fac_findname(*cpp);
302                                 if (fac == -1) {
303                                         fprintf(stderr, "%d: %s %s\n", linenum,
304                                                 "Unknown facility", *cpp);
305                                         return NULL;
306                                 }
307                                 pri = pri_findname(s);
308                                 if (pri == -1) {
309                                         fprintf(stderr, "%d: %s %s\n", linenum,
310                                                 "Unknown priority", s);
311                                         return NULL;
312                                 }
313                         } else {
314                                 pri = pri_findname(*cpp);
315                                 if (pri == -1) {
316                                         fprintf(stderr, "%d: %s %s\n", linenum,
317                                                 "Unknown priority", *cpp);
318                                         return NULL;
319                                 }
320                         }
321                         fil.fr_loglevel = fac|pri;
322                         cpp++;
323                 }
324         }
325
326         if (*cpp && !strcasecmp("quick", *cpp)) {
327                 cpp++;
328                 fil.fr_flags |= FR_QUICK;
329         }
330
331         *fil.fr_ifname = '\0';
332         if (*cpp && !strcasecmp(*cpp, "on")) {
333                 if (!*++cpp) {
334                         fprintf(stderr, "%d: interface name missing\n",
335                                 linenum);
336                         return NULL;
337                 }
338                 (void)strncpy(fil.fr_ifname, *cpp, IFNAMSIZ-1);
339                 fil.fr_ifname[IFNAMSIZ-1] = '\0';
340                 cpp++;
341                 if (!*cpp) {
342                         if ((fil.fr_flags & FR_RETMASK) == FR_RETRST) {
343                                 fprintf(stderr,
344                                         "%d: %s can only be used with TCP\n",
345                                         linenum, "return-rst");
346                                 return NULL;
347                         }
348                         return &fil;
349                 }
350
351                 if (*cpp) {
352                         if (!strcasecmp(*cpp, "dup-to") && *(cpp + 1)) {
353                                 cpp++;
354                                 if (to_interface(&fil.fr_dif, *cpp, linenum))
355                                         return NULL;
356                                 cpp++;
357                         }
358                         if (*cpp && !strcasecmp(*cpp, "to") && *(cpp + 1)) {
359                                 cpp++;
360                                 if (to_interface(&fil.fr_tif, *cpp, linenum))
361                                         return NULL;
362                                 cpp++;
363                         } else if (*cpp && !strcasecmp(*cpp, "fastroute")) {
364                                 if (!(fil.fr_flags & FR_INQUE)) {
365                                         fprintf(stderr,
366                                                 "can only use %s with 'in'\n",
367                                                 "fastroute");
368                                         return NULL;
369                                 }
370                                 fil.fr_flags |= FR_FASTROUTE;
371                                 cpp++;
372                         }
373                 }
374         }
375         if (*cpp && !strcasecmp(*cpp, "tos")) {
376                 if (!*++cpp) {
377                         fprintf(stderr, "%d: tos missing value\n", linenum);
378                         return NULL;
379                 }
380                 fil.fr_tos = strtol(*cpp, NULL, 0);
381                 fil.fr_mip.fi_tos = 0xff;
382                 cpp++;
383         }
384
385         if (*cpp && !strcasecmp(*cpp, "ttl")) {
386                 if (!*++cpp) {
387                         fprintf(stderr, "%d: ttl missing hopcount value\n",
388                                 linenum);
389                         return NULL;
390                 }
391                 if (ratoi(*cpp, &i, 0, 255))
392                         fil.fr_ttl = i;
393                 else {
394                         fprintf(stderr, "%d: invalid ttl (%s)\n",
395                                 linenum, *cpp);
396                         return NULL;
397                 }
398                 fil.fr_mip.fi_ttl = 0xff;
399                 cpp++;
400         }
401
402         /*
403          * check for "proto <protoname>" only decode udp/tcp/icmp as protoname
404          */
405         proto = NULL;
406         if (*cpp && !strcasecmp(*cpp, "proto")) {
407                 if (!*++cpp) {
408                         fprintf(stderr, "%d: protocol name missing\n", linenum);
409                         return NULL;
410                 }
411                 proto = *cpp++;
412                 if (!strcasecmp(proto, "tcp/udp")) {
413                         fil.fr_ip.fi_fl |= FI_TCPUDP;
414                         fil.fr_mip.fi_fl |= FI_TCPUDP;
415                 } else {
416                         if (!(p = getprotobyname(proto)) && !isdigit(*proto)) {
417                                 fprintf(stderr,
418                                         "%d: unknown protocol (%s)\n",
419                                         linenum, proto);
420                                 return NULL;
421                         }
422                         if (p)
423                                 fil.fr_proto = p->p_proto;
424                         else if (isdigit(*proto)) {
425                                 i = (int)strtol(proto, &endptr, 0);
426                                 if (*endptr != '\0' || i < 0 || i > 255) {
427                                         fprintf(stderr,
428                                                 "%d: unknown protocol (%s)\n",
429                                                 linenum, proto);
430                                         return NULL;            
431                                 }
432                                 fil.fr_proto = i;
433                         }
434                         fil.fr_mip.fi_p = 0xff;
435                 }
436         }
437         if ((fil.fr_proto != IPPROTO_TCP) &&
438             ((fil.fr_flags & FR_RETMASK) == FR_RETRST)) {
439                 fprintf(stderr, "%d: %s can only be used with TCP\n",
440                         linenum, "return-rst");
441                 return NULL;
442         }
443
444         /*
445          * get the from host and bit mask to use against packets
446          */
447
448         if (!*cpp) {
449                 fprintf(stderr, "%d: missing source specification\n", linenum);
450                 return NULL;
451         }
452         if (!strcasecmp(*cpp, "all")) {
453                 cpp++;
454                 if (!*cpp)
455                         return &fil;
456         } else {
457                 if (strcasecmp(*cpp, "from")) {
458                         fprintf(stderr, "%d: unexpected keyword (%s) - from\n",
459                                 linenum, *cpp);
460                         return NULL;
461                 }
462                 if (!*++cpp) {
463                         fprintf(stderr, "%d: missing host after from\n",
464                                 linenum);
465                         return NULL;
466                 }
467                 ch = 0;
468                 if (**cpp == '!') {
469                         fil.fr_flags |= FR_NOTSRCIP;
470                         (*cpp)++;
471                 }
472                 if (hostmask(&cpp, (u_32_t *)&fil.fr_src,
473                              (u_32_t *)&fil.fr_smsk, &fil.fr_sport, &ch,
474                              &fil.fr_stop, linenum)) {
475                         return NULL;
476                 }
477                 fil.fr_scmp = ch;
478                 if (!*cpp) {
479                         fprintf(stderr, "%d: missing to fields\n", linenum);
480                         return NULL;
481                 }
482
483                 /*
484                  * do the same for the to field (destination host)
485                  */
486                 if (strcasecmp(*cpp, "to")) {
487                         fprintf(stderr, "%d: unexpected keyword (%s) - to\n",
488                                 linenum, *cpp);
489                         return NULL;
490                 }
491                 if (!*++cpp) {
492                         fprintf(stderr, "%d: missing host after to\n", linenum);
493                         return NULL;
494                 }
495                 ch = 0;
496                 if (**cpp == '!') {
497                         fil.fr_flags |= FR_NOTDSTIP;
498                         (*cpp)++;
499                 }
500                 if (hostmask(&cpp, (u_32_t *)&fil.fr_dst,
501                              (u_32_t *)&fil.fr_dmsk, &fil.fr_dport, &ch,
502                              &fil.fr_dtop, linenum)) {
503                         return NULL;
504                 }
505                 fil.fr_dcmp = ch;
506         }
507
508         /*
509          * check some sanity, make sure we don't have icmp checks with tcp
510          * or udp or visa versa.
511          */
512         if (fil.fr_proto && (fil.fr_dcmp || fil.fr_scmp) &&
513             fil.fr_proto != IPPROTO_TCP && fil.fr_proto != IPPROTO_UDP) {
514                 fprintf(stderr, "%d: port operation on non tcp/udp\n", linenum);
515                 return NULL;
516         }
517         if (fil.fr_icmp && fil.fr_proto != IPPROTO_ICMP) {
518                 fprintf(stderr, "%d: icmp comparisons on wrong protocol\n",
519                         linenum);
520                 return NULL;
521         }
522
523         if (!*cpp)
524                 return &fil;
525
526         if (*cpp && !strcasecmp(*cpp, "flags")) {
527                 if (!*++cpp) {
528                         fprintf(stderr, "%d: no flags present\n", linenum);
529                         return NULL;
530                 }
531                 fil.fr_tcpf = tcp_flags(*cpp, &fil.fr_tcpfm, linenum);
532                 cpp++;
533         }
534
535         /*
536          * extras...
537          */
538         if (*cpp && (!strcasecmp(*cpp, "with") || !strcasecmp(*cpp, "and")))
539                 if (extras(&cpp, &fil, linenum))
540                         return NULL;
541
542         /*
543          * icmp types for use with the icmp protocol
544          */
545         if (*cpp && !strcasecmp(*cpp, "icmp-type")) {
546                 if (fil.fr_proto != IPPROTO_ICMP) {
547                         fprintf(stderr,
548                                 "%d: icmp with wrong protocol (%d)\n",
549                                 linenum, fil.fr_proto);
550                         return NULL;
551                 }
552                 if (addicmp(&cpp, &fil, linenum))
553                         return NULL;
554                 fil.fr_icmp = htons(fil.fr_icmp);
555                 fil.fr_icmpm = htons(fil.fr_icmpm);
556         }
557
558         /*
559          * Keep something...
560          */
561         while (*cpp && !strcasecmp(*cpp, "keep"))
562                 if (addkeep(&cpp, &fil, linenum))
563                         return NULL;
564
565         /*
566          * head of a new group ?
567          */
568         if (*cpp && !strcasecmp(*cpp, "head")) {
569                 if (!*++cpp) {
570                         fprintf(stderr, "%d: head without group #\n", linenum);
571                         return NULL;
572                 }
573                 if (ratoi(*cpp, &i, 0, USHRT_MAX))
574                         fil.fr_grhead = i;
575                 else {
576                         fprintf(stderr, "%d: invalid group (%s)\n",
577                                 linenum, *cpp);
578                         return NULL;
579                 }
580                 cpp++;
581         }
582
583         /*
584          * head of a new group ?
585          */
586         if (*cpp && !strcasecmp(*cpp, "group")) {
587                 if (!*++cpp) {
588                         fprintf(stderr, "%d: group without group #\n",
589                                 linenum);
590                         return NULL;
591                 }
592                 if (ratoi(*cpp, &i, 0, USHRT_MAX))
593                         fil.fr_group = i;
594                 else {
595                         fprintf(stderr, "%d: invalid group (%s)\n",
596                                 linenum, *cpp);
597                         return NULL;
598                 }
599                 cpp++;
600         }
601
602         /*
603          * leftovers...yuck
604          */
605         if (*cpp && **cpp) {
606                 fprintf(stderr, "%d: unknown words at end: [", linenum);
607                 for (; *cpp; cpp++)
608                         fprintf(stderr, "%s ", *cpp);
609                 fprintf(stderr, "]\n");
610                 return NULL;
611         }
612
613         /*
614          * lazy users...
615          */
616         if ((fil.fr_tcpf || fil.fr_tcpfm) && fil.fr_proto != IPPROTO_TCP) {
617                 fprintf(stderr, "%d: TCP protocol not specified\n", linenum);
618                 return NULL;
619         }
620         if (!(fil.fr_ip.fi_fl & FI_TCPUDP) && (fil.fr_proto != IPPROTO_TCP) &&
621             (fil.fr_proto != IPPROTO_UDP) && (fil.fr_dcmp || fil.fr_scmp)) {
622                 if (!fil.fr_proto) {
623                         fil.fr_ip.fi_fl |= FI_TCPUDP;
624                         fil.fr_mip.fi_fl |= FI_TCPUDP;
625                 } else {
626                         fprintf(stderr,
627                                 "%d: port comparisons for non-TCP/UDP\n",
628                                 linenum);
629                         return NULL;
630                 }
631         }
632 /*
633         if ((fil.fr_flags & FR_KEEPFRAG) &&
634             (!(fil.fr_ip.fi_fl & FI_FRAG) || !(fil.fr_ip.fi_fl & FI_FRAG))) {
635                 fprintf(stderr,
636                         "%d: must use 'with frags' with 'keep frags'\n",
637                         linenum);
638                 return NULL;
639         }
640 */
641         return &fil;
642 }
643
644
645 int to_interface(fdp, to, linenum)
646 frdest_t *fdp;
647 char *to;
648 int linenum;
649 {
650         int     r = 0;
651         char    *s;
652
653         s = index(to, ':');
654         fdp->fd_ifp = NULL;
655         if (s) {
656                 *s++ = '\0';
657                 fdp->fd_ip.s_addr = hostnum(s, &r, linenum);
658                 if (r == -1)
659                         return -1;
660         }
661         (void) strncpy(fdp->fd_ifname, to, sizeof(fdp->fd_ifname) - 1);
662         fdp->fd_ifname[sizeof(fdp->fd_ifname) - 1] = '\0';
663         return 0;
664 }
665
666
667 void print_toif(tag, fdp)
668 char *tag;
669 frdest_t *fdp;
670 {
671         printf("%s %s%s", tag, fdp->fd_ifname,
672                      (fdp->fd_ifp || (long)fdp->fd_ifp == -1) ? "" : "(!)");
673         if (fdp->fd_ip.s_addr)
674                 printf(":%s", inet_ntoa(fdp->fd_ip));
675         putchar(' ');
676 }
677
678
679 /*
680  * returns -1 if neither "hostmask/num" or "hostmask mask addr" are
681  * found in the line segments, there is an error processing this information,
682  * or there is an error processing ports information.
683  */
684 int     hostmask(seg, sa, msk, pp, cp, tp, linenum)
685 char    ***seg;
686 u_32_t  *sa, *msk;
687 u_short *pp, *tp;
688 u_char  *cp;
689 int     linenum;
690 {
691         char    *s, *endptr;
692         int     bits = -1, resolved;
693         struct  in_addr maskaddr;
694
695         /*
696          * is it possibly hostname/num ?
697          */
698         if ((s = index(**seg, '/')) || (s = index(**seg, ':'))) {
699                 *s++ = '\0';
700                 if (index(s, '.') || index(s, 'x')) {
701                         /* possibly of the form xxx.xxx.xxx.xxx
702                          * or 0xYYYYYYYY */
703                         if (inet_aton(s, &maskaddr) == 0) {
704                                 fprintf(stderr, "%d: bad mask (%s)\n",
705                                         linenum, s);
706                                 return -1;
707                         } 
708                         *msk = maskaddr.s_addr;
709                 } else {
710                         /*
711                          * set x most significant bits
712                          */
713                         bits = (int)strtol(s, &endptr, 0);
714                         if (*endptr != '\0' || bits > 32 || bits < 0) {
715                                 fprintf(stderr, "%d: bad mask (/%s)\n",
716                                         linenum, s);
717                                 return -1;
718                         }
719                         if (bits == 0)
720                                 *msk = 0;
721                         else
722                                 *msk = htonl(0xffffffff << (32 - bits));
723                 }
724                 *sa = hostnum(**seg, &resolved, linenum) & *msk;
725                 if (resolved == -1) {
726                         fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
727                         return -1;
728                 }
729                 (*seg)++;
730                 return ports(seg, pp, cp, tp, linenum);
731         }
732
733         /*
734          * look for extra segments if "mask" found in right spot
735          */
736         if (*(*seg+1) && *(*seg+2) && !strcasecmp(*(*seg+1), "mask")) {
737                 *sa = hostnum(**seg, &resolved, linenum);
738                 if (resolved == -1) {
739                         fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
740                         return -1;
741                 }
742                 (*seg)++;
743                 (*seg)++;
744                 if (inet_aton(**seg, &maskaddr) == 0) {
745                         fprintf(stderr, "%d: bad mask (%s)\n", linenum, **seg);
746                         return -1;
747                 }
748                 *msk = maskaddr.s_addr;
749                 (*seg)++;
750                 *sa &= *msk;
751                 return ports(seg, pp, cp, tp, linenum);
752         }
753
754         if (**seg) {
755                 *sa = hostnum(**seg, &resolved, linenum);
756                 if (resolved == -1) {
757                         fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
758                         return -1;
759                 }
760                 (*seg)++;
761                 *msk = (*sa ? inet_addr("255.255.255.255") : 0L);
762                 *sa &= *msk;
763                 return ports(seg, pp, cp, tp, linenum);
764         }
765         fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
766         return -1;
767 }
768
769 /*
770  * returns an ip address as a long var as a result of either a DNS lookup or
771  * straight inet_addr() call
772  */
773 u_32_t  hostnum(host, resolved, linenum)
774 char    *host;
775 int     *resolved;
776 int     linenum;
777 {
778         struct  hostent *hp;
779         struct  netent  *np;
780         struct  in_addr ip;
781
782         *resolved = 0;
783         if (!strcasecmp("any", host))
784                 return 0;
785         if (isdigit(*host) && inet_aton(host, &ip))
786                 return ip.s_addr;
787
788         if (!strcasecmp("<thishost>", host))
789                 host = thishost;
790
791         if (!(hp = gethostbyname(host))) {
792                 if (!(np = getnetbyname(host))) {
793                         *resolved = -1;
794                         fprintf(stderr, "%d: can't resolve hostname: %s\n",
795                                 linenum, host);
796                         return 0;
797                 }
798                 return htonl(np->n_net);
799         }
800         return *(u_32_t *)hp->h_addr;
801 }
802
803 /*
804  * check for possible presence of the port fields in the line
805  */
806 int     ports(seg, pp, cp, tp, linenum)
807 char    ***seg;
808 u_short *pp, *tp;
809 u_char  *cp;
810 int     linenum;
811 {
812         int     comp = -1;
813
814         if (!*seg || !**seg || !***seg)
815                 return 0;
816         if (!strcasecmp(**seg, "port") && *(*seg + 1) && *(*seg + 2)) {
817                 (*seg)++;
818                 if (isdigit(***seg) && *(*seg + 2)) {
819                         if (portnum(**seg, pp, linenum) == 0)
820                                 return -1;
821                         (*seg)++;
822                         if (!strcmp(**seg, "<>"))
823                                 comp = FR_OUTRANGE;
824                         else if (!strcmp(**seg, "><"))
825                                 comp = FR_INRANGE;
826                         else {
827                                 fprintf(stderr,
828                                         "%d: unknown range operator (%s)\n",
829                                         linenum, **seg);
830                                 return -1;
831                         }
832                         (*seg)++;
833                         if (**seg == NULL) {
834                                 fprintf(stderr, "%d: missing 2nd port value\n",
835                                         linenum);
836                                 return -1;
837                         }
838                         if (portnum(**seg, tp, linenum) == 0)
839                                 return -1;
840                 } else if (!strcmp(**seg, "=") || !strcasecmp(**seg, "eq"))
841                         comp = FR_EQUAL;
842                 else if (!strcmp(**seg, "!=") || !strcasecmp(**seg, "ne"))
843                         comp = FR_NEQUAL;
844                 else if (!strcmp(**seg, "<") || !strcasecmp(**seg, "lt"))
845                         comp = FR_LESST;
846                 else if (!strcmp(**seg, ">") || !strcasecmp(**seg, "gt"))
847                         comp = FR_GREATERT;
848                 else if (!strcmp(**seg, "<=") || !strcasecmp(**seg, "le"))
849                         comp = FR_LESSTE;
850                 else if (!strcmp(**seg, ">=") || !strcasecmp(**seg, "ge"))
851                         comp = FR_GREATERTE;
852                 else {
853                         fprintf(stderr, "%d: unknown comparator (%s)\n",
854                                         linenum, **seg);
855                         return -1;
856                 }
857                 if (comp != FR_OUTRANGE && comp != FR_INRANGE) {
858                         (*seg)++;
859                         if (portnum(**seg, pp, linenum) == 0)
860                                 return -1;
861                 }
862                 *cp = comp;
863                 (*seg)++;
864         }
865         return 0;
866 }
867
868 /*
869  * find the port number given by the name, either from getservbyname() or
870  * straight atoi(). Return 1 on success, 0 on failure
871  */
872 int     portnum(name, port, linenum)
873 char    *name;
874 u_short *port;
875 int     linenum;
876 {
877         struct  servent *sp, *sp2;
878         u_short p1 = 0;
879         int i;
880         if (isdigit(*name)) {
881                 if (ratoi(name, &i, 0, USHRT_MAX)) {
882                         *port = (u_short)i;
883                         return 1;
884                 }
885                 fprintf(stderr, "%d: unknown port \"%s\"\n", linenum, name);
886                 return 0;
887         }
888         if (proto != NULL && strcasecmp(proto, "tcp/udp") != 0) {
889                 sp = getservbyname(name, proto);
890                 if (sp) {
891                         *port = ntohs(sp->s_port);
892                         return 1;
893                 }
894                 fprintf(stderr, "%d: unknown service \"%s\".\n", linenum, name);
895                 return 0;
896         }
897         sp = getservbyname(name, "tcp");
898         if (sp) 
899                 p1 = sp->s_port;
900         sp2 = getservbyname(name, "udp");
901         if (!sp || !sp2) {
902                 fprintf(stderr, "%d: unknown tcp/udp service \"%s\".\n",
903                         linenum, name);
904                 return 0;
905         }
906         if (p1 != sp2->s_port) {
907                 fprintf(stderr, "%d: %s %d/tcp is a different port to ",
908                         linenum, name, p1);
909                 fprintf(stderr, "%d: %s %d/udp\n", linenum, name, sp->s_port);
910                 return 0;
911         }
912         *port = ntohs(p1);
913         return 1;
914 }
915
916
917 u_char tcp_flags(flgs, mask, linenum)
918 char *flgs;
919 u_char *mask;
920 int    linenum;
921 {
922         u_char tcpf = 0, tcpfm = 0, *fp = &tcpf;
923         char *s, *t;
924
925         for (s = flgs; *s; s++) {
926                 if (*s == '/' && fp == &tcpf) {
927                         fp = &tcpfm;
928                         continue;
929                 }
930                 if (!(t = index(flagset, *s))) {
931                         fprintf(stderr, "%d: unknown flag (%c)\n", linenum, *s);
932                         return 0;
933                 }
934                 *fp |= flags[t - flagset];
935         }
936         if (!tcpfm)
937                 tcpfm = 0xff;
938         *mask = tcpfm;
939         return tcpf;
940 }
941
942
943 /*
944  * deal with extra bits on end of the line
945  */
946 int     extras(cp, fr, linenum)
947 char    ***cp;
948 struct  frentry *fr;
949 int     linenum;
950 {
951         u_short secmsk;
952         u_long  opts;
953         int     notopt;
954         char    oflags;
955
956         opts = 0;
957         secmsk = 0;
958         notopt = 0;
959         (*cp)++;
960         if (!**cp)
961                 return -1;
962
963         while (**cp && (!strncasecmp(**cp, "ipopt", 5) ||
964                !strncasecmp(**cp, "not", 3) || !strncasecmp(**cp, "opt", 4) ||
965                !strncasecmp(**cp, "frag", 3) || !strncasecmp(**cp, "no", 2) ||
966                !strncasecmp(**cp, "short", 5))) {
967                 if (***cp == 'n' || ***cp == 'N') {
968                         notopt = 1;
969                         (*cp)++;
970                         continue;
971                 } else if (***cp == 'i' || ***cp == 'I') {
972                         if (!notopt)
973                                 fr->fr_ip.fi_fl |= FI_OPTIONS;
974                         fr->fr_mip.fi_fl |= FI_OPTIONS;
975                         goto nextopt;
976                 } else if (***cp == 'f' || ***cp == 'F') {
977                         if (!notopt)
978                                 fr->fr_ip.fi_fl |= FI_FRAG;
979                         fr->fr_mip.fi_fl |= FI_FRAG;
980                         goto nextopt;
981                 } else if (***cp == 'o' || ***cp == 'O') {
982                         if (!*(*cp + 1)) {
983                                 fprintf(stderr,
984                                         "%d: opt missing arguements\n",
985                                         linenum);
986                                 return -1;
987                         }
988                         (*cp)++;
989                         if (!(opts = optname(cp, &secmsk, linenum)))
990                                 return -1;
991                         oflags = FI_OPTIONS;
992                 } else if (***cp == 's' || ***cp == 'S') {
993                         if (fr->fr_tcpf) {
994                                 fprintf(stderr,
995                                 "%d: short cannot be used with TCP flags\n",
996                                         linenum);
997                                 return -1;
998                         }
999
1000                         if (!notopt)
1001                                 fr->fr_ip.fi_fl |= FI_SHORT;
1002                         fr->fr_mip.fi_fl |= FI_SHORT;
1003                         goto nextopt;
1004                 } else
1005                         return -1;
1006
1007                 if (!notopt || !opts)
1008                         fr->fr_mip.fi_fl |= oflags;
1009                 if (notopt) {
1010                   if (!secmsk) {
1011                                 fr->fr_mip.fi_optmsk |= opts;
1012                   } else {
1013                                 fr->fr_mip.fi_optmsk |= (opts & ~0x0100);
1014                   }
1015                 } else {
1016                                 fr->fr_mip.fi_optmsk |= opts;
1017                 }
1018                 fr->fr_mip.fi_secmsk |= secmsk;
1019
1020                 if (notopt) {
1021                         fr->fr_ip.fi_fl &= (~oflags & 0xf);
1022                         fr->fr_ip.fi_optmsk &= ~opts;
1023                         fr->fr_ip.fi_secmsk &= ~secmsk;
1024                 } else {
1025                         fr->fr_ip.fi_fl |= oflags;
1026                         fr->fr_ip.fi_optmsk |= opts;
1027                         fr->fr_ip.fi_secmsk |= secmsk;
1028                 }
1029 nextopt:
1030                 notopt = 0;
1031                 opts = 0;
1032                 oflags = 0;
1033                 secmsk = 0;
1034                 (*cp)++;
1035         }
1036         return 0;
1037 }
1038
1039
1040 u_32_t optname(cp, sp, linenum)
1041 char ***cp;
1042 u_short *sp;
1043 int linenum;
1044 {
1045         struct ipopt_names *io, *so;
1046         u_long msk = 0;
1047         u_short smsk = 0;
1048         char *s;
1049         int sec = 0;
1050
1051         for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) {
1052                 for (io = ionames; io->on_name; io++)
1053                         if (!strcasecmp(s, io->on_name)) {
1054                                 msk |= io->on_bit;
1055                                 break;
1056                         }
1057                 if (!io->on_name) {
1058                         fprintf(stderr, "%d: unknown IP option name %s\n",
1059                                 linenum, s);
1060                         return 0;
1061                 }
1062                 if (!strcasecmp(s, "sec-class"))
1063                         sec = 1;
1064         }
1065
1066         if (sec && !*(*cp + 1)) {
1067                 fprintf(stderr, "%d: missing security level after sec-class\n",
1068                         linenum);
1069                 return 0;
1070         }
1071
1072         if (sec) {
1073                 (*cp)++;
1074                 for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) {
1075                         for (so = secclass; so->on_name; so++)
1076                                 if (!strcasecmp(s, so->on_name)) {
1077                                         smsk |= so->on_bit;
1078                                         break;
1079                                 }
1080                         if (!so->on_name) {
1081                                 fprintf(stderr,
1082                                         "%d: no such security level: %s\n",
1083                                         linenum, s);
1084                                 return 0;
1085                         }
1086                 }
1087                 if (smsk)
1088                         *sp = smsk;
1089         }
1090         return msk;
1091 }
1092
1093
1094 #ifdef __STDC__
1095 void optprint(u_short *sec, u_long optmsk, u_long optbits)
1096 #else
1097 void optprint(sec, optmsk, optbits)
1098 u_short *sec;
1099 u_long optmsk, optbits;
1100 #endif
1101 {
1102         u_short secmsk = sec[0], secbits = sec[1];
1103         struct ipopt_names *io, *so;
1104         char *s;
1105         int secflag = 0;
1106
1107         s = " opt ";
1108         for (io = ionames; io->on_name; io++)
1109                 if ((io->on_bit & optmsk) &&
1110                     ((io->on_bit & optmsk) == (io->on_bit & optbits))) {
1111                         if ((io->on_value != IPOPT_SECURITY) ||
1112                             (!secmsk && !secbits)) {
1113                                 printf("%s%s", s, io->on_name);
1114                                 if (io->on_value == IPOPT_SECURITY)
1115                                         io++;
1116                                 s = ",";
1117                         } else
1118                                 secflag = 1;
1119                 }
1120
1121
1122         if (secmsk & secbits) {
1123                 printf("%ssec-class", s);
1124                 s = " ";
1125                 for (so = secclass; so->on_name; so++)
1126                         if ((secmsk & so->on_bit) &&
1127                             ((so->on_bit & secmsk) == (so->on_bit & secbits))) {
1128                                 printf("%s%s", s, so->on_name);
1129                                 s = ",";
1130                         }
1131         }
1132
1133         if ((optmsk && (optmsk != optbits)) ||
1134             (secmsk && (secmsk != secbits))) {
1135                 s = " ";
1136                 printf(" not opt");
1137                 if (optmsk != optbits) {
1138                         for (io = ionames; io->on_name; io++)
1139                                 if ((io->on_bit & optmsk) &&
1140                                     ((io->on_bit & optmsk) !=
1141                                      (io->on_bit & optbits))) {
1142                                         if ((io->on_value != IPOPT_SECURITY) ||
1143                                             (!secmsk && !secbits)) {
1144                                                 printf("%s%s", s, io->on_name);
1145                                                 s = ",";
1146                                                 if (io->on_value ==
1147                                                     IPOPT_SECURITY)
1148                                                         io++;
1149                                         } else
1150                                                 io++;
1151                                 }
1152                 }
1153
1154                 if (secmsk != secbits) {
1155                         printf("%ssec-class", s);
1156                         s = " ";
1157                         for (so = secclass; so->on_name; so++)
1158                                 if ((so->on_bit & secmsk) &&
1159                                     ((so->on_bit & secmsk) !=
1160                                      (so->on_bit & secbits))) {
1161                                         printf("%s%s", s, so->on_name);
1162                                         s = ",";
1163                                 }
1164                 }
1165         }
1166 }
1167
1168 char    *icmptypes[] = {
1169         "echorep", (char *)NULL, (char *)NULL, "unreach", "squench",
1170         "redir", (char *)NULL, (char *)NULL, "echo", "routerad",
1171         "routersol", "timex", "paramprob", "timest", "timestrep",
1172         "inforeq", "inforep", "maskreq", "maskrep", "END"
1173 };
1174
1175 /*
1176  * set the icmp field to the correct type if "icmp" word is found
1177  */
1178 int     addicmp(cp, fp, linenum)
1179 char    ***cp;
1180 struct  frentry *fp;
1181 int     linenum;
1182 {
1183         char    **t;
1184         int     i;
1185
1186         (*cp)++;
1187         if (!**cp)
1188                 return -1;
1189         if (!fp->fr_proto)      /* to catch lusers */
1190                 fp->fr_proto = IPPROTO_ICMP;
1191         if (isdigit(***cp)) {
1192                 if (!ratoi(**cp, &i, 0, 255)) {
1193                         fprintf(stderr,
1194                                 "%d: Invalid icmp-type (%s) specified\n",
1195                                 linenum, **cp);
1196                         return -1;
1197                 }
1198         } else {
1199                 for (t = icmptypes, i = 0; ; t++, i++) {
1200                         if (!*t)
1201                                 continue;
1202                         if (!strcasecmp("END", *t)) {
1203                                 i = -1;
1204                                 break;
1205                         }
1206                         if (!strcasecmp(*t, **cp))
1207                                 break;
1208                 }
1209                 if (i == -1) {
1210                         fprintf(stderr,
1211                                 "%d: Invalid icmp-type (%s) specified\n",
1212                                 linenum, **cp);
1213                         return -1;
1214                 }
1215         }
1216         fp->fr_icmp = (u_short)(i << 8);
1217         fp->fr_icmpm = (u_short)0xff00;
1218         (*cp)++;
1219         if (!**cp)
1220                 return 0;
1221
1222         if (**cp && strcasecmp("code", **cp))
1223                 return 0;
1224         (*cp)++;
1225         if (isdigit(***cp)) {
1226                 if (!ratoi(**cp, &i, 0, 255)) {
1227                         fprintf(stderr, 
1228                                 "%d: Invalid icmp code (%s) specified\n",
1229                                 linenum, **cp);
1230                         return -1;
1231                 }
1232                 fp->fr_icmp |= (u_short)i;
1233                 fp->fr_icmpm = (u_short)0xffff;
1234                 (*cp)++;
1235                 return 0;
1236         }
1237         fprintf(stderr, "%d: Invalid icmp code (%s) specified\n",
1238                 linenum, **cp);
1239         return -1;
1240 }
1241
1242
1243 #define MAX_ICMPCODE    15
1244
1245 char    *icmpcodes[] = {
1246         "net-unr", "host-unr", "proto-unr", "port-unr", "needfrag", "srcfail",
1247         "net-unk", "host-unk", "isolate", "net-prohib", "host-prohib",
1248         "net-tos", "host-tos", "filter-prohib", "host-preced", "preced-cutoff", 
1249         NULL };
1250 /*
1251  * Return the number for the associated ICMP unreachable code.
1252  */
1253 int icmpcode(str)
1254 char *str;
1255 {
1256         char    *s;
1257         int     i, len;
1258
1259         if (!(s = strrchr(str, ')')))
1260                 return -1;
1261         *s = '\0';
1262         if (isdigit(*str)) {
1263                 if (!ratoi(str, &i, 0, 255))
1264                         return -1;
1265                 else
1266                         return i;
1267         }
1268         len = strlen(str);
1269         for (i = 0; icmpcodes[i]; i++)
1270                 if (!strncasecmp(str, icmpcodes[i], MIN(len,
1271                                  strlen(icmpcodes[i])) ))
1272                         return i;
1273         return -1;
1274 }
1275
1276
1277 /*
1278  * set the icmp field to the correct type if "icmp" word is found
1279  */
1280 int     addkeep(cp, fp, linenum)
1281 char    ***cp;
1282 struct  frentry *fp;
1283 int     linenum; 
1284 {
1285         if (fp->fr_proto != IPPROTO_TCP && fp->fr_proto != IPPROTO_UDP &&
1286             fp->fr_proto != IPPROTO_ICMP && !(fp->fr_ip.fi_fl & FI_TCPUDP)) {
1287                 fprintf(stderr, "%d: Can only use keep with UDP/ICMP/TCP\n",
1288                         linenum);
1289                 return -1;
1290         }
1291
1292         (*cp)++;
1293         if (**cp && strcasecmp(**cp, "state") && strcasecmp(**cp, "frags")) {
1294                 fprintf(stderr, "%d: Unrecognised state keyword \"%s\"\n",
1295                         linenum, **cp);
1296                 return -1;
1297         }
1298
1299         if (***cp == 's' || ***cp == 'S')
1300                 fp->fr_flags |= FR_KEEPSTATE;
1301         else if (***cp == 'f' || ***cp == 'F')
1302                 fp->fr_flags |= FR_KEEPFRAG;
1303         (*cp)++;
1304         return 0;
1305 }
1306
1307
1308 /*
1309  * count consecutive 1's in bit mask.  If the mask generated by counting
1310  * consecutive 1's is different to that passed, return -1, else return #
1311  * of bits.
1312  */
1313 int     countbits(ip)
1314 u_32_t  ip;
1315 {
1316         u_32_t  ipn;
1317         int     cnt = 0, i, j;
1318
1319         ip = ipn = ntohl(ip);
1320         for (i = 32; i; i--, ipn *= 2)
1321                 if (ipn & 0x80000000)
1322                         cnt++;
1323                 else
1324                         break;
1325         ipn = 0;
1326         for (i = 32, j = cnt; i; i--, j--) {
1327                 ipn *= 2;
1328                 if (j > 0)
1329                         ipn++;
1330         }
1331         if (ipn == ip)
1332                 return cnt;
1333         return -1;
1334 }
1335
1336
1337 char    *portname(pr, port)
1338 int     pr, port;
1339 {
1340         static  char    buf[32];
1341         struct  protoent        *p = NULL;
1342         struct  servent *sv = NULL, *sv1 = NULL;
1343
1344         if (pr == -1) {
1345                 if ((sv = getservbyport(htons(port), "tcp"))) {
1346                         strncpy(buf, sv->s_name, sizeof(buf)-1);
1347                         buf[sizeof(buf)-1] = '\0';
1348                         sv1 = getservbyport(htons(port), "udp");
1349                         sv = strncasecmp(buf, sv->s_name, strlen(buf)) ?
1350                              NULL : sv1;
1351                 }
1352                 if (sv)
1353                         return buf;
1354         } else if (pr && (p = getprotobynumber(pr))) {
1355                 if ((sv = getservbyport(htons(port), p->p_name))) {
1356                         strncpy(buf, sv->s_name, sizeof(buf)-1);
1357                         buf[sizeof(buf)-1] = '\0';
1358                         return buf;
1359                 }
1360         }
1361
1362         (void) sprintf(buf, "%d", port);
1363         return buf;
1364 }
1365
1366
1367 /*
1368  * print the filter structure in a useful way
1369  */
1370 void    printfr(fp)
1371 struct  frentry *fp;
1372 {
1373         static  char    *pcmp1[] = { "*", "=", "!=", "<", ">", "<=", ">=",
1374                                     "<>", "><"};
1375         struct  protoent        *p;
1376         int     ones = 0, pr;
1377         char    *s, *u;
1378         u_char  *t;
1379         u_short sec[2];
1380
1381         if (fp->fr_flags & FR_PASS)
1382                 printf("pass");
1383         else if (fp->fr_flags & FR_BLOCK) {
1384                 printf("block");
1385                 if (fp->fr_flags & FR_RETICMP) {
1386                         if ((fp->fr_flags & FR_RETMASK) == FR_FAKEICMP)
1387                                 printf(" return-icmp-as-dest");
1388                         else if ((fp->fr_flags & FR_RETMASK) == FR_RETICMP)
1389                                 printf(" return-icmp");
1390                         if (fp->fr_icode) {
1391                                 if (fp->fr_icode <= MAX_ICMPCODE)
1392                                         printf("(%s)",
1393                                                 icmpcodes[(int)fp->fr_icode]);
1394                                 else
1395                                         printf("(%d)", fp->fr_icode);
1396                         }
1397                 } else if ((fp->fr_flags & FR_RETMASK) == FR_RETRST)
1398                         printf(" return-rst");
1399         } else if ((fp->fr_flags & FR_LOGMASK) == FR_LOG) {
1400                 printf("log");
1401                 if (fp->fr_flags & FR_LOGBODY)
1402                         printf(" body");
1403                 if (fp->fr_flags & FR_LOGFIRST)
1404                         printf(" first");
1405         } else if (fp->fr_flags & FR_ACCOUNT)
1406                 printf("count");
1407         else if (fp->fr_flags & FR_AUTH)
1408                 printf("auth");
1409         else if (fp->fr_flags & FR_PREAUTH)
1410                 printf("preauth");
1411         else if (fp->fr_skip)
1412                 printf("skip %hu", fp->fr_skip);
1413
1414         if (fp->fr_flags & FR_OUTQUE)
1415                 printf(" out ");
1416         else
1417                 printf(" in ");
1418
1419         if (((fp->fr_flags & FR_LOGB) == FR_LOGB) ||
1420             ((fp->fr_flags & FR_LOGP) == FR_LOGP)) {
1421                 printf("log ");
1422                 if (fp->fr_flags & FR_LOGBODY)
1423                         printf("body ");
1424                 if (fp->fr_flags & FR_LOGFIRST)
1425                         printf("first ");
1426                 if (fp->fr_flags & FR_LOGORBLOCK)
1427                         printf("or-block ");
1428                 if (fp->fr_loglevel != 0xffff) {
1429                         if (fp->fr_loglevel & LOG_FACMASK) {
1430                                 s = fac_toname(fp->fr_loglevel);
1431                                 if (s == NULL)
1432                                         s = "!!!";
1433                         } else
1434                                 s = "";
1435                         u = pri_toname(fp->fr_loglevel);
1436                         if (u == NULL)
1437                                 u = "!!!";
1438                         if (*s)
1439                                 printf("level %s.%s ", s, u);
1440                         else
1441                                 printf("level %s ", u);
1442                 }
1443                         
1444         }
1445         if (fp->fr_flags & FR_QUICK)
1446                 printf("quick ");
1447
1448         if (*fp->fr_ifname) {
1449                 printf("on %s%s ", fp->fr_ifname,
1450                         (fp->fr_ifa || (long)fp->fr_ifa == -1) ? "" : "(!)");
1451                 if (*fp->fr_dif.fd_ifname)
1452                         print_toif("dup-to", &fp->fr_dif);
1453                 if (*fp->fr_tif.fd_ifname)
1454                         print_toif("to", &fp->fr_tif);
1455                 if (fp->fr_flags & FR_FASTROUTE)
1456                         printf("fastroute ");
1457
1458         }
1459         if (fp->fr_mip.fi_tos)
1460                 printf("tos %#x ", fp->fr_tos);
1461         if (fp->fr_mip.fi_ttl)
1462                 printf("ttl %d ", fp->fr_ttl);
1463         if (fp->fr_ip.fi_fl & FI_TCPUDP) {
1464                         printf("proto tcp/udp ");
1465                         pr = -1;
1466         } else if ((pr = fp->fr_mip.fi_p)) {
1467                 if ((p = getprotobynumber(fp->fr_proto)))
1468                         printf("proto %s ", p->p_name);
1469                 else
1470                         printf("proto %d ", fp->fr_proto);
1471         }
1472
1473         printf("from %s", fp->fr_flags & FR_NOTSRCIP ? "!" : "");
1474         if (!fp->fr_src.s_addr && !fp->fr_smsk.s_addr)
1475                 printf("any ");
1476         else {
1477                 printf("%s", inet_ntoa(fp->fr_src));
1478                 if ((ones = countbits(fp->fr_smsk.s_addr)) == -1)
1479                         printf("/%s ", inet_ntoa(fp->fr_smsk));
1480                 else
1481                         printf("/%d ", ones);
1482         }
1483         if (fp->fr_scmp) {
1484                 if (fp->fr_scmp == FR_INRANGE || fp->fr_scmp == FR_OUTRANGE)
1485                         printf("port %d %s %d ", fp->fr_sport,
1486                                      pcmp1[fp->fr_scmp], fp->fr_stop);
1487                 else
1488                         printf("port %s %s ", pcmp1[fp->fr_scmp],
1489                                      portname(pr, fp->fr_sport));
1490         }
1491
1492         printf("to %s", fp->fr_flags & FR_NOTDSTIP ? "!" : "");
1493         if (!fp->fr_dst.s_addr && !fp->fr_dmsk.s_addr)
1494                 printf("any");
1495         else {
1496                 printf("%s", inet_ntoa(fp->fr_dst));
1497                 if ((ones = countbits(fp->fr_dmsk.s_addr)) == -1)
1498                         printf("/%s", inet_ntoa(fp->fr_dmsk));
1499                 else
1500                         printf("/%d", ones);
1501         }
1502         if (fp->fr_dcmp) {
1503                 if (fp->fr_dcmp == FR_INRANGE || fp->fr_dcmp == FR_OUTRANGE)
1504                         printf(" port %d %s %d", fp->fr_dport,
1505                                      pcmp1[fp->fr_dcmp], fp->fr_dtop);
1506                 else
1507                         printf(" port %s %s", pcmp1[fp->fr_dcmp],
1508                                      portname(pr, fp->fr_dport));
1509         }
1510         if ((fp->fr_ip.fi_fl & ~FI_TCPUDP) ||
1511             (fp->fr_mip.fi_fl & ~FI_TCPUDP) ||
1512             fp->fr_ip.fi_optmsk || fp->fr_mip.fi_optmsk ||
1513             fp->fr_ip.fi_secmsk || fp->fr_mip.fi_secmsk) {
1514                 printf(" with");
1515                 if (fp->fr_ip.fi_optmsk || fp->fr_mip.fi_optmsk ||
1516                     fp->fr_ip.fi_secmsk || fp->fr_mip.fi_secmsk) {
1517                         sec[0] = fp->fr_mip.fi_secmsk;
1518                         sec[1] = fp->fr_ip.fi_secmsk;
1519                         optprint(sec,
1520                                  fp->fr_mip.fi_optmsk, fp->fr_ip.fi_optmsk);
1521                 } else if (fp->fr_mip.fi_fl & FI_OPTIONS) {
1522                         if (!(fp->fr_ip.fi_fl & FI_OPTIONS))
1523                                 printf(" not");
1524                         printf(" ipopt");
1525                 }
1526                 if (fp->fr_mip.fi_fl & FI_SHORT) {
1527                         if (!(fp->fr_ip.fi_fl & FI_SHORT))
1528                                 printf(" not");
1529                         printf(" short");
1530                 }
1531                 if (fp->fr_mip.fi_fl & FI_FRAG) {
1532                         if (!(fp->fr_ip.fi_fl & FI_FRAG))
1533                                 printf(" not");
1534                         printf(" frag");
1535                 }
1536         }
1537         if (fp->fr_proto == IPPROTO_ICMP && fp->fr_icmpm) {
1538                 int     type = fp->fr_icmp, code;
1539
1540                 type = ntohs(fp->fr_icmp);
1541                 code = type & 0xff;
1542                 type /= 256;
1543                 if (type < (sizeof(icmptypes) / sizeof(char *)) &&
1544                     icmptypes[type])
1545                         printf(" icmp-type %s", icmptypes[type]);
1546                 else
1547                         printf(" icmp-type %d", type);
1548                 if (code)
1549                         printf(" code %d", code);
1550         }
1551         if (fp->fr_proto == IPPROTO_TCP && (fp->fr_tcpf || fp->fr_tcpfm)) {
1552                 printf(" flags ");
1553                 for (s = flagset, t = flags; *s; s++, t++)
1554                         if (fp->fr_tcpf & *t)
1555                                 (void)putchar(*s);
1556                 if (fp->fr_tcpfm) {
1557                         (void)putchar('/');
1558                         for (s = flagset, t = flags; *s; s++, t++)
1559                                 if (fp->fr_tcpfm & *t)
1560                                         (void)putchar(*s);
1561                 }
1562         }
1563
1564         if (fp->fr_flags & FR_KEEPSTATE)
1565                 printf(" keep state");
1566         if (fp->fr_flags & FR_KEEPFRAG)
1567                 printf(" keep frags");
1568         if (fp->fr_grhead)
1569                 printf(" head %d", fp->fr_grhead);
1570         if (fp->fr_group)
1571                 printf(" group %d", fp->fr_group);
1572         (void)putchar('\n');
1573 }
1574
1575 void    binprint(fp)
1576 struct frentry *fp;
1577 {
1578         int i = sizeof(*fp), j = 0;
1579         u_char *s;
1580
1581         for (s = (u_char *)fp; i; i--, s++) {
1582                 j++;
1583                 printf("%02x ", *s);
1584                 if (j == 16) {
1585                         printf("\n");
1586                         j = 0;
1587                 }
1588         }
1589         putchar('\n');
1590         (void)fflush(stdout);
1591 }
1592
1593
1594 int     ratoi(ps, pi, min, max)
1595 char    *ps;
1596 int     *pi, min, max;
1597 {
1598         int i;
1599         char *pe;
1600
1601         i = (int)strtol(ps, &pe, 0);
1602         if (*pe != '\0' || i < min || i > max)
1603                 return 0;
1604         *pi = i;
1605         return 1;
1606 }