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