pf: convert DIOCRGETADDRS to netlink

Sponsored by:	Rubicon Communications, LLC ("Netgate")
This commit is contained in:
Kristof Provost committed 2025-11-05 14:59:29 +01:00
1 parent 9bb1c46b4c
commit f27e44e2e3
5 files changed
+175 -1

No files matched your search

+82
View File
@@ -2742,6 +2742,88 @@ int pfctl_table_get_addrs(int dev, struct pfr_table *tbl, struct pfr_addr *addr,
return (0);
}
struct nl_addrs {
size_t max;
struct pfr_addr *addrs;
size_t count;
size_t total_count;
};
#define _OUT(_field) offsetof(struct pfr_addr, _field)
static const struct snl_attr_parser ap_pfr_addr[] = {
{ .type = PFR_A_AF, .off = _OUT(pfra_af), .cb = snl_attr_get_uint32 },
{ .type = PFR_A_NET, .off = _OUT(pfra_net), .cb = snl_attr_get_uint8 },
{ .type = PFR_A_NOT, .off = _OUT(pfra_not), .cb = snl_attr_get_bool },
{ .type = PFR_A_ADDR, .off = _OUT(pfra_ip6addr), .cb = snl_attr_get_in6_addr },
};
#undef _OUT
SNL_DECLARE_ATTR_PARSER(pfr_addr_parser, ap_pfr_addr);
static bool
snl_attr_get_pfr_addrs(struct snl_state *ss, struct nlattr *nla,
const void *arg __unused, void *target)
{
struct nl_addrs *a = (struct nl_addrs *)target;
bool ret;
if (a->count >= a->max)
return (false);
ret = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla),
&pfr_addr_parser, &a->addrs[a->count]);
if (ret)
a->count++;
return (ret);
}
#define _OUT(_field) offsetof(struct nl_addrs, _field)
static struct snl_attr_parser ap_table_get_addr[] = {
{ .type = PF_TA_ADDR, .off = 0, .cb = snl_attr_get_pfr_addrs },
{ .type = PF_TA_ADDR_COUNT, .off = _OUT(total_count), .cb = snl_attr_get_uint32 },
};
#undef _OUT
SNL_DECLARE_PARSER(table_get_addr_parser, struct genlmsghdr, snl_f_p_empty, ap_table_get_addr);
int
pfctl_table_get_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl,
struct pfr_addr *addr, int *size, int flags)
{
struct nl_addrs addrs = { 0 };
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_TABLE_GET_ADDR);
snl_add_msg_attr_table(&nw, PF_TA_TABLE, tbl);
snl_add_msg_attr_u32(&nw, PF_TA_FLAGS, flags);
if ((hdr = snl_finalize_msg(&nw)) == NULL)
return (ENXIO);
seq_id = hdr->nlmsg_seq;
if (! snl_send_message(&h->ss, hdr))
return (ENXIO);
addrs.addrs = addr;
addrs.max = *size;
while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
if (! snl_parse_nlmsg(&h->ss, hdr, &table_get_addr_parser, &addrs))
continue;
}
*size = addrs.total_count;
return (e.error);
}
int
pfctl_set_statusif(struct pfctl_handle *h, const char *ifname)
{
+2
View File
@@ -529,6 +529,8 @@ int pfctl_table_set_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl,
int pfctl_table_set_addrs(int dev, struct pfr_table *tbl, struct pfr_addr
*addr, int size, int *size2, int *nadd, int *ndel, int *nchange,
int flags);
int pfctl_table_get_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl, struct pfr_addr *addr,
int *size, int flags);
int pfctl_table_get_addrs(int dev, struct pfr_table *tbl, struct pfr_addr
*addr, int *size, int flags);
int pfctl_set_statusif(struct pfctl_handle *h, const char *ifname);
+1 -1
View File
@@ -182,7 +182,7 @@ pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
{
int ret;
ret = pfctl_table_get_addrs(dev, tbl, addr, size, flags);
ret = pfctl_table_get_addrs_h(pfh, tbl, addr, size, flags);
if (ret) {
errno = ret;
return (-1);
+88
View File
@@ -2246,6 +2246,87 @@ pf_handle_table_set_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
return (error);
}
static int
nlattr_add_pfr_addr(struct nl_writer *nw, int attr, const struct pfr_addr *a)
{
int off = nlattr_add_nested(nw, attr);
if (off == 0)
return (false);
nlattr_add_u32(nw, PFR_A_AF, a->pfra_af);
nlattr_add_u8(nw, PFR_A_NET, a->pfra_net);
nlattr_add_bool(nw, PFR_A_NOT, a->pfra_not);
nlattr_add_in6_addr(nw, PFR_A_ADDR, &a->pfra_u._pfra_ip6addr);
nlattr_set_len(nw, off);
return (true);
}
static int
pf_handle_table_get_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
{
struct pfioc_table attrs = { 0 };
struct pfr_addr *pfras;
struct nl_writer *nw = npt->nw;
struct genlmsghdr *ghdr_new;
int size = 0;
int error;
PF_RULES_RLOCK_TRACKER;
error = nl_parse_nlmsg(hdr, &table_addr_parser, npt, &attrs);
if (error != 0)
return (error);
PF_RULES_RLOCK();
/* Get required size. */
error = pfr_get_addrs(&attrs.pfrio_table, NULL,
&size, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
if (error != 0) {
PF_RULES_RUNLOCK();
return (error);
}
pfras = mallocarray(size, sizeof(struct pfr_addr), M_PF,
M_NOWAIT | M_ZERO);
if (pfras == NULL) {
PF_RULES_RUNLOCK();
return (ENOMEM);
}
/* Now get the addresses. */
error = pfr_get_addrs(&attrs.pfrio_table, pfras,
&size, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
PF_RULES_RUNLOCK();
if (error != 0)
goto out;
for (int i = 0; i < size; i++) {
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
nlmsg_abort(nw);
error = ENOMEM;
goto out;
}
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
ghdr_new->cmd = PFNL_CMD_TABLE_GET_ADDR;
ghdr_new->version = 0;
ghdr_new->reserved = 0;
if (i == 0)
nlattr_add_u32(nw, PF_TA_ADDR_COUNT, size);
nlattr_add_pfr_addr(nw, PF_TA_ADDR, &pfras[i]);
if (!nlmsg_end(nw)) {
nlmsg_abort(nw);
error = ENOMEM;
goto out;
}
}
out:
free(pfras, M_PF);
return (error);
}
static const struct nlhdr_parser *all_parsers[] = {
&state_parser,
&addrule_parser,
@@ -2504,6 +2585,13 @@ static const struct genl_cmd pf_cmds[] = {
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
.cmd_priv = PRIV_NETINET_PF,
},
{
.cmd_num = PFNL_CMD_TABLE_GET_ADDR,
.cmd_name = "TABLE_GET_ADDRS",
.cmd_cb = pf_handle_table_get_addrs,
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
.cmd_priv = PRIV_NETINET_PF,
},
};
void
+2
View File
@@ -70,6 +70,7 @@ enum {
PFNL_CMD_TABLE_ADD_ADDR = 32,
PFNL_CMD_TABLE_DEL_ADDR = 33,
PFNL_CMD_TABLE_SET_ADDR = 34,
PFNL_CMD_TABLE_GET_ADDR = 35,
__PFNL_CMD_MAX,
};
#define PFNL_CMD_MAX (__PFNL_CMD_MAX -1)
@@ -485,6 +486,7 @@ enum pf_table_addrs_t {
PF_TA_NBR_ADDED = 4, /* u32 */
PF_TA_NBR_DELETED = 5, /* u32 */
PF_TA_NBR_CHANGED = 6, /* u32 */
PF_TA_ADDR_COUNT = 7, /* u32 */
};
#ifdef _KERNEL