git: d909f06b907d - main - pf: convert DIOCADDADDR to netlink
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 17 Jul 2024 07:31:53 UTC
The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=d909f06b907d53ac4cbf9444ae75ca278900b0f3 commit d909f06b907d53ac4cbf9444ae75ca278900b0f3 Author: Kristof Provost <kp@FreeBSD.org> AuthorDate: 2024-07-16 16:58:59 +0000 Commit: Kristof Provost <kp@FreeBSD.org> CommitDate: 2024-07-17 05:52:55 +0000 pf: convert DIOCADDADDR to netlink Sponsored by: Rubicon Communications, LLC ("Netgate") --- lib/libpfctl/libpfctl.c | 52 +++++++++++++++++++++ lib/libpfctl/libpfctl.h | 1 + sbin/pfctl/pfctl.c | 2 +- sys/net/pfvar.h | 1 + sys/netpfil/pf/pf_ioctl.c | 117 ++++++++++++++++++++++++---------------------- sys/netpfil/pf/pf_nl.c | 48 +++++++++++++++++++ sys/netpfil/pf/pf_nl.h | 20 ++++++++ 7 files changed, 185 insertions(+), 56 deletions(-) diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c index b9fba232b8ca..398595c4715f 100644 --- a/lib/libpfctl/libpfctl.c +++ b/lib/libpfctl/libpfctl.c @@ -1105,6 +1105,19 @@ snl_add_msg_attr_addr_wrap(struct snl_writer *nw, uint32_t type, const struct pf snl_end_attr_nested(nw, off); } +static void +snl_add_msg_attr_pool_addr(struct snl_writer *nw, uint32_t type, const struct pf_pooladdr *pa) +{ + int off; + + off = snl_add_msg_attr_nested(nw, type); + + snl_add_msg_attr_string(nw, PF_PA_IFNAME, pa->ifname); + snl_add_msg_attr_addr_wrap(nw, PF_PA_ADDR, &pa->addr); + + snl_end_attr_nested(nw, off); +} + static void snl_add_msg_attr_rule_addr(struct snl_writer *nw, uint32_t type, const struct pf_rule_addr *addr) { @@ -2737,3 +2750,42 @@ pfctl_begin_addrs(struct pfctl_handle *h, uint32_t *ticket) return (e.error); } +int +pfctl_add_addr(struct pfctl_handle *h, const 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_ADD_ADDR); + + snl_add_msg_attr_u32(&nw, PF_AA_ACTION, pa->action); + snl_add_msg_attr_u32(&nw, PF_AA_TICKET, pa->ticket); + snl_add_msg_attr_u32(&nw, PF_AA_NR, pa->nr); + snl_add_msg_attr_u32(&nw, PF_AA_R_NUM, pa->r_num); + snl_add_msg_attr_u8(&nw, PF_AA_R_ACTION, pa->r_action); + snl_add_msg_attr_u8(&nw, PF_AA_R_LAST, pa->r_last); + snl_add_msg_attr_u8(&nw, PF_AA_AF, pa->af); + snl_add_msg_attr_string(&nw, PF_AA_ANCHOR, pa->anchor); + snl_add_msg_attr_pool_addr(&nw, PF_AA_ADDR, &pa->addr); + + 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 eebc97c52565..dd09b061efea 100644 --- a/lib/libpfctl/libpfctl.h +++ b/lib/libpfctl/libpfctl.h @@ -498,5 +498,6 @@ int pfctl_get_timeout(struct pfctl_handle *h, uint32_t timeout, uint32_t *second int pfctl_set_limit(struct pfctl_handle *h, const int index, const uint limit); int pfctl_get_limit(struct pfctl_handle *h, const int index, uint *limit); int pfctl_begin_addrs(struct pfctl_handle *h, uint32_t *ticket); +int pfctl_add_addr(struct pfctl_handle *h, const struct pfioc_pooladdr *pa); #endif diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index 450c64785b9c..a49e82809f9e 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -1727,7 +1727,7 @@ pfctl_add_pool(struct pfctl *pf, struct pfctl_pool *p, sa_family_t af) TAILQ_FOREACH(pa, &p->list, entries) { memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr)); if ((pf->opts & PF_OPT_NOACTION) == 0) { - if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr)) + if (pfctl_add_addr(pf->h, &pf->paddr) != 0) err(1, "DIOCADDADDR"); } } diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 0b90600a69ae..aa6dd52a7e69 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -2525,6 +2525,7 @@ int pf_ioctl_set_timeout(int, int, int *); int pf_ioctl_get_limit(int, unsigned int *); 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 *); void pf_krule_free(struct pf_krule *); void pf_krule_clear_counters(struct pf_krule *); diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index 2cb6923e1e69..2df6bcd30533 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -2528,6 +2528,67 @@ pf_ioctl_begin_addrs(uint32_t *ticket) return (0); } +int +pf_ioctl_add_addr(struct pfioc_pooladdr *pp) +{ + struct pf_kpooladdr *pa = NULL; + struct pfi_kkif *kif = NULL; + int error; + +#ifndef INET + if (pp->af == AF_INET) + return (EAFNOSUPPORT); +#endif /* INET */ +#ifndef INET6 + if (pp->af == AF_INET6) + return (EAFNOSUPPORT); +#endif /* INET6 */ + + if (pp->addr.addr.type != PF_ADDR_ADDRMASK && + pp->addr.addr.type != PF_ADDR_DYNIFTL && + pp->addr.addr.type != PF_ADDR_TABLE) + return (EINVAL); + + if (pp->addr.addr.p.dyn != NULL) + return (EINVAL); + + pa = malloc(sizeof(*pa), M_PFRULE, M_WAITOK); + error = pf_pooladdr_to_kpooladdr(&pp->addr, pa); + if (error != 0) + goto out; + if (pa->ifname[0]) + kif = pf_kkif_create(M_WAITOK); + PF_RULES_WLOCK(); + if (pp->ticket != V_ticket_pabuf) { + PF_RULES_WUNLOCK(); + if (pa->ifname[0]) + pf_kkif_free(kif); + error = EBUSY; + goto out; + } + if (pa->ifname[0]) { + pa->kif = pfi_kkif_attach(kif, pa->ifname); + kif = NULL; + pfi_kkif_ref(pa->kif); + } else + pa->kif = NULL; + if (pa->addr.type == PF_ADDR_DYNIFTL && ((error = + pfi_dynaddr_setup(&pa->addr, pp->af)) != 0)) { + if (pa->ifname[0]) + pfi_kkif_unref(pa->kif); + PF_RULES_WUNLOCK(); + goto out; + } + TAILQ_INSERT_TAIL(&V_pf_pabuf, pa, entries); + PF_RULES_WUNLOCK(); + + return (0); + +out: + free(pa, M_PFRULE); + return (error); +} + static int pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) { @@ -4199,62 +4260,8 @@ DIOCGETSTATESV2_full: case DIOCADDADDR: { struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; - struct pf_kpooladdr *pa; - struct pfi_kkif *kif = NULL; -#ifndef INET - if (pp->af == AF_INET) { - error = EAFNOSUPPORT; - break; - } -#endif /* INET */ -#ifndef INET6 - if (pp->af == AF_INET6) { - error = EAFNOSUPPORT; - break; - } -#endif /* INET6 */ - if (pp->addr.addr.type != PF_ADDR_ADDRMASK && - pp->addr.addr.type != PF_ADDR_DYNIFTL && - pp->addr.addr.type != PF_ADDR_TABLE) { - error = EINVAL; - break; - } - if (pp->addr.addr.p.dyn != NULL) { - error = EINVAL; - break; - } - pa = malloc(sizeof(*pa), M_PFRULE, M_WAITOK); - error = pf_pooladdr_to_kpooladdr(&pp->addr, pa); - if (error != 0) - break; - if (pa->ifname[0]) - kif = pf_kkif_create(M_WAITOK); - PF_RULES_WLOCK(); - if (pp->ticket != V_ticket_pabuf) { - PF_RULES_WUNLOCK(); - if (pa->ifname[0]) - pf_kkif_free(kif); - free(pa, M_PFRULE); - error = EBUSY; - break; - } - if (pa->ifname[0]) { - pa->kif = pfi_kkif_attach(kif, pa->ifname); - kif = NULL; - pfi_kkif_ref(pa->kif); - } else - pa->kif = NULL; - if (pa->addr.type == PF_ADDR_DYNIFTL && ((error = - pfi_dynaddr_setup(&pa->addr, pp->af)) != 0)) { - if (pa->ifname[0]) - pfi_kkif_unref(pa->kif); - PF_RULES_WUNLOCK(); - free(pa, M_PFRULE); - break; - } - TAILQ_INSERT_TAIL(&V_pf_pabuf, pa, entries); - PF_RULES_WUNLOCK(); + error = pf_ioctl_add_addr(pp); break; } diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c index 401baddde948..e855815dd73b 100644 --- a/sys/netpfil/pf/pf_nl.c +++ b/sys/netpfil/pf/pf_nl.c @@ -1509,6 +1509,45 @@ pf_handle_begin_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt) return (0); } +#define _OUT(_field) offsetof(struct pf_pooladdr, _field) +static const struct nlattr_parser nla_p_pool_addr[] = { + { .type = PF_PA_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = nlattr_get_nested }, + { .type = PF_PA_IFNAME, .off = _OUT(ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara }, +}; +NL_DECLARE_ATTR_PARSER(pool_addr_parser, nla_p_pool_addr); +#undef _OUT + +#define _OUT(_field) offsetof(struct pfioc_pooladdr, _field) +static const struct nlattr_parser nla_p_add_addr[] = { + { .type = PF_AA_ACTION, .off = _OUT(action), .cb = nlattr_get_uint32 }, + { .type = PF_AA_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 }, + { .type = PF_AA_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 }, + { .type = PF_AA_R_NUM, .off = _OUT(r_num), .cb = nlattr_get_uint32 }, + { .type = PF_AA_R_ACTION, .off = _OUT(r_action), .cb = nlattr_get_uint8 }, + { .type = PF_AA_R_LAST, .off = _OUT(r_last), .cb = nlattr_get_uint8 }, + { .type = PF_AA_AF, .off = _OUT(af), .cb = nlattr_get_uint8 }, + { .type = PF_AA_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara }, + { .type = PF_AA_ADDR, .off = _OUT(addr), .arg = &pool_addr_parser, .cb = nlattr_get_nested }, +}; +static const struct nlfield_parser nlf_p_add_addr[] = {}; +#undef _OUT +NL_DECLARE_PARSER(add_addr_parser, struct genlmsghdr, nlf_p_add_addr, nla_p_add_addr); + +static int +pf_handle_add_addr(struct nlmsghdr *hdr, struct nl_pstate *npt) +{ + struct pfioc_pooladdr attrs = { 0 }; + int error; + + error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs); + if (error != 0) + return (error); + + error = pf_ioctl_add_addr(&attrs); + + return (error); +} + static const struct nlhdr_parser *all_parsers[] = { &state_parser, &addrule_parser, @@ -1519,6 +1558,8 @@ static const struct nlhdr_parser *all_parsers[] = { &set_debug_parser, &set_timeout_parser, &set_limit_parser, + &pool_addr_parser, + &add_addr_parser, }; static int family_id; @@ -1657,6 +1698,13 @@ static const struct genl_cmd pf_cmds[] = { .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, .cmd_priv = PRIV_NETINET_PF, }, + { + .cmd_num = PFNL_CMD_ADD_ADDR, + .cmd_name = "ADD_ADDR", + .cmd_cb = pf_handle_add_addr, + .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 d50b5a1e9d43..2459fdc15a63 100644 --- a/sys/netpfil/pf/pf_nl.h +++ b/sys/netpfil/pf/pf_nl.h @@ -55,6 +55,7 @@ enum { PFNL_CMD_SET_LIMIT = 17, PFNL_CMD_GET_LIMIT = 18, PFNL_CMD_BEGIN_ADDRS = 19, + PFNL_CMD_ADD_ADDR = 20, __PFNL_CMD_MAX, }; #define PFNL_CMD_MAX (__PFNL_CMD_MAX -1) @@ -356,6 +357,25 @@ enum pf_begin_addrs_types_t { PF_BA_TICKET = 1, /* u32 */ }; +enum pf_pool_addr_types_t { + PF_PA_UNSPEC, + PF_PA_ADDR = 1, /* nested, pf_addr_wrap */ + PF_PA_IFNAME = 2, /* string */ +}; + +enum pf_add_addr_types_t { + PF_AA_UNSPEC, + PF_AA_ACTION = 1, /* u32 */ + PF_AA_TICKET = 2, /* u32 */ + PF_AA_NR = 3, /* u32 */ + PF_AA_R_NUM = 4, /* u32 */ + PF_AA_R_ACTION = 5, /* u8 */ + PF_AA_R_LAST = 6, /* u8 */ + PF_AA_AF = 7, /* u8 */ + PF_AA_ANCHOR = 8, /* string */ + PF_AA_ADDR = 9, /* nested, pf_pooladdr */ +}; + #ifdef _KERNEL void pf_nl_register(void);