Skip to content

Commit

Permalink
pf: convert DIOCGETADDR to netlink
Browse files Browse the repository at this point in the history
Sponsored by:	Rubicon Communications, LLC ("Netgate")
  • Loading branch information
kprovost committed Jul 22, 2024
1 parent 644b7b5 commit 9ae91f5
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 34 deletions.
63 changes: 63 additions & 0 deletions lib/libpfctl/libpfctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2833,3 +2833,66 @@ pfctl_get_addrs(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num,

return (e.error);
}

#define _OUT(_field) offsetof(struct pf_pooladdr, _field)
static const struct snl_attr_parser ap_pool_addr[] = {
{ .type = PF_PA_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = snl_attr_get_nested },
{ .type = PF_PA_IFNAME, .off = _OUT(ifname), .arg_u32 = IFNAMSIZ, .cb = snl_attr_copy_string },
};
SNL_DECLARE_ATTR_PARSER(pool_addr_parser, ap_pool_addr);
#undef _OUT

#define _OUT(_field) offsetof(struct pfioc_pooladdr, _field)
static const struct snl_attr_parser ap_get_addr[] = {
{ .type = PF_AA_ACTION, .off = _OUT(action), .cb = snl_attr_get_uint32 },
{ .type = PF_AA_TICKET, .off = _OUT(ticket), .cb = snl_attr_get_uint32 },
{ .type = PF_AA_NR, .off = _OUT(nr), .cb = snl_attr_get_uint32 },
{ .type = PF_AA_R_NUM, .off = _OUT(r_num), .cb = snl_attr_get_uint32 },
{ .type = PF_AA_R_ACTION, .off = _OUT(r_action), .cb = snl_attr_get_uint8 },
{ .type = PF_AA_R_LAST, .off = _OUT(r_last), .cb = snl_attr_get_uint8 },
{ .type = PF_AA_AF, .off = _OUT(af), .cb = snl_attr_get_uint8 },
{ .type = PF_AA_ANCHOR, .off = _OUT(anchor), .arg_u32 = MAXPATHLEN, .cb = snl_attr_copy_string },
{ .type = PF_AA_ADDR, .off = _OUT(addr), .arg = &pool_addr_parser, .cb = snl_attr_get_nested },
};
static struct snl_field_parser fp_get_addr[] = {};
SNL_DECLARE_PARSER(get_addr_parser, struct genlmsghdr, fp_get_addr, ap_get_addr);
#undef _OUT

int
pfctl_get_addr(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num,
uint8_t r_action, const char *anchor, uint32_t nr, struct pfioc_pooladdr *pa)
{
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_GET_ADDR);

snl_add_msg_attr_u32(&nw, PF_AA_TICKET, ticket);
snl_add_msg_attr_u32(&nw, PF_AA_R_NUM, r_num);
snl_add_msg_attr_u8(&nw, PF_AA_R_ACTION, r_action);
snl_add_msg_attr_string(&nw, PF_AA_ANCHOR, anchor);
snl_add_msg_attr_u32(&nw, PF_AA_NR, nr);

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, &get_addr_parser, pa))
continue;
}

return (0);
}
2 changes: 2 additions & 0 deletions lib/libpfctl/libpfctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -501,5 +501,7 @@ int pfctl_begin_addrs(struct pfctl_handle *h, uint32_t *ticket);
int pfctl_add_addr(struct pfctl_handle *h, const struct pfioc_pooladdr *pa);
int pfctl_get_addrs(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num,
uint8_t r_action, const char *anchor, uint32_t *nr);
int pfctl_get_addr(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num,
uint8_t r_action, const char *anchor, uint32_t nr, struct pfioc_pooladdr *pa);

#endif
11 changes: 3 additions & 8 deletions sbin/pfctl/pfctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -964,19 +964,14 @@ pfctl_get_pool(int dev, struct pfctl_pool *pool, u_int32_t nr,
u_int32_t pnr, mpnr;

memset(&pp, 0, sizeof(pp));
memcpy(pp.anchor, anchorname, sizeof(pp.anchor));
pp.r_action = r_action;
pp.r_num = nr;
pp.ticket = ticket;
if (pfctl_get_addrs(pfh, ticket, nr, r_action, anchorname, &pp.nr) != 0) {
if (pfctl_get_addrs(pfh, ticket, nr, r_action, anchorname, &mpnr) != 0) {
warn("DIOCGETADDRS");
return (-1);
}
mpnr = pp.nr;

TAILQ_INIT(&pool->list);
for (pnr = 0; pnr < mpnr; ++pnr) {
pp.nr = pnr;
if (ioctl(dev, DIOCGETADDR, &pp)) {
if (pfctl_get_addr(pfh, ticket, nr, r_action, anchorname, pnr, &pp) != 0) {
warn("DIOCGETADDR");
return (-1);
}
Expand Down
1 change: 1 addition & 0 deletions sys/net/pfvar.h
Original file line number Diff line number Diff line change
Expand Up @@ -2529,6 +2529,7 @@ int pf_ioctl_set_limit(int, unsigned int, unsigned int *);
int pf_ioctl_begin_addrs(uint32_t *);
int pf_ioctl_add_addr(struct pfioc_pooladdr *);
int pf_ioctl_get_addrs(struct pfioc_pooladdr *);
int pf_ioctl_get_addr(struct pfioc_pooladdr *);

void pf_krule_free(struct pf_krule *);
void pf_krule_clear_counters(struct pf_krule *);
Expand Down
61 changes: 35 additions & 26 deletions sys/netpfil/pf/pf_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2614,6 +2614,40 @@ pf_ioctl_get_addrs(struct pfioc_pooladdr *pp)
return (0);
}

int
pf_ioctl_get_addr(struct pfioc_pooladdr *pp)
{
struct pf_kpool *pool;
struct pf_kpooladdr *pa;
u_int32_t nr = 0;

PF_RULES_RLOCK_TRACKER;

pp->anchor[sizeof(pp->anchor) - 1] = 0;

PF_RULES_RLOCK();
pool = pf_get_kpool(pp->anchor, pp->ticket, pp->r_action,
pp->r_num, 0, 1, 1);
if (pool == NULL) {
PF_RULES_RUNLOCK();
return (EBUSY);
}
pa = TAILQ_FIRST(&pool->list);
while ((pa != NULL) && (nr < pp->nr)) {
pa = TAILQ_NEXT(pa, entries);
nr++;
}
if (pa == NULL) {
PF_RULES_RUNLOCK();
return (EBUSY);
}
pf_kpooladdr_to_pooladdr(pa, &pp->addr);
pf_addr_copyout(&pp->addr.addr);
PF_RULES_RUNLOCK();

return (0);
}

static int
pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
{
Expand Down Expand Up @@ -4299,33 +4333,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td

case DIOCGETADDR: {
struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
struct pf_kpool *pool;
struct pf_kpooladdr *pa;
u_int32_t nr = 0;

pp->anchor[sizeof(pp->anchor) - 1] = 0;

PF_RULES_RLOCK();
pool = pf_get_kpool(pp->anchor, pp->ticket, pp->r_action,
pp->r_num, 0, 1, 1);
if (pool == NULL) {
PF_RULES_RUNLOCK();
error = EBUSY;
break;
}
pa = TAILQ_FIRST(&pool->list);
while ((pa != NULL) && (nr < pp->nr)) {
pa = TAILQ_NEXT(pa, entries);
nr++;
}
if (pa == NULL) {
PF_RULES_RUNLOCK();
error = EBUSY;
break;
}
pf_kpooladdr_to_pooladdr(pa, &pp->addr);
pf_addr_copyout(&pp->addr.addr);
PF_RULES_RUNLOCK();
error = pf_ioctl_get_addr(pp);
break;
}

Expand Down
49 changes: 49 additions & 0 deletions sys/netpfil/pf/pf_nl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1597,6 +1597,48 @@ pf_handle_get_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
return (error);
}

static int
pf_handle_get_addr(struct nlmsghdr *hdr, struct nl_pstate *npt)
{
struct pfioc_pooladdr attrs = { 0 };
struct nl_writer *nw = npt->nw;
struct genlmsghdr *ghdr_new;
int error;

error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs);
if (error != 0)
return (error);

error = pf_ioctl_get_addr(&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_GET_ADDRS;
ghdr_new->version = 0;
ghdr_new->reserved = 0;

nlattr_add_u32(nw, PF_AA_ACTION, attrs.action);
nlattr_add_u32(nw, PF_AA_TICKET, attrs.ticket);
nlattr_add_u32(nw, PF_AA_NR, attrs.nr);
nlattr_add_u32(nw, PF_AA_R_NUM, attrs.r_num);
nlattr_add_u8(nw, PF_AA_R_ACTION, attrs.r_action);
nlattr_add_u8(nw, PF_AA_R_LAST, attrs.r_last);
nlattr_add_u8(nw, PF_AA_AF, attrs.af);
nlattr_add_string(nw, PF_AA_ANCHOR, attrs.anchor);
nlattr_add_pool_addr(nw, PF_AA_ADDR, &attrs.addr);

if (!nlmsg_end(nw)) {
nlmsg_abort(nw);
return (ENOMEM);
}

return (0);
}

static const struct nlhdr_parser *all_parsers[] = {
&state_parser,
&addrule_parser,
Expand Down Expand Up @@ -1761,6 +1803,13 @@ 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_GET_ADDR,
.cmd_name = "GET_ADDRS",
.cmd_cb = pf_handle_get_addr,
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
.cmd_priv = PRIV_NETINET_PF,
},
};

void
Expand Down
1 change: 1 addition & 0 deletions sys/netpfil/pf/pf_nl.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ enum {
PFNL_CMD_BEGIN_ADDRS = 19,
PFNL_CMD_ADD_ADDR = 20,
PFNL_CMD_GET_ADDRS = 21,
PFNL_CMD_GET_ADDR = 22,
__PFNL_CMD_MAX,
};
#define PFNL_CMD_MAX (__PFNL_CMD_MAX -1)
Expand Down

0 comments on commit 9ae91f5

Please sign in to comment.