git: 44f323ecdec0 - main - pf: implement DIOCGETRULES via netlink
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 27 Nov 2023 20:37:11 UTC
The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=44f323ecdec02dc947c34d08c34b881fe2da1ba6 commit 44f323ecdec02dc947c34d08c34b881fe2da1ba6 Author: Kristof Provost <kp@FreeBSD.org> AuthorDate: 2023-11-24 23:42:44 +0000 Commit: Kristof Provost <kp@FreeBSD.org> CommitDate: 2023-11-27 20:36:49 +0000 pf: implement DIOCGETRULES via netlink Sponsored by: Rubicon Communications, LLC ("Netgate") --- lib/libpfctl/libpfctl.c | 57 ++++++++++++++++++++++++++++++---------- sys/net/pfvar.h | 1 + sys/netpfil/pf/pf_ioctl.c | 56 +++++++++++++++++++++++----------------- sys/netpfil/pf/pf_nl.c | 66 +++++++++++++++++++++++++++++++++++++++++++++-- sys/netpfil/pf/pf_nl.h | 9 +++++++ 5 files changed, 149 insertions(+), 40 deletions(-) diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c index a600031ec0a9..513d2d0f01be 100644 --- a/lib/libpfctl/libpfctl.c +++ b/lib/libpfctl/libpfctl.c @@ -1119,26 +1119,55 @@ pfctl_add_rule(int dev __unused, const struct pfctl_rule *r, const char *anchor, return (e.error); } +#define _IN(_field) offsetof(struct genlmsghdr, _field) +#define _OUT(_field) offsetof(struct pfctl_rules_info, _field) +static struct snl_attr_parser ap_getrules[] = { + { .type = PF_GR_NR, .off = _OUT(nr), .cb = snl_attr_get_uint32 }, + { .type = PF_GR_TICKET, .off = _OUT(ticket), .cb = snl_attr_get_uint32 }, +}; +static struct snl_field_parser fp_getrules[] = { +}; +#undef _IN +#undef _OUT +SNL_DECLARE_PARSER(getrules_parser, struct genlmsghdr, fp_getrules, ap_getrules); + int -pfctl_get_rules_info(int dev, struct pfctl_rules_info *rules, uint32_t ruleset, +pfctl_get_rules_info(int dev __unused, struct pfctl_rules_info *rules, uint32_t ruleset, const char *path) { - struct pfioc_rule pr; - int ret; + struct snl_state ss = {}; + struct snl_errmsg_data e = {}; + struct nlmsghdr *hdr; + struct snl_writer nw; + uint32_t seq_id; + int family_id; - bzero(&pr, sizeof(pr)); - if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor)) - return (E2BIG); + snl_init(&ss, NETLINK_GENERIC); + family_id = snl_get_genl_family(&ss, PFNL_FAMILY_NAME); + if (family_id == 0) + return (ENOTSUP); - pr.rule.action = ruleset; - ret = ioctl(dev, DIOCGETRULES, &pr); - if (ret != 0) - return (ret); + snl_init_writer(&ss, &nw); + hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GETRULES); + hdr->nlmsg_flags |= NLM_F_DUMP; - rules->nr = pr.nr; - rules->ticket = pr.ticket; + snl_add_msg_attr_string(&nw, PF_GR_ANCHOR, path); + snl_add_msg_attr_u8(&nw, PF_GR_ACTION, ruleset); - return (0); + hdr = snl_finalize_msg(&nw); + if (hdr == NULL) + return (ENOMEM); + + seq_id = hdr->nlmsg_seq; + if (! snl_send_message(&ss, hdr)) + return (ENXIO); + + while ((hdr = snl_read_reply_multi(&ss, seq_id, &e)) != NULL) { + if (! snl_parse_nlmsg(&ss, hdr, &getrules_parser, rules)) + continue; + } + + return (e.error); } int @@ -1368,7 +1397,7 @@ SNL_DECLARE_PARSER(state_parser, struct genlmsghdr, fp_state, ap_state); static const struct snl_hdr_parser *all_parsers[] = { &state_parser, &skey_parser, &speer_parser, - &creator_parser, + &creator_parser, &getrules_parser }; static int diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 4b10190bf9ea..48162b786a86 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -2473,6 +2473,7 @@ int pf_keth_anchor_nvcopyout( struct pf_keth_ruleset *pf_find_or_create_keth_ruleset(const char *); void pf_keth_anchor_remove(struct pf_keth_rule *); +int pf_ioctl_getrules(struct pfioc_rule *); int pf_ioctl_addrule(struct pf_krule *, uint32_t, uint32_t, const char *, const char *, uid_t uid, pid_t); diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index 1598939c2375..ec55d43d3800 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -2021,6 +2021,36 @@ pf_rule_to_krule(const struct pf_rule *rule, struct pf_krule *krule) return (0); } +int +pf_ioctl_getrules(struct pfioc_rule *pr) +{ + struct pf_kruleset *ruleset; + struct pf_krule *tail; + int rs_num; + + PF_RULES_WLOCK(); + ruleset = pf_find_kruleset(pr->anchor); + if (ruleset == NULL) { + PF_RULES_WUNLOCK(); + return (EINVAL); + } + rs_num = pf_get_ruleset_number(pr->rule.action); + if (rs_num >= PF_RULESET_MAX) { + PF_RULES_WUNLOCK(); + return (EINVAL); + } + tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, + pf_krulequeue); + if (tail) + pr->nr = tail->nr + 1; + else + pr->nr = 0; + pr->ticket = ruleset->rules[rs_num].active.ticket; + PF_RULES_WUNLOCK(); + + return (0); +} + int pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket, uint32_t pool_ticket, const char *anchor, const char *anchor_call, @@ -3117,33 +3147,11 @@ DIOCADDRULENV_error: case DIOCGETRULES: { struct pfioc_rule *pr = (struct pfioc_rule *)addr; - struct pf_kruleset *ruleset; - struct pf_krule *tail; - int rs_num; pr->anchor[sizeof(pr->anchor) - 1] = 0; - PF_RULES_WLOCK(); - ruleset = pf_find_kruleset(pr->anchor); - if (ruleset == NULL) { - PF_RULES_WUNLOCK(); - error = EINVAL; - break; - } - rs_num = pf_get_ruleset_number(pr->rule.action); - if (rs_num >= PF_RULESET_MAX) { - PF_RULES_WUNLOCK(); - error = EINVAL; - break; - } - tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr, - pf_krulequeue); - if (tail) - pr->nr = tail->nr + 1; - else - pr->nr = 0; - pr->ticket = ruleset->rules[rs_num].active.ticket; - PF_RULES_WUNLOCK(); + error = pf_ioctl_getrules(pr); + break; } diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c index fe5ded0e86a4..86cc5ba9cc91 100644 --- a/sys/netpfil/pf/pf_nl.c +++ b/sys/netpfil/pf/pf_nl.c @@ -635,7 +635,64 @@ pf_handle_addrule(struct nlmsghdr *hdr, struct nl_pstate *npt) return (error); } -static const struct nlhdr_parser *all_parsers[] = { &state_parser, &addrule_parser }; +struct nl_parsed_getrules { + char *anchor; + uint8_t action; +}; +#define _IN(_field) offsetof(struct genlmsghdr, _field) +#define _OUT(_field) offsetof(struct pfioc_rule, _field) +static const struct nlattr_parser nla_p_getrules[] = { + { .type = PF_GR_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara }, + { .type = PF_GR_ACTION, .off = _OUT(rule.action), .cb = nlattr_get_uint8 }, +}; +static const struct nlfield_parser nlf_p_getrules[] = { +}; +NL_DECLARE_PARSER(getrules_parser, struct genlmsghdr, nlf_p_getrules, nla_p_getrules); + +static int +pf_handle_getrules(struct nlmsghdr *hdr, struct nl_pstate *npt) +{ + struct pfioc_rule attrs = {}; + int error; + struct nl_writer *nw = npt->nw; + struct genlmsghdr *ghdr_new; + + error = nl_parse_nlmsg(hdr, &getrules_parser, npt, &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_GETRULES; + ghdr_new->version = 0; + ghdr_new->reserved = 0; + + error = pf_ioctl_getrules(&attrs); + if (error != 0) + goto out; + + nlattr_add_u32(nw, PF_GR_NR, attrs.nr); + nlattr_add_u32(nw, PF_GR_TICKET, attrs.ticket); + + if (!nlmsg_end(nw)) { + error = ENOMEM; + goto out; + } + + return (0); + +out: + nlmsg_abort(nw); + return (error); +} + +static const struct nlhdr_parser *all_parsers[] = { + &state_parser, + &addrule_parser, + &getrules_parser +}; static int family_id; @@ -670,7 +727,12 @@ static const struct genl_cmd pf_cmds[] = { .cmd_cb = pf_handle_addrule, .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, }, - + { + .cmd_num = PFNL_CMD_GETRULES, + .cmd_name = "GETRULES", + .cmd_cb = pf_handle_getrules, + .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, + }, }; void diff --git a/sys/netpfil/pf/pf_nl.h b/sys/netpfil/pf/pf_nl.h index 8265ae1d1bfa..3ae77ffd3790 100644 --- a/sys/netpfil/pf/pf_nl.h +++ b/sys/netpfil/pf/pf_nl.h @@ -41,6 +41,7 @@ enum { PFNL_CMD_START = 3, PFNL_CMD_STOP = 4, PFNL_CMD_ADDRULE = 5, + PFNL_CMD_GETRULES = 6, __PFNL_CMD_MAX, }; #define PFNL_CMD_MAX (__PFNL_CMD_MAX -1) @@ -232,6 +233,14 @@ enum pf_addrule_type_t { PF_ART_RULE = 5, /* nested, pfrule_type_t */ }; +enum pf_getrules_type_t { + PF_GR_UNSPEC, + PF_GR_ANCHOR = 1, /* string */ + PF_GR_ACTION = 2, /* u8 */ + PF_GR_NR = 3, /* u32 */ + PF_GR_TICKET = 4, /* u32 */ +}; + #ifdef _KERNEL void pf_nl_register(void);