Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F150451210
D41637.id126790.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D41637.id126790.diff
View Options
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1531,6 +1531,9 @@
#define PFI_IFLAG_SKIP 0x0100 /* skip filtering on interface */
#ifdef _KERNEL
+struct pf_sctp_multihome_job;
+SLIST_HEAD(pf_sctp_multihome_jobs, pf_sctp_multihome_job);
+
struct pf_pdesc {
struct {
int done;
@@ -1578,10 +1581,22 @@
#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 {
+ SLIST_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 */
@@ -2249,6 +2264,11 @@
int pf_refragment6(struct ifnet *, struct mbuf **, struct m_tag *, bool);
#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
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -126,6 +126,8 @@
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");
SDT_PROBE_DEFINE3(pf, eth, test_rule, entry, "int", "struct ifnet *",
"struct mbuf *");
@@ -307,6 +309,8 @@
static int pf_test_state_icmp(struct pf_kstate **,
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 *);
@@ -5912,6 +5916,172 @@
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;
+
+ SLIST_FOREACH_SAFE(j, &pd->sctp_multihome_jobs, next, tmp) {
+ PF_RULES_RLOCK();
+ action = pf_test_rule(&r, &sm, 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;
+
+ SLIST_INSERT_HEAD(&pd->sctp_multihome_jobs, job, next);
+ break;
+ }
+ 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;
+
+ SLIST_INSERT_HEAD(&pd->sctp_multihome_jobs, job, next);
+ break;
+ }
+ 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, struct pfi_kkif *kif,
struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason)
@@ -7613,6 +7783,8 @@
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) {
@@ -7896,7 +8068,7 @@
/* pf_route() returns unlocked. */
if (rt) {
pf_route(m0, r, kif->pfik_ifp, s, &pd, inp);
- return (action);
+ goto out;
}
if (pf_dummynet(&pd, s, r, m0) != 0) {
action = PF_DROP;
@@ -7910,6 +8082,9 @@
if (s)
PF_STATE_UNLOCK(s);
+out:
+ pf_sctp_multihome_delayed(&pd, off, kif, s);
+
return (action);
}
#endif /* INET */
@@ -8441,7 +8616,7 @@
/* pf_route6() returns unlocked. */
if (rt) {
pf_route6(m0, r, kif->pfik_ifp, s, &pd, inp);
- return (action);
+ goto out;
}
if (pf_dummynet(&pd, s, r, m0) != 0) {
action = PF_DROP;
@@ -8458,8 +8633,11 @@
(mtag = m_tag_find(m, PACKET_TAG_PF_REASSEMBLED, NULL)) != NULL)
action = pf_refragment6(ifp, m0, mtag, pflags & PFIL_FWD);
+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
--- a/sys/netpfil/pf/pf_norm.c
+++ b/sys/netpfil/pf/pf_norm.c
@@ -2021,11 +2021,13 @@
}
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,
@@ -2040,7 +2042,8 @@
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,
@@ -2064,17 +2067,24 @@
* 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;
@@ -2092,6 +2102,14 @@
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;
@@ -2133,7 +2151,7 @@
/* 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);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Apr 2, 7:56 AM (4 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30714792
Default Alt Text
D41637.id126790.diff (10 KB)
Attached To
Mode
D41637: pf: support SCTP multihoming
Attached
Detach File
Event Timeline
Log In to Comment