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
This commit is contained in:
Kristof Provost 2021-04-29 11:07:02 +02:00
parent cc948296e6
commit 7606a45dcc
4 changed files with 192 additions and 27 deletions

View File

@ -1074,6 +1074,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;
@ -1240,6 +1253,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)

View File

@ -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 *);
@ -2395,6 +2397,72 @@ pf_rule_to_krule(const struct pf_rule *rule, struct pf_krule *krule)
return (0);
}
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 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
}
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 @@ pf_keepcounters(struct pfioc_nv *nv)
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);

View File

@ -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)

View File

@ -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);