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
);