aboutsummaryrefslogtreecommitdiff
path: root/lib/libpfctl/libpfctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpfctl/libpfctl.c')
-rw-r--r--lib/libpfctl/libpfctl.c507
1 files changed, 499 insertions, 8 deletions
diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index 7e5a07ccd55a..59783592a370 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -69,12 +69,15 @@ const char* PFCTL_SYNCOOKIES_MODE_NAMES[] = {
static int _pfctl_clear_states(int , const struct pfctl_kill *,
unsigned int *, uint64_t);
+static void _pfctl_verify_parsers(void);
struct pfctl_handle *
pfctl_open(const char *pf_device)
{
struct pfctl_handle *h;
+ _pfctl_verify_parsers();
+
h = calloc(1, sizeof(struct pfctl_handle));
h->fd = open(pf_device, O_RDWR);
@@ -389,8 +392,8 @@ static const struct snl_attr_parser ap_getstatus[] = {
{ .type = PF_GS_FCOUNTERS, .off = _OUT(fcounters), .cb = snl_attr_get_counters },
{ .type = PF_GS_SCOUNTERS, .off = _OUT(scounters), .cb = snl_attr_get_counters },
{ .type = PF_GS_CHKSUM, .off = _OUT(pf_chksum), .arg_u32 = PF_MD5_DIGEST_LENGTH, .cb = snl_attr_get_bytes },
- { .type = PF_GS_BCOUNTERS, .off = _OUT(bcounters), .arg_u32 = 2 * 2, .cb = snl_attr_get_uint64_array },
{ .type = PF_GS_PCOUNTERS, .off = _OUT(pcounters), .arg_u32 = 2 * 2 * 2, .cb = snl_attr_get_uint64_array },
+ { .type = PF_GS_BCOUNTERS, .off = _OUT(bcounters), .arg_u32 = 2 * 2, .cb = snl_attr_get_uint64_array },
{ .type = PF_GS_NCOUNTERS, .off = _OUT(ncounters), .cb = snl_attr_get_counters },
{ .type = PF_GS_FRAGMENTS, .off = _OUT(fragments), .cb = snl_attr_get_uint64 },
};
@@ -1313,6 +1316,11 @@ snl_add_msg_attr_pf_rule(struct snl_writer *nw, uint32_t type, const struct pfct
snl_add_msg_attr_ip6(nw, PF_RT_DIVERT_ADDRESS, &r->divert.addr.v6);
snl_add_msg_attr_u16(nw, PF_RT_DIVERT_PORT, r->divert.port);
+ snl_add_msg_attr_u8(nw, PF_RT_STATE_LIMIT, r->statelim.id);
+ snl_add_msg_attr_u32(nw, PF_RT_STATE_LIMIT_ACTION, r->statelim.limiter_action);
+ snl_add_msg_attr_u8(nw, PF_RT_SOURCE_LIMIT, r->sourcelim.id);
+ snl_add_msg_attr_u32(nw, PF_RT_SOURCE_LIMIT_ACTION, r->sourcelim.limiter_action);
+
snl_end_attr_nested(nw, off);
}
@@ -1704,6 +1712,10 @@ static struct snl_attr_parser ap_getrule[] = {
{ .type = PF_RT_TYPE_2, .off = _OUT(r.type), .cb = snl_attr_get_uint16 },
{ .type = PF_RT_CODE_2, .off = _OUT(r.code), .cb = snl_attr_get_uint16 },
{ .type = PF_RT_EXPTIME, .off = _OUT(r.exptime), .cb = snl_attr_get_time_t },
+ { .type = PF_RT_STATE_LIMIT, .off = _OUT(r.statelim.id), .cb = snl_attr_get_uint8 },
+ { .type = PF_RT_SOURCE_LIMIT, .off = _OUT(r.sourcelim.id), .cb = snl_attr_get_uint8 },
+ { .type = PF_RT_STATE_LIMIT_ACTION, .off = _OUT(r.statelim.limiter_action), .cb = snl_attr_get_uint32 },
+ { .type = PF_RT_SOURCE_LIMIT_ACTION, .off = _OUT(r.sourcelim.limiter_action), .cb = snl_attr_get_uint32 },
};
#undef _OUT
SNL_DECLARE_PARSER(getrule_parser, struct genlmsghdr, snl_f_p_empty, ap_getrule);
@@ -1956,15 +1968,9 @@ static struct snl_attr_parser ap_state[] = {
#undef _OUT
SNL_DECLARE_PARSER(state_parser, struct genlmsghdr, snl_f_p_empty, ap_state);
-static const struct snl_hdr_parser *all_parsers[] = {
- &state_parser, &skey_parser, &speer_parser,
- &creator_parser, &getrules_parser
-};
-
int
pfctl_get_states_h(struct pfctl_handle *h, struct pfctl_state_filter *filter, pfctl_get_state_fn f, void *arg)
{
- SNL_VERIFY_PARSERS(all_parsers);
int family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
int ret;
@@ -3757,7 +3763,8 @@ struct nl_astats {
struct pfr_astats *a;
size_t max;
size_t count;
- uint64_t total_count;
+ uint32_t total_count;
+ uint32_t zeroed;
};
#define _OUT(_field) offsetof(struct pfr_astats, _field)
@@ -3792,6 +3799,7 @@ snl_attr_get_pfr_astats(struct snl_state *ss, struct nlattr *nla,
static struct snl_attr_parser ap_table_get_astats[] = {
{ .type = PF_TAS_ASTATS, .off = 0, .cb = snl_attr_get_pfr_astats },
{ .type = PF_TAS_ASTATS_COUNT, .off = _OUT(total_count), .cb = snl_attr_get_uint32 },
+ { .type = PF_TAS_ASTATS_ZEROED, .off = _OUT(zeroed), .cb = snl_attr_get_uint32 },
};
#undef _OUT
SNL_DECLARE_PARSER(table_astats_parser, struct genlmsghdr, snl_f_p_empty, ap_table_get_astats);
@@ -3843,3 +3851,486 @@ pfctl_get_astats(struct pfctl_handle *h, const struct pfr_table *tbl,
return (0);
}
+
+static int
+_pfctl_clr_astats(struct pfctl_handle *h, const struct pfr_table *tbl,
+ struct pfr_addr *addrs, int size, int *nzero, int flags)
+{
+ struct snl_writer nw;
+ struct snl_errmsg_data e = {};
+ struct nlmsghdr *hdr;
+ uint32_t seq_id;
+ struct nl_astats attrs;
+ 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_TABLE_CLEAR_ASTATS);
+
+ snl_add_msg_attr_table(&nw, PF_TA_TABLE, tbl);
+ snl_add_msg_attr_u32(&nw, PF_TA_FLAGS, flags);
+ for (int i = 0; i < size; i++)
+ snl_add_msg_attr_pfr_addr(&nw, PF_TA_ADDR, &addrs[i]);
+
+ 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, &table_astats_parser, &attrs))
+ continue;
+ }
+
+ if (nzero)
+ *nzero = attrs.zeroed;
+
+ return (e.error);
+}
+
+int
+pfctl_clr_astats(struct pfctl_handle *h, const struct pfr_table *tbl,
+ struct pfr_addr *addrs, int size, int *nzero, int flags)
+{
+ int ret;
+ int off = 0;
+ int partial_zeroed;
+ int chunk_size;
+
+ do {
+ chunk_size = MIN(size - off, 256);
+ ret = _pfctl_clr_astats(h, tbl, &addrs[off], chunk_size,
+ &partial_zeroed, flags);
+ if (ret != 0)
+ break;
+ if (nzero)
+ *nzero += partial_zeroed;
+ off += chunk_size;
+ } while (off < size);
+
+ return (ret);
+}
+
+static int
+_pfctl_test_addrs(struct pfctl_handle *h, const struct pfr_table *tbl,
+ struct pfr_addr *addrs, int size, int *nmatch, int flags)
+{
+ struct snl_writer nw;
+ struct snl_errmsg_data e = {};
+ struct nlmsghdr *hdr;
+ uint32_t seq_id;
+ struct nl_astats attrs;
+ 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_TABLE_TEST_ADDRS);
+
+ snl_add_msg_attr_table(&nw, PF_TA_TABLE, tbl);
+ snl_add_msg_attr_u32(&nw, PF_TA_FLAGS, flags);
+ for (int i = 0; i < size; i++)
+ snl_add_msg_attr_pfr_addr(&nw, PF_TA_ADDR, &addrs[i]);
+
+ 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, &table_astats_parser, &attrs))
+ continue;
+ }
+
+ if (nmatch)
+ *nmatch = attrs.total_count;
+
+ return (e.error);
+}
+
+int
+pfctl_test_addrs(struct pfctl_handle *h, const struct pfr_table *tbl,
+ struct pfr_addr *addrs, int size, int *nmatch, int flags)
+{
+ int ret;
+ int off = 0;
+ int partial_match;
+ int chunk_size;
+
+ if (nmatch)
+ *nmatch = 0;
+
+ do {
+ chunk_size = MIN(size - off, 256);
+ ret = _pfctl_test_addrs(h, tbl, &addrs[off], chunk_size,
+ &partial_match, flags);
+ if (ret != 0)
+ break;
+ if (nmatch)
+ *nmatch += partial_match;
+ off += chunk_size;
+ } while (off < size);
+
+ 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);
+}
+
+static const struct snl_hdr_parser *all_parsers[] = {
+ &begin_addrs_parser,
+ &clear_states_parser,
+ &clr_addrs_parser,
+ &creator_parser,
+ &get_addr_parser,
+ &get_addrs_parser,
+ &get_limit_parser,
+ &get_timeout_parser,
+ &getrule_parser,
+ &getrules_parser,
+ &getstatus_parser,
+ &nadd_parser,
+ &natlook_parser,
+ &ndel_parser,
+ &ruleset_parser,
+ &skey_parser,
+ &source_parser,
+ &sourcelim_parser,
+ &speer_parser,
+ &srcnode_parser,
+ &state_parser,
+ &statelim_parser,
+ &table_add_addr_parser,
+ &table_astats_parser,
+ &table_del_addr_parser,
+ &table_get_addr_parser,
+ &table_set_addr_parser,
+ &tstats_clr_parser,
+ &tstats_parser,
+};
+
+static void
+_pfctl_verify_parsers(void)
+{
+ SNL_VERIFY_PARSERS(all_parsers);
+}