Date: Thu, 19 Sep 2024 20:21:17 GMT From: Kristof Provost <kp@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 9ec74b675e04 - main - pf: factor out pf_setup_pdesc() Message-ID: <202409192021.48JKLHBQ046347@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=9ec74b675e04304df3e29eec80d8d259a1254c17 commit 9ec74b675e04304df3e29eec80d8d259a1254c17 Author: Kristof Provost <kp@FreeBSD.org> AuthorDate: 2024-09-02 14:24:38 +0000 Commit: Kristof Provost <kp@FreeBSD.org> CommitDate: 2024-09-19 20:20:13 +0000 pf: factor out pf_setup_pdesc() factor our the code to set up pf_pdesc, a central structure in pf carrying information about the packet we're currently dealing with, into its own function. ok ryan dlg and additional testing sthen Obtained from: OpenBSD, henning <henning@openbsd.org>, c4202972a3 Obtained from: OpenBSD, claudio <claudio@openbsd.org>, 78d25123ea Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D46586 --- sys/net/pfvar.h | 8 + sys/netpfil/pf/pf.c | 624 +++++++++++++++++++++++++++-------------------- sys/netpfil/pf/pf_norm.c | 9 +- 3 files changed, 363 insertions(+), 278 deletions(-) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 4bb09d637def..9a0130dbf487 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1610,6 +1610,7 @@ struct pf_pdesc { struct pf_rule_actions act; u_int32_t p_len; /* total length of payload */ + u_int32_t rh_cnt; /* Route header count */ u_int16_t *ip_sum; u_int16_t *proto_sum; @@ -2350,8 +2351,15 @@ VNET_DECLARE(struct pf_krule, pf_default_rule); extern void pf_addrcpy(struct pf_addr *, struct pf_addr *, sa_family_t); void pf_free_rule(struct pf_krule *); +int pf_setup_pdesc(sa_family_t, int, + struct pf_pdesc *, struct mbuf *, + u_short *, u_short *, struct pfi_kkif *, + struct pf_krule **, struct pf_krule **, + struct pf_kruleset **, int *, int *, + struct pf_rule_actions *); int pf_test_eth(int, int, struct ifnet *, struct mbuf **, struct inpcb *); +int pf_scan_sctp(struct mbuf *, int, struct pf_pdesc *, struct pfi_kkif *); #ifdef INET int pf_test(int, int, struct ifnet *, struct mbuf **, struct inpcb *, struct pf_rule_actions *); diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 58bcd1f2ee71..59db6fd96953 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -324,7 +324,7 @@ static int pf_test_eth_rule(int, struct pfi_kkif *, static int pf_test_rule(struct pf_krule **, struct pf_kstate **, struct pfi_kkif *, struct mbuf *, int, struct pf_pdesc *, struct pf_krule **, - struct pf_kruleset **, struct inpcb *); + struct pf_kruleset **, struct inpcb *, int); static int pf_create_state(struct pf_krule *, struct pf_krule *, struct pf_krule *, struct pf_pdesc *, struct pf_ksrc_node *, struct pf_state_key *, @@ -4865,7 +4865,7 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0) static int pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, struct pfi_kkif *kif, struct mbuf *m, int off, struct pf_pdesc *pd, struct pf_krule **am, - struct pf_kruleset **rsm, struct inpcb *inp) + struct pf_kruleset **rsm, struct inpcb *inp, int hdrlen) { struct pf_krule *nr = NULL; struct pf_addr * const saddr = pd->src; @@ -4879,7 +4879,7 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, struct pfi_kkif *kif, struct tcphdr *th = &pd->hdr.tcp; struct pf_state_key *sk = NULL, *nk = NULL; u_short reason, transerror; - int rewrite = 0, hdrlen = 0; + int rewrite = 0; int tag = -1; int asd = 0; int match = 0; @@ -4905,23 +4905,19 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, struct pfi_kkif *kif, case IPPROTO_TCP: sport = th->th_sport; dport = th->th_dport; - hdrlen = sizeof(*th); break; case IPPROTO_UDP: sport = pd->hdr.udp.uh_sport; dport = pd->hdr.udp.uh_dport; - hdrlen = sizeof(pd->hdr.udp); break; case IPPROTO_SCTP: sport = pd->hdr.sctp.src_port; dport = pd->hdr.sctp.dest_port; - hdrlen = sizeof(pd->hdr.sctp); break; #ifdef INET case IPPROTO_ICMP: if (pd->af != AF_INET) break; - hdrlen = sizeof(pd->hdr.icmp); icmptype = pd->hdr.icmp.icmp_type; icmpcode = pd->hdr.icmp.icmp_code; state_icmp = pf_icmp_mapping(pd, icmptype, @@ -4939,7 +4935,6 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, struct pfi_kkif *kif, case IPPROTO_ICMPV6: if (af != AF_INET6) break; - hdrlen = sizeof(pd->hdr.icmp6); icmptype = pd->hdr.icmp6.icmp6_type; icmpcode = pd->hdr.icmp6.icmp6_code; state_icmp = pf_icmp_mapping(pd, icmptype, @@ -4955,7 +4950,7 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, struct pfi_kkif *kif, break; #endif /* INET6 */ default: - sport = dport = hdrlen = 0; + sport = dport = 0; break; } @@ -6662,7 +6657,8 @@ again: * That's why we pass V_pfi_all rather than kif. */ ret = pf_test_rule(&r, &sm, V_pfi_all, - j->m, off, &j->pd, &ra, &rs, NULL); + j->m, off, &j->pd, &ra, &rs, NULL, + sizeof(j->pd.hdr.sctp)); PF_RULES_RUNLOCK(); SDT_PROBE4(pf, sctp, multihome, test, kif, r, j->m, ret); if (ret != PF_DROP && sm != NULL) { @@ -8540,6 +8536,290 @@ pf_dummynet_route(struct pf_pdesc *pd, struct pf_kstate *s, return (0); } +int +pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf *m, + u_short *action, u_short *reason, struct pfi_kkif *kif, struct pf_krule **a, + struct pf_krule **r, struct pf_kruleset **ruleset, int *off, int *hdrlen, + struct pf_rule_actions *default_actions) +{ + + TAILQ_INIT(&pd->sctp_multihome_jobs); + if (default_actions != NULL) + memcpy(&pd->act, default_actions, sizeof(pd->act)); + pd->pf_mtag = pf_find_mtag(m); + + if (pd->pf_mtag && pd->pf_mtag->dnpipe) { + pd->act.dnpipe = pd->pf_mtag->dnpipe; + pd->act.flags = pd->pf_mtag->dnflags; + } + + pd->af = af; + + switch (af) { +#ifdef INET + case AF_INET: { + struct ip *h; + + h = mtod(m, struct ip *); + *off = h->ip_hl << 2; + if (*off < (int)sizeof(*h)) { + *action = PF_DROP; + REASON_SET(reason, PFRES_SHORT); + return (-1); + } + pd->src = (struct pf_addr *)&h->ip_src; + pd->dst = (struct pf_addr *)&h->ip_dst; + pd->sport = pd->dport = NULL; + pd->ip_sum = &h->ip_sum; + pd->proto_sum = NULL; + pd->proto = h->ip_p; + pd->dir = dir; + pd->sidx = (dir == PF_IN) ? 0 : 1; + pd->didx = (dir == PF_IN) ? 1 : 0; + pd->tos = h->ip_tos; + pd->tot_len = ntohs(h->ip_len); + pd->act.rtableid = -1; + + /* fragments not reassembled handled later */ + if (h->ip_off & htons(IP_MF | IP_OFFMASK)) + return (0); + + switch (h->ip_p) { + case IPPROTO_TCP: { + struct tcphdr *th = &pd->hdr.tcp; + + if (!pf_pull_hdr(m, *off, th, sizeof(*th), action, + reason, AF_INET)) + return (-1); + *hdrlen = sizeof(*th); + pd->p_len = pd->tot_len - *off - (th->th_off << 2); + pd->sport = &th->th_sport; + pd->dport = &th->th_dport; + break; + } + case IPPROTO_UDP: { + struct udphdr *uh = &pd->hdr.udp; + + if (!pf_pull_hdr(m, *off, uh, sizeof(*uh), action, + reason, AF_INET)) + return (-1); + *hdrlen = sizeof(*uh); + if (uh->uh_dport == 0 || + ntohs(uh->uh_ulen) > m->m_pkthdr.len - *off || + ntohs(uh->uh_ulen) < sizeof(struct udphdr)) { + *action = PF_DROP; + REASON_SET(reason, PFRES_SHORT); + return (-1); + } + pd->sport = &uh->uh_sport; + pd->dport = &uh->uh_dport; + break; + } + case IPPROTO_SCTP: { + if (!pf_pull_hdr(m, *off, &pd->hdr.sctp, sizeof(pd->hdr.sctp), + action, reason, AF_INET)) { + return (-1); + } + *hdrlen = sizeof(pd->hdr.sctp); + pd->p_len = pd->tot_len - *off; + + pd->sport = &pd->hdr.sctp.src_port; + pd->dport = &pd->hdr.sctp.dest_port; + if (pd->hdr.sctp.src_port == 0 || pd->hdr.sctp.dest_port == 0) { + *action = PF_DROP; + REASON_SET(reason, PFRES_SHORT); + return (-1); + } + if (pf_scan_sctp(m, *off, pd, kif) != PF_PASS) { + *action = PF_DROP; + REASON_SET(reason, PFRES_SHORT); + return (-1); + } + break; + } + case IPPROTO_ICMP: { + if (!pf_pull_hdr(m, *off, &pd->hdr.icmp, ICMP_MINLEN, + action, reason, AF_INET)) + return (-1); + *hdrlen = ICMP_MINLEN; + break; + } + } + break; + } +#endif +#ifdef INET6 + case AF_INET6: { + struct ip6_hdr *h; + int terminal = 0; + + h = mtod(m, struct ip6_hdr *); + pd->src = (struct pf_addr *)&h->ip6_src; + pd->dst = (struct pf_addr *)&h->ip6_dst; + pd->sport = pd->dport = NULL; + pd->ip_sum = NULL; + pd->proto_sum = NULL; + pd->dir = dir; + pd->sidx = (dir == PF_IN) ? 0 : 1; + pd->didx = (dir == PF_IN) ? 1 : 0; + pd->tos = IPV6_DSCP(h); + pd->tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr); + *off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr); + pd->proto = h->ip6_nxt; + pd->act.rtableid = -1; + + do { + switch (pd->proto) { + case IPPROTO_FRAGMENT: + if (kif == NULL || r == NULL) /* pflog */ + *action = PF_DROP; + else + *action = pf_test_fragment(r, kif, + m, h, pd, a, ruleset); + if (*action == PF_DROP) + REASON_SET(reason, PFRES_FRAG); + return (-1); + case IPPROTO_ROUTING: { + struct ip6_rthdr rthdr; + + if (pd->rh_cnt++) { + DPFPRINTF(PF_DEBUG_MISC, + ("pf: IPv6 more than one rthdr")); + *action = PF_DROP; + REASON_SET(reason, PFRES_IPOPTIONS); + return (-1); + } + if (!pf_pull_hdr(m, *off, &rthdr, sizeof(rthdr), + NULL, reason, pd->af)) { + DPFPRINTF(PF_DEBUG_MISC, + ("pf: IPv6 short rthdr")); + *action = PF_DROP; + REASON_SET(reason, PFRES_SHORT); + return (-1); + } + if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) { + DPFPRINTF(PF_DEBUG_MISC, + ("pf: IPv6 rthdr0")); + *action = PF_DROP; + REASON_SET(reason, PFRES_IPOPTIONS); + return (-1); + } + /* FALLTHROUGH */ + } + case IPPROTO_AH: + case IPPROTO_HOPOPTS: + case IPPROTO_DSTOPTS: { + /* get next header and header length */ + struct ip6_ext opt6; + + if (!pf_pull_hdr(m, *off, &opt6, sizeof(opt6), + NULL, reason, pd->af)) { + DPFPRINTF(PF_DEBUG_MISC, + ("pf: IPv6 short opt")); + *action = PF_DROP; + return (-1); + } + if (pd->proto == IPPROTO_AH) + *off += (opt6.ip6e_len + 2) * 4; + else + *off += (opt6.ip6e_len + 1) * 8; + pd->proto = opt6.ip6e_nxt; + /* goto the next header */ + break; + } + default: + terminal++; + break; + } + } while (!terminal); + + switch (pd->proto) { + case IPPROTO_TCP: { + struct tcphdr *th = &pd->hdr.tcp; + + if (!pf_pull_hdr(m, *off, th, sizeof(*th), action, + reason, AF_INET6)) + return (-1); + *hdrlen = sizeof(*th); + pd->p_len = pd->tot_len - *off - (th->th_off << 2); + pd->sport = &th->th_sport; + pd->dport = &th->th_dport; + break; + } + case IPPROTO_UDP: { + struct udphdr *uh = &pd->hdr.udp; + + if (!pf_pull_hdr(m, *off, uh, sizeof(*uh), action, + reason, AF_INET6)) + return (-1); + *hdrlen = sizeof(*uh); + if (uh->uh_dport == 0 || + ntohs(uh->uh_ulen) > m->m_pkthdr.len - *off || + ntohs(uh->uh_ulen) < sizeof(struct udphdr)) { + *action = PF_DROP; + REASON_SET(reason, PFRES_SHORT); + return (-1); + } + pd->sport = &uh->uh_sport; + pd->dport = &uh->uh_dport; + break; + } + case IPPROTO_SCTP: { + if (!pf_pull_hdr(m, *off, &pd->hdr.sctp, sizeof(pd->hdr.sctp), + action, reason, AF_INET6)) { + return (-1); + } + *hdrlen = sizeof(pd->hdr.sctp); + pd->p_len = pd->tot_len - *off; + + pd->sport = &pd->hdr.sctp.src_port; + pd->dport = &pd->hdr.sctp.dest_port; + if (pd->hdr.sctp.src_port == 0 || pd->hdr.sctp.dest_port == 0) { + *action = PF_DROP; + REASON_SET(reason, PFRES_SHORT); + return (-1); + } + if (pf_scan_sctp(m, *off, pd, kif) != PF_PASS) { + *action = PF_DROP; + REASON_SET(reason, PFRES_SHORT); + return (-1); + } + break; + } + case IPPROTO_ICMPV6: { + size_t icmp_hlen = sizeof(struct icmp6_hdr); + + if (!pf_pull_hdr(m, *off, &pd->hdr.icmp6, icmp_hlen, + action, reason, AF_INET6)) + return (-1); + /* ICMP headers we look further into to match state */ + switch (pd->hdr.icmp6.icmp6_type) { + case MLD_LISTENER_QUERY: + case MLD_LISTENER_REPORT: + icmp_hlen = sizeof(struct mld_hdr); + break; + case ND_NEIGHBOR_SOLICIT: + case ND_NEIGHBOR_ADVERT: + icmp_hlen = sizeof(struct nd_neighbor_solicit); + break; + } + if (icmp_hlen > sizeof(struct icmp6_hdr) && + !pf_pull_hdr(m, *off, &pd->hdr.icmp6, icmp_hlen, + action, reason, AF_INET6)) + return (-1); + *hdrlen = icmp_hlen; + break; + } + } + break; + } +#endif + default: + panic("pf_setup_pdesc called with illegal af %u", af); + } + return (0); +} + #ifdef INET int pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, @@ -8554,7 +8834,7 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct pf_kstate *s = NULL; struct pf_kruleset *ruleset = NULL; struct pf_pdesc pd; - int off, dirndx, use_2nd_queue = 0; + int off, hdrlen, dirndx, use_2nd_queue = 0; uint16_t tag; uint8_t rt; @@ -8591,11 +8871,31 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, return (PF_DROP); } + if (__predict_false(m->m_len < sizeof(struct ip)) && + (m = *m0 = m_pullup(*m0, sizeof(struct ip))) == NULL) { + DPFPRINTF(PF_DEBUG_URGENT, + ("pf_test: m_len < sizeof(struct ip), pullup failed\n")); + PF_RULES_RUNLOCK(); + return (PF_DROP); + } + memset(&pd, 0, sizeof(pd)); - TAILQ_INIT(&pd.sctp_multihome_jobs); - if (default_actions != NULL) - memcpy(&pd.act, default_actions, sizeof(pd.act)); - pd.pf_mtag = pf_find_mtag(m); + pd.dir = dir; + + if (pf_normalize_ip(m0, kif, &reason, &pd) != PF_PASS) { + /* We do IP header normalization and packet reassembly here */ + action = PF_DROP; + goto done; + } + m = *m0; /* pf_normalize messes with m0 */ + h = mtod(m, struct ip *); + + if (pf_setup_pdesc(AF_INET, dir, &pd, m, &action, &reason, kif, &a, &r, + &ruleset, &off, &hdrlen, default_actions) == -1) { + if (action != PF_PASS) + pd.act.log |= PF_LOG_FORCE; + goto done; + } if (pd.pf_mtag != NULL && (pd.pf_mtag->flags & PF_MTAG_FLAG_ROUTE_TO)) { pd.pf_mtag->flags &= ~PF_MTAG_FLAG_ROUTE_TO; @@ -8614,11 +8914,6 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, return (PF_PASS); } - if (pd.pf_mtag && pd.pf_mtag->dnpipe) { - pd.act.dnpipe = pd.pf_mtag->dnpipe; - pd.act.flags = pd.pf_mtag->dnflags; - } - if (ip_dn_io_ptr != NULL && pd.pf_mtag != NULL && pd.pf_mtag->flags & PF_MTAG_FLAG_DUMMYNET) { /* Dummynet re-injects packets after they've @@ -8633,24 +8928,6 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, return (PF_PASS); } - pd.sport = pd.dport = NULL; - pd.proto_sum = NULL; - pd.dir = dir; - pd.sidx = (dir == PF_IN) ? 0 : 1; - pd.didx = (dir == PF_IN) ? 1 : 0; - pd.af = AF_INET; - pd.act.rtableid = -1; - - if (__predict_false(m->m_len < sizeof(struct ip)) && - (m = *m0 = m_pullup(*m0, sizeof(struct ip))) == NULL) { - DPFPRINTF(PF_DEBUG_URGENT, - ("pf_test: m_len < sizeof(struct ip), pullup failed\n")); - PF_RULES_RUNLOCK(); - return (PF_DROP); - } - h = mtod(m, struct ip *); - off = h->ip_hl << 2; - if (__predict_false(ip_divert_ptr != NULL) && ((mtag = m_tag_locate(m, MTAG_PF_DIVERT, 0, NULL)) != NULL)) { struct pf_divert_mtag *dt = (struct pf_divert_mtag *)(mtag+1); @@ -8672,28 +8949,7 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, mtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL); if (mtag != NULL) m_tag_delete(m, mtag); - } else if (pf_normalize_ip(m0, kif, &reason, &pd) != PF_PASS) { - /* We do IP header normalization and packet reassembly here */ - action = PF_DROP; - goto done; } - m = *m0; /* pf_normalize messes with m0 */ - h = mtod(m, struct ip *); - - off = h->ip_hl << 2; - if (off < (int)sizeof(struct ip)) { - action = PF_DROP; - REASON_SET(&reason, PFRES_SHORT); - pd.act.log = PF_LOG_FORCE; - goto done; - } - - pd.src = (struct pf_addr *)&h->ip_src; - pd.dst = (struct pf_addr *)&h->ip_dst; - pd.ip_sum = &h->ip_sum; - pd.proto = h->ip_p; - pd.tos = h->ip_tos & ~IPTOS_ECN_MASK; - pd.tot_len = ntohs(h->ip_len); /* handle fragments that didn't get reassembled by normalization */ if (h->ip_off & htons(IP_MF | IP_OFFMASK)) { @@ -8703,16 +8959,6 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, switch (h->ip_p) { case IPPROTO_TCP: { - if (!pf_pull_hdr(m, off, &pd.hdr.tcp, sizeof(pd.hdr.tcp), - &action, &reason, AF_INET)) { - if (action != PF_PASS) - pd.act.log = PF_LOG_FORCE; - goto done; - } - pd.p_len = pd.tot_len - off - (pd.hdr.tcp.th_off << 2); - - pd.sport = &pd.hdr.tcp.th_sport; - pd.dport = &pd.hdr.tcp.th_dport; /* Respond to SYN with a syncookie. */ if ((pd.hdr.tcp.th_flags & (TH_SYN|TH_ACK|TH_RST)) == TH_SYN && @@ -8768,28 +9014,13 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, break; } else { action = pf_test_rule(&r, &s, kif, m, off, &pd, - &a, &ruleset, inp); + &a, &ruleset, inp, hdrlen); } } break; } case IPPROTO_UDP: { - if (!pf_pull_hdr(m, off, &pd.hdr.udp, sizeof(pd.hdr.udp), - &action, &reason, AF_INET)) { - if (action != PF_PASS) - pd.act.log = PF_LOG_FORCE; - goto done; - } - pd.sport = &pd.hdr.udp.uh_sport; - pd.dport = &pd.hdr.udp.uh_dport; - if (pd.hdr.udp.uh_dport == 0 || - ntohs(pd.hdr.udp.uh_ulen) > m->m_pkthdr.len - off || - ntohs(pd.hdr.udp.uh_ulen) < sizeof(struct udphdr)) { - action = PF_DROP; - REASON_SET(&reason, PFRES_SHORT); - goto done; - } action = pf_test_state_udp(&s, kif, m, off, h, &pd); if (action == PF_PASS) { if (V_pfsync_update_state_ptr != NULL) @@ -8798,26 +9029,11 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; } else if (s == NULL) action = pf_test_rule(&r, &s, kif, m, off, &pd, - &a, &ruleset, inp); + &a, &ruleset, inp, hdrlen); break; } case IPPROTO_SCTP: { - if (!pf_pull_hdr(m, off, &pd.hdr.sctp, sizeof(pd.hdr.sctp), - &action, &reason, AF_INET)) { - if (action != PF_PASS) - pd.act.log |= PF_LOG_FORCE; - goto done; - } - pd.p_len = pd.tot_len - off; - - pd.sport = &pd.hdr.sctp.src_port; - pd.dport = &pd.hdr.sctp.dest_port; - if (pd.hdr.sctp.src_port == 0 || pd.hdr.sctp.dest_port == 0) { - action = PF_DROP; - REASON_SET(&reason, PFRES_SHORT); - goto done; - } action = pf_normalize_sctp(dir, kif, m, 0, off, h, &pd); if (action == PF_DROP) goto done; @@ -8830,18 +9046,12 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; } else if (s == NULL) { action = pf_test_rule(&r, &s, kif, m, off, - &pd, &a, &ruleset, inp); + &pd, &a, &ruleset, inp, hdrlen); } break; } case IPPROTO_ICMP: { - if (!pf_pull_hdr(m, off, &pd.hdr.icmp, ICMP_MINLEN, - &action, &reason, AF_INET)) { - if (action != PF_PASS) - pd.act.log = PF_LOG_FORCE; - goto done; - } action = pf_test_state_icmp(&s, kif, m, off, h, &pd, &reason); if (action == PF_PASS) { if (V_pfsync_update_state_ptr != NULL) @@ -8850,7 +9060,7 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; } else if (s == NULL) action = pf_test_rule(&r, &s, kif, m, off, &pd, - &a, &ruleset, inp); + &a, &ruleset, inp, hdrlen); break; } @@ -8870,7 +9080,7 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, a = s->anchor.ptr; } else if (s == NULL) action = pf_test_rule(&r, &s, kif, m, off, &pd, - &a, &ruleset, inp); + &a, &ruleset, inp, hdrlen); break; } @@ -9141,7 +9351,7 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb struct pf_kstate *s = NULL; struct pf_kruleset *ruleset = NULL; struct pf_pdesc pd; - int off, terminal = 0, dirndx, rh_cnt = 0, use_2nd_queue = 0; + int off, hdrlen, dirndx, use_2nd_queue = 0; uint16_t tag; uint8_t rt; @@ -9189,11 +9399,33 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb return (PF_DROP); } + if (__predict_false(m->m_len < sizeof(struct ip6_hdr)) && + (m = *m0 = m_pullup(*m0, sizeof(struct ip6_hdr))) == NULL) { + DPFPRINTF(PF_DEBUG_URGENT, + ("pf_test6: m_len < sizeof(struct ip6_hdr)" + ", pullup failed\n")); + PF_RULES_RUNLOCK(); + return (PF_DROP); + } + memset(&pd, 0, sizeof(pd)); - TAILQ_INIT(&pd.sctp_multihome_jobs); - if (default_actions != NULL) - memcpy(&pd.act, default_actions, sizeof(pd.act)); - pd.pf_mtag = pf_find_mtag(m); + pd.dir = dir; + + /* We do IP header normalization and packet reassembly here */ + if (pf_normalize_ip6(m0, kif, &reason, &pd) != PF_PASS) { + action = PF_DROP; + goto done; + } + m = *m0; /* pf_normalize messes with m0 */ + h = mtod(m, struct ip6_hdr *); + off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr); + + if (pf_setup_pdesc(AF_INET6, dir, &pd, m, &action, &reason, kif, &a, &r, + &ruleset, &off, &hdrlen, default_actions) == -1) { + if (action != PF_PASS) + pd.act.log |= PF_LOG_FORCE; + goto done; + } if (pd.pf_mtag != NULL && (pd.pf_mtag->flags & PF_MTAG_FLAG_ROUTE_TO)) { pd.pf_mtag->flags &= ~PF_MTAG_FLAG_ROUTE_TO; @@ -9213,11 +9445,6 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb return (PF_PASS); } - if (pd.pf_mtag && pd.pf_mtag->dnpipe) { - pd.act.dnpipe = pd.pf_mtag->dnpipe; - pd.act.flags = pd.pf_mtag->dnflags; - } - if (ip_dn_io_ptr != NULL && pd.pf_mtag != NULL && pd.pf_mtag->flags & PF_MTAG_FLAG_DUMMYNET) { pf_dummynet_flag_remove(m, pd.pf_mtag); @@ -9228,35 +9455,6 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb return (PF_PASS); } - pd.sport = pd.dport = NULL; - pd.ip_sum = NULL; - pd.proto_sum = NULL; - pd.dir = dir; - pd.sidx = (dir == PF_IN) ? 0 : 1; - pd.didx = (dir == PF_IN) ? 1 : 0; - pd.af = AF_INET6; - pd.act.rtableid = -1; - - if (__predict_false(m->m_len < sizeof(struct ip6_hdr)) && - (m = *m0 = m_pullup(*m0, sizeof(struct ip6_hdr))) == NULL) { - DPFPRINTF(PF_DEBUG_URGENT, - ("pf_test6: m_len < sizeof(struct ip6_hdr)" - ", pullup failed\n")); - PF_RULES_RUNLOCK(); - return (PF_DROP); - } - h = mtod(m, struct ip6_hdr *); - off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr); - - /* We do IP header normalization and packet reassembly here */ - if (pf_normalize_ip6(m0, kif, &reason, &pd) != PF_PASS) { - action = PF_DROP; - goto done; - } - m = *m0; /* pf_normalize messes with m0 */ - h = mtod(m, struct ip6_hdr *); - off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr); - /* * we do not support jumbogram. if we keep going, zero ip6_plen * will do something bad, so drop the packet for now. @@ -9267,94 +9465,12 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb goto done; } - pd.src = (struct pf_addr *)&h->ip6_src; - pd.dst = (struct pf_addr *)&h->ip6_dst; - pd.tos = IPV6_DSCP(h); - pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr); - - pd.proto = h->ip6_nxt; - do { - switch (pd.proto) { - case IPPROTO_FRAGMENT: - action = pf_test_fragment(&r, kif, m, h, &pd, &a, - &ruleset); - if (action == PF_DROP) - REASON_SET(&reason, PFRES_FRAG); - goto done; - case IPPROTO_ROUTING: { - struct ip6_rthdr rthdr; - - if (rh_cnt++) { - DPFPRINTF(PF_DEBUG_MISC, - ("pf: IPv6 more than one rthdr\n")); - action = PF_DROP; - REASON_SET(&reason, PFRES_IPOPTIONS); - pd.act.log = PF_LOG_FORCE; - goto done; - } - if (!pf_pull_hdr(m, off, &rthdr, sizeof(rthdr), NULL, - &reason, pd.af)) { - DPFPRINTF(PF_DEBUG_MISC, - ("pf: IPv6 short rthdr\n")); - action = PF_DROP; - REASON_SET(&reason, PFRES_SHORT); - pd.act.log = PF_LOG_FORCE; - goto done; - } - if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) { - DPFPRINTF(PF_DEBUG_MISC, - ("pf: IPv6 rthdr0\n")); - action = PF_DROP; - REASON_SET(&reason, PFRES_IPOPTIONS); - pd.act.log = PF_LOG_FORCE; - goto done; - } - /* FALLTHROUGH */ - } - case IPPROTO_AH: - case IPPROTO_HOPOPTS: - case IPPROTO_DSTOPTS: { - /* get next header and header length */ - struct ip6_ext opt6; - - if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6), - NULL, &reason, pd.af)) { - DPFPRINTF(PF_DEBUG_MISC, - ("pf: IPv6 short opt\n")); - action = PF_DROP; - pd.act.log = PF_LOG_FORCE; - goto done; - } - if (pd.proto == IPPROTO_AH) - off += (opt6.ip6e_len + 2) * 4; - else - off += (opt6.ip6e_len + 1) * 8; - pd.proto = opt6.ip6e_nxt; - /* goto the next header */ - break; - } - default: - terminal++; - break; - } - } while (!terminal); - /* if there's no routing header, use unmodified mbuf for checksumming */ if (!n) n = m; switch (pd.proto) { case IPPROTO_TCP: { - if (!pf_pull_hdr(m, off, &pd.hdr.tcp, sizeof(pd.hdr.tcp), - &action, &reason, AF_INET6)) { - if (action != PF_PASS) - pd.act.log |= PF_LOG_FORCE; - goto done; - } - pd.p_len = pd.tot_len - off - (pd.hdr.tcp.th_off << 2); - pd.sport = &pd.hdr.tcp.th_sport; - pd.dport = &pd.hdr.tcp.th_dport; - /* Respond to SYN with a syncookie. */ if ((pd.hdr.tcp.th_flags & (TH_SYN|TH_ACK|TH_RST)) == TH_SYN && pd.dir == PF_IN && pf_synflood_check(&pd)) { @@ -9408,28 +9524,13 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb break; } else { action = pf_test_rule(&r, &s, kif, m, off, &pd, - &a, &ruleset, inp); + &a, &ruleset, inp, hdrlen); } } break; } case IPPROTO_UDP: { - if (!pf_pull_hdr(m, off, &pd.hdr.udp, sizeof(pd.hdr.udp), - &action, &reason, AF_INET6)) { - if (action != PF_PASS) - pd.act.log |= PF_LOG_FORCE; - goto done; - } - pd.sport = &pd.hdr.udp.uh_sport; - pd.dport = &pd.hdr.udp.uh_dport; - if (pd.hdr.udp.uh_dport == 0 || - ntohs(pd.hdr.udp.uh_ulen) > m->m_pkthdr.len - off || - ntohs(pd.hdr.udp.uh_ulen) < sizeof(struct udphdr)) { - action = PF_DROP; - REASON_SET(&reason, PFRES_SHORT); - goto done; - } action = pf_test_state_udp(&s, kif, m, off, h, &pd); if (action == PF_PASS) { if (V_pfsync_update_state_ptr != NULL) @@ -9438,24 +9539,11 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb a = s->anchor.ptr; } else if (s == NULL) action = pf_test_rule(&r, &s, kif, m, off, &pd, - &a, &ruleset, inp); + &a, &ruleset, inp, hdrlen); break; } case IPPROTO_SCTP: { - if (!pf_pull_hdr(m, off, &pd.hdr.sctp, sizeof(pd.hdr.sctp), - &action, &reason, AF_INET6)) { - if (action != PF_PASS) - pd.act.log |= PF_LOG_FORCE; - goto done; - } - pd.sport = &pd.hdr.sctp.src_port; - pd.dport = &pd.hdr.sctp.dest_port; - if (pd.hdr.sctp.src_port == 0 || pd.hdr.sctp.dest_port == 0) { - action = PF_DROP; - REASON_SET(&reason, PFRES_SHORT); - goto done; - } action = pf_normalize_sctp(dir, kif, m, 0, off, h, &pd); if (action == PF_DROP) goto done; @@ -9468,7 +9556,7 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb a = s->anchor.ptr; } else if (s == NULL) { action = pf_test_rule(&r, &s, kif, m, off, - &pd, &a, &ruleset, inp); + &pd, &a, &ruleset, inp, hdrlen); } break; } @@ -9481,12 +9569,6 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb } case IPPROTO_ICMPV6: { - if (!pf_pull_hdr(m, off, &pd.hdr.icmp6, sizeof(pd.hdr.icmp6), - &action, &reason, AF_INET6)) { - if (action != PF_PASS) - pd.act.log |= PF_LOG_FORCE; - goto done; - } action = pf_test_state_icmp(&s, kif, m, off, h, &pd, &reason); if (action == PF_PASS) { if (V_pfsync_update_state_ptr != NULL) @@ -9495,7 +9577,7 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb a = s->anchor.ptr; } else if (s == NULL) action = pf_test_rule(&r, &s, kif, m, off, &pd, - &a, &ruleset, inp); + &a, &ruleset, inp, hdrlen); break; } @@ -9508,7 +9590,7 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb a = s->anchor.ptr; } else if (s == NULL) action = pf_test_rule(&r, &s, kif, m, off, &pd, - &a, &ruleset, inp); + &a, &ruleset, inp, hdrlen); break; } @@ -9520,7 +9602,7 @@ done: } /* handle dangerous IPv6 extension headers. */ - if (action == PF_PASS && rh_cnt && + if (action == PF_PASS && pd.rh_cnt && !((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) { action = PF_DROP; REASON_SET(&reason, PFRES_IPOPTIONS); diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c index 295377bef3e8..aaeb027ca8bd 100644 --- a/sys/netpfil/pf/pf_norm.c +++ b/sys/netpfil/pf/pf_norm.c @@ -2066,8 +2066,8 @@ pf_normalize_mss(struct mbuf *m, int off, struct pf_pdesc *pd) return (0); } -static int -pf_scan_sctp(struct mbuf *m, int ipoff, int off, struct pf_pdesc *pd, +int +pf_scan_sctp(struct mbuf *m, int off, struct pf_pdesc *pd, struct pfi_kkif *kif) { struct sctp_chunkhdr ch = { }; @@ -2203,11 +2203,6 @@ pf_normalize_sctp(int dir, struct pfi_kkif *kif, struct mbuf *m, int ipoff, PF_RULES_RASSERT(); - /* Unconditionally scan the SCTP packet, because we need to look for - * things like shutdown and asconf chunks. */ - if (pf_scan_sctp(m, ipoff, off, pd, kif) != PF_PASS) - goto sctp_drop; - r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr); /* Check if there any scrub rules. Lack of scrub rules means enforced * packet normalization operation just like in OpenBSD. */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202409192021.48JKLHBQ046347>