Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 14 May 2021 13:06:43 GMT
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 41bb01e095b1 - stable/13 - pf: Introduce DIOCCLRSTATESNV
Message-ID:  <202105141306.14ED6hIw052234@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=41bb01e095b198b4d27b3d860c649267ad35c1d9

commit 41bb01e095b198b4d27b3d860c649267ad35c1d9
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2021-04-29 09:07:02 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2021-05-14 08:15:27 +0000

    pf: Introduce DIOCCLRSTATESNV
    
    Introduce an nvlist variant of DIOCCLRSTATES.
    
    MFC after:      1 week
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D30052
    
    (cherry picked from commit 7606a45dcc87cb6b222af929dad37b615cb925cf)
---
 sys/net/pfvar.h           |  14 ++++
 sys/netpfil/pf/pf_ioctl.c | 199 +++++++++++++++++++++++++++++++++++++++-------
 sys/netpfil/pf/pf_nv.c    |   1 +
 sys/netpfil/pf/pf_nv.h    |   5 ++
 4 files changed, 192 insertions(+), 27 deletions(-)

diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index c6761a5d87f1..dd2f189b948a 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1072,6 +1072,19 @@ struct pfioc_src_node_kill {
 	u_int		    psnk_killed;
 };
 
+#ifdef _KERNEL
+struct pf_kstate_kill {
+	struct pf_state_cmp	psk_pfcmp;
+	sa_family_t		psk_af;
+	int			psk_proto;
+	struct pf_rule_addr	psk_src;
+	struct pf_rule_addr	psk_dst;
+	char			psk_ifname[IFNAMSIZ];
+	char			psk_label[PF_RULE_LABEL_SIZE];
+	u_int			psk_killed;
+};
+#endif
+
 struct pfioc_state_kill {
 	struct pf_state_cmp	psk_pfcmp;
 	sa_family_t		psk_af;
@@ -1238,6 +1251,7 @@ struct pfioc_iface {
 #define DIOCGETRULENV	_IOWR('D',  7, struct pfioc_nv)
 /* XXX cut 8 - 17 */
 #define DIOCCLRSTATES	_IOWR('D', 18, struct pfioc_state_kill)
+#define DIOCCLRSTATESNV	_IOWR('D', 18, struct pfioc_nv)
 #define DIOCGETSTATE	_IOWR('D', 19, struct pfioc_state)
 #define DIOCSETSTATUSIF _IOWR('D', 20, struct pfioc_if)
 #define DIOCGETSTATUS	_IOWR('D', 21, struct pf_status)
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index d9e313f62683..79da65e0ec98 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -200,7 +200,9 @@ struct cdev *pf_dev;
 /*
  * XXX - These are new and need to be checked when moveing to a new version
  */
-static void		 pf_clear_states(void);
+static void		 pf_clear_all_states(void);
+static unsigned int	 pf_clear_states(const struct pf_kstate_kill *);
+static int		 pf_clearstates_nv(struct pfioc_nv *);
 static int		 pf_clear_tables(void);
 static void		 pf_clear_srcnodes(struct pf_ksrc_node *);
 static void		 pf_kill_srcnodes(struct pfioc_src_node_kill *);
@@ -2475,6 +2477,72 @@ relock_DIOCKILLSTATES:
 	return (killed);
 }
 
+static int
+pf_state_kill_to_kstate_kill(const struct pfioc_state_kill *psk,
+    struct pf_kstate_kill *kill)
+{
+	bzero(kill, sizeof(*kill));
+
+	bcopy(&psk->psk_pfcmp, &kill->psk_pfcmp, sizeof(kill->psk_pfcmp));
+	kill->psk_af = psk->psk_af;
+	kill->psk_proto = psk->psk_proto;
+	bcopy(&psk->psk_src, &kill->psk_src, sizeof(kill->psk_src));
+	bcopy(&psk->psk_dst, &kill->psk_dst, sizeof(kill->psk_dst));
+	strlcpy(kill->psk_ifname, psk->psk_ifname, sizeof(kill->psk_ifname));
+	strlcpy(kill->psk_label, psk->psk_label, sizeof(kill->psk_label));
+
+	return (0);
+}
+
+static int
+pf_nvstate_cmp_to_state_cmp(const nvlist_t *nvl, struct pf_state_cmp *cmp)
+{
+	int error = 0;
+
+	bzero(cmp, sizeof(*cmp));
+
+	PFNV_CHK(pf_nvuint64(nvl, "id", &cmp->id));
+	PFNV_CHK(pf_nvuint32(nvl, "creatorid", &cmp->creatorid));
+	PFNV_CHK(pf_nvuint8(nvl, "direction", &cmp->direction));
+
+errout:
+	return (error);
+}
+
+static int
+pf_nvstate_kill_to_kstate_kill(const nvlist_t *nvl,
+    struct pf_kstate_kill *kill)
+{
+	int error = 0;
+
+	bzero(kill, sizeof(*kill));
+
+	if (! nvlist_exists_nvlist(nvl, "cmp"))
+		return (EINVAL);
+
+	PFNV_CHK(pf_nvstate_cmp_to_state_cmp(nvlist_get_nvlist(nvl, "cmp"),
+	    &kill->psk_pfcmp));
+	PFNV_CHK(pf_nvuint8(nvl, "af", &kill->psk_af));
+	PFNV_CHK(pf_nvint(nvl, "proto", &kill->psk_proto));
+
+	if (! nvlist_exists_nvlist(nvl, "src"))
+		return (EINVAL);
+	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "src"),
+	    &kill->psk_src));
+	if (! nvlist_exists_nvlist(nvl, "dst"))
+		return (EINVAL);
+	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"),
+	    &kill->psk_dst));
+
+	PFNV_CHK(pf_nvstring(nvl, "ifname", kill->psk_ifname,
+	    sizeof(kill->psk_ifname)));
+	PFNV_CHK(pf_nvstring(nvl, "label", kill->psk_label,
+	    sizeof(kill->psk_label)));
+
+errout:
+	return (error);
+}
+
 static int
 pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
     uint32_t pool_ticket, const char *anchor, const char *anchor_call,
@@ -3305,33 +3373,19 @@ DIOCCHANGERULE_error:
 	}
 
 	case DIOCCLRSTATES: {
-		struct pf_state		*s;
 		struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
-		u_int			 i, killed = 0;
+		struct pf_kstate_kill	 kill;
 
-		for (i = 0; i <= pf_hashmask; i++) {
-			struct pf_idhash *ih = &V_pf_idhash[i];
+		error = pf_state_kill_to_kstate_kill(psk, &kill);
+		if (error)
+			break;
 
-relock_DIOCCLRSTATES:
-			PF_HASHROW_LOCK(ih);
-			LIST_FOREACH(s, &ih->states, entry)
-				if (!psk->psk_ifname[0] ||
-				    !strcmp(psk->psk_ifname,
-				    s->kif->pfik_name)) {
-					/*
-					 * Don't send out individual
-					 * delete messages.
-					 */
-					s->state_flags |= PFSTATE_NOSYNC;
-					pf_unlink_state(s, PF_ENTER_LOCKED);
-					killed++;
-					goto relock_DIOCCLRSTATES;
-				}
-			PF_HASHROW_UNLOCK(ih);
-		}
-		psk->psk_killed = killed;
-		if (V_pfsync_clear_states_ptr != NULL)
-			V_pfsync_clear_states_ptr(V_pf_status.hostid, psk->psk_ifname);
+		psk->psk_killed = pf_clear_states(&kill);
+		break;
+	}
+
+	case DIOCCLRSTATESNV: {
+		error = pf_clearstates_nv((struct pfioc_nv *)addr);
 		break;
 	}
 
@@ -5224,7 +5278,7 @@ pf_tbladdr_copyout(struct pf_addr_wrap *aw)
  * XXX - Check for version missmatch!!!
  */
 static void
-pf_clear_states(void)
+pf_clear_all_states(void)
 {
 	struct pf_state	*s;
 	u_int i;
@@ -5375,6 +5429,97 @@ on_error:
 	return (error);
 }
 
+static unsigned int
+pf_clear_states(const struct pf_kstate_kill *kill)
+{
+	struct pf_state	*s;
+	unsigned int	 killed = 0;
+
+	for (unsigned int i = 0; i <= pf_hashmask; i++) {
+		struct pf_idhash *ih = &V_pf_idhash[i];
+
+relock_DIOCCLRSTATES:
+		PF_HASHROW_LOCK(ih);
+		LIST_FOREACH(s, &ih->states, entry)
+			if (!kill->psk_ifname[0] ||
+			    !strcmp(kill->psk_ifname,
+			    s->kif->pfik_name)) {
+				/*
+				 * Don't send out individual
+				 * delete messages.
+				 */
+				s->state_flags |= PFSTATE_NOSYNC;
+				pf_unlink_state(s, PF_ENTER_LOCKED);
+				killed++;
+				goto relock_DIOCCLRSTATES;
+			}
+		PF_HASHROW_UNLOCK(ih);
+	}
+
+	if (V_pfsync_clear_states_ptr != NULL)
+		V_pfsync_clear_states_ptr(V_pf_status.hostid, kill->psk_ifname);
+
+	return (killed);
+}
+
+static int
+pf_clearstates_nv(struct pfioc_nv *nv)
+{
+	struct pf_kstate_kill	 kill;
+	nvlist_t		*nvl = NULL;
+	void			*nvlpacked = NULL;
+	int			 error = 0;
+	unsigned int		 killed;
+
+#define ERROUT(x)	ERROUT_FUNCTION(on_error, x)
+
+	if (nv->len > pf_ioctl_maxcount)
+		ERROUT(ENOMEM);
+
+	nvlpacked = malloc(nv->len, M_TEMP, M_WAITOK);
+	if (nvlpacked == NULL)
+		ERROUT(ENOMEM);
+
+	error = copyin(nv->data, nvlpacked, nv->len);
+	if (error)
+		ERROUT(error);
+
+	nvl = nvlist_unpack(nvlpacked, nv->len, 0);
+	if (nvl == NULL)
+		ERROUT(EBADMSG);
+
+	error = pf_nvstate_kill_to_kstate_kill(nvl, &kill);
+	if (error)
+		ERROUT(error);
+
+	killed = pf_clear_states(&kill);
+
+	free(nvlpacked, M_TEMP);
+	nvlpacked = NULL;
+	nvlist_destroy(nvl);
+	nvl = nvlist_create(0);
+	if (nvl == NULL)
+		ERROUT(ENOMEM);
+
+	nvlist_add_number(nvl, "killed", killed);
+
+	nvlpacked = nvlist_pack(nvl, &nv->len);
+	if (nvlpacked == NULL)
+		ERROUT(ENOMEM);
+
+	if (nv->size == 0)
+		ERROUT(0);
+	else if (nv->size < nv->len)
+		ERROUT(ENOSPC);
+
+	error = copyout(nvlpacked, nv->data, nv->len);
+
+on_error:
+	nvlist_destroy(nvl);
+	free(nvlpacked, M_TEMP);
+	return (error);
+}
+
 /*
  * XXX - Check for version missmatch!!!
  */
@@ -5434,7 +5579,7 @@ shutdown_pf(void)
 		pf_commit_altq(t[0]);
 #endif
 
-		pf_clear_states();
+		pf_clear_all_states();
 
 		pf_clear_srcnodes(NULL);
 
diff --git a/sys/netpfil/pf/pf_nv.c b/sys/netpfil/pf/pf_nv.c
index 8a2082d3e0bb..1fdb52e5fad0 100644
--- a/sys/netpfil/pf/pf_nv.c
+++ b/sys/netpfil/pf/pf_nv.c
@@ -104,6 +104,7 @@ pf_nvbinary(const nvlist_t *nvl, const char *name, void *data,
 PF_NV_IMPL_UINT(uint8, uint8_t, UINT8_MAX);
 PF_NV_IMPL_UINT(uint16, uint16_t, UINT16_MAX);
 PF_NV_IMPL_UINT(uint32, uint32_t, UINT32_MAX);
+PF_NV_IMPL_UINT(uint64, uint64_t, UINT64_MAX);
 
 int
 pf_nvint(const nvlist_t *nvl, const char *name, int *val)
diff --git a/sys/netpfil/pf/pf_nv.h b/sys/netpfil/pf/pf_nv.h
index d50f46a1f5cd..589a1972fa43 100644
--- a/sys/netpfil/pf/pf_nv.h
+++ b/sys/netpfil/pf/pf_nv.h
@@ -48,6 +48,11 @@ int	pf_nvuint32_array(const nvlist_t *, const char *, uint32_t *,
 	    size_t, size_t *);
 void	pf_uint32_array_nv(nvlist_t *, const char *, const uint32_t *,
 	    size_t);
+int	pf_nvuint64(const nvlist_t *, const char *, uint64_t *);
+int	pf_nvuint64_array(const nvlist_t *, const char *, uint64_t *,
+	    size_t, size_t *);
+void	pf_uint64_array_nv(nvlist_t *, const char *, const uint64_t *,
+	    size_t);
 
 int	pf_nvstring(const nvlist_t *, const char *, char *, size_t);
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202105141306.14ED6hIw052234>