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
72 struct frentry *parse(line, linenum)
76 static struct frentry fil;
77 char *cps[31], **cpp, *endptr, *s;
78 struct protoent *p = NULL;
79 int i, cnt = 1, j, ch;
82 while (*line && isspace(*line))
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;
93 * break line up into max of 20 segments
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");
102 fprintf(stderr, "%d: not enough segments in line\n", linenum);
108 * The presence of an '@' followed by a number gives the position in
109 * the current rule list to insert this one.
112 fil.fr_hits = (U_QUAD_T)atoi(*cpp++ + 1) + 1;
116 * Check the first keyword in the rule and any options that are
117 * expected to follow it.
119 if (!strcasecmp("block", *cpp)) {
120 fil.fr_flags |= FR_BLOCK;
121 if (!strncasecmp(*(cpp+1), "return-icmp-as-dest", 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) {
128 if (strlen(*cpp) == i) {
129 if (*(cpp + 1) && **(cpp +1) == '(') {
137 * The ICMP code is not required to follow in ()'s
139 if ((i >= 0) && (*(*cpp + i) == '(')) {
141 j = icmpcode(*cpp + i);
144 "%d: unrecognised icmp code %s\n",
150 } else if (!strcasecmp(*(cpp+1), "return-rst")) {
151 fil.fr_flags |= FR_RETRST;
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;
166 } else if (!strcasecmp("preauth", *cpp)) {
167 fil.fr_flags |= FR_PREAUTH;
168 } else if (!strcasecmp("skip", *cpp)) {
170 if (ratoui(*cpp, &k, 0, UINT_MAX))
173 fprintf(stderr, "%d: integer must follow skip\n",
177 } else if (!strcasecmp("log", *cpp)) {
178 fil.fr_flags |= FR_LOG;
179 if (!strcasecmp(*(cpp+1), "body")) {
180 fil.fr_flags |= FR_LOGBODY;
183 if (!strcasecmp(*(cpp+1), "first")) {
184 fil.fr_flags |= FR_LOGFIRST;
187 if (*cpp && !strcasecmp(*(cpp+1), "or-block")) {
188 fil.fr_flags |= FR_LOGORBLOCK;
191 if (!strcasecmp(*(cpp+1), "level")) {
193 if (loglevel(cpp, &fil.fr_loglevel, linenum) == -1)
199 * Doesn't start with one of the action words
201 fprintf(stderr, "%d: unknown keyword (%s)\n", linenum, *cpp);
205 fprintf(stderr, "%d: missing 'in'/'out' keyword\n", linenum);
210 * Get the direction for filtering. Impose restrictions on direction
211 * if blocking with returning ICMP or an RST has been requested.
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) {
219 "%d: Can only use return-icmp with 'in'\n",
222 } else if (fil.fr_flags & FR_RETRST) {
224 "%d: Can only use return-rst with 'in'\n",
230 fprintf(stderr, "%d: missing source specification\n", linenum);
234 if (!strcasecmp("log", *cpp)) {
236 fprintf(stderr, "%d: missing source specification\n",
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;
248 if (*cpp && !strcasecmp(*cpp, "first")) {
249 fil.fr_flags |= FR_LOGFIRST;
252 if (*cpp && !strcasecmp(*cpp, "or-block")) {
253 if (!(fil.fr_flags & FR_PASS)) {
255 "%d: or-block must be used with pass\n",
259 fil.fr_flags |= FR_LOGORBLOCK;
262 if (*cpp && !strcasecmp(*cpp, "level")) {
263 if (loglevel(cpp, &fil.fr_loglevel, linenum) == -1)
270 if (*cpp && !strcasecmp("quick", *cpp)) {
271 if (fil.fr_skip != 0) {
272 fprintf(stderr, "%d: cannot use skip with quick\n",
277 fil.fr_flags |= FR_QUICK;
281 * Parse rule options that are available if a rule is tied to an
284 *fil.fr_ifname = '\0';
285 *fil.fr_oifname = '\0';
286 if (*cpp && !strcasecmp(*cpp, "on")) {
288 fprintf(stderr, "%d: interface name missing\n",
293 s = index(*cpp, ',');
296 (void)strncpy(fil.fr_ifnames[1], s, IFNAMSIZ - 1);
297 fil.fr_ifnames[1][IFNAMSIZ - 1] = '\0';
299 strcpy(fil.fr_ifnames[1], "*");
301 (void)strncpy(fil.fr_ifnames[0], *cpp, IFNAMSIZ - 1);
302 fil.fr_ifnames[0][IFNAMSIZ - 1] = '\0';
306 if ((fil.fr_flags & FR_RETMASK) == FR_RETRST) {
308 "%d: %s can only be used with TCP\n",
309 linenum, "return-rst");
316 if (!strcasecmp(*cpp, "dup-to") && *(cpp + 1)) {
318 if (to_interface(&fil.fr_dif, *cpp, linenum))
322 if (*cpp && !strcasecmp(*cpp, "to") && *(cpp + 1)) {
324 if (to_interface(&fil.fr_tif, *cpp, linenum))
327 } else if (*cpp && !strcasecmp(*cpp, "fastroute")) {
328 if (!(fil.fr_flags & FR_INQUE)) {
330 "can only use %s with 'in'\n",
334 fil.fr_flags |= FR_FASTROUTE;
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.
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)))) {
352 s = index(*cpp, ',');
355 (void)strncpy(fil.fr_ifnames[3], s,
357 fil.fr_ifnames[3][IFNAMSIZ - 1] = '\0';
360 (void)strncpy(fil.fr_ifnames[2], *cpp, IFNAMSIZ - 1);
361 fil.fr_ifnames[2][IFNAMSIZ - 1] = '\0';
364 strcpy(fil.fr_ifnames[2], "*");
366 if (*cpp && !strcasecmp(*cpp, "tos")) {
368 fprintf(stderr, "%d: tos missing value\n", linenum);
371 fil.fr_tos = strtol(*cpp, NULL, 0);
372 fil.fr_mip.fi_tos = 0xff;
376 if (*cpp && !strcasecmp(*cpp, "ttl")) {
378 fprintf(stderr, "%d: ttl missing hopcount value\n",
382 if (ratoi(*cpp, &i, 0, 255))
385 fprintf(stderr, "%d: invalid ttl (%s)\n",
389 fil.fr_mip.fi_ttl = 0xff;
394 * check for "proto <protoname>" only decode udp/tcp/icmp as protoname
397 if (*cpp && !strcasecmp(*cpp, "proto")) {
399 fprintf(stderr, "%d: protocol name missing\n", linenum);
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")) {
408 "%d: use proto ipv6-icmp with IPv6 (or use proto 1 if you really mean icmp)\n",
411 if (!(p = getprotobyname(proto)) && !isdigit(*proto)) {
413 "%d: unknown protocol (%s)\n",
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) {
423 "%d: unknown protocol (%s)\n",
429 fil.fr_mip.fi_p = 0xff;
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");
440 * get the from host and bit mask to use against packets
444 fprintf(stderr, "%d: missing source specification\n", linenum);
447 if (!strcasecmp(*cpp, "all")) {
452 if (strcasecmp(*cpp, "from")) {
453 fprintf(stderr, "%d: unexpected keyword (%s) - from\n",
458 fprintf(stderr, "%d: missing host after from\n",
462 if (!strcmp(*cpp, "!")) {
463 fil.fr_flags |= FR_NOTSRCIP;
466 "%d: missing host after from\n",
470 } else if (**cpp == '!') {
471 fil.fr_flags |= FR_NOTSRCIP;
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)) {
481 if ((ch != 0) && (fil.fr_proto != IPPROTO_TCP) &&
482 (fil.fr_proto != IPPROTO_UDP) &&
483 !(fil.fr_ip.fi_fl & FI_TCPUDP)) {
485 "%d: cannot use port and neither tcp or udp\n",
492 fprintf(stderr, "%d: missing to fields\n", linenum);
497 * do the same for the to field (destination host)
499 if (strcasecmp(*cpp, "to")) {
500 fprintf(stderr, "%d: unexpected keyword (%s) - to\n",
505 fprintf(stderr, "%d: missing host after to\n", linenum);
509 if (!strcmp(*cpp, "!")) {
510 fil.fr_flags |= FR_NOTDSTIP;
513 "%d: missing host after from\n",
517 } else if (**cpp == '!') {
518 fil.fr_flags |= FR_NOTDSTIP;
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)) {
526 if ((ch != 0) && (fil.fr_proto != IPPROTO_TCP) &&
527 (fil.fr_proto != IPPROTO_UDP) &&
528 !(fil.fr_ip.fi_fl & FI_TCPUDP)) {
530 "%d: cannot use port and neither tcp or udp\n",
539 * check some sanity, make sure we don't have icmp checks with tcp
540 * or udp or visa versa.
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);
547 if (fil.fr_icmp && fil.fr_proto != IPPROTO_ICMP) {
548 fprintf(stderr, "%d: icmp comparisons on wrong protocol\n",
556 if (*cpp && !strcasecmp(*cpp, "flags")) {
558 fprintf(stderr, "%d: no flags present\n", linenum);
561 fil.fr_tcpf = tcp_flags(*cpp, &fil.fr_tcpfm, linenum);
568 if ((fil.fr_v == 4) && *cpp && (!strcasecmp(*cpp, "with") ||
569 !strcasecmp(*cpp, "and")))
570 if (extras(&cpp, &fil, linenum))
574 * icmp types for use with the icmp protocol
576 if (*cpp && !strcasecmp(*cpp, "icmp-type")) {
577 if (fil.fr_proto != IPPROTO_ICMP &&
578 fil.fr_proto != IPPROTO_ICMPV6) {
580 "%d: icmp with wrong protocol (%d)\n",
581 linenum, fil.fr_proto);
584 if (addicmp(&cpp, &fil, linenum))
586 fil.fr_icmp = htons(fil.fr_icmp);
587 fil.fr_icmpm = htons(fil.fr_icmpm);
593 while (*cpp && !strcasecmp(*cpp, "keep"))
594 if (addkeep(&cpp, &fil, linenum))
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"
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]));
611 * head of a new group ?
613 if (*cpp && !strcasecmp(*cpp, "head")) {
614 if (fil.fr_skip != 0) {
615 fprintf(stderr, "%d: cannot use skip with head\n",
620 fprintf(stderr, "%d: head without group #\n", linenum);
623 if (ratoui(*cpp, &k, 0, UINT_MAX))
624 fil.fr_grhead = (u_32_t)k;
626 fprintf(stderr, "%d: invalid group (%s)\n",
634 * head of a new group ?
636 if (*cpp && !strcasecmp(*cpp, "group")) {
638 fprintf(stderr, "%d: group without group #\n",
642 if (ratoui(*cpp, &k, 0, UINT_MAX))
645 fprintf(stderr, "%d: invalid group (%s)\n",
656 fprintf(stderr, "%d: unknown words at end: [", linenum);
658 fprintf(stderr, "%s ", *cpp);
659 fprintf(stderr, "]\n");
666 if ((fil.fr_tcpf || fil.fr_tcpfm) && fil.fr_proto != IPPROTO_TCP) {
667 fprintf(stderr, "%d: TCP protocol not specified\n", linenum);
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)) {
673 fil.fr_ip.fi_fl |= FI_TCPUDP;
674 fil.fr_mip.fi_fl |= FI_TCPUDP;
677 "%d: port comparisons for non-TCP/UDP\n",
683 if ((fil.fr_flags & FR_KEEPFRAG) &&
684 (!(fil.fr_ip.fi_fl & FI_FRAG) || !(fil.fr_ip.fi_fl & FI_FRAG))) {
686 "%d: must use 'with frags' with 'keep frags'\n",
695 int loglevel(cpp, facpri, linenum)
706 fprintf(stderr, "%d: %s\n", linenum,
707 "missing identifier after level");
711 s = index(*cpp, '.');
714 fac = fac_findname(*cpp);
716 fprintf(stderr, "%d: %s %s\n", linenum,
717 "Unknown facility", *cpp);
720 pri = pri_findname(s);
722 fprintf(stderr, "%d: %s %s\n", linenum,
723 "Unknown priority", s);
727 pri = pri_findname(*cpp);
729 fprintf(stderr, "%d: %s %s\n", linenum,
730 "Unknown priority", *cpp);
739 int to_interface(fdp, to, linenum)
750 if (hostnum((u_32_t *)&fdp->fd_ip, s, linenum) == -1)
753 (void) strncpy(fdp->fd_ifname, to, sizeof(fdp->fd_ifname) - 1);
754 fdp->fd_ifname[sizeof(fdp->fd_ifname) - 1] = '\0';
759 void print_toif(tag, fdp)
763 printf("%s %s%s", tag, fdp->fd_ifname,
764 (fdp->fd_ifp || (long)fdp->fd_ifp == -1) ? "" : "(!)");
766 if (use_inet6 && IP6_NOTZERO(&fdp->fd_ip6.in6)) {
769 inet_ntop(AF_INET6, &fdp->fd_ip6, ipv6addr,
770 sizeof(fdp->fd_ip6));
771 printf(":%s", ipv6addr);
774 if (fdp->fd_ip.s_addr)
775 printf(":%s", inet_ntoa(fdp->fd_ip));
781 * deal with extra bits on end of the line
783 int extras(cp, fr, linenum)
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') {
808 } else if (***cp == 'i' || ***cp == 'I') {
810 fr->fr_ip.fi_fl |= FI_OPTIONS;
811 fr->fr_mip.fi_fl |= FI_OPTIONS;
813 } else if (***cp == 'f' || ***cp == 'F') {
815 fr->fr_ip.fi_fl |= FI_FRAG;
816 fr->fr_mip.fi_fl |= FI_FRAG;
818 } else if (***cp == 'o' || ***cp == 'O') {
821 "%d: opt missing arguements\n",
826 if (!(opts = optname(cp, &secmsk, linenum)))
829 } else if (***cp == 's' || ***cp == 'S') {
832 "%d: short cannot be used with TCP flags\n",
838 fr->fr_ip.fi_fl |= FI_SHORT;
839 fr->fr_mip.fi_fl |= FI_SHORT;
844 if (!notopt || !opts)
845 fr->fr_mip.fi_fl |= oflags;
848 fr->fr_mip.fi_optmsk |= opts;
850 fr->fr_mip.fi_optmsk |= (opts & ~0x0100);
853 fr->fr_mip.fi_optmsk |= opts;
855 fr->fr_mip.fi_secmsk |= secmsk;
858 fr->fr_ip.fi_fl &= (~oflags & 0xf);
859 fr->fr_ip.fi_optmsk &= ~opts;
860 fr->fr_ip.fi_secmsk &= ~secmsk;
862 fr->fr_ip.fi_fl |= oflags;
863 fr->fr_ip.fi_optmsk |= opts;
864 fr->fr_ip.fi_secmsk |= secmsk;
877 u_32_t optname(cp, sp, linenum)
882 struct ipopt_names *io, *so;
888 for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) {
889 for (io = ionames; io->on_name; io++)
890 if (!strcasecmp(s, io->on_name)) {
895 fprintf(stderr, "%d: unknown IP option name %s\n",
899 if (!strcasecmp(s, "sec-class"))
903 if (sec && !*(*cp + 1)) {
904 fprintf(stderr, "%d: missing security level after sec-class\n",
911 for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) {
912 for (so = secclass; so->on_name; so++)
913 if (!strcasecmp(s, so->on_name)) {
919 "%d: no such security level: %s\n",
932 void optprint(u_short *sec, u_long optmsk, u_long optbits)
934 void optprint(sec, optmsk, optbits)
936 u_long optmsk, optbits;
939 u_short secmsk = sec[0], secbits = sec[1];
940 struct ipopt_names *io, *so;
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)
957 if (secmsk & secbits) {
958 printf("%ssec-class", 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);
968 if ((optmsk && (optmsk != optbits)) ||
969 (secmsk && (secmsk != secbits))) {
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);
989 if (secmsk != secbits) {
990 printf("%ssec-class", 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);
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"
1011 * set the icmp field to the correct type if "icmp" word is found
1013 int addicmp(cp, fp, linenum)
1025 if (isdigit(***cp)) {
1026 if (!ratoi(**cp, &i, 0, 255)) {
1028 "%d: Invalid icmp-type (%s) specified\n",
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");
1037 for (t = icmptypes, i = 0; ; t++, i++) {
1040 if (!strcasecmp("END", *t)) {
1044 if (!strcasecmp(*t, **cp))
1049 "%d: Invalid icmp-type (%s) specified\n",
1054 fp->fr_icmp = (u_short)(i << 8);
1055 fp->fr_icmpm = (u_short)0xff00;
1060 if (**cp && strcasecmp("code", **cp))
1063 if (isdigit(***cp)) {
1064 if (!ratoi(**cp, &i, 0, 255)) {
1066 "%d: Invalid icmp code (%s) specified\n",
1074 "%d: Invalid icmp code (%s) specified\n",
1080 fp->fr_icmp |= (u_short)i;
1081 fp->fr_icmpm = (u_short)0xffff;
1087 #define MAX_ICMPCODE 15
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 };
1095 * Return the number for the associated ICMP unreachable code.
1103 if ((s = strrchr(str, ')')))
1105 if (isdigit(*str)) {
1106 if (!ratoi(str, &i, 0, 255))
1112 for (i = 0; icmpcodes[i]; i++)
1113 if (!strncasecmp(str, icmpcodes[i], MIN(len,
1114 strlen(icmpcodes[i])) ))
1121 * set the icmp field to the correct type if "icmp" word is found
1123 int addkeep(cp, fp, linenum)
1132 fprintf(stderr, "%d: Missing keyword after keep\n",
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",
1147 if ((fp->fr_flags & FR_KEEPSTATE) == 0) {
1148 fprintf(stderr, "%d: state-age with no 'keep state'\n",
1154 fprintf(stderr, "%d: state-age with no arg\n",
1158 fp->fr_age[0] = atoi(**cp);
1159 s = index(**cp, '/');
1162 fp->fr_age[1] = atoi(s);
1164 fp->fr_age[1] = fp->fr_age[0];
1166 fprintf(stderr, "%d: Unrecognised state keyword \"%s\"\n",
1175 void printifname(format, name, ifp)
1176 char *format, *name;
1179 printf("%s%s", format, name);
1180 if ((ifp == NULL) && strcmp(name, "-") && strcmp(name, "*"))
1186 * print the filter structure in a useful way
1197 if (fp->fr_flags & FR_PASS)
1199 if (fp->fr_flags & FR_NOMATCH)
1201 else if (fp->fr_flags & FR_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");
1209 if (fp->fr_icode <= MAX_ICMPCODE)
1211 icmpcodes[(int)fp->fr_icode]);
1213 printf("(%d)", fp->fr_icode);
1215 } else if ((fp->fr_flags & FR_RETMASK) == FR_RETRST)
1216 printf(" return-rst");
1217 } else if ((fp->fr_flags & FR_LOGMASK) == FR_LOG) {
1219 } else if (fp->fr_flags & FR_ACCOUNT)
1221 else if (fp->fr_flags & FR_AUTH) {
1223 if ((fp->fr_flags & FR_RETMASK) == FR_RETRST)
1224 printf(" return-rst");
1225 } else if (fp->fr_flags & FR_PREAUTH)
1227 else if (fp->fr_skip)
1228 printf("skip %hu", fp->fr_skip);
1230 if (fp->fr_flags & FR_OUTQUE)
1235 if (((fp->fr_flags & FR_LOGB) == FR_LOGB) ||
1236 ((fp->fr_flags & FR_LOGP) == FR_LOGP)) {
1241 if (fp->fr_flags & FR_QUICK)
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]);
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 ");
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)
1264 if (*fp->fr_ifnames[2]) {
1265 printifname("", fp->fr_ifnames[2],
1270 if (*fp->fr_ifnames[3])
1271 printifname("", fp->fr_ifnames[3],
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 ");
1284 } else if ((pr = fp->fr_mip.fi_p)) {
1285 if ((p = getprotobynumber(fp->fr_proto)))
1286 printf("proto %s ", p->p_name);
1288 printf("proto %d ", fp->fr_proto);
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);
1295 printportcmp(pr, &fp->fr_tuc.ftu_src);
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);
1301 printportcmp(pr, &fp->fr_tuc.ftu_dst);
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) {
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;
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))
1319 if (fp->fr_mip.fi_fl & FI_SHORT) {
1320 if (!(fp->fr_ip.fi_fl & FI_SHORT))
1324 if (fp->fr_mip.fi_fl & FI_FRAG) {
1325 if (!(fp->fr_ip.fi_fl & FI_FRAG))
1330 if (fp->fr_proto == IPPROTO_ICMP && fp->fr_icmpm != 0) {
1331 int type = fp->fr_icmp, code;
1333 type = ntohs(fp->fr_icmp);
1336 if (type < (sizeof(icmptypes) / sizeof(char *) - 1) &&
1338 printf(" icmp-type %s", icmptypes[type]);
1340 printf(" icmp-type %d", type);
1341 if (ntohs(fp->fr_icmpm) & 0xff)
1342 printf(" code %d", code);
1344 if (fp->fr_proto == IPPROTO_ICMPV6 && fp->fr_icmpm != 0) {
1345 int type = fp->fr_icmp, code;
1347 type = ntohs(fp->fr_icmp);
1350 printf(" icmp-type %d", type);
1351 if (ntohs(fp->fr_icmpm) & 0xff)
1352 printf(" code %d", code);
1354 if (fp->fr_proto == IPPROTO_TCP && (fp->fr_tcpf || fp->fr_tcpfm)) {
1356 if (fp->fr_tcpf & ~TCPF_ALL)
1357 printf("0x%x", fp->fr_tcpf);
1359 for (s = flagset, t = flags; *s; s++, t++)
1360 if (fp->fr_tcpf & *t)
1364 if (fp->fr_tcpfm & ~TCPF_ALL)
1365 printf("0x%x", fp->fr_tcpfm);
1367 for (s = flagset, t = flags; *s; s++, t++)
1368 if (fp->fr_tcpfm & *t)
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]);
1380 printf(" head %d", fp->fr_grhead);
1382 printf(" group %d", fp->fr_group);
1383 (void)putchar('\n');
1389 int i = sizeof(*fp), j = 0;
1392 for (s = (u_char *)fp; i; i--, s++) {
1394 printf("%02x ", *s);
1401 (void)fflush(stdout);
1411 if (fp->fr_flags & FR_LOGBODY)
1413 if (fp->fr_flags & FR_LOGFIRST)
1415 if (fp->fr_flags & FR_LOGORBLOCK)
1416 printf(" or-block");
1417 if (fp->fr_loglevel != 0xffff) {
1419 if (fp->fr_loglevel & LOG_FACMASK) {
1420 s = fac_toname(fp->fr_loglevel);
1425 u = pri_toname(fp->fr_loglevel);
1429 printf("%s.%s", s, u);