diff options
| author | Kristof Provost <kp@FreeBSD.org> | 2026-01-06 21:33:31 +0000 |
|---|---|---|
| committer | Kristof Provost <kp@FreeBSD.org> | 2026-01-14 06:44:39 +0000 |
| commit | c72fb110e47f5a52e64683a8759a11eb69b34bd3 (patch) | |
| tree | 4bae4f8dd2268403f4d846c397c03bfdf29afff4 | |
| parent | 4616481212302b5d875cfc7a00766af017318f7f (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.c | 314 | ||||
| -rw-r--r-- | lib/libpfctl/libpfctl.h | 99 | ||||
| -rw-r--r-- | sbin/pfctl/pfctl.c | 189 | ||||
| -rw-r--r-- | sbin/pfctl/pfctl_parser.c | 4 | ||||
| -rw-r--r-- | sbin/pfctl/pfctl_parser.h | 8 | ||||
| -rw-r--r-- | sys/net/pfvar.h | 108 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf_ioctl.c | 163 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf_nl.c | 407 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf_nl.h | 79 |
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); |
