diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1572,6 +1572,7 @@ 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 @@ 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 *); diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -275,6 +275,14 @@ 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 @@ case DIOCOSFPGET: case DIOCGETSRCNODES: case DIOCCLRSRCNODES: + case DIOCGETSYNCOOKIES: case DIOCIGETIFACES: case DIOCGIFSPEEDV0: case DIOCGIFSPEEDV1: @@ -2183,6 +2192,7 @@ case DIOCRTSTADDRS: case DIOCOSFPGET: case DIOCGETSRCNODES: + case DIOCGETSYNCOOKIES: case DIOCIGETIFACES: case DIOCGIFSPEEDV1: case DIOCGIFSPEEDV0: @@ -4538,6 +4548,14 @@ 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; diff --git a/sys/netpfil/pf/pf_syncookies.c b/sys/netpfil/pf/pf_syncookies.c --- a/sys/netpfil/pf/pf_syncookies.c +++ b/sys/netpfil/pf/pf_syncookies.c @@ -110,6 +110,7 @@ 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 @@ } 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)