FreeBSD Bugzilla – Attachment 194089 Details for
Bug 226850
[pf] Matching but failed rules block without return
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
fail-policy.diff
fail-policy.diff (text/plain), 12.87 KB, created by
Kajetan Staszkiewicz
on 2018-06-09 03:49:21 UTC
(
hide
)
Description:
fail-policy.diff
Filename:
MIME Type:
Creator:
Kajetan Staszkiewicz
Created:
2018-06-09 03:49:21 UTC
Size:
12.87 KB
patch
obsolete
>diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y >index b50bc25fef5..fdb582ce45c 100644 >--- a/sbin/pfctl/parse.y >+++ b/sbin/pfctl/parse.y >@@ -70,20 +70,21 @@ __FBSDID("$FreeBSD$"); > #include "pfctl.h" > > static struct pfctl *pf = NULL; > static int debug = 0; > static int rulestate = 0; > static u_int16_t returnicmpdefault = > (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; > static u_int16_t returnicmp6default = > (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; > static int blockpolicy = PFRULE_DROP; >+static int failpolicy = PFRULE_DROP; > static int require_order = 1; > static int default_statelock; > > TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); > static struct file { > TAILQ_ENTRY(file) entry; > FILE *stream; > char *name; > int lineno; > int errors; >@@ -444,22 +445,22 @@ int parseport(char *, struct range *r, int); > !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1]))) > > %} > > %token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS > %token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE > %token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF > %token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL > %token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE > %token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR >-%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID >-%token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID >+%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY FAILPOLICY >+%token RANDOMID REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID > %token ANTISPOOF FOR INCLUDE > %token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY > %token ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME > %token UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL > %token LOAD RULESET_OPTIMIZATION PRIO > %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE > %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY > %token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS > %token DIVERTTO DIVERTREPLY > %token <v.string> STRING >@@ -629,20 +630,34 @@ option : SET OPTIMIZATION STRING { > YYERROR; > blockpolicy = PFRULE_DROP; > } > | SET BLOCKPOLICY RETURN { > if (pf->opts & PF_OPT_VERBOSE) > printf("set block-policy return\n"); > if (check_rulestate(PFCTL_STATE_OPTION)) > YYERROR; > blockpolicy = PFRULE_RETURN; > } >+ | SET FAILPOLICY DROP { >+ if (pf->opts & PF_OPT_VERBOSE) >+ printf("set fail-policy drop\n"); >+ if (check_rulestate(PFCTL_STATE_OPTION)) >+ YYERROR; >+ failpolicy= PFRULE_DROP; >+ } >+ | SET FAILPOLICY RETURN { >+ if (pf->opts & PF_OPT_VERBOSE) >+ printf("set fail-policy return\n"); >+ if (check_rulestate(PFCTL_STATE_OPTION)) >+ YYERROR; >+ failpolicy = PFRULE_FAILRETURN; >+ } > | SET REQUIREORDER yesno { > if (pf->opts & PF_OPT_VERBOSE) > printf("set require-order %s\n", > $3 == 1 ? "yes" : "no"); > require_order = $3; > } > | SET FINGERPRINTS STRING { > if (pf->opts & PF_OPT_VERBOSE) > printf("set fingerprints \"%s\"\n", $3); > if (check_rulestate(PFCTL_STATE_OPTION)) { >@@ -2306,20 +2321,21 @@ pfrule : action dir logquick interface route af proto fromto > r.max_src_conn_rate.seconds; > r.rule_flag |= PFRULE_SRCTRACK; > if (srctrack == PF_SRCTRACK_RULE) > r.rule_flag |= PFRULE_RULESRCTRACK; > } > if (r.keep_state && !statelock) > r.rule_flag |= default_statelock; > > if ($9.fragment) > r.rule_flag |= PFRULE_FRAGMENT; >+ r.rule_flag |= failpolicy; > r.allow_opts = $9.allowopts; > > decide_address_family($8.src.host, &r.af); > decide_address_family($8.dst.host, &r.af); > > if ($5.rt) { > if (!r.direction) { > yyerror("direction must be explicit " > "with rules that specify routing"); > YYERROR; >@@ -5454,20 +5470,21 @@ lookup(char *s) > { "cbq", CBQ}, > { "code", CODE}, > { "codelq", CODEL}, > { "crop", FRAGCROP}, > { "debug", DEBUG}, > { "divert-reply", DIVERTREPLY}, > { "divert-to", DIVERTTO}, > { "drop", DROP}, > { "drop-ovl", FRAGDROP}, > { "dup-to", DUPTO}, >+ { "fail-policy", FAILPOLICY}, > { "fairq", FAIRQ}, > { "fastroute", FASTROUTE}, > { "file", FILENAME}, > { "fingerprints", FINGERPRINTS}, > { "flags", FLAGS}, > { "floating", FLOATING}, > { "flush", FLUSH}, > { "for", FOR}, > { "fragment", FRAGMENT}, > { "from", FROM}, >@@ -5918,20 +5935,21 @@ parse_config(char *filename, struct pfctl *xpf) > int errors = 0; > struct sym *sym; > > pf = xpf; > errors = 0; > rulestate = PFCTL_STATE_NONE; > returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; > returnicmp6default = > (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; > blockpolicy = PFRULE_DROP; >+ failpolicy = PFRULE_DROP; > require_order = 1; > > if ((file = pushfile(filename, 0)) == NULL) { > warn("cannot open the main config file!"); > return (-1); > } > > yyparse(); > errors = file->errors; > popfile(); >diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5 >index 3ff63bb14c5..e923c2a7f7b 100644 >--- a/share/man/man5/pf.conf.5 >+++ b/share/man/man5/pf.conf.5 >@@ -491,20 +491,45 @@ Packet is silently dropped. > .It Ar return > A TCP RST is returned for blocked TCP packets, > an ICMP UNREACHABLE is returned for blocked UDP packets, > and all other packets are silently dropped. > .El > .Pp > For example: > .Bd -literal -offset indent > set block-policy return > .Ed >+ >+.It Ar set fail-policy >+The >+.Ar fail-policy >+option sets the behaviour of rules which should pass a packet but unable to >+do so. This might happen when a nat or route-to rule uses an empty table as list >+of targets or if a rule fails to create state or source node. >+The following >+.Ar block >+actions are possible: >+.Pp >+.Bl -tag -width xxxxxxxx -compact >+.It Ar drop >+Incoming packet is silently dropped. >+.It Ar return >+Incoming packet is dropped and TCP RST is returned for TCP packets, >+an ICMP UNREACHABLE is returned for UDP packets, >+and no response is sent for other packets. >+.El >+.Pp >+For example: >+.Bd -literal -offset indent >+set fail-policy return >+.Ed >+ > .It Ar set state-policy > The > .Ar state-policy > option sets the default behaviour for states: > .Pp > .Bl -tag -width group-bound -compact > .It Ar if-bound > States are bound to interface. > .It Ar floating > States can match packets on any interfaces (the default). >diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h >index 0baa8a4d067..f8e267cdc06 100644 >--- a/sys/net/pfvar.h >+++ b/sys/net/pfvar.h >@@ -605,20 +605,21 @@ struct pf_rule { > > /* scrub flags */ > #define PFRULE_NODF 0x0100 > #define PFRULE_RANDOMID 0x0800 > #define PFRULE_REASSEMBLE_TCP 0x1000 > #define PFRULE_SET_TOS 0x2000 > > /* rule flags again */ > #define PFRULE_IFBOUND 0x00010000 /* if-bound */ > #define PFRULE_STATESLOPPY 0x00020000 /* sloppy state tracking */ >+#define PFRULE_FAILRETURN 0x00040000 /* return on failed rules */ > > #define PFSTATE_HIWAT 10000 /* default state table size */ > #define PFSTATE_ADAPT_START 6000 /* default adaptive timeout start */ > #define PFSTATE_ADAPT_END 12000 /* default adaptive timeout end */ > > > struct pf_threshold { > u_int32_t limit; > #define PF_THRESHOLD_MULT 1000 > #define PF_THRESHOLD_MAX 0xffffffff / PF_THRESHOLD_MULT >diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c >index 3798e937712..2578b03d5bb 100644 >--- a/sys/netpfil/pf/pf.c >+++ b/sys/netpfil/pf/pf.c >@@ -2466,20 +2466,92 @@ pf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af, > h6->ip6_hlim = IPV6_DEFHLIM; > > pfse->pfse_type = PFSE_IP6; > break; > #endif /* INET6 */ > } > pfse->pfse_m = m; > pf_send(pfse); > } > >+static void >+pf_return(struct pf_rule *r, struct pf_rule *nr, struct pf_pdesc *pd, >+ struct pf_state_key *sk, int off, struct mbuf *m, struct tcphdr *th, >+ struct pfi_kif *kif, u_int16_t bproto_sum, u_int16_t bip_sum, int hdrlen, >+ u_short *reason) >+{ >+ struct pf_addr * const saddr = pd->src; >+ struct pf_addr * const daddr = pd->dst; >+ sa_family_t af = pd->af; >+ >+ /* undo NAT changes, if they have taken place */ >+ if (nr != NULL) { >+ PF_ACPY(saddr, &sk->addr[pd->sidx], af); >+ PF_ACPY(daddr, &sk->addr[pd->didx], af); >+ if (pd->sport) >+ *pd->sport = sk->port[pd->sidx]; >+ if (pd->dport) >+ *pd->dport = sk->port[pd->didx]; >+ if (pd->proto_sum) >+ *pd->proto_sum = bproto_sum; >+ if (pd->ip_sum) >+ *pd->ip_sum = bip_sum; >+ m_copyback(m, off, hdrlen, pd->hdr.any); >+ } >+ if (pd->proto == IPPROTO_TCP && !(th->th_flags & TH_RST)) { >+ u_int32_t ack = ntohl(th->th_seq) + pd->p_len; >+ int len = 0; >+#ifdef INET >+ struct ip *h4; >+#endif >+#ifdef INET6 >+ struct ip6_hdr *h6; >+#endif >+ >+ switch (af) { >+#ifdef INET >+ case AF_INET: >+ h4 = mtod(m, struct ip *); >+ len = ntohs(h4->ip_len) - off; >+ break; >+#endif >+#ifdef INET6 >+ case AF_INET6: >+ h6 = mtod(m, struct ip6_hdr *); >+ len = ntohs(h6->ip6_plen) - (off - sizeof(*h6)); >+ break; >+#endif >+ } >+ >+ if (pf_check_proto_cksum(m, off, len, IPPROTO_TCP, af)) >+ REASON_SET(reason, PFRES_PROTCKSUM); >+ else { >+ if (th->th_flags & TH_SYN) >+ ack++; >+ if (th->th_flags & TH_FIN) >+ ack++; >+ pf_send_tcp(m, r, af, pd->dst, >+ pd->src, th->th_dport, th->th_sport, >+ ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, >+ r->return_ttl, 1, 0, kif->pfik_ifp); >+ } >+ } else if (pd->proto != IPPROTO_ICMP && af == AF_INET && >+ r->return_icmp) >+ pf_send_icmp(m, r->return_icmp >> 8, >+ r->return_icmp & 255, af, r); >+ else if (pd->proto != IPPROTO_ICMPV6 && af == AF_INET6 && >+ r->return_icmp6) >+ pf_send_icmp(m, r->return_icmp6 >> 8, >+ r->return_icmp6 & 255, af, r); >+} >+ >+ > static int > pf_ieee8021q_setpcp(struct mbuf *m, u_int8_t prio) > { > struct m_tag *mtag; > > KASSERT(prio <= PF_PRIO_MAX, > ("%s with invalid pcp", __func__)); > > mtag = m_tag_locate(m, MTAG_8021Q, MTAG_8021Q_PCP_OUT, NULL); > if (mtag == NULL) { >@@ -3430,102 +3502,45 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, > if (rewrite) > m_copyback(m, off, hdrlen, pd->hdr.any); > PFLOG_PACKET(kif, m, af, direction, reason, r->log ? r : nr, a, > ruleset, pd, 1); > } > > if ((r->action == PF_DROP) && > ((r->rule_flag & PFRULE_RETURNRST) || > (r->rule_flag & PFRULE_RETURNICMP) || > (r->rule_flag & PFRULE_RETURN))) { >- /* undo NAT changes, if they have taken place */ >- if (nr != NULL) { >- PF_ACPY(saddr, &sk->addr[pd->sidx], af); >- PF_ACPY(daddr, &sk->addr[pd->didx], af); >- if (pd->sport) >- *pd->sport = sk->port[pd->sidx]; >- if (pd->dport) >- *pd->dport = sk->port[pd->didx]; >- if (pd->proto_sum) >- *pd->proto_sum = bproto_sum; >- if (pd->ip_sum) >- *pd->ip_sum = bip_sum; >- m_copyback(m, off, hdrlen, pd->hdr.any); >- } >- if (pd->proto == IPPROTO_TCP && >- ((r->rule_flag & PFRULE_RETURNRST) || >- (r->rule_flag & PFRULE_RETURN)) && >- !(th->th_flags & TH_RST)) { >- u_int32_t ack = ntohl(th->th_seq) + pd->p_len; >- int len = 0; >-#ifdef INET >- struct ip *h4; >-#endif >-#ifdef INET6 >- struct ip6_hdr *h6; >-#endif >- >- switch (af) { >-#ifdef INET >- case AF_INET: >- h4 = mtod(m, struct ip *); >- len = ntohs(h4->ip_len) - off; >- break; >-#endif >-#ifdef INET6 >- case AF_INET6: >- h6 = mtod(m, struct ip6_hdr *); >- len = ntohs(h6->ip6_plen) - (off - sizeof(*h6)); >- break; >-#endif >- } >- >- if (pf_check_proto_cksum(m, off, len, IPPROTO_TCP, af)) >- REASON_SET(&reason, PFRES_PROTCKSUM); >- else { >- if (th->th_flags & TH_SYN) >- ack++; >- if (th->th_flags & TH_FIN) >- ack++; >- pf_send_tcp(m, r, af, pd->dst, >- pd->src, th->th_dport, th->th_sport, >- ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, >- r->return_ttl, 1, 0, kif->pfik_ifp); >- } >- } else if (pd->proto != IPPROTO_ICMP && af == AF_INET && >- r->return_icmp) >- pf_send_icmp(m, r->return_icmp >> 8, >- r->return_icmp & 255, af, r); >- else if (pd->proto != IPPROTO_ICMPV6 && af == AF_INET6 && >- r->return_icmp6) >- pf_send_icmp(m, r->return_icmp6 >> 8, >- r->return_icmp6 & 255, af, r); >+ pf_return(r, nr, pd, sk, off, m, th, kif, bproto_sum, >+ bip_sum, hdrlen, &reason); > } > > if (r->action == PF_DROP) > goto cleanup; > > if (tag > 0 && pf_tag_packet(m, pd, tag)) { > REASON_SET(&reason, PFRES_MEMORY); > goto cleanup; > } > if (rtableid >= 0) > M_SETFIB(m, rtableid); > > if (!state_icmp && (r->keep_state || nr != NULL || > (pd->flags & PFDESC_TCP_NORM))) { > int action; > action = pf_create_state(r, nr, a, pd, nsn, nk, sk, m, off, > sport, dport, &rewrite, kif, sm, tag, bproto_sum, bip_sum, > hdrlen); >- if (action != PF_PASS) >+ if (action != PF_PASS && r->rule_flag & PFRULE_FAILRETURN) { >+ pf_return(r, nr, pd, sk, off, m, th, kif, >+ bproto_sum, bip_sum, hdrlen, &reason); > return (action); >+ } > } else { > if (sk != NULL) > uma_zfree(V_pf_state_key_z, sk); > if (nk != NULL) > uma_zfree(V_pf_state_key_z, nk); > } > > /* copy back packet headers if we performed NAT operations */ > if (rewrite) > m_copyback(m, off, hdrlen, pd->hdr.any);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 226850
:
191739
|
194089
|
194340
|
194357