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