aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristof Provost <kp@FreeBSD.org>2026-01-06 21:33:31 +0000
committerKristof Provost <kp@FreeBSD.org>2026-01-14 06:44:39 +0000
commitc72fb110e47f5a52e64683a8759a11eb69b34bd3 (patch)
tree4bae4f8dd2268403f4d846c397c03bfdf29afff4
parent4616481212302b5d875cfc7a00766af017318f7f (diff)
pf: convert state limiter interface to netlink
This is a new feature with new ioctl calls, so we can safely remove them right now. Sponsored by: Rubicon Communications, LLC ("Netgate")
-rw-r--r--lib/libpfctl/libpfctl.c314
-rw-r--r--lib/libpfctl/libpfctl.h99
-rw-r--r--sbin/pfctl/pfctl.c189
-rw-r--r--sbin/pfctl/pfctl_parser.c4
-rw-r--r--sbin/pfctl/pfctl_parser.h8
-rw-r--r--sys/net/pfvar.h108
-rw-r--r--sys/netpfil/pf/pf_ioctl.c163
-rw-r--r--sys/netpfil/pf/pf_nl.c407
-rw-r--r--sys/netpfil/pf/pf_nl.h79
9 files changed, 1035 insertions, 336 deletions
diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index c3fdaf70ad0d..a5abe1cadd64 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -3915,3 +3915,317 @@ pfctl_clr_astats(struct pfctl_handle *h, const struct pfr_table *tbl,
return (ret);
}
+static void
+snl_add_msg_attr_limit_rate(struct snl_writer *nw, uint32_t type,
+ const struct pfctl_limit_rate *rate)
+{
+ int off;
+
+ off = snl_add_msg_attr_nested(nw, type);
+
+ snl_add_msg_attr_u32(nw, PF_LR_LIMIT, rate->limit);
+ snl_add_msg_attr_u32(nw, PF_LR_SECONDS, rate->seconds);
+
+ snl_end_attr_nested(nw, off);
+}
+
+#define _OUT(_field) offsetof(struct pfctl_limit_rate, _field)
+static const struct snl_attr_parser ap_limit_rate[] = {
+ { .type = PF_LR_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
+ { .type = PF_LR_SECONDS, .off = _OUT(seconds), .cb = snl_attr_get_uint32 },
+};
+SNL_DECLARE_ATTR_PARSER(limit_rate_parser, ap_limit_rate);
+#undef _OUT
+
+#define _OUT(_field) offsetof(struct pfctl_state_lim, _field)
+static struct snl_attr_parser ap_statelim[] = {
+ { .type = PF_SL_NAME, .off = _OUT(name), .arg_u32 = PF_STATELIM_NAME_LEN, .cb = snl_attr_copy_string },
+ { .type = PF_SL_ID, .off = _OUT(id), .cb = snl_attr_get_uint32 },
+ { .type = PF_SL_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
+ { .type = PF_SL_RATE, .off = _OUT(rate), .arg = &limit_rate_parser, .cb = snl_attr_get_nested },
+ { .type = PF_SL_DESCR, .off = _OUT(description), .arg_u32 = PF_STATELIM_DESCR_LEN, .cb = snl_attr_copy_string },
+ { .type = PF_SL_INUSE, .off = _OUT(inuse), .cb = snl_attr_get_uint32 },
+ { .type = PF_SL_ADMITTED, .off = _OUT(admitted), .cb = snl_attr_get_uint64 },
+ { .type = PF_SL_HARDLIMITED, .off = _OUT(hardlimited), .cb = snl_attr_get_uint64 },
+ { .type = PF_SL_RATELIMITED, .off = _OUT(ratelimited), .cb = snl_attr_get_uint64 },
+};
+#undef _OUT
+SNL_DECLARE_PARSER(statelim_parser, struct genlmsghdr, snl_f_p_empty, ap_statelim);
+
+int
+pfctl_state_limiter_nget(struct pfctl_handle *h, struct pfctl_state_lim *lim)
+{
+ struct snl_writer nw;
+ struct snl_errmsg_data e = {};
+ struct nlmsghdr *hdr;
+ uint32_t seq_id;
+ int family_id;
+
+ family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
+ if (family_id == 0)
+ return (ENOTSUP);
+
+ snl_init_writer(&h->ss, &nw);
+ hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_STATE_LIMITER_NGET);
+
+ snl_add_msg_attr_u32(&nw, PF_SL_ID, lim->id);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL)
+ return (ENXIO);
+ seq_id = hdr->nlmsg_seq;
+
+ if (! snl_send_message(&h->ss, hdr))
+ return (ENXIO);
+
+ while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
+ if (! snl_parse_nlmsg(&h->ss, hdr, &statelim_parser, lim))
+ continue;
+ }
+
+ return (e.error);
+}
+
+int
+pfctl_state_limiter_add(struct pfctl_handle *h, struct pfctl_state_lim *lim)
+{
+ struct snl_writer nw;
+ struct snl_errmsg_data e = {};
+ struct nlmsghdr *hdr;
+ uint32_t seq_id;
+ int family_id;
+
+ family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
+ if (family_id == 0)
+ return (ENOTSUP);
+
+ snl_init_writer(&h->ss, &nw);
+ hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_STATE_LIMITER_ADD);
+
+ snl_add_msg_attr_u32(&nw, PF_SL_ID, lim->id);
+ snl_add_msg_attr_u32(&nw, PF_SL_TICKET, lim->ticket);
+ snl_add_msg_attr_string(&nw, PF_SL_NAME, lim->name);
+ snl_add_msg_attr_u32(&nw, PF_SL_LIMIT, lim->limit);
+ snl_add_msg_attr_limit_rate(&nw, PF_SL_RATE, &lim->rate);
+ snl_add_msg_attr_string(&nw, PF_SL_DESCR, lim->description);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL)
+ return (ENXIO);
+ seq_id = hdr->nlmsg_seq;
+
+ if (! snl_send_message(&h->ss, hdr))
+ return (ENXIO);
+
+ while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
+ if (! snl_parse_nlmsg(&h->ss, hdr, &statelim_parser, &lim))
+ continue;
+ }
+
+ return (e.error);
+}
+
+#define _OUT(_field) offsetof(struct pfctl_source_lim, _field)
+static struct snl_attr_parser ap_sourcelim[] = {
+ { .type = PF_SCL_NAME, .off = _OUT(name), .arg_u32 = PF_SOURCELIM_NAME_LEN, .cb = snl_attr_copy_string },
+ { .type = PF_SCL_ID, .off = _OUT(id), .cb = snl_attr_get_uint32 },
+ { .type = PF_SCL_ENTRIES, .off = _OUT(entries), .cb = snl_attr_get_uint32 },
+ { .type = PF_SCL_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
+ { .type = PF_SCL_RATE, .off = _OUT(rate), .arg = &limit_rate_parser, .cb = snl_attr_get_nested },
+ { .type = PF_SCL_OVERLOAD_TBL_NAME, .off = _OUT(overload_tblname), .arg_u32 = PF_TABLE_NAME_SIZE, .cb = snl_attr_copy_string },
+ { .type = PF_SCL_OVERLOAD_HIGH_WM, .off = _OUT(overload_hwm), .cb = snl_attr_get_uint32 },
+ { .type = PF_SCL_OVERLOAD_LOW_WM, .off = _OUT(overload_lwm), .cb = snl_attr_get_uint32 },
+ { .type = PF_SCL_INET_PREFIX, .off = _OUT(inet_prefix), .cb = snl_attr_get_uint32 },
+ { .type = PF_SCL_INET6_PREFIX, .off = _OUT(inet6_prefix), .cb = snl_attr_get_uint32 },
+ { .type = PF_SCL_DESCR, .off = _OUT(description), .arg_u32 = PF_SOURCELIM_DESCR_LEN, .cb = snl_attr_copy_string },
+ { .type = PF_SCL_NENTRIES, .off = _OUT(nentries), .cb = snl_attr_get_uint32 },
+ { .type = PF_SCL_INUSE, .off = _OUT(inuse), .cb = snl_attr_get_uint32 },
+ { .type = PF_SCL_ADDR_ALLOCS, .off = _OUT(addrallocs), .cb = snl_attr_get_uint64 },
+ { .type = PF_SCL_ADDR_NOMEM, .off = _OUT(addrnomem), .cb = snl_attr_get_uint64 },
+ { .type = PF_SCL_ADMITTED, .off = _OUT(admitted), .cb = snl_attr_get_uint64 },
+ { .type = PF_SCL_ADDRLIMITED, .off = _OUT(addrlimited), .cb = snl_attr_get_uint64 },
+ { .type = PF_SCL_HARDLIMITED, .off = _OUT(hardlimited), .cb = snl_attr_get_uint64 },
+ { .type = PF_SCL_RATELIMITED, .off = _OUT(ratelimited), .cb = snl_attr_get_uint64 },
+};
+#undef _OUT
+SNL_DECLARE_PARSER(sourcelim_parser, struct genlmsghdr, snl_f_p_empty, ap_sourcelim);
+
+int
+pfctl_source_limiter_add(struct pfctl_handle *h, struct pfctl_source_lim *lim)
+{
+ struct snl_writer nw;
+ struct snl_errmsg_data e = {};
+ struct nlmsghdr *hdr;
+ uint32_t seq_id;
+ int family_id;
+
+ family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
+ if (family_id == 0)
+ return (ENOTSUP);
+
+ snl_init_writer(&h->ss, &nw);
+ hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_SOURCE_LIMITER_ADD);
+
+ snl_add_msg_attr_u32(&nw, PF_SCL_TICKET, lim->ticket);
+ snl_add_msg_attr_string(&nw, PF_SCL_NAME, lim->name);
+ snl_add_msg_attr_u32(&nw, PF_SCL_ID, lim->id);
+ snl_add_msg_attr_u32(&nw, PF_SCL_ENTRIES, lim->entries);
+ snl_add_msg_attr_u32(&nw, PF_SCL_LIMIT, lim->limit);
+ snl_add_msg_attr_limit_rate(&nw, PF_SCL_RATE, &lim->rate);
+ snl_add_msg_attr_string(&nw, PF_SCL_OVERLOAD_TBL_NAME, lim->overload_tblname);
+ snl_add_msg_attr_u32(&nw, PF_SCL_OVERLOAD_HIGH_WM, lim->overload_hwm);
+ snl_add_msg_attr_u32(&nw, PF_SCL_OVERLOAD_LOW_WM, lim->overload_lwm);
+ snl_add_msg_attr_u32(&nw, PF_SCL_INET_PREFIX, lim->inet_prefix);
+ snl_add_msg_attr_u32(&nw, PF_SCL_INET6_PREFIX, lim->inet6_prefix);
+ snl_add_msg_attr_string(&nw, PF_SCL_DESCR, lim->description);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL)
+ return (ENXIO);
+ seq_id = hdr->nlmsg_seq;
+
+ if (! snl_send_message(&h->ss, hdr))
+ return (ENXIO);
+
+ while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
+ if (! snl_parse_nlmsg(&h->ss, hdr, &sourcelim_parser, &lim))
+ continue;
+ }
+
+ return (e.error);
+}
+
+static int
+_pfctl_source_limiter_get(struct pfctl_handle *h, int cmd, struct pfctl_source_lim *lim)
+{
+ struct snl_writer nw;
+ struct snl_errmsg_data e = {};
+ struct nlmsghdr *hdr;
+ uint32_t seq_id;
+ int family_id;
+
+ family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
+ if (family_id == 0)
+ return (ENOTSUP);
+
+ snl_init_writer(&h->ss, &nw);
+ hdr = snl_create_genl_msg_request(&nw, family_id, cmd);
+
+ snl_add_msg_attr_u32(&nw, PF_SCL_ID, lim->id);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL)
+ return (ENXIO);
+ seq_id = hdr->nlmsg_seq;
+
+ if (! snl_send_message(&h->ss, hdr))
+ return (ENXIO);
+
+ while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
+ if (! snl_parse_nlmsg(&h->ss, hdr, &sourcelim_parser, lim))
+ continue;
+ }
+
+ return (e.error);
+}
+
+int
+pfctl_source_limiter_get(struct pfctl_handle *h, struct pfctl_source_lim *lim)
+{
+ return (_pfctl_source_limiter_get(h, PFNL_CMD_SOURCE_LIMITER_GET, lim));
+}
+
+int
+pfctl_source_limiter_nget(struct pfctl_handle *h, struct pfctl_source_lim *lim)
+{
+ return (_pfctl_source_limiter_get(h, PFNL_CMD_SOURCE_LIMITER_NGET, lim));
+}
+
+#define _OUT(_field) offsetof(struct pfctl_source, _field)
+static struct snl_attr_parser ap_source[] = {
+ { .type = PF_SRC_AF, .off = _OUT(af), .cb = snl_attr_get_uint8 },
+ { .type = PF_SRC_RDOMAIN, .off = _OUT(rdomain), .cb = snl_attr_get_uint32 },
+ { .type = PF_SRC_ADDR, .off = _OUT(addr), .cb = snl_attr_get_in6_addr },
+ { .type = PF_SRC_INUSE, .off = _OUT(inuse), .cb = snl_attr_get_uint32 },
+ { .type = PF_SRC_ADMITTED, .off = _OUT(admitted), .cb = snl_attr_get_uint64 },
+ { .type = PF_SRC_HARDLIMITED, .off = _OUT(hardlimited), .cb = snl_attr_get_uint64 },
+ { .type = PF_SRC_RATELIMITED, .off = _OUT(ratelimited), .cb = snl_attr_get_uint64 },
+ { .type = PF_SRC_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
+ { .type = PF_SRC_INET_PREFIX, .off = _OUT(inet_prefix), .cb = snl_attr_get_uint32 },
+ {. type = PF_SRC_INET6_PREFIX, .off = _OUT(inet6_prefix), .cb = snl_attr_get_uint32 },
+};
+#undef _OUT
+SNL_DECLARE_PARSER(source_parser, struct genlmsghdr, snl_f_p_empty, ap_source);
+
+int
+pfctl_source_get(struct pfctl_handle *h, int id, pfctl_get_source_fn fn, void *arg)
+{
+ struct snl_writer nw;
+ struct snl_errmsg_data e = {};
+ struct nlmsghdr *hdr;
+ uint32_t seq_id;
+ int family_id, error;
+
+ family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
+ if (family_id == 0)
+ return (ENOTSUP);
+
+ snl_init_writer(&h->ss, &nw);
+ hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_SOURCE_NGET);
+
+ snl_add_msg_attr_u32(&nw, PF_SRC_ID, id);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL)
+ return (ENXIO);
+ seq_id = hdr->nlmsg_seq;
+
+ if (! snl_send_message(&h->ss, hdr))
+ return (ENXIO);
+
+ while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
+ struct pfctl_source src;
+
+ if (! snl_parse_nlmsg(&h->ss, hdr, &source_parser, &src))
+ continue;
+
+ error = fn(&src, arg);
+ if (error != 0) {
+ e.error = error;
+ break;
+ }
+ }
+
+ return (e.error);
+}
+
+int
+pfctl_source_clear(struct pfctl_handle *h, struct pfctl_source_clear *kill)
+{
+ struct snl_writer nw;
+ struct snl_errmsg_data e = {};
+ struct nlmsghdr *hdr;
+ uint32_t seq_id;
+ int family_id;
+
+ family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
+ if (family_id == 0)
+ return (ENOTSUP);
+
+ snl_init_writer(&h->ss, &nw);
+ hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_SOURCE_CLEAR);
+
+ snl_add_msg_attr_string(&nw, PF_SC_NAME, kill->name);
+ snl_add_msg_attr_u32(&nw, PF_SC_ID, kill->id);
+ snl_add_msg_attr_u32(&nw, PF_SC_RDOMAIN, kill->rdomain);
+ snl_add_msg_attr_u8(&nw, PF_SC_AF, kill->af);
+ snl_add_msg_attr_ip6(&nw, PF_SC_ADDR, &kill->addr.v6);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL)
+ return (ENXIO);
+ seq_id = hdr->nlmsg_seq;
+
+ if (! snl_send_message(&h->ss, hdr))
+ return (ENXIO);
+
+ while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
+ }
+
+ return (e.error);
+}
+
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
index 785ac2bc7fd7..670688893a6a 100644
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -592,4 +592,103 @@ int pfctl_get_astats(struct pfctl_handle *h, const struct pfr_table *tbl,
int pfctl_clr_astats(struct pfctl_handle *h, const struct pfr_table *tbl,
struct pfr_addr *addr, int size, int *nzero, int flags);
+struct pfctl_limit_rate {
+ unsigned int limit;
+ unsigned int seconds;
+};
+
+struct pfctl_state_lim {
+ uint32_t ticket;
+ char name[PF_STATELIM_NAME_LEN];
+ uint32_t id;
+ unsigned int limit;
+
+ struct pfctl_limit_rate rate;
+
+ char description[PF_STATELIM_DESCR_LEN];
+
+ unsigned int inuse;
+ uint64_t admitted;
+ uint64_t hardlimited;
+ uint64_t ratelimited;
+};
+
+int pfctl_state_limiter_nget(struct pfctl_handle *h, struct pfctl_state_lim *lim);
+int pfctl_state_limiter_add(struct pfctl_handle *h, struct pfctl_state_lim *lim);
+
+struct pfctl_source_lim {
+ uint32_t ticket;
+
+ char name[PF_SOURCELIM_NAME_LEN];
+ uint32_t id;
+
+ /* limit on the total number of address entries */
+ unsigned int entries;
+
+ /* limit on the number of states per address entry */
+ unsigned int limit;
+
+ /* rate limit on the creation of states by an address entry */
+ struct pfctl_limit_rate rate;
+
+ /*
+ * when the number of states on an entry exceeds hwm, add
+ * the address to the specified table. when the number of
+ * states goes below lwm, remove it from the table.
+ */
+ char overload_tblname[PF_TABLE_NAME_SIZE];
+ unsigned int overload_hwm;
+ unsigned int overload_lwm;
+
+ /*
+ * mask addresses before they're used for entries. /64s
+ * everywhere for inet6 makes it easy to use too much memory.
+ */
+ unsigned int inet_prefix;
+ unsigned int inet6_prefix;
+
+ char description[PF_SOURCELIM_DESCR_LEN];
+
+ unsigned int nentries;
+ unsigned int inuse;
+
+ uint64_t addrallocs;
+ uint64_t addrnomem;
+ uint64_t admitted;
+ uint64_t addrlimited;
+ uint64_t hardlimited;
+ uint64_t ratelimited;
+};
+
+int pfctl_source_limiter_get(struct pfctl_handle *h, struct pfctl_source_lim *lim);
+int pfctl_source_limiter_nget(struct pfctl_handle *h, struct pfctl_source_lim *lim);
+int pfctl_source_limiter_add(struct pfctl_handle *h, struct pfctl_source_lim *lim);
+
+struct pfctl_source {
+ sa_family_t af;
+ unsigned int rdomain;
+ struct pf_addr addr;
+
+ unsigned int inet_prefix;
+ unsigned int inet6_prefix;
+
+ unsigned int limit;
+ unsigned int inuse;
+ uint64_t admitted;
+ uint64_t hardlimited;
+ uint64_t ratelimited;
+};
+typedef int (*pfctl_get_source_fn)(struct pfctl_source *, void *);
+int pfctl_source_get(struct pfctl_handle *h, int id,
+ pfctl_get_source_fn fn, void *arg);
+
+struct pfctl_source_clear {
+ char name[PF_SOURCELIM_NAME_LEN];
+ uint32_t id;
+ sa_family_t af;
+ unsigned int rdomain;
+ struct pf_addr addr;
+};
+int pfctl_source_clear(struct pfctl_handle *h, struct pfctl_source_clear *);
+
#endif
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 04deccf7e890..256868a399d2 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -126,7 +126,7 @@ int pfctl_ruleset_trans(struct pfctl *, char *, struct pfctl_anchor *, bool);
void pfctl_load_statelims(struct pfctl *);
void pfctl_load_statelim(struct pfctl *, struct pfctl_statelim *);
void pfctl_load_sourcelims(struct pfctl *);
-void pfctl_load_sourcelim(struct pfctl *, struct pfctl_sourcelim *);
+void pfctl_load_sourcelim(struct pfctl *, struct pfctl_source_lim *);
int pfctl_eth_ruleset_trans(struct pfctl *, char *,
struct pfctl_eth_anchor *);
int pfctl_load_eth_ruleset(struct pfctl *, char *,
@@ -1260,8 +1260,9 @@ pfctl_print_title(char *title)
int
pfctl_show_statelims(int dev, enum pfctl_show format)
{
- struct pfioc_statelim stlim;
+ struct pfctl_state_lim stlim;
uint32_t id = PF_STATELIM_ID_MIN;
+ int error;
if (format == PFCTL_SHOW_LABELS) {
printf("%3s %8s/%-8s %5s/%-5s %8s %8s %8s\n", "ID", "USE",
@@ -1272,12 +1273,13 @@ pfctl_show_statelims(int dev, enum pfctl_show format)
memset(&stlim, 0, sizeof(stlim));
stlim.id = id;
- if (ioctl(dev, DIOCGETNSTATELIM, &stlim) == -1) {
- if (errno == ENOENT) {
+ error = pfctl_state_limiter_nget(pfh, &stlim);
+ if (error != 0) {
+ if (error == ENOENT) {
/* we're done */
return (0);
}
- warn("DIOCGETNSTATELIM %u", stlim.id);
+ warnc(error, "DIOCGETNSTATELIM %u", stlim.id);
return (-1);
}
@@ -1323,100 +1325,51 @@ pf_addr_inc(struct pf_addr *addr)
}
static int
-pfctl_show_sources(int dev, const struct pfioc_sourcelim *srlim,
- enum pfctl_show format, int opts)
+pfctl_print_source(struct pfctl_source *e, void *arg)
{
- struct pfioc_source sr = { .id = srlim->id };
- struct pfioc_source_entry *entries, *e;
- unsigned int nentries;
- size_t len, used;
-
- if (format != PFCTL_SHOW_LABELS)
- errx(1, "%s format is not PFCTL_SHOW_LABELS", __func__);
-
- nentries = srlim->nentries;
- if (nentries == 0)
- return (0);
- if (nentries > 128) /* arbitrary */
- nentries = 128;
-
- entries = reallocarray(NULL, nentries, sizeof(*entries));
- if (entries == NULL)
- err(1, "alloc %u source limiter entries", nentries);
-
- len = nentries * sizeof(*entries);
-
- e = entries;
-
- /* start from af 0 address 0 */
- memset(e, 0, sizeof(*e));
-
- sr.entry_size = sizeof(*e);
- sr.key = e;
-
- for (;;) {
- sr.entries = entries;
- sr.entrieslen = len;
-
- if (ioctl(dev, DIOCGETNSOURCE, &sr) == -1) {
- switch (errno) {
- case ESRCH: /* can't find the sourcelim */
- case ENOENT: /* no more sources */
- return (0); /* we're done */
- }
- warn("DIOCGETNSOURCE %u", sr.id);
- return (-1);
- }
-
- used = 0;
- if (sr.entrieslen > len)
- errx(1, "DIOCGETNSOURCE used too much buffer");
-
- e = entries;
- for (;;) {
- if (used > sr.entrieslen)
- errx(1, "DIOCGETNSOURCE weird entrieslen");
-
- print_addr_str(e->af, &e->addr);
- switch (e->af) {
- case AF_INET:
- printf("/%u ", sr.inet_prefix);
- break;
- case AF_INET6:
- printf("/%u ", sr.inet6_prefix);
- break;
- default:
- printf("/af? ");
- break;
- }
- printf("rdomain %u ", e->rdomain);
+ print_addr_str(e->af, &e->addr);
+ switch (e->af) {
+ case AF_INET:
+ printf("/%u ", e->inet_prefix);
+ break;
+ case AF_INET6:
+ printf("/%u ", e->inet6_prefix);
+ break;
+ default:
+ printf("/af? ");
+ break;
+ }
+ printf("rdomain %u ", e->rdomain);
- printf("inuse %u/%u ", e->inuse, sr.limit);
- printf("admit %ju hardlim %ju ratelim %ju\n",
- e->admitted, e->hardlimited, e->ratelimited);
+ printf("inuse %u/%u ", e->inuse, e->limit);
+ printf("admit %ju hardlim %ju ratelim %ju\n",
+ e->admitted, e->hardlimited, e->ratelimited);
- used += sizeof(*e);
- if (used == sr.entrieslen)
- break;
+ return (0);
+}
- e++;
- }
+static int
+pfctl_show_sources(int dev, const struct pfctl_source_lim *srlim,
+ enum pfctl_show format, int opts)
+{
+ int error;
- /* reuse the last entry as the next key */
- e->af += pf_addr_inc(&e->addr);
- sr.key = e;
- }
+ if (format != PFCTL_SHOW_LABELS)
+ errx(1, "%s format is not PFCTL_SHOW_LABELS", __func__);
- return (0);
+ error = pfctl_source_get(pfh, srlim->id, pfctl_print_source, NULL);
+ if (error != 0)
+ warnc(error, "DIOCGETNSOURCE %u", srlim->id);
+ return (error);
}
int
pfctl_show_sourcelims(int dev, enum pfctl_show format, int opts,
const char *idopt)
{
- struct pfioc_sourcelim srlim;
+ struct pfctl_source_lim srlim;
uint32_t id = PF_SOURCELIM_ID_MIN;
- unsigned long cmd = DIOCGETNSOURCELIM;
+ int error;
if (idopt != NULL) {
const char *errstr;
@@ -1425,8 +1378,6 @@ pfctl_show_sourcelims(int dev, enum pfctl_show format, int opts,
&errstr);
if (errstr != NULL)
errx(1, "source limiter id: %s", errstr);
-
- cmd = DIOCGETSOURCELIM;
}
if (format == PFCTL_SHOW_LABELS) {
@@ -1439,12 +1390,18 @@ pfctl_show_sourcelims(int dev, enum pfctl_show format, int opts,
memset(&srlim, 0, sizeof(srlim));
srlim.id = id;
- if (ioctl(dev, cmd, &srlim) == -1) {
- if (errno == ESRCH) {
+ if (idopt != NULL) {
+ error = pfctl_source_limiter_get(pfh, &srlim);
+ } else {
+ error = pfctl_source_limiter_nget(pfh, &srlim);
+ }
+
+ if (error != 0) {
+ if (error == ESRCH) {
/* we're done */
return (0);
}
- warn("DIOCGETNSOURCELIM %u", srlim.id);
+ warnc(error, "DIOCGETNSOURCELIM %u", srlim.id);
return (-1);
}
@@ -1485,7 +1442,7 @@ pfctl_show_sourcelims(int dev, enum pfctl_show format, int opts,
void
pfctl_kill_source(int dev, const char *idopt, const char *source, int opts)
{
- struct pfioc_source_kill ioc;
+ struct pfctl_source_clear clear = { 0 };
unsigned int id;
const char *errstr;
struct addrinfo hints, *res;
@@ -1508,22 +1465,22 @@ pfctl_kill_source(int dev, const char *idopt, const char *source, int opts)
if (error != 0)
errx(1, "source limiter address: %s", gai_strerror(error));
- ioc.id = id;
- ioc.af = res->ai_family;
- copy_satopfaddr(&ioc.addr, res->ai_addr);
- ioc.rmstates = 0;
+ clear.id = id;
+ clear.af = res->ai_family;
+ copy_satopfaddr(&clear.addr, res->ai_addr);
freeaddrinfo(res);
- if (ioctl(dev, DIOCCLRSOURCE, &ioc) == -1) {
- switch (errno) {
- case ESRCH:
- errx(1, "source limiter %u not found", id);
- case ENOENT:
- errx(1, "source limiter %u: %s not found", id, source);
- default:
- err(1, "kill source limiter %u entry %s", id, source);
- }
+ error = pfctl_source_clear(pfh, &clear);
+ switch (error) {
+ case 0:
+ break;
+ case ESRCH:
+ errx(1, "source limiter %u not found", id);
+ case ENOENT:
+ errx(1, "source limiter %u: %s not found", id, source);
+ default:
+ err(1, "kill source limiter %u entry %s", id, source);
}
}
@@ -2325,14 +2282,17 @@ pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pfctl_anchor *a, bool d
void
pfctl_load_statelim(struct pfctl *pf, struct pfctl_statelim *stlim)
{
+ int error;
+
if (pf->opts & PF_OPT_VERBOSE)
print_statelim(&stlim->ioc);
if (pf->opts & PF_OPT_NOACTION)
return;
- if (ioctl(pf->dev, DIOCADDSTATELIM, &stlim->ioc) == -1) {
- err(1, "DIOCADDSTATELIM %s id %u", stlim->ioc.name,
+ error = pfctl_state_limiter_add(pf->h, &stlim->ioc);
+ if (error) {
+ errc(1, error, "DIOCADDSTATELIM %s id %u", stlim->ioc.name,
stlim->ioc.id);
}
}
@@ -2356,17 +2316,20 @@ pfctl_load_statelims(struct pfctl *pf)
}
void
-pfctl_load_sourcelim(struct pfctl *pf, struct pfctl_sourcelim *srlim)
+pfctl_load_sourcelim(struct pfctl *pf, struct pfctl_source_lim *srlim)
{
+ int error;
+
if (pf->opts & PF_OPT_VERBOSE)
- print_sourcelim(&srlim->ioc);
+ print_sourcelim(srlim);
if (pf->opts & PF_OPT_NOACTION)
return;
- if (ioctl(pf->dev, DIOCADDSOURCELIM, &srlim->ioc) == -1) {
- err(1, "DIOCADDSOURCELIM %s id %u", srlim->ioc.name,
- srlim->ioc.id);
+ error = pfctl_source_limiter_add(pf->h, srlim);
+ if (error != 0) {
+ errc(1, error, "DIOCADDSOURCELIM %s id %u", srlim->name,
+ srlim->id);
}
}
@@ -2382,7 +2345,7 @@ pfctl_load_sourcelims(struct pfctl *pf)
RB_FOREACH(srlim, pfctl_sourcelim_ids, &pf->sourcelim_ids)
{
srlim->ioc.ticket = ticket;
- pfctl_load_sourcelim(pf, srlim);
+ pfctl_load_sourcelim(pf, &srlim->ioc);
}
/* Don't free the sourcelims because we're about to exit anyway. */
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 617d3f8e0733..25d52f4ec823 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -856,7 +856,7 @@ print_eth_rule(struct pfctl_eth_rule *r, const char *anchor_call,
}
void
-print_statelim(const struct pfioc_statelim *ioc)
+print_statelim(const struct pfctl_state_lim *ioc)
{
printf("state limiter %s id %u limit %u", ioc->name, ioc->id,
ioc->limit);
@@ -867,7 +867,7 @@ print_statelim(const struct pfioc_statelim *ioc)
}
void
-print_sourcelim(const struct pfioc_sourcelim *ioc)
+print_sourcelim(const struct pfctl_source_lim *ioc)
{
printf("source limiter %s id %u limit %u states %u", ioc->name,
ioc->id, ioc->entries, ioc->limit);
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index 6d0417cde061..8934238da148 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -76,7 +76,7 @@
struct pfr_buffer; /* forward definition */
struct pfctl_statelim {
- struct pfioc_statelim ioc;
+ struct pfctl_state_lim ioc;
RB_ENTRY(pfctl_statelim) entry;
};
@@ -84,7 +84,7 @@ RB_HEAD(pfctl_statelim_ids, pfctl_statelim);
RB_HEAD(pfctl_statelim_nms, pfctl_statelim);
struct pfctl_sourcelim {
- struct pfioc_sourcelim ioc;
+ struct pfctl_source_lim ioc;
RB_ENTRY(pfctl_sourcelim) entry;
};
@@ -343,8 +343,8 @@ int pfctl_load_anchors(int, struct pfctl *);
void print_pool(struct pfctl_pool *, u_int16_t, u_int16_t, int);
void print_src_node(struct pfctl_src_node *, int);
-void print_statelim(const struct pfioc_statelim *);
-void print_sourcelim(const struct pfioc_sourcelim *);
+void print_statelim(const struct pfctl_state_lim *);
+void print_sourcelim(const struct pfctl_source_lim *);
void print_eth_rule(struct pfctl_eth_rule *, const char *, int);
void print_rule(struct pfctl_rule *, const char *, int, int);
void print_tabledef(const char *, int, int, struct node_tinithead *);
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 025a30378f1f..5329c5ebdd9e 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1205,6 +1205,11 @@ struct pf_kstate {
* State limiter
*/
+struct pf_limiter_rate {
+ unsigned int limit;
+ unsigned int seconds;
+};
+
struct pf_statelim {
RB_ENTRY(pf_statelim) pfstlim_id_tree;
RB_ENTRY(pf_statelim) pfstlim_nm_tree;
@@ -1217,10 +1222,7 @@ struct pf_statelim {
/* config */
unsigned int pfstlim_limit;
- struct {
- unsigned int limit;
- unsigned int seconds;
- } pfstlim_rate;
+ struct pf_limiter_rate pfstlim_rate;
/* run state */
struct mtx pfstlim_lock;
@@ -1340,10 +1342,7 @@ struct pf_sourcelim {
unsigned int pfsrlim_ipv4_prefix;
unsigned int pfsrlim_ipv6_prefix;
- struct {
- unsigned int limit;
- unsigned int seconds;
- } pfsrlim_rate;
+ struct pf_limiter_rate pfsrlim_rate;
struct {
char name[PF_TABLE_NAME_SIZE];
@@ -2074,25 +2073,29 @@ enum pf_syncookies_mode {
#define PF_SYNCOOKIES_HIWATPCT 25
#define PF_SYNCOOKIES_LOWATPCT (PF_SYNCOOKIES_HIWATPCT / 2)
+#define PF_STATELIM_ID_NONE 0
+#define PF_STATELIM_ID_MIN 1
+#define PF_STATELIM_ID_MAX 255 /* fits in pf_state uint8_t */
+#define PF_STATELIM_LIMIT_MIN 1
+#define PF_STATELIM_LIMIT_MAX (1 << 24) /* pf is pretty scalable */
+
+#define PF_SOURCELIM_ID_NONE 0
+#define PF_SOURCELIM_ID_MIN 1
+#define PF_SOURCELIM_ID_MAX 255 /* fits in pf_state uint8_t */
+
+#ifdef _KERNEL
+
struct pfioc_statelim {
uint32_t ticket;
char name[PF_STATELIM_NAME_LEN];
uint32_t id;
-#define PF_STATELIM_ID_NONE 0
-#define PF_STATELIM_ID_MIN 1
-#define PF_STATELIM_ID_MAX 255 /* fits in pf_state uint8_t */
/* limit on the total number of states */
unsigned int limit;
-#define PF_STATELIM_LIMIT_MIN 1
-#define PF_STATELIM_LIMIT_MAX (1 << 24) /* pf is pretty scalable */
/* rate limit on the creation of states */
- struct {
- unsigned int limit;
- unsigned int seconds;
- } rate;
+ struct pf_limiter_rate rate;
char description[PF_STATELIM_DESCR_LEN];
@@ -2108,9 +2111,6 @@ struct pfioc_sourcelim {
char name[PF_SOURCELIM_NAME_LEN];
uint32_t id;
-#define PF_SOURCELIM_ID_NONE 0
-#define PF_SOURCELIM_ID_MIN 1
-#define PF_SOURCELIM_ID_MAX 255 /* fits in pf_state uint8_t */
/* limit on the total number of address entries */
unsigned int entries;
@@ -2119,10 +2119,7 @@ struct pfioc_sourcelim {
unsigned int limit;
/* rate limit on the creation of states by an address entry */
- struct {
- unsigned int limit;
- unsigned int seconds;
- } rate;
+ struct pf_limiter_rate rate;
/*
* when the number of states on an entry exceeds hwm, add
@@ -2154,37 +2151,6 @@ struct pfioc_sourcelim {
uint64_t ratelimited; /* counter */
};
-struct pfioc_source_entry {
- sa_family_t af;
- unsigned int rdomain;
- struct pf_addr addr;
-
- /* stats */
-
- unsigned int inuse; /* gauge */
- uint64_t admitted; /* counter */
- uint64_t hardlimited; /* counter */
- uint64_t ratelimited; /* counter */
-};
-
-struct pfioc_source {
- char name[PF_SOURCELIM_NAME_LEN];
- uint32_t id;
-
- /* copied from the parent source limiter */
-
- unsigned int inet_prefix;
- unsigned int inet6_prefix;
- unsigned int limit;
-
- /* source entries */
- size_t entry_size; /* sizeof(struct pfioc_source_entry) */
-
- struct pfioc_source_entry *key;
- struct pfioc_source_entry *entries;
- size_t entrieslen; /* bytes */
-};
-
struct pfioc_source_kill {
char name[PF_SOURCELIM_NAME_LEN];
uint32_t id;
@@ -2195,7 +2161,28 @@ struct pfioc_source_kill {
unsigned int rmstates; /* kill the states too? */
};
-#ifdef _KERNEL
+int pf_statelim_add(const struct pfioc_statelim *);
+struct pf_statelim *pf_statelim_rb_find(struct pf_statelim_id_tree *,
+ struct pf_statelim *);
+struct pf_statelim *pf_statelim_rb_nfind(struct pf_statelim_id_tree *,
+ struct pf_statelim *);
+int pf_statelim_get(struct pfioc_statelim *,
+ struct pf_statelim *(*rbt_op)(struct pf_statelim_id_tree *,
+ struct pf_statelim *));
+int pf_sourcelim_add(const struct pfioc_sourcelim *);
+struct pf_sourcelim *pf_sourcelim_rb_find(struct pf_sourcelim_id_tree *,
+ struct pf_sourcelim *);
+struct pf_sourcelim *pf_sourcelim_rb_nfind(struct pf_sourcelim_id_tree *,
+ struct pf_sourcelim *);
+int pf_sourcelim_get(struct pfioc_sourcelim *,
+ struct pf_sourcelim *(*rbt_op)(struct pf_sourcelim_id_tree *,
+ struct pf_sourcelim *));
+struct pf_source *pf_source_rb_find(struct pf_source_ioc_tree *,
+ struct pf_source *);
+struct pf_source *pf_source_rb_nfind(struct pf_source_ioc_tree *,
+ struct pf_source *);
+int pf_source_clr(struct pfioc_source_kill *);
+
struct pf_kstatus {
counter_u64_t counters[PFRES_MAX]; /* reason for passing/dropping */
counter_u64_t lcounters[KLCNT_MAX]; /* limit counters */
@@ -2569,15 +2556,6 @@ struct pfioc_iface {
#define DIOCGETETHRULESETS _IOWR('D', 100, struct pfioc_nv)
#define DIOCGETETHRULESET _IOWR('D', 101, struct pfioc_nv)
#define DIOCSETREASS _IOWR('D', 102, u_int32_t)
-#define DIOCADDSTATELIM _IOW('D', 103, struct pfioc_statelim)
-#define DIOCADDSOURCELIM _IOW('D', 104, struct pfioc_sourcelim)
-#define DIOCGETSTATELIM _IOWR('D', 105, struct pfioc_statelim)
-#define DIOCGETSOURCELIM _IOWR('D', 106, struct pfioc_sourcelim)
-#define DIOCGETSOURCE _IOWR('D', 107, struct pfioc_source)
-#define DIOCGETNSTATELIM _IOWR('D', 108, struct pfioc_statelim)
-#define DIOCGETNSOURCELIM _IOWR('D', 109, struct pfioc_sourcelim)
-#define DIOCGETNSOURCE _IOWR('D', 110, struct pfioc_source)
-#define DIOCCLRSOURCE _IOWR('D', 111, struct pfioc_source_kill)
struct pf_ifspeed_v0 {
char ifname[IFNAMSIZ];
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 0bc8b30181d6..bc998113dbbb 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -1613,7 +1613,7 @@ pf_addr_copyout(struct pf_addr_wrap *addr)
}
}
-static int
+int
pf_statelim_add(const struct pfioc_statelim *ioc)
{
struct pf_statelim *pfstlim;
@@ -1976,7 +1976,7 @@ pf_statelim_rollback(void)
RB_INIT(&V_pf_statelim_nm_tree_inactive);
}
-static struct pf_statelim *
+struct pf_statelim *
pf_statelim_rb_find(struct pf_statelim_id_tree *tree, struct pf_statelim *key)
{
PF_RULES_ASSERT();
@@ -1984,7 +1984,7 @@ pf_statelim_rb_find(struct pf_statelim_id_tree *tree, struct pf_statelim *key)
return (RB_FIND(pf_statelim_id_tree, tree, key));
}
-static struct pf_statelim *
+struct pf_statelim *
pf_statelim_rb_nfind(struct pf_statelim_id_tree *tree, struct pf_statelim *key)
{
PF_RULES_ASSERT();
@@ -1992,7 +1992,7 @@ pf_statelim_rb_nfind(struct pf_statelim_id_tree *tree, struct pf_statelim *key)
return (RB_NFIND(pf_statelim_id_tree, tree, key));
}
-static int
+int
pf_statelim_get(struct pfioc_statelim *ioc,
struct pf_statelim *(*rbt_op)(struct pf_statelim_id_tree *,
struct pf_statelim *))
@@ -2028,7 +2028,7 @@ unlock:
return (error);
}
-static int
+int
pf_sourcelim_add(const struct pfioc_sourcelim *ioc)
{
struct pf_sourcelim *pfsrlim;
@@ -2187,7 +2187,7 @@ pf_sourcelim_rollback(void)
RB_INIT(&V_pf_sourcelim_nm_tree_inactive);
}
-static struct pf_sourcelim *
+struct pf_sourcelim *
pf_sourcelim_rb_find(struct pf_sourcelim_id_tree *tree,
struct pf_sourcelim *key)
{
@@ -2195,7 +2195,7 @@ pf_sourcelim_rb_find(struct pf_sourcelim_id_tree *tree,
return (RB_FIND(pf_sourcelim_id_tree, tree, key));
}
-static struct pf_sourcelim *
+struct pf_sourcelim *
pf_sourcelim_rb_nfind(struct pf_sourcelim_id_tree *tree,
struct pf_sourcelim *key)
{
@@ -2203,7 +2203,7 @@ pf_sourcelim_rb_nfind(struct pf_sourcelim_id_tree *tree,
return (RB_NFIND(pf_sourcelim_id_tree, tree, key));
}
-static int
+int
pf_sourcelim_get(struct pfioc_sourcelim *ioc,
struct pf_sourcelim *(*rbt_op)(struct pf_sourcelim_id_tree *,
struct pf_sourcelim *))
@@ -2262,7 +2262,7 @@ unlock:
return (error);
}
-static struct pf_source *
+struct pf_source *
pf_source_rb_find(struct pf_source_ioc_tree *tree,
struct pf_source *key)
{
@@ -2271,7 +2271,7 @@ pf_source_rb_find(struct pf_source_ioc_tree *tree,
return (RB_FIND(pf_source_ioc_tree, tree, key));
}
-static struct pf_source *
+struct pf_source *
pf_source_rb_nfind(struct pf_source_ioc_tree *tree,
struct pf_source *key)
{
@@ -2280,100 +2280,7 @@ pf_source_rb_nfind(struct pf_source_ioc_tree *tree,
return (RB_NFIND(pf_source_ioc_tree, tree, key));
}
-static int
-pf_source_get(struct pfioc_source *ioc,
- struct pf_source *(*rbt_op)(struct pf_source_ioc_tree *,
- struct pf_source *))
-{
- struct pf_sourcelim plkey = { .pfsrlim_id = ioc->id };
- struct pfioc_source_entry e, *uentry;
- struct pf_source key;
- struct pf_sourcelim *pfsrlim;
- struct pf_source *pfsr;
- size_t used = 0, len = ioc->entrieslen;
- int error = 0;
- PF_RULES_RLOCK_TRACKER;
-
- if (ioc->entry_size != sizeof(e))
- return (EINVAL);
- if (len < sizeof(e))
- return (EMSGSIZE);
-
- error = copyin(ioc->key, &e, sizeof(e));
- if (error != 0)
- return (error);
-
- PF_RULES_RLOCK();
-
-#if 0
- if (ioc->ticket != pf_main_ruleset.rules.active.ticket) {
- error = EBUSY;
- goto unlock;
- }
-#endif
-
- pfsrlim = pf_sourcelim_rb_find(&V_pf_sourcelim_id_tree_active, &plkey);
- if (pfsrlim == NULL) {
- error = ESRCH;
- goto unlock;
- }
-
- key.pfsr_af = e.af;
- key.pfsr_rdomain = e.rdomain;
- key.pfsr_addr = e.addr;
- pfsr = (*rbt_op)(&pfsrlim->pfsrlim_ioc_sources, &key);
- if (pfsr == NULL) {
- error = ENOENT;
- goto unlock;
- }
-
- memset(&e, 0, sizeof(e));
-
- uentry = ioc->entries;
- for (;;) {
- e.af = pfsr->pfsr_af;
- e.rdomain = pfsr->pfsr_rdomain;
- e.addr = pfsr->pfsr_addr;
-
- e.inuse = pfsr->pfsr_inuse;
- e.admitted = pfsr->pfsr_counters.admitted;
- e.hardlimited = pfsr->pfsr_counters.hardlimited;
- e.ratelimited = pfsr->pfsr_counters.ratelimited;
-
- error = copyout(&e, uentry, sizeof(e));
- if (error != 0)
- goto unlock;
-
- used += sizeof(e);
- if (used == len)
- break;
-
- pfsr = RB_NEXT(pf_source_ioc_tree, srlim->pfsrlim_ioc_sources, pfsr);
- if (pfsr == NULL)
- break;
-
- if ((len - used) < sizeof(e)) {
- error = EMSGSIZE;
- goto unlock;
- }
-
- uentry++;
- }
- MPASS(error == 0);
-
- ioc->inet_prefix = pfsrlim->pfsrlim_ipv4_prefix;
- ioc->inet6_prefix = pfsrlim->pfsrlim_ipv6_prefix;
- ioc->limit = pfsrlim->pfsrlim_limit;
-
- ioc->entrieslen = used;
-
-unlock:
- PF_RULES_RUNLOCK();
-
- return (error);
-}
-
-static int
+int
pf_source_clr(struct pfioc_source_kill *ioc)
{
extern struct pf_source_list pf_source_gc;
@@ -3876,12 +3783,6 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
case DIOCGETTIMEOUT:
case DIOCCLRRULECTRS:
case DIOCGETLIMIT:
- case DIOCGETSTATELIM:
- case DIOCGETNSTATELIM:
- case DIOCGETSOURCELIM:
- case DIOCGETNSOURCELIM:
- case DIOCGETSOURCE:
- case DIOCGETNSOURCE:
case DIOCGETALTQSV0:
case DIOCGETALTQSV1:
case DIOCGETALTQV0:
@@ -3941,12 +3842,6 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
#endif
case DIOCGETTIMEOUT:
case DIOCGETLIMIT:
- case DIOCGETSTATELIM:
- case DIOCGETNSTATELIM:
- case DIOCGETSOURCELIM:
- case DIOCGETNSOURCELIM:
- case DIOCGETSOURCE:
- case DIOCGETNSOURCE:
case DIOCGETALTQSV0:
case DIOCGETALTQSV1:
case DIOCGETALTQV0:
@@ -5235,42 +5130,6 @@ DIOCGETSTATESV2_full:
break;
}
- case DIOCADDSTATELIM:
- error = pf_statelim_add((struct pfioc_statelim *)addr);
- break;
- case DIOCGETSTATELIM:
- error = pf_statelim_get((struct pfioc_statelim *)addr,
- pf_statelim_rb_find);
- break;
- case DIOCGETNSTATELIM:
- error = pf_statelim_get((struct pfioc_statelim *)addr,
- pf_statelim_rb_nfind);
- break;
-
- case DIOCADDSOURCELIM:
- error = pf_sourcelim_add((struct pfioc_sourcelim *)addr);
- break;
- case DIOCGETSOURCELIM:
- error = pf_sourcelim_get((struct pfioc_sourcelim *)addr,
- pf_sourcelim_rb_find);
- break;
- case DIOCGETNSOURCELIM:
- error = pf_sourcelim_get((struct pfioc_sourcelim *)addr,
- pf_sourcelim_rb_nfind);
- break;
-
- case DIOCGETSOURCE:
- error = pf_source_get((struct pfioc_source *)addr,
- pf_source_rb_find);
- break;
- case DIOCGETNSOURCE:
- error = pf_source_get((struct pfioc_source *)addr,
- pf_source_rb_nfind);
- break;
- case DIOCCLRSOURCE:
- error = pf_source_clr((struct pfioc_source_kill *)addr);
- break;
-
case DIOCCLRRULECTRS: {
/* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */
struct pf_kruleset *ruleset = &pf_main_ruleset;
diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c
index 6e19beec5bfe..9522fad10839 100644
--- a/sys/netpfil/pf/pf_nl.c
+++ b/sys/netpfil/pf/pf_nl.c
@@ -2463,6 +2463,346 @@ pf_handle_table_clear_astats(struct nlmsghdr *hdr, struct nl_pstate *npt)
return (error);
}
+static const struct nlattr_parser nla_p_rate[] = {
+ { .type = PF_LR_LIMIT, .off = 0, .cb = nlattr_get_uint32 },
+ { .type = PF_LR_SECONDS, .off = sizeof(unsigned int), .cb = nlattr_get_uint32 },
+};
+NL_DECLARE_ATTR_PARSER(rate_parser, nla_p_rate);
+
+#define _OUT(_field) offsetof(struct pfioc_statelim, _field)
+static const struct nlattr_parser nla_p_state_limiter[] = {
+ { .type = PF_SL_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
+ { .type = PF_SL_NAME, .off = _OUT(name), .arg = (void *)PF_STATELIM_NAME_LEN, .cb = nlattr_get_chara },
+ { .type = PF_SL_ID, .off = _OUT(id), .cb = nlattr_get_uint32 },
+ { .type = PF_SL_LIMIT, .off = _OUT(limit), .cb = nlattr_get_uint32 },
+ { .type = PF_SL_RATE, .off = _OUT(rate), .arg = &rate_parser, .cb = nlattr_get_nested },
+ { .type = PF_SL_DESCR, .off = _OUT(description), .arg = (void *)PF_STATELIM_DESCR_LEN, .cb = nlattr_get_chara },
+};
+NL_DECLARE_PARSER(state_limiter_parser, struct genlmsghdr, nlf_p_empty, nla_p_state_limiter);
+#undef _OUT
+
+static int
+pf_handle_state_limiter_add(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pfioc_statelim attrs = { 0 };
+ struct nl_writer *nw = npt->nw;
+ struct genlmsghdr *ghdr_new;
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &state_limiter_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ error = pf_statelim_add(&attrs);
+ if (error != 0)
+ return (error);
+
+ if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
+ return (ENOMEM);
+
+ ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
+ ghdr_new->cmd = PFNL_CMD_STATE_LIMITER_ADD;
+
+ nlattr_add_u32(nw, PF_SL_ID, attrs.id);
+
+ if (!nlmsg_end(nw))
+ return (ENOMEM);
+
+ return (error);
+}
+
+static bool
+nlattr_add_limiter_rate(struct nl_writer *nw, int attrtype,
+ const struct pf_limiter_rate *rate)
+{
+ int off = nlattr_add_nested(nw, attrtype);
+ if (off == 0)
+ return (false);
+
+ nlattr_add_u32(nw, PF_LR_LIMIT, rate->limit);
+ nlattr_add_u32(nw, PF_LR_SECONDS, rate->seconds);
+
+ nlattr_set_len(nw, off);
+
+ return (true);
+}
+
+static int
+pf_handle_state_limiter_get(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pfioc_statelim attrs = { 0 };
+ struct nl_writer *nw = npt->nw;
+ struct genlmsghdr *ghdr = (struct genlmsghdr *)(hdr + 1);
+ struct genlmsghdr *ghdr_new;
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &state_limiter_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ error = pf_statelim_get(&attrs,
+ ghdr->cmd == PFNL_CMD_STATE_LIMITER_GET ? pf_statelim_rb_find :
+ pf_statelim_rb_nfind);
+ if (error != 0)
+ return (error);
+
+ if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
+ return (ENOMEM);
+
+ ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
+ ghdr_new->cmd = PFNL_CMD_STATE_LIMITER_GET;
+
+ nlattr_add_string(nw, PF_SL_NAME, attrs.name);
+ nlattr_add_u32(nw, PF_SL_ID, attrs.id);
+ nlattr_add_u32(nw, PF_SL_LIMIT, attrs.limit);
+ nlattr_add_limiter_rate(nw, PF_SL_RATE, &attrs.rate);
+ nlattr_add_string(nw, PF_SL_DESCR, attrs.description);
+ nlattr_add_u32(nw, PF_SL_INUSE, attrs.inuse);
+ nlattr_add_u64(nw, PF_SL_ADMITTED, attrs.admitted);
+ nlattr_add_u64(nw, PF_SL_HARDLIMITED, attrs.hardlimited);
+ nlattr_add_u64(nw, PF_SL_RATELIMITED, attrs.ratelimited);
+
+ if (!nlmsg_end(nw))
+ return (ENOMEM);
+
+ return (error);
+}
+
+#define _OUT(_field) offsetof(struct pfioc_sourcelim, _field)
+static const struct nlattr_parser nla_p_source_limiter[] = {
+ { .type = PF_SCL_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
+ { .type = PF_SCL_NAME, .off = _OUT(name), .arg = (void *)PF_STATELIM_NAME_LEN, .cb = nlattr_get_chara },
+ { .type = PF_SCL_ID, .off = _OUT(id), .cb = nlattr_get_uint32 },
+ { .type = PF_SCL_ENTRIES, .off = _OUT(entries), .cb = nlattr_get_uint32 },
+ { .type = PF_SCL_LIMIT, .off = _OUT(limit), .cb = nlattr_get_uint32 },
+ { .type = PF_SCL_RATE, .off = _OUT(rate), .arg = &rate_parser, .cb = nlattr_get_nested },
+ { .type = PF_SCL_OVERLOAD_TBL_NAME, .off = _OUT(overload_tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
+ { .type = PF_SCL_OVERLOAD_HIGH_WM, .off = _OUT(overload_hwm), .cb = nlattr_get_uint32 },
+ { .type = PF_SCL_OVERLOAD_LOW_WM, .off = _OUT(overload_lwm), .cb = nlattr_get_uint32 },
+ { .type = PF_SCL_INET_PREFIX, .off = _OUT(inet_prefix), .cb = nlattr_get_uint32 },
+ { .type = PF_SCL_INET6_PREFIX, .off = _OUT(inet6_prefix), .cb = nlattr_get_uint32 },
+ { .type = PF_SCL_DESCR, .off = _OUT(description), .arg = (void *)PF_STATELIM_DESCR_LEN, .cb = nlattr_get_chara },
+};
+#undef _OUT
+NL_DECLARE_PARSER(source_limiter_parser, struct genlmsghdr, nlf_p_empty, nla_p_source_limiter);
+
+static int
+pf_handle_source_limiter_add(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pfioc_sourcelim attrs = { 0 };
+ struct nl_writer *nw = npt->nw;
+ struct genlmsghdr *ghdr_new;
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &source_limiter_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ error = pf_sourcelim_add(&attrs);
+ if (error != 0)
+ return (error);
+
+ if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
+ return (ENOMEM);
+
+ ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
+ ghdr_new->cmd = PFNL_CMD_SOURCE_LIMITER_ADD;
+
+ nlattr_add_u32(nw, PF_SCL_ID, attrs.id);
+
+ if (!nlmsg_end(nw))
+ return (ENOMEM);
+
+ return (error);
+}
+
+static int
+pf_handle_source_limiter_get(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pfioc_sourcelim attrs = { 0 };
+ struct nl_writer *nw = npt->nw;
+ struct genlmsghdr *ghdr = (struct genlmsghdr *)(hdr + 1);
+ struct genlmsghdr *ghdr_new;
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &source_limiter_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ error = pf_sourcelim_get(&attrs,
+ ghdr->cmd == PFNL_CMD_SOURCE_LIMITER_GET ? pf_sourcelim_rb_find :
+ pf_sourcelim_rb_nfind);
+ if (error != 0)
+ return (error);
+
+ if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
+ return (ENOMEM);
+
+ ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
+ ghdr_new->cmd = ghdr->cmd;
+
+ nlattr_add_string(nw, PF_SCL_NAME, attrs.name);
+ nlattr_add_u32(nw, PF_SCL_ID, attrs.id);
+ nlattr_add_u32(nw, PF_SCL_ENTRIES, attrs.entries);
+ nlattr_add_u32(nw, PF_SCL_LIMIT, attrs.limit);
+ nlattr_add_limiter_rate(nw, PF_SCL_RATE, &attrs.rate);
+ nlattr_add_string(nw, PF_SCL_OVERLOAD_TBL_NAME, attrs.overload_tblname);
+ nlattr_add_u32(nw, PF_SCL_OVERLOAD_HIGH_WM, attrs.overload_hwm);
+ nlattr_add_u32(nw, PF_SCL_OVERLOAD_LOW_WM, attrs.overload_lwm);
+ nlattr_add_u32(nw, PF_SCL_INET_PREFIX, attrs.inet_prefix);
+ nlattr_add_u32(nw, PF_SCL_INET6_PREFIX, attrs.inet6_prefix);
+ nlattr_add_string(nw, PF_SCL_DESCR, attrs.description);
+ nlattr_add_u32(nw, PF_SCL_NENTRIES, attrs.nentries);
+ nlattr_add_u32(nw, PF_SCL_INUSE, attrs.inuse);
+ nlattr_add_u64(nw, PF_SCL_ADDR_ALLOCS, attrs.addrallocs);
+ nlattr_add_u64(nw, PF_SCL_ADDR_NOMEM, attrs.addrnomem);
+ nlattr_add_u64(nw, PF_SCL_ADMITTED, attrs.admitted);
+ nlattr_add_u64(nw, PF_SCL_ADDRLIMITED, attrs.addrlimited);
+ nlattr_add_u64(nw, PF_SCL_HARDLIMITED, attrs.hardlimited);
+ nlattr_add_u64(nw, PF_SCL_RATELIMITED, attrs.ratelimited);
+
+ if (!nlmsg_end(nw))
+ return (ENOMEM);
+
+ return (error);
+}
+
+struct nlattr_source {
+ char name[PF_SOURCELIM_NAME_LEN];
+ uint32_t id;
+ sa_family_t af;
+ unsigned int rdomain;
+ struct pf_addr addr;
+};
+#define _OUT(_field) offsetof(struct nlattr_source, _field)
+static const struct nlattr_parser nla_p_source[] = {
+ { .type = PF_SRC_NAME, .off = _OUT(name), .arg = (void *)PF_SOURCELIM_NAME_LEN, .cb = nlattr_get_chara },
+ { .type = PF_SRC_ID, .off = _OUT(id), .cb = nlattr_get_uint32 },
+ { .type = PF_SRC_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
+ { .type = PF_SRC_RDOMAIN, .off = _OUT(rdomain), .cb = nlattr_get_uint32 },
+ { .type = PF_SRC_ADDR, .off = _OUT(addr), .cb = nlattr_get_in6_addr },
+};
+#undef _OUT
+NL_DECLARE_PARSER(source_parser, struct genlmsghdr, nlf_p_empty, nla_p_source);
+
+static int
+pf_handle_source_get(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct nlattr_source attrs = { 0 };
+ struct pf_source key;
+ struct pf_sourcelim plkey;
+ struct nl_writer *nw = npt->nw;
+ struct genlmsghdr *ghdr = (struct genlmsghdr *)(hdr + 1);
+ struct genlmsghdr *ghdr_new;
+ struct pf_sourcelim *pfsrlim;
+ struct pf_source *pfsr;
+ int error;
+ PF_RULES_RLOCK_TRACKER;
+
+ error = nl_parse_nlmsg(hdr, &source_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ PF_RULES_RLOCK();
+ plkey.pfsrlim_id = attrs.id;
+ pfsrlim = pf_sourcelim_rb_find(&V_pf_sourcelim_id_tree_active, &plkey);
+ if (pfsrlim == NULL) {
+ error = ESRCH;
+ goto out;
+ }
+
+ key.pfsr_af = attrs.af;
+ key.pfsr_rdomain = attrs.rdomain;
+ key.pfsr_addr = attrs.addr;
+
+ pfsr = (ghdr->cmd == PFNL_CMD_SOURCE_GET ? pf_source_rb_find :
+ pf_source_rb_nfind)(&pfsrlim->pfsrlim_ioc_sources, &key);
+ if (pfsr == NULL) {
+ error = ENOENT;
+ goto out;
+ }
+
+ for (;;) {
+ if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
+ error = ENOMEM;
+ goto out;
+ }
+
+ ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
+ ghdr_new->cmd = ghdr->cmd;
+
+ nlattr_add_u8(nw, PF_SRC_AF, pfsr->pfsr_af);
+ nlattr_add_u32(nw, PF_SRC_RDOMAIN, pfsr->pfsr_rdomain);
+ nlattr_add_in6_addr(nw, PF_SRC_ADDR, &pfsr->pfsr_addr.v6);
+
+ nlattr_add_u32(nw, PF_SRC_INUSE, pfsr->pfsr_inuse);
+ nlattr_add_u64(nw, PF_SRC_ADMITTED, pfsr->pfsr_counters.admitted);
+ nlattr_add_u64(nw, PF_SRC_HARDLIMITED, pfsr->pfsr_counters.hardlimited);
+ nlattr_add_u64(nw, PF_SRC_RATELIMITED, pfsr->pfsr_counters.ratelimited);
+
+ nlattr_add_u32(nw, PF_SRC_LIMIT, pfsrlim->pfsrlim_limit);
+ nlattr_add_u32(nw, PF_SRC_INET_PREFIX, pfsrlim->pfsrlim_ipv4_prefix);
+ nlattr_add_u32(nw, PF_SRC_INET6_PREFIX, pfsrlim->pfsrlim_ipv6_prefix);
+
+ if (!nlmsg_end(nw)) {
+ nlmsg_abort(nw);
+ error = ENOMEM;
+ goto out;
+ }
+
+ pfsr = RB_NEXT(pf_source_ioc_tree, srlim->pfsrlim_ioc_sources, pfsr);
+ if (pfsr == NULL)
+ break;
+ }
+
+out:
+ PF_RULES_RUNLOCK();
+ return (error);
+}
+
+
+#define _OUT(_field) offsetof(struct pfioc_source_kill, _field)
+static const struct nlattr_parser nla_p_source_clear[] = {
+ { .type = PF_SC_NAME, .off = _OUT(name), .arg = (void *)PF_SOURCELIM_NAME_LEN, .cb = nlattr_get_chara },
+ { .type = PF_SC_ID, .off = _OUT(id), .cb = nlattr_get_uint32 },
+ { .type = PF_SC_RDOMAIN, .off = _OUT(rdomain), .cb = nlattr_get_uint32 },
+ { .type = PF_SC_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
+ { .type = PF_SC_ADDR, .off = _OUT(addr), .cb = nlattr_get_in6_addr },
+};
+#undef _OUT
+NL_DECLARE_PARSER(source_clear_parser, struct genlmsghdr, nlf_p_empty, nla_p_source_clear);
+
+static int
+pf_handle_source_clear(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pfioc_source_kill attrs = { 0 };
+ struct nl_writer *nw = npt->nw;
+ struct genlmsghdr *ghdr = (struct genlmsghdr *)(hdr + 1);
+ struct genlmsghdr *ghdr_new;
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &source_clear_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ error = pf_source_clr(&attrs);
+ if (error != 0)
+ return (error);
+
+ if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
+ return (ENOMEM);
+
+ ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
+ ghdr_new->cmd = ghdr->cmd;
+
+ nlattr_add_string(nw, PF_SCL_NAME, attrs.name);
+
+ if (!nlmsg_end(nw))
+ return (ENOMEM);
+
+ return (error);
+}
+
static const struct nlhdr_parser *all_parsers[] = {
&state_parser,
&addrule_parser,
@@ -2479,6 +2819,10 @@ static const struct nlhdr_parser *all_parsers[] = {
&table_parser,
&table_addr_parser,
&table_astats_parser,
+ &state_limiter_parser,
+ &source_limiter_parser,
+ &source_parser,
+ &source_clear_parser,
};
static uint16_t family_id;
@@ -2743,6 +3087,69 @@ static const struct genl_cmd pf_cmds[] = {
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
.cmd_priv = PRIV_NETINET_PF,
},
+ {
+ .cmd_num = PFNL_CMD_STATE_LIMITER_ADD,
+ .cmd_name = "STATE_LIMITER_ADD",
+ .cmd_cb = pf_handle_state_limiter_add,
+ .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_STATE_LIMITER_GET,
+ .cmd_name = "STATE_LIMITER_GET",
+ .cmd_cb = pf_handle_state_limiter_get,
+ .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_STATE_LIMITER_NGET,
+ .cmd_name = "STATE_LIMITER_NGET",
+ .cmd_cb = pf_handle_state_limiter_get,
+ .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_SOURCE_LIMITER_ADD,
+ .cmd_name = "SOURCE_LIMITER_ADD",
+ .cmd_cb = pf_handle_source_limiter_add,
+ .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_SOURCE_LIMITER_GET,
+ .cmd_name = "SOURCE_LIMITER_GET",
+ .cmd_cb = pf_handle_source_limiter_get,
+ .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_SOURCE_LIMITER_NGET,
+ .cmd_name = "SOURCE_LIMITER_NGET",
+ .cmd_cb = pf_handle_source_limiter_get,
+ .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_SOURCE_GET,
+ .cmd_name = "SOURCE_GET",
+ .cmd_cb = pf_handle_source_get,
+ .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_SOURCE_NGET,
+ .cmd_name = "SOURCE_NGET",
+ .cmd_cb = pf_handle_source_get,
+ .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_SOURCE_CLEAR,
+ .cmd_name = "SOURCE_CLEAR",
+ .cmd_cb = pf_handle_source_clear,
+ .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
};
void
diff --git a/sys/netpfil/pf/pf_nl.h b/sys/netpfil/pf/pf_nl.h
index d45766b91a30..696b81f9434e 100644
--- a/sys/netpfil/pf/pf_nl.h
+++ b/sys/netpfil/pf/pf_nl.h
@@ -73,6 +73,15 @@ enum {
PFNL_CMD_TABLE_GET_ADDR = 35,
PFNL_CMD_TABLE_GET_ASTATS = 36,
PFNL_CMD_TABLE_CLEAR_ASTATS = 37,
+ PFNL_CMD_STATE_LIMITER_ADD = 38,
+ PFNL_CMD_STATE_LIMITER_GET = 39,
+ PFNL_CMD_STATE_LIMITER_NGET = 40,
+ PFNL_CMD_SOURCE_LIMITER_ADD = 41,
+ PFNL_CMD_SOURCE_LIMITER_GET = 42,
+ PFNL_CMD_SOURCE_LIMITER_NGET = 43,
+ PFNL_CMD_SOURCE_GET = 44,
+ PFNL_CMD_SOURCE_NGET = 45,
+ PFNL_CMD_SOURCE_CLEAR = 46,
__PFNL_CMD_MAX,
};
#define PFNL_CMD_MAX (__PFNL_CMD_MAX -1)
@@ -509,6 +518,76 @@ enum pf_table_astats_t {
PF_TAS_ASTATS_COUNT = 4, /* u32 */
PF_TAS_ASTATS_ZEROED = 5, /* u32 */
};
+
+enum pf_limit_rate_t {
+ PF_LR_UNSPEC,
+ PF_LR_LIMIT = 1, /* u32 */
+ PF_LR_SECONDS = 2, /* u32 */
+};
+
+enum pf_state_limit_t {
+ PF_SL_UNSPEC,
+ PF_SL_TICKET = 1, /* u32 */
+ PF_SL_NAME = 2, /* string */
+ PF_SL_ID = 3, /* u32 */
+ PF_SL_LIMIT = 4, /* u32 */
+ PF_SL_RATE = 5, /* nested, pf_limit_rate_t */
+ PF_SL_DESCR = 6, /* string */
+ PF_SL_INUSE = 7, /* u32 */
+ PF_SL_ADMITTED = 8, /* u64 */
+ PF_SL_HARDLIMITED = 9, /* u64 */
+ PF_SL_RATELIMITED = 10, /* u64 */
+};
+
+enum pf_source_limit_t {
+ PF_SCL_UNSPEC,
+ PF_SCL_TICKET = 1, /* u32 */
+ PF_SCL_NAME = 2, /* string */
+ PF_SCL_ID = 3, /* u32 */
+ PF_SCL_ENTRIES = 4, /* u32 */
+ PF_SCL_LIMIT = 5, /* u32 */
+ PF_SCL_RATE = 6, /* nested, pf_limit_rate_t */
+ PF_SCL_OVERLOAD_TBL_NAME = 7, /* string*/
+ PF_SCL_OVERLOAD_HIGH_WM = 8, /* u32 */
+ PF_SCL_OVERLOAD_LOW_WM = 9, /* u32 */
+ PF_SCL_INET_PREFIX = 10, /* u32 */
+ PF_SCL_INET6_PREFIX = 11, /* u32 */
+ PF_SCL_DESCR = 12, /* string */
+ PF_SCL_NENTRIES = 13, /* u32 */
+ PF_SCL_INUSE = 14, /* u32 */
+ PF_SCL_ADDR_ALLOCS = 15, /* u64 */
+ PF_SCL_ADDR_NOMEM = 16, /* u64 */
+ PF_SCL_ADMITTED = 17, /* u64 */
+ PF_SCL_ADDRLIMITED = 18, /* u64 */
+ PF_SCL_HARDLIMITED = 19, /* u64 */
+ PF_SCL_RATELIMITED = 20, /* u64 */
+};
+
+enum pf_source_t {
+ PF_SRC_UNSPEC,
+ PF_SRC_NAME = 1, /* string */
+ PF_SRC_ID = 2, /* u32 */
+ PF_SRC_AF = 3, /* u8 */
+ PF_SRC_RDOMAIN = 4, /* u32 */
+ PF_SRC_ADDR = 5, /* in6_addr */
+ PF_SRC_INUSE = 6, /* u32 */
+ PF_SRC_ADMITTED = 7, /* u64 */
+ PF_SRC_HARDLIMITED = 8, /* u64 */
+ PF_SRC_RATELIMITED = 9, /* u64 */
+ PF_SRC_LIMIT = 10, /* u32 */
+ PF_SRC_INET_PREFIX = 11, /* u32 */
+ PF_SRC_INET6_PREFIX = 12, /* u32 */
+};
+
+enum pf_source_clear_t {
+ PF_SC_UNSPEC,
+ PF_SC_NAME = 1, /* string */
+ PF_SC_ID = 2, /* u32*/
+ PF_SC_RDOMAIN = 3, /* u32 */
+ PF_SC_AF = 4, /* u8 */
+ PF_SC_ADDR = 5, /* in6_addr */
+};
+
#ifdef _KERNEL
void pf_nl_register(void);