git: 71d3c7041d70 - main - pf: convert DIOCNATLOOK to netlink
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 04 Jun 2024 14:59:35 UTC
The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=71d3c7041d7021ae15ff3b366b6cba9e4190283e commit 71d3c7041d7021ae15ff3b366b6cba9e4190283e Author: Kristof Provost <kp@FreeBSD.org> AuthorDate: 2024-05-31 13:51:38 +0000 Commit: Kristof Provost <kp@FreeBSD.org> CommitDate: 2024-06-04 12:59:58 +0000 pf: convert DIOCNATLOOK to netlink Sponsored by: Rubicon Communications, LLC ("Netgate") --- contrib/pf/ftp-proxy/filter.c | 62 ++++++++++++------------ contrib/pf/tftp-proxy/filter.c | 56 +++++++++++----------- lib/libpfctl/libpfctl.c | 55 +++++++++++++++++++++ lib/libpfctl/libpfctl.h | 18 +++++++ sys/netpfil/pf/pf_nl.c | 106 +++++++++++++++++++++++++++++++++++++++++ sys/netpfil/pf/pf_nl.h | 12 +++++ 6 files changed, 250 insertions(+), 59 deletions(-) diff --git a/contrib/pf/ftp-proxy/filter.c b/contrib/pf/ftp-proxy/filter.c index 7893be97f9b2..e3276f88489e 100644 --- a/contrib/pf/ftp-proxy/filter.c +++ b/contrib/pf/ftp-proxy/filter.c @@ -352,27 +352,27 @@ int server_lookup4(struct sockaddr_in *client, struct sockaddr_in *proxy, struct sockaddr_in *server) { - struct pfioc_natlook pnl; - - memset(&pnl, 0, sizeof pnl); - pnl.direction = PF_OUT; - pnl.af = AF_INET; - pnl.proto = IPPROTO_TCP; - memcpy(&pnl.saddr.v4, &client->sin_addr.s_addr, sizeof pnl.saddr.v4); - memcpy(&pnl.daddr.v4, &proxy->sin_addr.s_addr, sizeof pnl.daddr.v4); - pnl.sport = client->sin_port; - pnl.dport = proxy->sin_port; - - if (ioctl(pfctl_fd(pfh), DIOCNATLOOK, &pnl) == -1) + struct pfctl_natlook_key k = {}; + struct pfctl_natlook r = {}; + + k.direction = PF_OUT; + k.af = AF_INET; + k.proto = IPPROTO_TCP; + memcpy(&k.saddr.v4, &client->sin_addr.s_addr, sizeof(k.saddr.v4)); + memcpy(&k.daddr.v4, &proxy->sin_addr.s_addr, sizeof(k.daddr.v4)); + k.sport = client->sin_port; + k.dport = proxy->sin_port; + + if (pfctl_natlook(pfh, &k, &r)) return (-1); memset(server, 0, sizeof(struct sockaddr_in)); server->sin_len = sizeof(struct sockaddr_in); server->sin_family = AF_INET; - memcpy(&server->sin_addr.s_addr, &pnl.rdaddr.v4, - sizeof server->sin_addr.s_addr); - server->sin_port = pnl.rdport; - + memcpy(&server->sin_addr.s_addr, &r.daddr.v4, + sizeof(server->sin_addr.s_addr)); + server->sin_port = r.dport; + return (0); } @@ -380,26 +380,26 @@ int server_lookup6(struct sockaddr_in6 *client, struct sockaddr_in6 *proxy, struct sockaddr_in6 *server) { - struct pfioc_natlook pnl; - - memset(&pnl, 0, sizeof pnl); - pnl.direction = PF_OUT; - pnl.af = AF_INET6; - pnl.proto = IPPROTO_TCP; - memcpy(&pnl.saddr.v6, &client->sin6_addr.s6_addr, sizeof pnl.saddr.v6); - memcpy(&pnl.daddr.v6, &proxy->sin6_addr.s6_addr, sizeof pnl.daddr.v6); - pnl.sport = client->sin6_port; - pnl.dport = proxy->sin6_port; - - if (ioctl(pfctl_fd(pfh), DIOCNATLOOK, &pnl) == -1) + struct pfctl_natlook_key k = {}; + struct pfctl_natlook r = {}; + + k.direction = PF_OUT; + k.af = AF_INET6; + k.proto = IPPROTO_TCP; + memcpy(&k.saddr.v6, &client->sin6_addr.s6_addr, sizeof(k.saddr.v6)); + memcpy(&k.daddr.v6, &proxy->sin6_addr.s6_addr, sizeof(k.daddr.v6)); + k.sport = client->sin6_port; + k.dport = proxy->sin6_port; + + if (pfctl_natlook(pfh, &k, &r)) return (-1); memset(server, 0, sizeof(struct sockaddr_in6)); server->sin6_len = sizeof(struct sockaddr_in6); server->sin6_family = AF_INET6; - memcpy(&server->sin6_addr.s6_addr, &pnl.rdaddr.v6, - sizeof server->sin6_addr); - server->sin6_port = pnl.rdport; + memcpy(&server->sin6_addr.s6_addr, &r.daddr.v6, + sizeof(server->sin6_addr)); + server->sin6_port = r.dport; return (0); } diff --git a/contrib/pf/tftp-proxy/filter.c b/contrib/pf/tftp-proxy/filter.c index 1e6d54303996..3cf2e1fcf3ab 100644 --- a/contrib/pf/tftp-proxy/filter.c +++ b/contrib/pf/tftp-proxy/filter.c @@ -363,26 +363,26 @@ int server_lookup4(struct sockaddr_in *client, struct sockaddr_in *proxy, struct sockaddr_in *server, u_int8_t proto) { - struct pfioc_natlook pnl; - - memset(&pnl, 0, sizeof pnl); - pnl.direction = PF_OUT; - pnl.af = AF_INET; - pnl.proto = proto; - memcpy(&pnl.saddr.v4, &client->sin_addr.s_addr, sizeof pnl.saddr.v4); - memcpy(&pnl.daddr.v4, &proxy->sin_addr.s_addr, sizeof pnl.daddr.v4); - pnl.sport = client->sin_port; - pnl.dport = proxy->sin_port; - - if (ioctl(pfctl_fd(pfh), DIOCNATLOOK, &pnl) == -1) + struct pfctl_natlook_key k = {}; + struct pfctl_natlook r = {}; + + k.direction = PF_OUT; + k.af = AF_INET; + k.proto = proto; + memcpy(&k.saddr.v4, &client->sin_addr.s_addr, sizeof(k.saddr.v4)); + memcpy(&k.daddr.v4, &proxy->sin_addr.s_addr, sizeof(k.daddr.v4)); + k.sport = client->sin_port; + k.dport = proxy->sin_port; + + if (pfctl_natlook(pfh, &k, &r)) return (-1); memset(server, 0, sizeof(struct sockaddr_in)); server->sin_len = sizeof(struct sockaddr_in); server->sin_family = AF_INET; - memcpy(&server->sin_addr.s_addr, &pnl.rdaddr.v4, + memcpy(&server->sin_addr.s_addr, &r.daddr.v4, sizeof server->sin_addr.s_addr); - server->sin_port = pnl.rdport; + server->sin_port = r.dport; return (0); } @@ -391,26 +391,26 @@ int server_lookup6(struct sockaddr_in6 *client, struct sockaddr_in6 *proxy, struct sockaddr_in6 *server, u_int8_t proto) { - struct pfioc_natlook pnl; - - memset(&pnl, 0, sizeof pnl); - pnl.direction = PF_OUT; - pnl.af = AF_INET6; - pnl.proto = proto; - memcpy(&pnl.saddr.v6, &client->sin6_addr.s6_addr, sizeof pnl.saddr.v6); - memcpy(&pnl.daddr.v6, &proxy->sin6_addr.s6_addr, sizeof pnl.daddr.v6); - pnl.sport = client->sin6_port; - pnl.dport = proxy->sin6_port; - - if (ioctl(pfctl_fd(pfh), DIOCNATLOOK, &pnl) == -1) + struct pfctl_natlook_key k = {}; + struct pfctl_natlook r = {}; + + k.direction = PF_OUT; + k.af = AF_INET6; + k.proto = proto; + memcpy(&k.saddr.v6, &client->sin6_addr.s6_addr, sizeof k.saddr.v6); + memcpy(&k.daddr.v6, &proxy->sin6_addr.s6_addr, sizeof k.daddr.v6); + k.sport = client->sin6_port; + k.dport = proxy->sin6_port; + + if (pfctl_natlook(pfh, &k, &r)) return (-1); memset(server, 0, sizeof(struct sockaddr_in6)); server->sin6_len = sizeof(struct sockaddr_in6); server->sin6_family = AF_INET6; - memcpy(&server->sin6_addr.s6_addr, &pnl.rdaddr.v6, + memcpy(&server->sin6_addr.s6_addr, &r.daddr.v6, sizeof server->sin6_addr); - server->sin6_port = pnl.rdport; + server->sin6_port = r.dport; return (0); } diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c index 771097a33dab..d5cd6c4bda60 100644 --- a/lib/libpfctl/libpfctl.c +++ b/lib/libpfctl/libpfctl.c @@ -2435,3 +2435,58 @@ pfctl_set_statusif(struct pfctl_handle *h, const char *ifname) return (e.error); } + +#define _IN(_field) offsetof(struct genlmsghdr, _field) +#define _OUT(_field) offsetof(struct pfctl_natlook, _field) +static struct snl_attr_parser ap_natlook[] = { + { .type = PF_NL_SRC_ADDR, .off = _OUT(saddr), .cb = snl_attr_get_in6_addr }, + { .type = PF_NL_DST_ADDR, .off = _OUT(daddr), .cb = snl_attr_get_in6_addr }, + { .type = PF_NL_SRC_PORT, .off = _OUT(sport), .cb = snl_attr_get_uint16 }, + { .type = PF_NL_DST_PORT, .off = _OUT(dport), .cb = snl_attr_get_uint16 }, +}; +static struct snl_field_parser fp_natlook[] = {}; +#undef _IN +#undef _OUT +SNL_DECLARE_PARSER(natlook_parser, struct genlmsghdr, fp_natlook, ap_natlook); + +int +pfctl_natlook(struct pfctl_handle *h, const struct pfctl_natlook_key *k, + struct pfctl_natlook *r) +{ + 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_NATLOOK); + hdr->nlmsg_flags |= NLM_F_DUMP; + + snl_add_msg_attr_u8(&nw, PF_NL_AF, k->af); + snl_add_msg_attr_u8(&nw, PF_NL_DIRECTION, k->direction); + snl_add_msg_attr_u8(&nw, PF_NL_PROTO, k->proto); + snl_add_msg_attr_ip6(&nw, PF_NL_SRC_ADDR, &k->saddr.v6); + snl_add_msg_attr_ip6(&nw, PF_NL_DST_ADDR, &k->daddr.v6); + snl_add_msg_attr_u16(&nw, PF_NL_SRC_PORT, k->sport); + snl_add_msg_attr_u16(&nw, PF_NL_DST_PORT, k->dport); + + 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, &natlook_parser, r)) + continue; + } + + return (e.error); +} diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h index e130fe0fe842..e7625252638c 100644 --- a/lib/libpfctl/libpfctl.h +++ b/lib/libpfctl/libpfctl.h @@ -475,4 +475,22 @@ 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); +struct pfctl_natlook_key { + sa_family_t af; + uint8_t direction; + uint8_t proto; + struct pf_addr saddr; + struct pf_addr daddr; + uint16_t sport; + uint16_t dport; +}; +struct pfctl_natlook { + struct pf_addr saddr; + struct pf_addr daddr; + uint16_t sport; + uint16_t dport; +}; +int pfctl_natlook(struct pfctl_handle *h, + const struct pfctl_natlook_key *k, struct pfctl_natlook *r); + #endif diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c index 67a785e54d6f..b9dc7358ae28 100644 --- a/sys/netpfil/pf/pf_nl.c +++ b/sys/netpfil/pf/pf_nl.c @@ -26,6 +26,9 @@ * SUCH DAMAGE. * */ +#include <sys/cdefs.h> +#include "opt_inet.h" +#include "opt_inet6.h" #include <sys/param.h> #include <sys/malloc.h> @@ -1222,12 +1225,108 @@ pf_handle_clear_status(struct nlmsghdr *hdr, struct nl_pstate *npt) return (0); } +struct pf_nl_natlook { + sa_family_t af; + uint8_t direction; + uint8_t proto; + struct pf_addr src; + struct pf_addr dst; + uint16_t sport; + uint16_t dport; +}; + +#define _IN(_field) offsetof(struct genlmsghdr, _field) +#define _OUT(_field) offsetof(struct pf_nl_natlook, _field) +static const struct nlattr_parser nla_p_natlook[] = { + { .type = PF_NL_AF, .off = _OUT(af), .cb = nlattr_get_uint8 }, + { .type = PF_NL_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 }, + { .type = PF_NL_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 }, + { .type = PF_NL_SRC_ADDR, .off = _OUT(src), .cb = nlattr_get_in6_addr }, + { .type = PF_NL_DST_ADDR, .off = _OUT(dst), .cb = nlattr_get_in6_addr }, + { .type = PF_NL_SRC_PORT, .off = _OUT(sport), .cb = nlattr_get_uint16 }, + { .type = PF_NL_DST_PORT, .off = _OUT(dport), .cb = nlattr_get_uint16 }, +}; +static const struct nlfield_parser nlf_p_natlook[] = {}; +#undef _IN +#undef _OUT +NL_DECLARE_PARSER(natlook_parser, struct genlmsghdr, nlf_p_natlook, nla_p_natlook); + +static int +pf_handle_natlook(struct nlmsghdr *hdr, struct nl_pstate *npt) +{ + struct pf_nl_natlook attrs = {}; + struct pf_state_key_cmp key = {}; + struct nl_writer *nw = npt->nw; + struct pf_state_key *sk; + struct pf_kstate *state; + struct genlmsghdr *ghdr_new; + int error, m; + int sidx, didx; + + error = nl_parse_nlmsg(hdr, &natlook_parser, npt, &attrs); + if (error != 0) + return (error); + + if (attrs.proto == 0 || + PF_AZERO(&attrs.src, attrs.af) || + PF_AZERO(&attrs.dst, attrs.af) || + ((attrs.proto == IPPROTO_TCP || attrs.proto == IPPROTO_UDP) && + (attrs.sport == 0 || attrs.dport == 0))) + return (EINVAL); + + /* NATLOOK src and dst are reversed, so reverse sidx/didx */ + sidx = (attrs.direction == PF_IN) ? 1 : 0; + didx = (attrs.direction == PF_IN) ? 0 : 1; + + key.af = attrs.af; + key.proto = attrs.proto; + PF_ACPY(&key.addr[sidx], &attrs.src, attrs.af); + key.port[sidx] = attrs.sport; + PF_ACPY(&key.addr[didx], &attrs.dst, attrs.af); + key.port[didx] = attrs.dport; + + state = pf_find_state_all(&key, attrs.direction, &m); + if (state == NULL) + return (ENOENT); + if (m > 1) { + PF_STATE_UNLOCK(state); + return (E2BIG); + } + + if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) { + PF_STATE_UNLOCK(state); + return (ENOMEM); + } + + ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr); + ghdr_new->cmd = PFNL_CMD_NATLOOK; + ghdr_new->version = 0; + ghdr_new->reserved = 0; + + sk = state->key[sidx]; + + nlattr_add_in6_addr(nw, PF_NL_SRC_ADDR, &sk->addr[sidx].v6); + nlattr_add_in6_addr(nw, PF_NL_DST_ADDR, &sk->addr[didx].v6); + nlattr_add_u16(nw, PF_NL_SRC_PORT, sk->port[sidx]); + nlattr_add_u16(nw, PF_NL_DST_PORT, sk->port[didx]); + + PF_STATE_UNLOCK(state); + + if (!nlmsg_end(nw)) { + nlmsg_abort(nw); + return (ENOMEM); + } + + return (0); +} + static const struct nlhdr_parser *all_parsers[] = { &state_parser, &addrule_parser, &getrules_parser, &clear_states_parser, &set_statusif_parser, + &natlook_parser, }; static int family_id; @@ -1317,6 +1416,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_NATLOOK, + .cmd_name = "NATLOOK", + .cmd_cb = pf_handle_natlook, + .cmd_flags = GENL_CMD_CAP_DUMP | 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 10440eaf6366..7c2ef3712dc7 100644 --- a/sys/netpfil/pf/pf_nl.h +++ b/sys/netpfil/pf/pf_nl.h @@ -48,6 +48,7 @@ enum { PFNL_CMD_SET_STATUSIF = 10, PFNL_CMD_GET_STATUS = 11, PFNL_CMD_CLEAR_STATUS = 12, + PFNL_CMD_NATLOOK = 13, __PFNL_CMD_MAX, }; #define PFNL_CMD_MAX (__PFNL_CMD_MAX -1) @@ -316,6 +317,17 @@ enum pf_get_status_types_t { PF_GS_BCOUNTERS = 16, /* u64 array */ }; +enum pf_natlook_types_t { + PF_NL_UNSPEC, + PF_NL_AF = 1, /* u8 */ + PF_NL_DIRECTION = 2, /* u8 */ + PF_NL_PROTO = 3, /* u8 */ + PF_NL_SRC_ADDR = 4, /* in6_addr */ + PF_NL_DST_ADDR = 5, /* in6_addr */ + PF_NL_SRC_PORT = 6, /* u16 */ + PF_NL_DST_PORT = 7, /* u16 */ +}; + #ifdef _KERNEL void pf_nl_register(void);