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