aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristof Provost <kp@FreeBSD.org>2021-04-29 15:20:36 +0000
committerKristof Provost <kp@FreeBSD.org>2021-05-14 08:18:13 +0000
commit1cbb276258a4e7d5133da02e318bfe4edc2f7f80 (patch)
treeb01d3f13c30192f21373c3b7c7022a1ef7b3908d
parent30164294a6d39f5dc39fa23cf55dc37faa594360 (diff)
downloadsrc-1cbb276258a4e7d5133da02e318bfe4edc2f7f80.tar.gz
src-1cbb276258a4e7d5133da02e318bfe4edc2f7f80.zip
pf: Introduce DIOCKILLSTATESNV
Introduce an nvlist based alternative to DIOCKILLSTATES. MFC after: 1 week Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D30054 (cherry picked from commit e989530a09b6e9f77b89c950ecf32f1b4fa709da)
-rw-r--r--sys/net/pfvar.h1
-rw-r--r--sys/netpfil/pf/pf_ioctl.c110
2 files changed, 96 insertions, 15 deletions
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index f1eeaa458609..abbabd842c43 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1269,6 +1269,7 @@ struct pfioc_iface {
#define DIOCGETLIMIT _IOWR('D', 39, struct pfioc_limit)
#define DIOCSETLIMIT _IOWR('D', 40, struct pfioc_limit)
#define DIOCKILLSTATES _IOWR('D', 41, struct pfioc_state_kill)
+#define DIOCKILLSTATESNV _IOWR('D', 41, struct pfioc_nv)
#define DIOCSTARTALTQ _IO ('D', 42)
#define DIOCSTOPALTQ _IO ('D', 43)
#define DIOCADDALTQV0 _IOWR('D', 45, struct pfioc_altq_v0)
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 1d4d36ded254..f38261caa8e9 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -202,6 +202,11 @@ struct cdev *pf_dev;
*/
static void pf_clear_all_states(void);
static unsigned int pf_clear_states(const struct pf_kstate_kill *);
+static int pf_killstates(struct pf_kstate_kill *,
+ unsigned int *);
+static int pf_killstates_row(struct pf_kstate_kill *,
+ struct pf_idhash *);
+static int pf_killstates_nv(struct pfioc_nv *);
static int pf_clearstates_nv(struct pfioc_nv *);
static int pf_clear_tables(void);
static void pf_clear_srcnodes(struct pf_ksrc_node *);
@@ -2413,7 +2418,7 @@ pf_label_match(const struct pf_krule *rule, const char *label)
}
static int
-pf_killstates_row(struct pfioc_state_kill *psk, struct pf_idhash *ih)
+pf_killstates_row(struct pf_kstate_kill *psk, struct pf_idhash *ih)
{
struct pf_state *s;
struct pf_state_key *sk;
@@ -3402,25 +3407,20 @@ DIOCCHANGERULE_error:
}
case DIOCKILLSTATES: {
- struct pf_state *s;
struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
- u_int i, killed = 0;
+ struct pf_kstate_kill kill;
- if (psk->psk_pfcmp.id) {
- if (psk->psk_pfcmp.creatorid == 0)
- psk->psk_pfcmp.creatorid = V_pf_status.hostid;
- if ((s = pf_find_state_byid(psk->psk_pfcmp.id,
- psk->psk_pfcmp.creatorid))) {
- pf_unlink_state(s, PF_ENTER_LOCKED);
- psk->psk_killed = 1;
- }
+ error = pf_state_kill_to_kstate_kill(psk, &kill);
+ if (error)
break;
- }
- for (i = 0; i <= pf_hashmask; i++)
- killed += pf_killstates_row(psk, &V_pf_idhash[i]);
+ psk->psk_killed = 0;
+ error = pf_killstates(&kill, &psk->psk_killed);
+ break;
+ }
- psk->psk_killed = killed;
+ case DIOCKILLSTATESNV: {
+ error = pf_killstates_nv((struct pfioc_nv *)addr);
break;
}
@@ -5478,6 +5478,86 @@ relock_DIOCCLRSTATES:
}
static int
+pf_killstates(struct pf_kstate_kill *kill, unsigned int *killed)
+{
+ struct pf_state *s;
+
+ if (kill->psk_pfcmp.id) {
+ if (kill->psk_pfcmp.creatorid == 0)
+ kill->psk_pfcmp.creatorid = V_pf_status.hostid;
+ if ((s = pf_find_state_byid(kill->psk_pfcmp.id,
+ kill->psk_pfcmp.creatorid))) {
+ pf_unlink_state(s, PF_ENTER_LOCKED);
+ *killed = 1;
+ }
+ return (0);
+ }
+
+ for (unsigned int i = 0; i <= pf_hashmask; i++)
+ *killed += pf_killstates_row(kill, &V_pf_idhash[i]);
+
+ return (0);
+}
+
+static int
+pf_killstates_nv(struct pfioc_nv *nv)
+{
+ struct pf_kstate_kill kill;
+ nvlist_t *nvl = NULL;
+ void *nvlpacked = NULL;
+ int error = 0;
+ unsigned int killed = 0;
+
+#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);
+
+ error = pf_killstates(&kill, &killed);
+
+ 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);
+}
+
+static int
pf_clearstates_nv(struct pfioc_nv *nv)
{
struct pf_kstate_kill kill;