2 * Copyright (C) 1993-2001 by Darren Reed.
4 * See the IPFILTER.LICENCE file for details on licencing.
6 #if defined(__sgi) && (IRIX > 602)
7 # include <sys/ptimers.h>
10 #if !defined(__SVR4) && !defined(__svr4__)
13 #include <sys/byteorder.h>
15 #include <sys/param.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>
23 #if __FreeBSD_version >= 300000
24 # include <net/if_var.h>
33 #include <arpa/nameser.h>
34 #include <arpa/inet.h>
38 #include "ip_compat.h"
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 $";
48 extern struct ipopt_names ionames[], secclass[];
52 int addicmp __P((char ***, struct frentry *, int));
53 int extras __P((char ***, struct frentry *, int));
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 *));
64 extern char flagset[];
65 extern u_char flags[];
70 * parse a line read from the input filter rule file
75 * > 0 programmer error
77 struct frentry *parse(line, linenum, status)
80 int *status; /* good, bad, or indifferent */
82 static struct frentry fil;
83 char *cps[31], **cpp, *endptr, *s;
84 struct protoent *p = NULL;
85 int i, cnt = 1, j, ch;
88 *status = 100; /* default to error */
90 while (*line && isspace(*line))
97 bzero((char *)&fil, sizeof(fil));
98 fil.fr_mip.fi_v = 0xf;
99 fil.fr_ip.fi_v = use_inet6 ? 6 : 4;
100 fil.fr_loglevel = 0xffff;
103 * break line up into max of 20 segments
105 if (opts & OPT_DEBUG)
106 fprintf(stderr, "parse [%s]\n", line);
107 for (i = 0, *cps = strtok(line, " \b\t\r\n"); cps[i] && i < 30; cnt++)
108 cps[++i] = strtok(NULL, " \b\t\r\n");
112 fprintf(stderr, "%d: not enough segments in line\n", linenum);
119 * The presence of an '@' followed by a number gives the position in
120 * the current rule list to insert this one.
123 fil.fr_hits = (U_QUAD_T)atoi(*cpp++ + 1) + 1;
127 * Check the first keyword in the rule and any options that are
128 * expected to follow it.
130 if (!strcasecmp("block", *cpp)) {
131 fil.fr_flags |= FR_BLOCK;
132 if (!strncasecmp(*(cpp+1), "return-icmp-as-dest", 19) &&
134 fil.fr_flags |= FR_FAKEICMP;
135 else if (!strncasecmp(*(cpp+1), "return-icmp", 11) && (i = 11))
136 fil.fr_flags |= FR_RETICMP;
137 if (fil.fr_flags & FR_RETICMP) {
139 if (strlen(*cpp) == i) {
140 if (*(cpp + 1) && **(cpp +1) == '(') {
148 * The ICMP code is not required to follow in ()'s
150 if ((i >= 0) && (*(*cpp + i) == '(')) {
152 j = icmpcode(*cpp + i);
155 "%d: unrecognised icmp code %s\n",
162 } else if (!strcasecmp(*(cpp+1), "return-rst")) {
163 fil.fr_flags |= FR_RETRST;
166 } else if (!strcasecmp("count", *cpp)) {
167 fil.fr_flags |= FR_ACCOUNT;
168 } else if (!strcasecmp("pass", *cpp)) {
169 fil.fr_flags |= FR_PASS;
170 } else if (!strcasecmp("nomatch", *cpp)) {
171 fil.fr_flags |= FR_NOMATCH;
172 } else if (!strcasecmp("auth", *cpp)) {
173 fil.fr_flags |= FR_AUTH;
174 if (!strncasecmp(*(cpp+1), "return-rst", 10)) {
175 fil.fr_flags |= FR_RETRST;
178 } else if (!strcasecmp("preauth", *cpp)) {
179 fil.fr_flags |= FR_PREAUTH;
180 } else if (!strcasecmp("skip", *cpp)) {
182 if (ratoui(*cpp, &k, 0, UINT_MAX))
185 fprintf(stderr, "%d: integer must follow skip\n",
190 } else if (!strcasecmp("log", *cpp)) {
191 fil.fr_flags |= FR_LOG;
192 if (!strcasecmp(*(cpp+1), "body")) {
193 fil.fr_flags |= FR_LOGBODY;
196 if (!strcasecmp(*(cpp+1), "first")) {
197 fil.fr_flags |= FR_LOGFIRST;
200 if (*cpp && !strcasecmp(*(cpp+1), "or-block")) {
201 fil.fr_flags |= FR_LOGORBLOCK;
204 if (!strcasecmp(*(cpp+1), "level")) {
206 if (loglevel(cpp, &fil.fr_loglevel, linenum) == -1) {
207 /* NB loglevel prints its own error message */
215 * Doesn't start with one of the action words
217 fprintf(stderr, "%d: unknown keyword (%s)\n", linenum, *cpp);
222 fprintf(stderr, "%d: missing 'in'/'out' keyword\n", linenum);
228 * Get the direction for filtering. Impose restrictions on direction
229 * if blocking with returning ICMP or an RST has been requested.
231 if (!strcasecmp("in", *cpp))
232 fil.fr_flags |= FR_INQUE;
233 else if (!strcasecmp("out", *cpp)) {
234 fil.fr_flags |= FR_OUTQUE;
235 if (fil.fr_flags & FR_RETICMP) {
237 "%d: Can only use return-icmp with 'in'\n",
241 } else if (fil.fr_flags & FR_RETRST) {
243 "%d: Can only use return-rst with 'in'\n",
250 fprintf(stderr, "%d: missing source specification\n", linenum);
255 if (!strcasecmp("log", *cpp)) {
257 fprintf(stderr, "%d: missing source specification\n",
262 if (fil.fr_flags & FR_PASS)
263 fil.fr_flags |= FR_LOGP;
264 else if (fil.fr_flags & FR_BLOCK)
265 fil.fr_flags |= FR_LOGB;
266 if (*cpp && !strcasecmp(*cpp, "body")) {
267 fil.fr_flags |= FR_LOGBODY;
270 if (*cpp && !strcasecmp(*cpp, "first")) {
271 fil.fr_flags |= FR_LOGFIRST;
274 if (*cpp && !strcasecmp(*cpp, "or-block")) {
275 if (!(fil.fr_flags & FR_PASS)) {
277 "%d: or-block must be used with pass\n",
282 fil.fr_flags |= FR_LOGORBLOCK;
285 if (*cpp && !strcasecmp(*cpp, "level")) {
286 if (loglevel(cpp, &fil.fr_loglevel, linenum) == -1) {
295 if (*cpp && !strcasecmp("quick", *cpp)) {
296 if (fil.fr_skip != 0) {
297 fprintf(stderr, "%d: cannot use skip with quick\n",
303 fil.fr_flags |= FR_QUICK;
307 * Parse rule options that are available if a rule is tied to an
310 *fil.fr_ifname = '\0';
311 *fil.fr_oifname = '\0';
312 if (*cpp && !strcasecmp(*cpp, "on")) {
314 fprintf(stderr, "%d: interface name missing\n",
320 s = index(*cpp, ',');
323 (void)strncpy(fil.fr_ifnames[1], s, IFNAMSIZ - 1);
324 fil.fr_ifnames[1][IFNAMSIZ - 1] = '\0';
326 strcpy(fil.fr_ifnames[1], "*");
328 (void)strncpy(fil.fr_ifnames[0], *cpp, IFNAMSIZ - 1);
329 fil.fr_ifnames[0][IFNAMSIZ - 1] = '\0';
333 if ((fil.fr_flags & FR_RETMASK) == FR_RETRST) {
335 "%d: %s can only be used with TCP\n",
336 linenum, "return-rst");
345 if (!strcasecmp(*cpp, "dup-to") && *(cpp + 1)) {
347 if (to_interface(&fil.fr_dif, *cpp, linenum)) {
353 if (*cpp && !strcasecmp(*cpp, "to") && *(cpp + 1)) {
355 if (to_interface(&fil.fr_tif, *cpp, linenum)) {
360 } else if (*cpp && !strcasecmp(*cpp, "fastroute")) {
361 if (!(fil.fr_flags & FR_INQUE)) {
363 "can only use %s with 'in'\n",
368 fil.fr_flags |= FR_FASTROUTE;
374 * Set the "other" interface name. Lets you specify both
375 * inbound and outbound interfaces for state rules. Do not
376 * prevent both interfaces from being the same.
378 strcpy(fil.fr_ifnames[3], "*");
379 if ((*cpp != NULL) && (*(cpp + 1) != NULL) &&
380 ((((fil.fr_flags & FR_INQUE) != 0) &&
381 (strcasecmp(*cpp, "out-via") == 0)) ||
382 (((fil.fr_flags & FR_OUTQUE) != 0) &&
383 (strcasecmp(*cpp, "in-via") == 0)))) {
386 s = index(*cpp, ',');
389 (void)strncpy(fil.fr_ifnames[3], s,
391 fil.fr_ifnames[3][IFNAMSIZ - 1] = '\0';
394 (void)strncpy(fil.fr_ifnames[2], *cpp, IFNAMSIZ - 1);
395 fil.fr_ifnames[2][IFNAMSIZ - 1] = '\0';
398 strcpy(fil.fr_ifnames[2], "*");
400 if (*cpp && !strcasecmp(*cpp, "tos")) {
402 fprintf(stderr, "%d: tos missing value\n", linenum);
406 fil.fr_tos = strtol(*cpp, NULL, 0);
407 fil.fr_mip.fi_tos = 0xff;
411 if (*cpp && !strcasecmp(*cpp, "ttl")) {
413 fprintf(stderr, "%d: ttl missing hopcount value\n",
418 if (ratoi(*cpp, &i, 0, 255))
421 fprintf(stderr, "%d: invalid ttl (%s)\n",
426 fil.fr_mip.fi_ttl = 0xff;
431 * check for "proto <protoname>" only decode udp/tcp/icmp as protoname
434 if (*cpp && !strcasecmp(*cpp, "proto")) {
436 fprintf(stderr, "%d: protocol name missing\n", linenum);
441 if (!strcasecmp(proto, "tcp/udp")) {
442 fil.fr_ip.fi_fl |= FI_TCPUDP;
443 fil.fr_mip.fi_fl |= FI_TCPUDP;
444 } else if (use_inet6 && !strcasecmp(proto, "icmp")) {
446 "%d: use proto ipv6-icmp with IPv6 (or use proto 1 if you really mean icmp)\n",
449 if (!(p = getprotobyname(proto)) && !isdigit(*proto)) {
451 "%d: unknown protocol (%s)\n",
457 fil.fr_proto = p->p_proto;
458 else if (isdigit(*proto)) {
459 i = (int)strtol(proto, &endptr, 0);
460 if (*endptr != '\0' || i < 0 || i > 255) {
462 "%d: unknown protocol (%s)\n",
469 fil.fr_mip.fi_p = 0xff;
472 if ((fil.fr_proto != IPPROTO_TCP) &&
473 ((fil.fr_flags & FR_RETMASK) == FR_RETRST)) {
474 fprintf(stderr, "%d: %s can only be used with TCP\n",
475 linenum, "return-rst");
481 * get the from host and bit mask to use against packets
485 fprintf(stderr, "%d: missing source specification\n", linenum);
489 if (!strcasecmp(*cpp, "all")) {
496 if (strcasecmp(*cpp, "from")) {
497 fprintf(stderr, "%d: unexpected keyword (%s) - from\n",
503 fprintf(stderr, "%d: missing host after from\n",
508 if (!strcmp(*cpp, "!")) {
509 fil.fr_flags |= FR_NOTSRCIP;
512 "%d: missing host after from\n",
517 } else if (**cpp == '!') {
518 fil.fr_flags |= FR_NOTSRCIP;
522 if (hostmask(&cpp, (u_32_t *)&fil.fr_src,
523 (u_32_t *)&fil.fr_smsk, &fil.fr_sport, &ch,
524 &fil.fr_stop, linenum)) {
529 if ((ch != 0) && (fil.fr_proto != IPPROTO_TCP) &&
530 (fil.fr_proto != IPPROTO_UDP) &&
531 !(fil.fr_ip.fi_fl & FI_TCPUDP)) {
533 "%d: cannot use port and neither tcp or udp\n",
541 fprintf(stderr, "%d: missing to fields\n", linenum);
547 * do the same for the to field (destination host)
549 if (strcasecmp(*cpp, "to")) {
550 fprintf(stderr, "%d: unexpected keyword (%s) - to\n",
556 fprintf(stderr, "%d: missing host after to\n", linenum);
561 if (!strcmp(*cpp, "!")) {
562 fil.fr_flags |= FR_NOTDSTIP;
565 "%d: missing host after from\n",
570 } else if (**cpp == '!') {
571 fil.fr_flags |= FR_NOTDSTIP;
574 if (hostmask(&cpp, (u_32_t *)&fil.fr_dst,
575 (u_32_t *)&fil.fr_dmsk, &fil.fr_dport, &ch,
576 &fil.fr_dtop, linenum)) {
580 if ((ch != 0) && (fil.fr_proto != IPPROTO_TCP) &&
581 (fil.fr_proto != IPPROTO_UDP) &&
582 !(fil.fr_ip.fi_fl & FI_TCPUDP)) {
584 "%d: cannot use port and neither tcp or udp\n",
594 * check some sanity, make sure we don't have icmp checks with tcp
595 * or udp or visa versa.
597 if (fil.fr_proto && (fil.fr_dcmp || fil.fr_scmp) &&
598 fil.fr_proto != IPPROTO_TCP && fil.fr_proto != IPPROTO_UDP) {
599 fprintf(stderr, "%d: port operation on non tcp/udp\n", linenum);
603 if (fil.fr_icmp && fil.fr_proto != IPPROTO_ICMP) {
604 fprintf(stderr, "%d: icmp comparisons on wrong protocol\n",
615 if (*cpp && !strcasecmp(*cpp, "flags")) {
617 fprintf(stderr, "%d: no flags present\n", linenum);
621 fil.fr_tcpf = tcp_flags(*cpp, &fil.fr_tcpfm, linenum);
628 if ((fil.fr_v == 4) && *cpp && (!strcasecmp(*cpp, "with") ||
629 !strcasecmp(*cpp, "and")))
630 if (extras(&cpp, &fil, linenum)) {
636 * icmp types for use with the icmp protocol
638 if (*cpp && !strcasecmp(*cpp, "icmp-type")) {
639 if (fil.fr_proto != IPPROTO_ICMP &&
640 fil.fr_proto != IPPROTO_ICMPV6) {
642 "%d: icmp with wrong protocol (%d)\n",
643 linenum, fil.fr_proto);
647 if (addicmp(&cpp, &fil, linenum)) {
651 fil.fr_icmp = htons(fil.fr_icmp);
652 fil.fr_icmpm = htons(fil.fr_icmpm);
658 while (*cpp && !strcasecmp(*cpp, "keep"))
659 if (addkeep(&cpp, &fil, linenum)) {
665 * This is here to enforce the old interface binding behaviour.
666 * That is, "on X" is equivalent to "<dir> on X <!dir>-via -,X"
668 if (fil.fr_flags & FR_KEEPSTATE) {
669 if (*fil.fr_ifnames[0] && !*fil.fr_ifnames[3]) {
670 bcopy(fil.fr_ifnames[0], fil.fr_ifnames[3],
671 sizeof(fil.fr_ifnames[3]));
672 strncpy(fil.fr_ifnames[2], "*",
673 sizeof(fil.fr_ifnames[3]));
678 * head of a new group ?
680 if (*cpp && !strcasecmp(*cpp, "head")) {
681 if (fil.fr_skip != 0) {
682 fprintf(stderr, "%d: cannot use skip with head\n",
688 fprintf(stderr, "%d: head without group #\n", linenum);
692 if (ratoui(*cpp, &k, 0, UINT_MAX))
693 fil.fr_grhead = (u_32_t)k;
695 fprintf(stderr, "%d: invalid group (%s)\n",
704 * head of a new group ?
706 if (*cpp && !strcasecmp(*cpp, "group")) {
708 fprintf(stderr, "%d: group without group #\n",
713 if (ratoui(*cpp, &k, 0, UINT_MAX))
716 fprintf(stderr, "%d: invalid group (%s)\n",
728 fprintf(stderr, "%d: unknown words at end: [", linenum);
730 fprintf(stderr, "%s ", *cpp);
731 fprintf(stderr, "]\n");
739 if ((fil.fr_tcpf || fil.fr_tcpfm) && fil.fr_proto != IPPROTO_TCP) {
740 fprintf(stderr, "%d: TCP protocol not specified\n", linenum);
744 if (!(fil.fr_ip.fi_fl & FI_TCPUDP) && (fil.fr_proto != IPPROTO_TCP) &&
745 (fil.fr_proto != IPPROTO_UDP) && (fil.fr_dcmp || fil.fr_scmp)) {
747 fil.fr_ip.fi_fl |= FI_TCPUDP;
748 fil.fr_mip.fi_fl |= FI_TCPUDP;
751 "%d: port comparisons for non-TCP/UDP\n",
758 if ((fil.fr_flags & FR_KEEPFRAG) &&
759 (!(fil.fr_ip.fi_fl & FI_FRAG) || !(fil.fr_ip.fi_fl & FI_FRAG))) {
761 "%d: must use 'with frags' with 'keep frags'\n",
772 int loglevel(cpp, facpri, linenum)
783 fprintf(stderr, "%d: %s\n", linenum,
784 "missing identifier after level");
788 s = index(*cpp, '.');
791 fac = fac_findname(*cpp);
793 fprintf(stderr, "%d: %s %s\n", linenum,
794 "Unknown facility", *cpp);
797 pri = pri_findname(s);
799 fprintf(stderr, "%d: %s %s\n", linenum,
800 "Unknown priority", s);
804 pri = pri_findname(*cpp);
806 fprintf(stderr, "%d: %s %s\n", linenum,
807 "Unknown priority", *cpp);
816 int to_interface(fdp, to, linenum)
827 if (hostnum((u_32_t *)&fdp->fd_ip, s, linenum) == -1)
830 (void) strncpy(fdp->fd_ifname, to, sizeof(fdp->fd_ifname) - 1);
831 fdp->fd_ifname[sizeof(fdp->fd_ifname) - 1] = '\0';
836 void print_toif(tag, fdp)
840 printf("%s %s%s", tag, fdp->fd_ifname,
841 (fdp->fd_ifp || (long)fdp->fd_ifp == -1) ? "" : "(!)");
843 if (use_inet6 && IP6_NOTZERO(&fdp->fd_ip6.in6)) {
846 inet_ntop(AF_INET6, &fdp->fd_ip6, ipv6addr,
847 sizeof(fdp->fd_ip6));
848 printf(":%s", ipv6addr);
851 if (fdp->fd_ip.s_addr)
852 printf(":%s", inet_ntoa(fdp->fd_ip));
858 * deal with extra bits on end of the line
860 int extras(cp, fr, linenum)
877 while (**cp && (!strncasecmp(**cp, "ipopt", 5) ||
878 !strcasecmp(**cp, "not") || !strncasecmp(**cp, "opt", 3) ||
879 !strncasecmp(**cp, "frag", 4) || !strcasecmp(**cp, "no") ||
880 !strcasecmp(**cp, "short"))) {
881 if (***cp == 'n' || ***cp == 'N') {
885 } else if (***cp == 'i' || ***cp == 'I') {
887 fr->fr_ip.fi_fl |= FI_OPTIONS;
888 fr->fr_mip.fi_fl |= FI_OPTIONS;
890 } else if (***cp == 'f' || ***cp == 'F') {
892 fr->fr_ip.fi_fl |= FI_FRAG;
893 fr->fr_mip.fi_fl |= FI_FRAG;
895 } else if (***cp == 'o' || ***cp == 'O') {
898 "%d: opt missing arguements\n",
903 if (!(opts = optname(cp, &secmsk, linenum)))
906 } else if (***cp == 's' || ***cp == 'S') {
909 "%d: short cannot be used with TCP flags\n",
915 fr->fr_ip.fi_fl |= FI_SHORT;
916 fr->fr_mip.fi_fl |= FI_SHORT;
921 if (!notopt || !opts)
922 fr->fr_mip.fi_fl |= oflags;
925 fr->fr_mip.fi_optmsk |= opts;
927 fr->fr_mip.fi_optmsk |= (opts & ~0x0100);
930 fr->fr_mip.fi_optmsk |= opts;
932 fr->fr_mip.fi_secmsk |= secmsk;
935 fr->fr_ip.fi_fl &= (~oflags & 0xf);
936 fr->fr_ip.fi_optmsk &= ~opts;
937 fr->fr_ip.fi_secmsk &= ~secmsk;
939 fr->fr_ip.fi_fl |= oflags;
940 fr->fr_ip.fi_optmsk |= opts;
941 fr->fr_ip.fi_secmsk |= secmsk;
954 u_32_t optname(cp, sp, linenum)
959 struct ipopt_names *io, *so;
965 for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) {
966 for (io = ionames; io->on_name; io++)
967 if (!strcasecmp(s, io->on_name)) {
972 fprintf(stderr, "%d: unknown IP option name %s\n",
976 if (!strcasecmp(s, "sec-class"))
980 if (sec && !*(*cp + 1)) {
981 fprintf(stderr, "%d: missing security level after sec-class\n",
988 for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) {
989 for (so = secclass; so->on_name; so++)
990 if (!strcasecmp(s, so->on_name)) {
996 "%d: no such security level: %s\n",
1009 void optprint(u_short *sec, u_long optmsk, u_long optbits)
1011 void optprint(sec, optmsk, optbits)
1013 u_long optmsk, optbits;
1016 u_short secmsk = sec[0], secbits = sec[1];
1017 struct ipopt_names *io, *so;
1021 for (io = ionames; io->on_name; io++)
1022 if ((io->on_bit & optmsk) &&
1023 ((io->on_bit & optmsk) == (io->on_bit & optbits))) {
1024 if ((io->on_value != IPOPT_SECURITY) ||
1025 (!secmsk && !secbits)) {
1026 printf("%s%s", s, io->on_name);
1027 if (io->on_value == IPOPT_SECURITY)
1034 if (secmsk & secbits) {
1035 printf("%ssec-class", s);
1037 for (so = secclass; so->on_name; so++)
1038 if ((secmsk & so->on_bit) &&
1039 ((so->on_bit & secmsk) == (so->on_bit & secbits))) {
1040 printf("%s%s", s, so->on_name);
1045 if ((optmsk && (optmsk != optbits)) ||
1046 (secmsk && (secmsk != secbits))) {
1049 if (optmsk != optbits) {
1050 for (io = ionames; io->on_name; io++)
1051 if ((io->on_bit & optmsk) &&
1052 ((io->on_bit & optmsk) !=
1053 (io->on_bit & optbits))) {
1054 if ((io->on_value != IPOPT_SECURITY) ||
1055 (!secmsk && !secbits)) {
1056 printf("%s%s", s, io->on_name);
1066 if (secmsk != secbits) {
1067 printf("%ssec-class", s);
1069 for (so = secclass; so->on_name; so++)
1070 if ((so->on_bit & secmsk) &&
1071 ((so->on_bit & secmsk) !=
1072 (so->on_bit & secbits))) {
1073 printf("%s%s", s, so->on_name);
1080 char *icmptypes[] = {
1081 "echorep", (char *)NULL, (char *)NULL, "unreach", "squench",
1082 "redir", (char *)NULL, (char *)NULL, "echo", "routerad",
1083 "routersol", "timex", "paramprob", "timest", "timestrep",
1084 "inforeq", "inforep", "maskreq", "maskrep", "END"
1088 * set the icmp field to the correct type if "icmp" word is found
1090 int addicmp(cp, fp, linenum)
1102 if (isdigit(***cp)) {
1103 if (!ratoi(**cp, &i, 0, 255)) {
1105 "%d: Invalid icmp-type (%s) specified\n",
1109 } else if (fp->fr_proto == IPPROTO_ICMPV6) {
1110 fprintf(stderr, "%d: Unknown ICMPv6 type (%s) specified, %s",
1111 linenum, **cp, "(use numeric value instead)\n");
1114 for (t = icmptypes, i = 0; ; t++, i++) {
1117 if (!strcasecmp("END", *t)) {
1121 if (!strcasecmp(*t, **cp))
1126 "%d: Invalid icmp-type (%s) specified\n",
1131 fp->fr_icmp = (u_short)(i << 8);
1132 fp->fr_icmpm = (u_short)0xff00;
1137 if (**cp && strcasecmp("code", **cp))
1140 if (isdigit(***cp)) {
1141 if (!ratoi(**cp, &i, 0, 255)) {
1143 "%d: Invalid icmp code (%s) specified\n",
1151 "%d: Invalid icmp code (%s) specified\n",
1157 fp->fr_icmp |= (u_short)i;
1158 fp->fr_icmpm = (u_short)0xffff;
1164 #define MAX_ICMPCODE 15
1166 char *icmpcodes[] = {
1167 "net-unr", "host-unr", "proto-unr", "port-unr", "needfrag",
1168 "srcfail", "net-unk", "host-unk", "isolate", "net-prohib",
1169 "host-prohib", "net-tos", "host-tos", "filter-prohib", "host-preced",
1170 "preced-cutoff", NULL };
1172 * Return the number for the associated ICMP unreachable code.
1180 if ((s = strrchr(str, ')')))
1182 if (isdigit(*str)) {
1183 if (!ratoi(str, &i, 0, 255))
1189 for (i = 0; icmpcodes[i]; i++)
1190 if (!strncasecmp(str, icmpcodes[i], MIN(len,
1191 strlen(icmpcodes[i])) ))
1198 * set the icmp field to the correct type if "icmp" word is found
1200 int addkeep(cp, fp, linenum)
1209 fprintf(stderr, "%d: Missing keyword after keep\n",
1214 if (strcasecmp(**cp, "state") == 0)
1215 fp->fr_flags |= FR_KEEPSTATE;
1216 else if (strncasecmp(**cp, "frag", 4) == 0)
1217 fp->fr_flags |= FR_KEEPFRAG;
1218 else if (strcasecmp(**cp, "state-age") == 0) {
1219 if (fp->fr_ip.fi_p == IPPROTO_TCP) {
1220 fprintf(stderr, "%d: cannot use state-age with tcp\n",
1224 if ((fp->fr_flags & FR_KEEPSTATE) == 0) {
1225 fprintf(stderr, "%d: state-age with no 'keep state'\n",
1231 fprintf(stderr, "%d: state-age with no arg\n",
1235 fp->fr_age[0] = atoi(**cp);
1236 s = index(**cp, '/');
1239 fp->fr_age[1] = atoi(s);
1241 fp->fr_age[1] = fp->fr_age[0];
1243 fprintf(stderr, "%d: Unrecognised state keyword \"%s\"\n",
1252 void printifname(format, name, ifp)
1253 char *format, *name;
1256 printf("%s%s", format, name);
1257 if ((ifp == NULL) && strcmp(name, "-") && strcmp(name, "*"))
1263 * print the filter structure in a useful way
1274 if (fp->fr_flags & FR_PASS)
1276 if (fp->fr_flags & FR_NOMATCH)
1278 else if (fp->fr_flags & FR_BLOCK) {
1280 if (fp->fr_flags & FR_RETICMP) {
1281 if ((fp->fr_flags & FR_RETMASK) == FR_FAKEICMP)
1282 printf(" return-icmp-as-dest");
1283 else if ((fp->fr_flags & FR_RETMASK) == FR_RETICMP)
1284 printf(" return-icmp");
1286 if (fp->fr_icode <= MAX_ICMPCODE)
1288 icmpcodes[(int)fp->fr_icode]);
1290 printf("(%d)", fp->fr_icode);
1292 } else if ((fp->fr_flags & FR_RETMASK) == FR_RETRST)
1293 printf(" return-rst");
1294 } else if ((fp->fr_flags & FR_LOGMASK) == FR_LOG) {
1296 } else if (fp->fr_flags & FR_ACCOUNT)
1298 else if (fp->fr_flags & FR_AUTH) {
1300 if ((fp->fr_flags & FR_RETMASK) == FR_RETRST)
1301 printf(" return-rst");
1302 } else if (fp->fr_flags & FR_PREAUTH)
1304 else if (fp->fr_skip)
1305 printf("skip %hu", fp->fr_skip);
1307 if (fp->fr_flags & FR_OUTQUE)
1312 if (((fp->fr_flags & FR_LOGB) == FR_LOGB) ||
1313 ((fp->fr_flags & FR_LOGP) == FR_LOGP)) {
1318 if (fp->fr_flags & FR_QUICK)
1321 if (*fp->fr_ifname) {
1322 printifname("on ", fp->fr_ifname, fp->fr_ifa);
1323 if (*fp->fr_ifnames[1] && strcmp(fp->fr_ifnames[1], "*"))
1324 printifname(",", fp->fr_ifnames[1], fp->fr_ifas[1]);
1327 if (*fp->fr_dif.fd_ifname)
1328 print_toif("dup-to", &fp->fr_dif);
1329 if (*fp->fr_tif.fd_ifname)
1330 print_toif("to", &fp->fr_tif);
1331 if (fp->fr_flags & FR_FASTROUTE)
1332 printf("fastroute ");
1334 if ((*fp->fr_ifnames[2] && strcmp(fp->fr_ifnames[2], "*")) ||
1335 (*fp->fr_ifnames[3] && strcmp(fp->fr_ifnames[3], "*"))) {
1336 if (fp->fr_flags & FR_OUTQUE)
1341 if (*fp->fr_ifnames[2]) {
1342 printifname("", fp->fr_ifnames[2],
1347 if (*fp->fr_ifnames[3])
1348 printifname("", fp->fr_ifnames[3],
1354 if (fp->fr_mip.fi_tos)
1355 printf("tos %#x ", fp->fr_tos);
1356 if (fp->fr_mip.fi_ttl)
1357 printf("ttl %d ", fp->fr_ttl);
1358 if (fp->fr_ip.fi_fl & FI_TCPUDP) {
1359 printf("proto tcp/udp ");
1361 } else if ((pr = fp->fr_mip.fi_p)) {
1362 if ((p = getprotobynumber(fp->fr_proto)))
1363 printf("proto %s ", p->p_name);
1365 printf("proto %d ", fp->fr_proto);
1368 printf("from %s", fp->fr_flags & FR_NOTSRCIP ? "!" : "");
1369 printhostmask(fp->fr_v, (u_32_t *)&fp->fr_src.s_addr,
1370 (u_32_t *)&fp->fr_smsk.s_addr);
1372 printportcmp(pr, &fp->fr_tuc.ftu_src);
1374 printf(" to %s", fp->fr_flags & FR_NOTDSTIP ? "!" : "");
1375 printhostmask(fp->fr_v, (u_32_t *)&fp->fr_dst.s_addr,
1376 (u_32_t *)&fp->fr_dmsk.s_addr);
1378 printportcmp(pr, &fp->fr_tuc.ftu_dst);
1380 if ((fp->fr_ip.fi_fl & ~FI_TCPUDP) ||
1381 (fp->fr_mip.fi_fl & ~FI_TCPUDP) ||
1382 fp->fr_ip.fi_optmsk || fp->fr_mip.fi_optmsk ||
1383 fp->fr_ip.fi_secmsk || fp->fr_mip.fi_secmsk) {
1385 if (fp->fr_ip.fi_optmsk || fp->fr_mip.fi_optmsk ||
1386 fp->fr_ip.fi_secmsk || fp->fr_mip.fi_secmsk) {
1387 sec[0] = fp->fr_mip.fi_secmsk;
1388 sec[1] = fp->fr_ip.fi_secmsk;
1390 fp->fr_mip.fi_optmsk, fp->fr_ip.fi_optmsk);
1391 } else if (fp->fr_mip.fi_fl & FI_OPTIONS) {
1392 if (!(fp->fr_ip.fi_fl & FI_OPTIONS))
1396 if (fp->fr_mip.fi_fl & FI_SHORT) {
1397 if (!(fp->fr_ip.fi_fl & FI_SHORT))
1401 if (fp->fr_mip.fi_fl & FI_FRAG) {
1402 if (!(fp->fr_ip.fi_fl & FI_FRAG))
1407 if (fp->fr_proto == IPPROTO_ICMP && fp->fr_icmpm != 0) {
1408 int type = fp->fr_icmp, code;
1410 type = ntohs(fp->fr_icmp);
1413 if (type < (sizeof(icmptypes) / sizeof(char *) - 1) &&
1415 printf(" icmp-type %s", icmptypes[type]);
1417 printf(" icmp-type %d", type);
1418 if (ntohs(fp->fr_icmpm) & 0xff)
1419 printf(" code %d", code);
1421 if (fp->fr_proto == IPPROTO_ICMPV6 && fp->fr_icmpm != 0) {
1422 int type = fp->fr_icmp, code;
1424 type = ntohs(fp->fr_icmp);
1427 printf(" icmp-type %d", type);
1428 if (ntohs(fp->fr_icmpm) & 0xff)
1429 printf(" code %d", code);
1431 if (fp->fr_proto == IPPROTO_TCP && (fp->fr_tcpf || fp->fr_tcpfm)) {
1433 if (fp->fr_tcpf & ~TCPF_ALL)
1434 printf("0x%x", fp->fr_tcpf);
1436 for (s = flagset, t = flags; *s; s++, t++)
1437 if (fp->fr_tcpf & *t)
1441 if (fp->fr_tcpfm & ~TCPF_ALL)
1442 printf("0x%x", fp->fr_tcpfm);
1444 for (s = flagset, t = flags; *s; s++, t++)
1445 if (fp->fr_tcpfm & *t)
1450 if (fp->fr_flags & FR_KEEPSTATE)
1451 printf(" keep state");
1452 if (fp->fr_flags & FR_KEEPFRAG)
1453 printf(" keep frags");
1454 if (fp->fr_age[0] != 0 || fp->fr_age[1]!= 0)
1455 printf(" state-age %u/%u", fp->fr_age[0], fp->fr_age[1]);
1457 printf(" head %d", fp->fr_grhead);
1459 printf(" group %d", fp->fr_group);
1460 (void)putchar('\n');
1466 int i = sizeof(*fp), j = 0;
1469 for (s = (u_char *)fp; i; i--, s++) {
1471 printf("%02x ", *s);
1478 (void)fflush(stdout);
1488 if (fp->fr_flags & FR_LOGBODY)
1490 if (fp->fr_flags & FR_LOGFIRST)
1492 if (fp->fr_flags & FR_LOGORBLOCK)
1493 printf(" or-block");
1494 if (fp->fr_loglevel != 0xffff) {
1496 if (fp->fr_loglevel & LOG_FACMASK) {
1497 s = fac_toname(fp->fr_loglevel);
1502 u = pri_toname(fp->fr_loglevel);
1506 printf("%s.%s", s, u);