pf: syncookie ioctl interface

Kernel side implementation to allow switching between on and off modes,
and allow this configuration to be retrieved.

MFC after:	1 week
Sponsored by:	Modirum MDPay
Differential Revision:	https://reviews.freebsd.org/D31139
This commit is contained in:
Kristof Provost 2021-05-26 10:18:19 +02:00
parent 8e1864ed07
commit 231e83d342
3 changed files with 103 additions and 1 deletions

View File

@ -1572,6 +1572,7 @@ struct pf_idhash {
struct mtx lock;
};
extern u_long pf_ioctl_maxcount;
extern u_long pf_hashmask;
extern u_long pf_srchashmask;
#define PF_HASHSIZ (131072)
@ -1840,7 +1841,6 @@ void pf_send_tcp(const struct pf_krule *, sa_family_t,
u_int16_t);
void pf_syncookies_init(void);
int pf_syncookies_setmode(u_int8_t);
int pf_get_syncookies(struct pfioc_nv *);
int pf_set_syncookies(struct pfioc_nv *);
int pf_synflood_check(struct pf_pdesc *);

View File

@ -275,6 +275,14 @@ pflog_packet_t *pflog_packet_ptr = NULL;
extern u_long pf_ioctl_maxcount;
#define ERROUT_FUNCTION(target, x) \
do { \
error = (x); \
SDT_PROBE3(pf, ioctl, function, error, __func__, error, \
__LINE__); \
goto target; \
} while (0)
static void
pfattach_vnet(void)
{
@ -2136,6 +2144,7 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
case DIOCOSFPGET:
case DIOCGETSRCNODES:
case DIOCCLRSRCNODES:
case DIOCGETSYNCOOKIES:
case DIOCIGETIFACES:
case DIOCGIFSPEEDV0:
case DIOCGIFSPEEDV1:
@ -2183,6 +2192,7 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
case DIOCRTSTADDRS:
case DIOCOSFPGET:
case DIOCGETSRCNODES:
case DIOCGETSYNCOOKIES:
case DIOCIGETIFACES:
case DIOCGIFSPEEDV1:
case DIOCGIFSPEEDV0:
@ -4538,6 +4548,14 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
error = pf_keepcounters((struct pfioc_nv *)addr);
break;
case DIOCGETSYNCOOKIES:
error = pf_get_syncookies((struct pfioc_nv *)addr);
break;
case DIOCSETSYNCOOKIES:
error = pf_set_syncookies((struct pfioc_nv *)addr);
break;
case DIOCSETHOSTID: {
u_int32_t *hostid = (u_int32_t *)addr;

View File

@ -110,6 +110,7 @@ struct pf_syncookie_status {
VNET_DEFINE_STATIC(struct pf_syncookie_status, pf_syncookie_status);
#define V_pf_syncookie_status VNET(pf_syncookie_status)
static int pf_syncookies_setmode(u_int8_t);
void pf_syncookie_rotate(void *);
void pf_syncookie_newkey(void);
uint32_t pf_syncookie_mac(struct pf_pdesc *, union pf_syncookie,
@ -127,6 +128,89 @@ pf_syncookies_init(void)
}
int
pf_get_syncookies(struct pfioc_nv *nv)
{
nvlist_t *nvl = NULL;
void *nvlpacked = NULL;
nvl = nvlist_create(0);
if (nvl == NULL)
return (ENOMEM);
nvlist_add_bool(nvl, "enabled",
V_pf_status.syncookies_mode != PF_SYNCOOKIES_NEVER);
nvlist_add_bool(nvl, "adaptive", false);
nvlpacked = nvlist_pack(nvl, &nv->len);
if (nvlpacked == NULL) {
nvlist_destroy(nvl);
return (ENOMEM);
}
if (nv->size == 0) {
nvlist_destroy(nvl);
free(nvlpacked, M_TEMP);
return (0);
} else if (nv->size < nv->len) {
nvlist_destroy(nvl);
free(nvlpacked, M_TEMP);
return (ENOSPC);
}
return (copyout(nvlpacked, nv->data, nv->len));
}
int
pf_set_syncookies(struct pfioc_nv *nv)
{
nvlist_t *nvl = NULL;
void *nvlpacked = NULL;
int error;
bool enabled, adaptive;
if (nv->len > pf_ioctl_maxcount)
return (ENOMEM);
nvlpacked = malloc(nv->len, M_TEMP, M_WAITOK);
if (nvlpacked == NULL)
return (ENOMEM);
error = copyin(nv->data, nvlpacked, nv->len);
if (error) {
free(nvlpacked, M_TEMP);
return (error);
}
nvl = nvlist_unpack(nvlpacked, nv->len, 0);
if (nvl == NULL) {
free(nvlpacked, M_TEMP);
return (EBADMSG);
}
if (! nvlist_exists_bool(nvl, "enabled")
|| ! nvlist_exists_bool(nvl, "adaptive")) {
nvlist_destroy(nvl);
free(nvlpacked, M_TEMP);
return (EBADMSG);
}
enabled = nvlist_get_bool(nvl, "enabled");
adaptive = nvlist_get_bool(nvl, "adaptive");
if (adaptive) {
nvlist_destroy(nvl);
free(nvlpacked, M_TEMP);
return (ENOTSUP);
}
PF_RULES_WLOCK();
error = pf_syncookies_setmode(enabled ?
PF_SYNCOOKIES_ALWAYS : PF_SYNCOOKIES_NEVER);
PF_RULES_WUNLOCK();
return (error);
}
static int
pf_syncookies_setmode(u_int8_t mode)
{
if (mode > PF_SYNCOOKIES_MODE_MAX)