Date: Fri, 29 Jun 2018 16:46:19 +0000 (UTC) From: Kristof Provost <kp@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r335798 - in stable/11: sbin/pfctl share/man/man5 sys/netpfil/pf Message-ID: <201806291646.w5TGkJ6N082672@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kp Date: Fri Jun 29 16:46:19 2018 New Revision: 335798 URL: https://svnweb.freebsd.org/changeset/base/335798 Log: MFC r335569: pf: Support "return" statements in passing rules when they fail. Normally pf rules are expected to do one of two things: pass the traffic or block it. Blocking can be silent - "drop", or loud - "return", "return-rst", "return-icmp". Yet there is a 3rd category of traffic passing through pf: Packets matching a "pass" rule but when applying the rule fails. This happens when redirection table is empty or when src node or state creation fails. Such rules always fail silently without notifying the sender. Allow users to configure this behaviour too, so that pf returns an error packet in these cases. PR: 226850 Submitted by: Kajetan Staszkiewicz <vegeta tuxpowered.net> Sponsored by: InnoGames GmbH Modified: stable/11/sbin/pfctl/parse.y stable/11/share/man/man5/pf.conf.5 stable/11/sys/netpfil/pf/pf.c Directory Properties: stable/11/ (props changed) Modified: stable/11/sbin/pfctl/parse.y ============================================================================== --- stable/11/sbin/pfctl/parse.y Fri Jun 29 16:07:56 2018 (r335797) +++ stable/11/sbin/pfctl/parse.y Fri Jun 29 16:46:19 2018 (r335798) @@ -79,6 +79,7 @@ static u_int16_t returnicmpdefault = 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; @@ -453,8 +454,8 @@ int parseport(char *, struct range *r, int); %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 @@ -638,6 +639,20 @@ option : SET OPTIMIZATION STRING { 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_RETURN; + } | SET REQUIREORDER yesno { if (pf->opts & PF_OPT_VERBOSE) printf("set require-order %s\n", @@ -2634,7 +2649,12 @@ probability : STRING { ; -action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; } +action : PASS { + $$.b1 = PF_PASS; + $$.b2 = failpolicy; + $$.w = returnicmpdefault; + $$.w2 = returnicmp6default; + } | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } ; @@ -5466,6 +5486,7 @@ lookup(char *s) { "drop", DROP}, { "drop-ovl", FRAGDROP}, { "dup-to", DUPTO}, + { "fail-policy", FAILPOLICY}, { "fairq", FAIRQ}, { "fastroute", FASTROUTE}, { "file", FILENAME}, @@ -5930,6 +5951,7 @@ parse_config(char *filename, struct pfctl *xpf) returnicmp6default = (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; blockpolicy = PFRULE_DROP; + failpolicy = PFRULE_DROP; require_order = 1; if ((file = pushfile(filename, 0)) == NULL) { Modified: stable/11/share/man/man5/pf.conf.5 ============================================================================== --- stable/11/share/man/man5/pf.conf.5 Fri Jun 29 16:07:56 2018 (r335797) +++ stable/11/share/man/man5/pf.conf.5 Fri Jun 29 16:46:19 2018 (r335798) @@ -498,6 +498,31 @@ 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 were 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 Modified: stable/11/sys/netpfil/pf/pf.c ============================================================================== --- stable/11/sys/netpfil/pf/pf.c Fri Jun 29 16:07:56 2018 (r335797) +++ stable/11/sys/netpfil/pf/pf.c Fri Jun 29 16:46:19 2018 (r335798) @@ -2485,6 +2485,81 @@ pf_send_tcp(struct mbuf *replyto, const struct pf_rule 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 && + ((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); +} + + static int pf_ieee8021q_setpcp(struct mbuf *m, u_int8_t prio) { @@ -3449,68 +3524,8 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm ((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) @@ -3529,8 +3544,11 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm 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_RETURN) { + 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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201806291646.w5TGkJ6N082672>