git: 6d1714a44e63 - stable/14 - pf: mark removed connections within a multihome association as shutting down

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Mon, 02 Oct 2023 09:33:26 UTC
The branch stable/14 has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=6d1714a44e634f3063f6cd0a4fab0782ddc87fe7

commit 6d1714a44e634f3063f6cd0a4fab0782ddc87fe7
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2023-09-05 16:30:42 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2023-10-02 09:32:14 +0000

    pf: mark removed connections within a multihome association as shutting down
    
    Parse IP removal in ASCONF chunks, find the affected state(s) and mark
    them as shutting down. This will cause them to time out according to
    PFTM_TCP_CLOSING timeouts, rather than waiting for the established
    session timeout.
    
    MFC after:      3 weeks
    Sponsored by:   Orange Business Services
    
    (cherry picked from commit 4d3af82f78961180149e8a579b481dc382f76eef)
---
 sys/net/pfvar.h     |  1 +
 sys/netpfil/pf/pf.c | 87 ++++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 73 insertions(+), 15 deletions(-)

diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index a8567ab74fe3..15fa671ddcbe 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1599,6 +1599,7 @@ struct pf_sctp_multihome_job {
 	struct pf_addr				 src;
 	struct pf_addr				 dst;
 	struct mbuf				*m;
+	int					 op;
 };
 
 #endif
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 085ab5827e26..6a8ba7be56cf 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -5933,17 +5933,57 @@ pf_sctp_multihome_delayed(struct pf_pdesc *pd, int off, struct pfi_kkif *kif,
 	PF_RULES_RLOCK_TRACKER;
 
 	TAILQ_FOREACH_SAFE(j, &pd->sctp_multihome_jobs, next, tmp) {
-		PF_RULES_RLOCK();
-		j->pd.sctp_flags |= PFDESC_SCTP_ADD_IP;
-		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) {
-			/* Inherit v_tag values. */
-			sm->src.scrub->pfss_v_tag = s->src.scrub->pfss_flags;
-			sm->dst.scrub->pfss_v_tag = s->dst.scrub->pfss_flags;
-			PF_STATE_UNLOCK(sm);
+		switch (j->op) {
+		case  SCTP_ADD_IP_ADDRESS: {
+			j->pd.sctp_flags |= PFDESC_SCTP_ADD_IP;
+			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) {
+				/* Inherit v_tag values. */
+				sm->src.scrub->pfss_v_tag = s->src.scrub->pfss_flags;
+				sm->dst.scrub->pfss_v_tag = s->dst.scrub->pfss_flags;
+				PF_STATE_UNLOCK(sm);
+			}
+			break;
+		}
+		case SCTP_DEL_IP_ADDRESS: {
+			struct pf_state_key_cmp key;
+			uint8_t psrc;
+
+			bzero(&key, sizeof(key));
+			key.af = j->pd.af;
+			key.proto = IPPROTO_SCTP;
+			if (j->pd.dir == PF_IN)	{	/* wire side, straight */
+				PF_ACPY(&key.addr[0], j->pd.src, key.af);
+				PF_ACPY(&key.addr[1], j->pd.dst, key.af);
+				key.port[0] = j->pd.hdr.sctp.src_port;
+				key.port[1] = j->pd.hdr.sctp.dest_port;
+			} else {			/* stack side, reverse */
+				PF_ACPY(&key.addr[1], j->pd.src, key.af);
+				PF_ACPY(&key.addr[0], j->pd.dst, key.af);
+				key.port[1] = j->pd.hdr.sctp.src_port;
+				key.port[0] = j->pd.hdr.sctp.dest_port;
+			}
+
+			sm = pf_find_state(kif, &key, j->pd.dir);
+			if (sm != NULL) {
+				PF_STATE_LOCK_ASSERT(sm);
+				if (j->pd.dir == sm->direction) {
+					psrc = PF_PEER_SRC;
+				} else {
+					psrc = PF_PEER_DST;
+				}
+				pf_set_protostate(sm, psrc, SCTP_SHUTDOWN_PENDING);
+				sm->timeout = PFTM_TCP_CLOSING;
+				PF_STATE_UNLOCK(sm);
+			}
+			break;
+		default:
+			panic("Unknown op %#x", j->op);
+		}
 		}
 
 		free(j, M_PFTEMP);
@@ -5952,7 +5992,7 @@ pf_sctp_multihome_delayed(struct pf_pdesc *pd, int off, struct pfi_kkif *kif,
 
 static int
 pf_multihome_scan(struct mbuf *m, int start, int len, struct pf_pdesc *pd,
-    struct pfi_kkif *kif)
+    struct pfi_kkif *kif, int op)
 {
 	int			 off = 0;
 	struct pf_sctp_multihome_job	*job;
@@ -6014,6 +6054,7 @@ pf_multihome_scan(struct mbuf *m, int start, int len, struct pf_pdesc *pd,
 			memcpy(&job->dst, pd->dst, sizeof(job->dst));
 			job->pd.dst = &job->dst;
 			job->m = m;
+			job->op = op;
 
 			TAILQ_INSERT_TAIL(&pd->sctp_multihome_jobs, job, next);
 			break;
@@ -6044,6 +6085,7 @@ pf_multihome_scan(struct mbuf *m, int start, int len, struct pf_pdesc *pd,
 			memcpy(&job->dst, pd->dst, sizeof(job->dst));
 			job->pd.dst = &job->dst;
 			job->m = m;
+			job->op = op;
 
 			TAILQ_INSERT_TAIL(&pd->sctp_multihome_jobs, job, next);
 			break;
@@ -6058,7 +6100,22 @@ pf_multihome_scan(struct mbuf *m, int start, int len, struct pf_pdesc *pd,
 				return (PF_DROP);
 
 			ret = pf_multihome_scan(m, start + off + sizeof(ah),
-			    ntohs(ah.ph.param_length) - sizeof(ah), pd, kif);
+			    ntohs(ah.ph.param_length) - sizeof(ah), pd, kif,
+			    SCTP_ADD_IP_ADDRESS);
+			if (ret != PF_PASS)
+				return (ret);
+			break;
+		}
+		case SCTP_DEL_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,
+			    SCTP_DEL_IP_ADDRESS);
 			if (ret != PF_PASS)
 				return (ret);
 			break;
@@ -6079,7 +6136,7 @@ pf_multihome_scan_init(struct mbuf *m, int start, int len, struct pf_pdesc *pd,
 	start += sizeof(struct sctp_init_chunk);
 	len -= sizeof(struct sctp_init_chunk);
 
-	return (pf_multihome_scan(m, start, len, pd, kif));
+	return (pf_multihome_scan(m, start, len, pd, kif, SCTP_ADD_IP_ADDRESS));
 }
 
 int
@@ -6089,7 +6146,7 @@ pf_multihome_scan_asconf(struct mbuf *m, int start, int len,
 	start += sizeof(struct sctp_asconf_chunk);
 	len -= sizeof(struct sctp_asconf_chunk);
 
-	return (pf_multihome_scan(m, start, len, pd, kif));
+	return (pf_multihome_scan(m, start, len, pd, kif, SCTP_ADD_IP_ADDRESS));
 }
 
 static int