From nobody Mon Oct 2 09:33:23 2023 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4RzbNh0NDQz4vrcN; Mon, 2 Oct 2023 09:33:24 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4RzbNg62whz4SZM; Mon, 2 Oct 2023 09:33:23 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1696239203; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=FQ/Lv+ndT5Ocv8/2H3DQS6s5VxFl92j2cHu+SubfDxw=; b=MtGyxAOuruyztIEPhj1c7xEUPGCXzqwfrTMSTrFfmmYGAet5E5pKZ/IS3VACBcw+9fpAok T4L6O0YLSxJebl4Qw2CC76TADoMvqTVaiclGDqpcEMZCslNQHMZnAruR4pNbxf7vgidX0z ZmONyjwgnmbacFXBoRTZk1vzpy84BQRf103bOhzElrKNjQN+VCuPw4W1ElObfn4f9wIZ6M szXKeNLfiUX4Yz+3bZvx0+kDmFmbjR+bSk6J/TZBSa7Vkcx9dSp6QPQaPf8v1fj6u5Xiue JX9Wi9WSzNwlZRawTltW35rtgzzKkj+8aDO/LCs5Arn4//vxBCJ9v3qQidSQRQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1696239203; a=rsa-sha256; cv=none; b=d7KpnLDVxRDh+MHcQyDoRsIl69eMmlJiLG9jPHIAN7ZmNtzkeu6tyizNhzEaxGgMkbT9kk 20MouKEIsZRZHyrMQud08b3yU9vw4M4TfIIm9HJQJLSNjeaPX2n/u52YWxa9eXGMFDlwGL IysjjPmXXVSIEE7Ye14eZCBcH+Smfb/kLNTrvkw72X7giAITxI4X27FGOnhHiAGoq4wc/+ ISuNADfWiXgHLyAhQzzIDUXqnYijhHLcTwcoy/2aicCKXDeLwbIv1dIWUDDyCUlo1+PPdC SZyJPyjr4roOApqpnbPawPZ8hG4gRqS15boktQzaOY5NPMWnm9BRnvG1ae51QA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1696239203; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=FQ/Lv+ndT5Ocv8/2H3DQS6s5VxFl92j2cHu+SubfDxw=; b=Ra679D4lYDS94Pz5Zh1O5T4AGkbeZmbvYxqjdqvXjXJNoxGgXbZaWdSv1kJJFkpfl8mg1L im7sMVEsgSG5BomYMnHukQ1UPMJQljpfytwNYAQzbuaL9SBSwLTazb5Nt8r3xsB7adC10M zuNKuF8j4wtb/C2vhv10qnSRCGARLW1UF9Fw/kTiZqvqCRhW9vWEvz6kEvCousQTDu5cns bXwovcgd5ikyoNOiedSQAqeTTRg0cHbewBPXzGMFw+EGqd+DKJnLugL2cTyjndLOP6SxxP uwO4gg2jHFKbQCJgkBJW34A3EPhpZsxEhvuSCdLwo1m8AGIMmhewsk7ZZl78HA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4RzbNg4kLhz16YX; Mon, 2 Oct 2023 09:33:23 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 3929XNLS002814; Mon, 2 Oct 2023 09:33:23 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 3929XNP0002811; Mon, 2 Oct 2023 09:33:23 GMT (envelope-from git) Date: Mon, 2 Oct 2023 09:33:23 GMT Message-Id: <202310020933.3929XNP0002811@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Kristof Provost Subject: git: 41cc99739ee6 - stable/13 - pf: support SCTP multihoming List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kp X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: 41cc99739ee635b7a6952ee45e1b7c9d995077aa Auto-Submitted: auto-generated The branch stable/13 has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=41cc99739ee635b7a6952ee45e1b7c9d995077aa commit 41cc99739ee635b7a6952ee45e1b7c9d995077aa Author: Kristof Provost AuthorDate: 2023-08-02 17:05:00 +0000 Commit: Kristof Provost CommitDate: 2023-10-02 08:51:43 +0000 pf: support SCTP multihoming SCTP may announce additional IP addresses it'll use in the INIT/INIT_ACK chunks, or in ASCONF chunks at any time during the connection. Parse these parameters, evaluate the ruleset for the new connection and if allowed create the corresponding states. MFC after: 3 weeks Sponsored by: Orange Business Services Differential Revision: https://reviews.freebsd.org/D41637 (cherry picked from commit 10aa9ddb4d45ab0c8f56b0e91c7e8de213030c0f) --- sys/net/pfvar.h | 22 ++- sys/netpfil/pf/pf.c | 347 ++++++++++++++++++++++++++++++++++++----------- sys/netpfil/pf/pf_norm.c | 34 +++-- 3 files changed, 312 insertions(+), 91 deletions(-) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 4043bb8e0e54..07a4140e450f 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1280,6 +1280,9 @@ struct pfi_kkif { #define PFI_IFLAG_SKIP 0x0100 /* skip filtering on interface */ #ifdef _KERNEL +struct pf_sctp_multihome_job; +TAILQ_HEAD(pf_sctp_multihome_jobs, pf_sctp_multihome_job); + struct pf_pdesc { struct { int done; @@ -1327,10 +1330,22 @@ struct pf_pdesc { #define PFDESC_SCTP_SHUTDOWN 0x0010 #define PFDESC_SCTP_SHUTDOWN_COMPLETE 0x0020 #define PFDESC_SCTP_DATA 0x0040 -#define PFDESC_SCTP_OTHER 0x0080 +#define PFDESC_SCTP_ASCONF 0x0080 +#define PFDESC_SCTP_OTHER 0x0100 u_int16_t sctp_flags; u_int32_t sctp_initiate_tag; + + struct pf_sctp_multihome_jobs sctp_multihome_jobs; +}; + +struct pf_sctp_multihome_job { + TAILQ_ENTRY(pf_sctp_multihome_job) next; + struct pf_pdesc pd; + struct pf_addr src; + struct pf_addr dst; + struct mbuf *m; }; + #endif /* flags for RDR options */ @@ -1996,6 +2011,11 @@ void pf_addr_inc(struct pf_addr *, sa_family_t); int pf_refragment6(struct ifnet *, struct mbuf **, struct m_tag *); #endif /* INET6 */ +int pf_multihome_scan_init(struct mbuf *, int, int, struct pf_pdesc *, + struct pfi_kkif *); +int pf_multihome_scan_asconf(struct mbuf *, int, int, struct pf_pdesc *, + struct pfi_kkif *); + u_int32_t pf_new_isn(struct pf_kstate *); void *pf_pull_hdr(struct mbuf *, int, void *, int, u_short *, u_short *, sa_family_t); diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 51f81172bad2..cb4ab2da4633 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -118,6 +118,8 @@ SDT_PROBE_DEFINE4(pf, ip, test6, done, "int", "int", "struct pf_krule *", SDT_PROBE_DEFINE5(pf, ip, state, lookup, "struct pfi_kkif *", "struct pf_state_key_cmp *", "int", "struct pf_pdesc *", "struct pf_kstate *"); +SDT_PROBE_DEFINE4(pf, sctp, multihome, test, "struct pfi_kkif *", + "struct pf_krule *", "struct mbuf *", "int"); /* * Global variables @@ -288,6 +290,8 @@ static int pf_test_state_udp(struct pf_kstate **, int, static int pf_test_state_icmp(struct pf_kstate **, int, struct pfi_kkif *, struct mbuf *, int, void *, struct pf_pdesc *, u_short *); +static void pf_sctp_multihome_delayed(struct pf_pdesc *, int, + struct pfi_kkif *, struct pf_kstate *); static int pf_test_state_sctp(struct pf_kstate **, struct pfi_kkif *, struct mbuf *, int, void *, struct pf_pdesc *, u_short *); @@ -5253,6 +5257,255 @@ pf_test_state_udp(struct pf_kstate **state, int direction, struct pfi_kkif *kif, return (PF_PASS); } +static int +pf_test_state_sctp(struct pf_kstate **state, struct pfi_kkif *kif, + struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason) +{ + struct pf_state_key_cmp key; + struct pf_state_peer *src; //, *dst; + struct sctphdr *sh = &pd->hdr.sctp; + u_int8_t psrc; //, pdst; + + bzero(&key, sizeof(key)); + key.af = pd->af; + key.proto = IPPROTO_SCTP; + if (pd->dir == PF_IN) { /* wire side, straight */ + PF_ACPY(&key.addr[0], pd->src, key.af); + PF_ACPY(&key.addr[1], pd->dst, key.af); + key.port[0] = sh->src_port; + key.port[1] = sh->dest_port; + } else { /* stack side, reverse */ + PF_ACPY(&key.addr[1], pd->src, key.af); + PF_ACPY(&key.addr[0], pd->dst, key.af); + key.port[1] = sh->src_port; + key.port[0] = sh->dest_port; + } + + STATE_LOOKUP(kif, &key, pd->dir, *state, pd); + + if (pd->dir == (*state)->direction) { + src = &(*state)->src; + psrc = PF_PEER_SRC; + } else { + src = &(*state)->dst; + psrc = PF_PEER_DST; + } + + /* Track state. */ + if (pd->sctp_flags & PFDESC_SCTP_INIT) { + if (src->state < SCTP_COOKIE_WAIT) { + pf_set_protostate(*state, psrc, SCTP_COOKIE_WAIT); + (*state)->timeout = PFTM_TCP_OPENING; + } + } + if (pd->sctp_flags & PFDESC_SCTP_COOKIE) { + if (src->state < SCTP_ESTABLISHED) { + pf_set_protostate(*state, psrc, SCTP_ESTABLISHED); + (*state)->timeout = PFTM_TCP_ESTABLISHED; + } + } + if (pd->sctp_flags & (PFDESC_SCTP_SHUTDOWN | PFDESC_SCTP_ABORT | + PFDESC_SCTP_SHUTDOWN_COMPLETE)) { + if (src->state < SCTP_SHUTDOWN_PENDING) { + pf_set_protostate(*state, psrc, SCTP_SHUTDOWN_PENDING); + (*state)->timeout = PFTM_TCP_CLOSING; + } + } + + (*state)->expire = time_uptime; + + /* translate source/destination address, if necessary */ + if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { + uint16_t checksum = 0; + struct pf_state_key *nk = (*state)->key[pd->didx]; + + if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) || + nk->port[pd->sidx] != pd->hdr.sctp.src_port) { + pf_change_ap(m, pd->src, &pd->hdr.sctp.src_port, + pd->ip_sum, &checksum, &nk->addr[pd->sidx], + nk->port[pd->sidx], 1, pd->af); + } + + if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) || + nk->port[pd->didx] != pd->hdr.sctp.dest_port) { + pf_change_ap(m, pd->dst, &pd->hdr.sctp.dest_port, + pd->ip_sum, &checksum, &nk->addr[pd->didx], + nk->port[pd->didx], 1, pd->af); + } + } + + return (PF_PASS); +} + +static void +pf_sctp_multihome_delayed(struct pf_pdesc *pd, int off, struct pfi_kkif *kif, + struct pf_kstate *s) +{ + struct pf_sctp_multihome_job *j, *tmp; + int action;; + struct pf_kstate *sm = NULL; + struct pf_krule *ra = NULL; + struct pf_krule *r = &V_pf_default_rule; + struct pf_kruleset *rs = NULL; + + PF_RULES_RLOCK_TRACKER; + + TAILQ_FOREACH_SAFE(j, &pd->sctp_multihome_jobs, next, tmp) { + PF_RULES_RLOCK(); + action = pf_test_rule(&r, &sm, pd->dir, kif, + j->m, off, &j->pd, &ra, &rs, NULL); + PF_RULES_RUNLOCK(); + SDT_PROBE4(pf, sctp, multihome, test, kif, r, j->m, action); + if (sm) + PF_STATE_UNLOCK(sm); + + free(j, M_PFTEMP); + } +} + +static int +pf_multihome_scan(struct mbuf *m, int start, int len, struct pf_pdesc *pd, + struct pfi_kkif *kif) +{ + int off = 0; + struct pf_sctp_multihome_job *job; + + while (off < len) { + struct sctp_paramhdr h; + + if (!pf_pull_hdr(m, start + off, &h, sizeof(h), NULL, NULL, + pd->af)) + return (PF_DROP); + + /* Parameters are at least 4 bytes. */ + if (ntohs(h.param_length) < 4) + return (PF_DROP); + + switch (ntohs(h.param_type)) { + case SCTP_IPV4_ADDRESS: { + struct in_addr t; + + if (ntohs(h.param_length) != + (sizeof(struct sctp_paramhdr) + sizeof(t))) + return (PF_DROP); + + if (!pf_pull_hdr(m, start + off + sizeof(h), &t, sizeof(t), + NULL, NULL, pd->af)) + return (PF_DROP); + + /* + * Avoid duplicating states. We'll already have + * created a state based on the source address of + * the packet, but SCTP endpoints may also list this + * address again in the INIT(_ACK) parameters. + */ + if (t.s_addr == pd->src->v4.s_addr) + break; + + if (in_nullhost(t)) + t.s_addr = pd->src->v4.s_addr; + + /* + * We hold the state lock (idhash) here, which means + * that we can't acquire the keyhash, or we'll get a + * LOR (and potentially double-lock things too). We also + * can't release the state lock here, so instead we'll + * enqueue this for async handling. + * There's a relatively small race here, in that a + * packet using the new addresses could arrive already, + * but that's just though luck for it. + */ + job = malloc(sizeof(*job), M_PFTEMP, M_NOWAIT | M_ZERO); + if (! job) + return (PF_DROP); + + memcpy(&job->pd, pd, sizeof(*pd)); + + // New source address! + memcpy(&job->src, &t, sizeof(t)); + job->pd.src = &job->src; + memcpy(&job->dst, pd->dst, sizeof(job->dst)); + job->pd.dst = &job->dst; + job->m = m; + + TAILQ_INSERT_TAIL(&pd->sctp_multihome_jobs, job, next); + break; + } +#ifdef INET6 + case SCTP_IPV6_ADDRESS: { + struct in6_addr t; + + if (ntohs(h.param_length) != + (sizeof(struct sctp_paramhdr) + sizeof(t))) + return (PF_DROP); + + if (!pf_pull_hdr(m, start + off + sizeof(h), &t, sizeof(t), + NULL, NULL, pd->af)) + return (PF_DROP); + if (memcmp(&t, &pd->src->v6, sizeof(t)) == 0) + break; + if (memcmp(&t, &in6addr_any, sizeof(t)) == 0) + memcpy(&t, &pd->src->v6, sizeof(t)); + + job = malloc(sizeof(*job), M_PFTEMP, M_NOWAIT | M_ZERO); + if (! job) + return (PF_DROP); + + memcpy(&job->pd, pd, sizeof(*pd)); + memcpy(&job->src, &t, sizeof(t)); + job->pd.src = &job->src; + memcpy(&job->dst, pd->dst, sizeof(job->dst)); + job->pd.dst = &job->dst; + job->m = m; + + TAILQ_INSERT_TAIL(&pd->sctp_multihome_jobs, job, next); + break; + } +#endif + case SCTP_ADD_IP_ADDRESS: { + int ret; + struct sctp_asconf_paramhdr ah; + + if (!pf_pull_hdr(m, start + off, &ah, sizeof(ah), + NULL, NULL, pd->af)) + return (PF_DROP); + + ret = pf_multihome_scan(m, start + off + sizeof(ah), + ntohs(ah.ph.param_length) - sizeof(ah), pd, kif); + if (ret != PF_PASS) + return (ret); + break; + } + default: + break; + } + + off += roundup(ntohs(h.param_length), 4); + } + + return (PF_PASS); +} + +int +pf_multihome_scan_init(struct mbuf *m, int start, int len, struct pf_pdesc *pd, + struct pfi_kkif *kif) +{ + start += sizeof(struct sctp_init_chunk); + len -= sizeof(struct sctp_init_chunk); + + return (pf_multihome_scan(m, start, len, pd, kif)); +} + +int +pf_multihome_scan_asconf(struct mbuf *m, int start, int len, + struct pf_pdesc *pd, struct pfi_kkif *kif) +{ + start += sizeof(struct sctp_asconf_chunk); + len -= sizeof(struct sctp_asconf_chunk); + + return (pf_multihome_scan(m, start, len, pd, kif)); +} + static int pf_test_state_icmp(struct pf_kstate **state, int direction, struct pfi_kkif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason) @@ -5857,86 +6110,6 @@ pf_test_state_icmp(struct pf_kstate **state, int direction, struct pfi_kkif *kif } } -static int -pf_test_state_sctp(struct pf_kstate **state, struct pfi_kkif *kif, - struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason) -{ - struct pf_state_key_cmp key; - struct pf_state_peer *src; //, *dst; - struct sctphdr *sh = &pd->hdr.sctp; - u_int8_t psrc; //, pdst; - - bzero(&key, sizeof(key)); - key.af = pd->af; - key.proto = IPPROTO_SCTP; - if (pd->dir == PF_IN) { /* wire side, straight */ - PF_ACPY(&key.addr[0], pd->src, key.af); - PF_ACPY(&key.addr[1], pd->dst, key.af); - key.port[0] = sh->src_port; - key.port[1] = sh->dest_port; - } else { /* stack side, reverse */ - PF_ACPY(&key.addr[1], pd->src, key.af); - PF_ACPY(&key.addr[0], pd->dst, key.af); - key.port[1] = sh->src_port; - key.port[0] = sh->dest_port; - } - - STATE_LOOKUP(kif, &key, pd->dir, *state, pd); - - if (pd->dir == (*state)->direction) { - src = &(*state)->src; - psrc = PF_PEER_SRC; - } else { - src = &(*state)->dst; - psrc = PF_PEER_DST; - } - - /* Track state. */ - if (pd->sctp_flags & PFDESC_SCTP_INIT) { - if (src->state < SCTP_COOKIE_WAIT) { - pf_set_protostate(*state, psrc, SCTP_COOKIE_WAIT); - (*state)->timeout = PFTM_TCP_OPENING; - } - } - if (pd->sctp_flags & PFDESC_SCTP_COOKIE) { - if (src->state < SCTP_ESTABLISHED) { - pf_set_protostate(*state, psrc, SCTP_ESTABLISHED); - (*state)->timeout = PFTM_TCP_ESTABLISHED; - } - } - if (pd->sctp_flags & (PFDESC_SCTP_SHUTDOWN | PFDESC_SCTP_ABORT | - PFDESC_SCTP_SHUTDOWN_COMPLETE)) { - if (src->state < SCTP_SHUTDOWN_PENDING) { - pf_set_protostate(*state, psrc, SCTP_SHUTDOWN_PENDING); - (*state)->timeout = PFTM_TCP_CLOSING; - } - } - - (*state)->expire = time_uptime; - - /* translate source/destination address, if necessary */ - if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { - uint16_t checksum = 0; - struct pf_state_key *nk = (*state)->key[pd->didx]; - - if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) || - nk->port[pd->sidx] != pd->hdr.sctp.src_port) { - pf_change_ap(m, pd->src, &pd->hdr.sctp.src_port, - pd->ip_sum, &checksum, &nk->addr[pd->sidx], - nk->port[pd->sidx], 1, pd->af); - } - - if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) || - nk->port[pd->didx] != pd->hdr.sctp.dest_port) { - pf_change_ap(m, pd->dst, &pd->hdr.sctp.dest_port, - pd->ip_sum, &checksum, &nk->addr[pd->didx], - nk->port[pd->didx], 1, pd->af); - } - } - - return (PF_PASS); -} - static int pf_test_state_other(struct pf_kstate **state, int direction, struct pfi_kkif *kif, struct mbuf *m, struct pf_pdesc *pd) @@ -6632,6 +6805,7 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb * if (m->m_flags & M_SKIP_FIREWALL) return (PF_PASS); + TAILQ_INIT(&pd.sctp_multihome_jobs); pd.pf_mtag = pf_find_mtag(m); PF_RULES_RLOCK(); @@ -6793,6 +6967,8 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb * log = action != PF_PASS; 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) { @@ -7054,7 +7230,7 @@ done: /* pf_route() returns unlocked. */ if (r->rt) { pf_route(m0, r, dir, kif->pfik_ifp, s, &pd, inp); - return (action); + goto out; } break; } @@ -7064,6 +7240,9 @@ done: if (s) PF_STATE_UNLOCK(s); +out: + pf_sctp_multihome_delayed(&pd, off, kif, s); + return (action); } #endif /* INET */ @@ -7091,6 +7270,7 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb return (PF_PASS); memset(&pd, 0, sizeof(pd)); + TAILQ_INIT(&pd.sctp_multihome_jobs); pd.pf_mtag = pf_find_mtag(m); if (pd.pf_mtag && pd.pf_mtag->flags & PF_TAG_GENERATED) @@ -7535,7 +7715,7 @@ done: /* pf_route6() returns unlocked. */ if (r->rt) { pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd, inp); - return (action); + goto out; } break; } @@ -7548,8 +7728,11 @@ done: (mtag = m_tag_find(m, PF_REASSEMBLED, NULL)) != NULL) action = pf_refragment6(ifp, m0, mtag); +out: SDT_PROBE4(pf, ip, test6, done, action, reason, r, s); + pf_sctp_multihome_delayed(&pd, off, kif, s); + return (action); } #endif /* INET6 */ diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c index 7e8baf451891..ec3f63c9f262 100644 --- a/sys/netpfil/pf/pf_norm.c +++ b/sys/netpfil/pf/pf_norm.c @@ -1989,11 +1989,13 @@ pf_normalize_tcpopt(struct pf_krule *r, struct mbuf *m, struct tcphdr *th, } static int -pf_scan_sctp(struct mbuf *m, int ipoff, int off, struct pf_pdesc *pd) +pf_scan_sctp(struct mbuf *m, int ipoff, int off, struct pf_pdesc *pd, + struct pfi_kkif *kif) { struct sctp_chunkhdr ch = { }; int chunk_off = sizeof(struct sctphdr); int chunk_start; + int ret; while (off + chunk_off < pd->tot_len) { if (!pf_pull_hdr(m, off + chunk_off, &ch, sizeof(ch), NULL, @@ -2008,7 +2010,8 @@ pf_scan_sctp(struct mbuf *m, int ipoff, int off, struct pf_pdesc *pd) chunk_off += roundup(ntohs(ch.chunk_length), 4); switch (ch.chunk_type) { - case SCTP_INITIATION: { + case SCTP_INITIATION: + case SCTP_INITIATION_ACK: { struct sctp_init_chunk init; if (!pf_pull_hdr(m, off + chunk_start, &init, @@ -2032,17 +2035,24 @@ pf_scan_sctp(struct mbuf *m, int ipoff, int off, struct pf_pdesc *pd) * RFC 9260, Section 3.1, INIT chunks MUST have zero * verification tag. */ - if (pd->hdr.sctp.v_tag != 0) + if (ch.chunk_type == SCTP_INITIATION && + pd->hdr.sctp.v_tag != 0) return (PF_DROP); pd->sctp_initiate_tag = init.init.initiate_tag; - pd->sctp_flags |= PFDESC_SCTP_INIT; + if (ch.chunk_type == SCTP_INITIATION) + pd->sctp_flags |= PFDESC_SCTP_INIT; + else + pd->sctp_flags |= PFDESC_SCTP_INIT_ACK; + + ret = pf_multihome_scan_init(m, off + chunk_start, + ntohs(init.ch.chunk_length), pd, kif); + if (ret != PF_PASS) + return (ret); + break; } - case SCTP_INITIATION_ACK: - pd->sctp_flags |= PFDESC_SCTP_INIT_ACK; - break; case SCTP_ABORT_ASSOCIATION: pd->sctp_flags |= PFDESC_SCTP_ABORT; break; @@ -2060,6 +2070,14 @@ pf_scan_sctp(struct mbuf *m, int ipoff, int off, struct pf_pdesc *pd) case SCTP_DATA: pd->sctp_flags |= PFDESC_SCTP_DATA; break; + case SCTP_ASCONF: + pd->sctp_flags |= PFDESC_SCTP_ASCONF; + + ret = pf_multihome_scan_asconf(m, off + chunk_start, + ntohs(ch.chunk_length), pd, kif); + if (ret != PF_PASS) + return (ret); + break; default: pd->sctp_flags |= PFDESC_SCTP_OTHER; break; @@ -2101,7 +2119,7 @@ pf_normalize_sctp(int dir, struct pfi_kkif *kif, struct mbuf *m, int ipoff, /* 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) != PF_PASS) + 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);