git: 30bad751e8bf - main - pf: convert DIOCGETTIMEOUT/DIOCSETTIMEOUT to netlink
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 06 Jun 2024 20:40:36 UTC
The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=30bad751e8bf7bea01a1756ec9112490875c4a92 commit 30bad751e8bf7bea01a1756ec9112490875c4a92 Author: Kristof Provost <kp@FreeBSD.org> AuthorDate: 2024-06-05 03:58:56 +0000 Commit: Kristof Provost <kp@FreeBSD.org> CommitDate: 2024-06-06 18:46:18 +0000 pf: convert DIOCGETTIMEOUT/DIOCSETTIMEOUT to netlink --- lib/libpfctl/libpfctl.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++ lib/libpfctl/libpfctl.h | 2 ++ sbin/pfctl/parse.y | 4 +-- sbin/pfctl/pfctl.c | 19 ++++------- sbin/pfctl/pfctl_parser.h | 2 +- sys/net/pfvar.h | 2 ++ sys/netpfil/pf/pf_ioctl.c | 65 +++++++++++++++++++++++------------- sys/netpfil/pf/pf_nl.c | 76 ++++++++++++++++++++++++++++++++++++++++++ sys/netpfil/pf/pf_nl.h | 8 +++++ 9 files changed, 224 insertions(+), 38 deletions(-) diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c index 42339af5642b..a31fe6f0aff4 100644 --- a/lib/libpfctl/libpfctl.c +++ b/lib/libpfctl/libpfctl.c @@ -2522,3 +2522,87 @@ pfctl_set_debug(struct pfctl_handle *h, uint32_t level) return (e.error); } + +int +pfctl_set_timeout(struct pfctl_handle *h, uint32_t timeout, uint32_t seconds) +{ + 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_SET_TIMEOUT); + + snl_add_msg_attr_u32(&nw, PF_TO_TIMEOUT, timeout); + snl_add_msg_attr_u32(&nw, PF_TO_SECONDS, seconds); + + 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); +} + +struct pfctl_nl_timeout { + uint32_t seconds; +}; +#define _OUT(_field) offsetof(struct pfctl_nl_timeout, _field) +static struct snl_attr_parser ap_get_timeout[] = { + { .type = PF_TO_SECONDS, .off = _OUT(seconds), .cb = snl_attr_get_uint32 }, +}; +static struct snl_field_parser fp_get_timeout[] = {}; +#undef _OUT +SNL_DECLARE_PARSER(get_timeout_parser, struct genlmsghdr, fp_get_timeout, ap_get_timeout); + +int +pfctl_get_timeout(struct pfctl_handle *h, uint32_t timeout, uint32_t *seconds) +{ + struct snl_writer nw; + struct pfctl_nl_timeout to = {}; + 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_TIMEOUT); + hdr->nlmsg_flags |= NLM_F_DUMP; + + snl_add_msg_attr_u32(&nw, PF_TO_TIMEOUT, timeout); + + 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_timeout_parser, &to)) + continue; + } + + if (seconds != NULL) + *seconds = to.seconds; + + return (e.error); +} + diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h index ae1457e9304b..6d59d66a924a 100644 --- a/lib/libpfctl/libpfctl.h +++ b/lib/libpfctl/libpfctl.h @@ -493,5 +493,7 @@ struct pfctl_natlook { int pfctl_natlook(struct pfctl_handle *h, const struct pfctl_natlook_key *k, struct pfctl_natlook *r); int pfctl_set_debug(struct pfctl_handle *h, uint32_t level); +int pfctl_set_timeout(struct pfctl_handle *h, uint32_t timeout, uint32_t seconds); +int pfctl_get_timeout(struct pfctl_handle *h, uint32_t timeout, uint32_t *seconds); #endif diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index 19e029c881d1..2876eb6e89dc 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -5165,7 +5165,7 @@ timeout_spec : STRING NUMBER yyerror("only positive values permitted"); YYERROR; } - if (pfctl_set_timeout(pf, $1, $2, 0) != 0) { + if (pfctl_apply_timeout(pf, $1, $2, 0) != 0) { yyerror("unknown timeout %s", $1); free($1); YYERROR; @@ -5179,7 +5179,7 @@ timeout_spec : STRING NUMBER yyerror("only positive values permitted"); YYERROR; } - if (pfctl_set_timeout(pf, "interval", $2, 0) != 0) + if (pfctl_apply_timeout(pf, "interval", $2, 0) != 0) YYERROR; } ; diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index 8776ec7f82dc..d97043fc5c66 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -1656,17 +1656,15 @@ pfctl_show_running(int dev) int pfctl_show_timeouts(int dev, int opts) { - struct pfioc_tm pt; + uint32_t seconds; int i; if (opts & PF_OPT_SHOWALL) pfctl_print_title("TIMEOUTS:"); - memset(&pt, 0, sizeof(pt)); for (i = 0; pf_timeouts[i].name; i++) { - pt.timeout = pf_timeouts[i].timeout; - if (ioctl(dev, DIOCGETTIMEOUT, &pt)) + if (pfctl_get_timeout(pfh, pf_timeouts[i].timeout, &seconds)) err(1, "DIOCGETTIMEOUT"); - printf("%-20s %10d", pf_timeouts[i].name, pt.seconds); + printf("%-20s %10d", pf_timeouts[i].name, seconds); if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START && pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END) printf(" states"); @@ -2469,7 +2467,7 @@ pfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit) } int -pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet) +pfctl_apply_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet) { int i; @@ -2499,12 +2497,7 @@ pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet) int pfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds) { - struct pfioc_tm pt; - - memset(&pt, 0, sizeof(pt)); - pt.timeout = timeout; - pt.seconds = seconds; - if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) { + if (pfctl_set_timeout(pf->h, timeout, seconds)) { warnx("DIOCSETTIMEOUT"); return (1); } @@ -2553,7 +2546,7 @@ pfctl_set_optimization(struct pfctl *pf, const char *opt) } for (i = 0; hint[i].name; i++) - if ((r = pfctl_set_timeout(pf, hint[i].name, + if ((r = pfctl_apply_timeout(pf, hint[i].name, hint[i].timeout, 1))) return (r); diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h index 58532ad37e12..06ab5d052631 100644 --- a/sbin/pfctl/pfctl_parser.h +++ b/sbin/pfctl/pfctl_parser.h @@ -285,7 +285,7 @@ int pfctl_add_pool(struct pfctl *, struct pfctl_pool *, sa_family_t); void pfctl_move_pool(struct pfctl_pool *, struct pfctl_pool *); void pfctl_clear_pool(struct pfctl_pool *); -int pfctl_set_timeout(struct pfctl *, const char *, int, int); +int pfctl_apply_timeout(struct pfctl *, const char *, int, int); int pfctl_set_reassembly(struct pfctl *, int, int); int pfctl_set_optimization(struct pfctl *, const char *); int pfctl_set_limit(struct pfctl *, const char *, unsigned int); diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 0ea4741f8937..16d3d90f4862 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -2503,6 +2503,8 @@ int pf_ioctl_addrule(struct pf_krule *, uint32_t, uint32_t, const char *, const char *, uid_t uid, pid_t); void pf_ioctl_clear_status(void); +int pf_ioctl_get_timeout(int, int *); +int pf_ioctl_set_timeout(int, int, int *); 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 99cb3bd85d57..cef50c00283b 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -2443,6 +2443,46 @@ pf_ioctl_clear_status(void) PF_RULES_WUNLOCK(); } +int +pf_ioctl_set_timeout(int timeout, int seconds, int *prev_seconds) +{ + uint32_t old; + + if (timeout < 0 || timeout >= PFTM_MAX || + seconds < 0) + return (EINVAL); + + PF_RULES_WLOCK(); + old = V_pf_default_rule.timeout[timeout]; + if (timeout == PFTM_INTERVAL && seconds == 0) + seconds = 1; + V_pf_default_rule.timeout[timeout] = seconds; + if (timeout == PFTM_INTERVAL && seconds < old) + wakeup(pf_purge_thread); + + if (prev_seconds != NULL) + *prev_seconds = old; + + PF_RULES_WUNLOCK(); + + return (0); +} + +int +pf_ioctl_get_timeout(int timeout, int *seconds) +{ + PF_RULES_RLOCK_TRACKER; + + if (timeout < 0 || timeout >= PFTM_MAX) + return (EINVAL); + + PF_RULES_RLOCK(); + *seconds = V_pf_default_rule.timeout[timeout]; + PF_RULES_RUNLOCK(); + + return (0); +} + static int pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) { @@ -3838,35 +3878,16 @@ DIOCGETSTATESV2_full: case DIOCSETTIMEOUT: { struct pfioc_tm *pt = (struct pfioc_tm *)addr; - int old; - if (pt->timeout < 0 || pt->timeout >= PFTM_MAX || - pt->seconds < 0) { - error = EINVAL; - break; - } - PF_RULES_WLOCK(); - old = V_pf_default_rule.timeout[pt->timeout]; - if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0) - pt->seconds = 1; - V_pf_default_rule.timeout[pt->timeout] = pt->seconds; - if (pt->timeout == PFTM_INTERVAL && pt->seconds < old) - wakeup(pf_purge_thread); - pt->seconds = old; - PF_RULES_WUNLOCK(); + error = pf_ioctl_set_timeout(pt->timeout, pt->seconds, + &pt->seconds); break; } case DIOCGETTIMEOUT: { struct pfioc_tm *pt = (struct pfioc_tm *)addr; - if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) { - error = EINVAL; - break; - } - PF_RULES_RLOCK(); - pt->seconds = V_pf_default_rule.timeout[pt->timeout]; - PF_RULES_RUNLOCK(); + error = pf_ioctl_get_timeout(pt->timeout, &pt->seconds); break; } diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c index cf5146c716c6..026f8caab535 100644 --- a/sys/netpfil/pf/pf_nl.c +++ b/sys/netpfil/pf/pf_nl.c @@ -1349,6 +1349,67 @@ pf_handle_set_debug(struct nlmsghdr *hdr, struct nl_pstate *npt) return (0); } +struct pf_nl_set_timeout +{ + uint32_t timeout; + uint32_t seconds; +}; +#define _OUT(_field) offsetof(struct pf_nl_set_timeout, _field) +static const struct nlattr_parser nla_p_set_timeout[] = { + { .type = PF_TO_TIMEOUT, .off = _OUT(timeout), .cb = nlattr_get_uint32 }, + { .type = PF_TO_SECONDS, .off = _OUT(seconds), .cb = nlattr_get_uint32 }, +}; +static const struct nlfield_parser nlf_p_set_timeout[] = {}; +#undef _OUT +NL_DECLARE_PARSER(set_timeout_parser, struct genlmsghdr, nlf_p_set_timeout, nla_p_set_timeout); + +static int +pf_handle_set_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt) +{ + struct pf_nl_set_timeout attrs = {}; + int error; + + error = nl_parse_nlmsg(hdr, &set_timeout_parser, npt, &attrs); + if (error != 0) + return (error); + + return (pf_ioctl_set_timeout(attrs.timeout, attrs.seconds, NULL)); +} + +static int +pf_handle_get_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt) +{ + struct pf_nl_set_timeout attrs = {}; + struct nl_writer *nw = npt->nw; + struct genlmsghdr *ghdr_new; + int error; + + error = nl_parse_nlmsg(hdr, &set_timeout_parser, npt, &attrs); + if (error != 0) + return (error); + + error = pf_ioctl_get_timeout(attrs.timeout, &attrs.seconds); + 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_TIMEOUT; + ghdr_new->version = 0; + ghdr_new->reserved = 0; + + nlattr_add_u32(nw, PF_TO_SECONDS, attrs.seconds); + + if (!nlmsg_end(nw)) { + nlmsg_abort(nw); + return (ENOMEM); + } + + return (0); +} + static const struct nlhdr_parser *all_parsers[] = { &state_parser, &addrule_parser, @@ -1357,6 +1418,7 @@ static const struct nlhdr_parser *all_parsers[] = { &set_statusif_parser, &natlook_parser, &set_debug_parser, + &set_timeout_parser, }; static int family_id; @@ -1460,6 +1522,20 @@ 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_SET_TIMEOUT, + .cmd_name = "SET_TIMEOUT", + .cmd_cb = pf_handle_set_timeout, + .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL, + .cmd_priv = PRIV_NETINET_PF, + }, + { + .cmd_num = PFNL_CMD_GET_TIMEOUT, + .cmd_name = "GET_TIMEOUT", + .cmd_cb = pf_handle_get_timeout, + .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 ab199e308a38..5f9d8166ca50 100644 --- a/sys/netpfil/pf/pf_nl.h +++ b/sys/netpfil/pf/pf_nl.h @@ -50,6 +50,8 @@ enum { PFNL_CMD_CLEAR_STATUS = 12, PFNL_CMD_NATLOOK = 13, PFNL_CMD_SET_DEBUG = 14, + PFNL_CMD_SET_TIMEOUT = 15, + PFNL_CMD_GET_TIMEOUT = 16, __PFNL_CMD_MAX, }; #define PFNL_CMD_MAX (__PFNL_CMD_MAX -1) @@ -334,6 +336,12 @@ enum pf_set_debug_types_t { PF_SD_LEVEL = 1, /* u32 */ }; +enum pf_timeout_types_t { + PF_TO_UNSPEC, + PF_TO_TIMEOUT = 1, /* u32 */ + PF_TO_SECONDS = 2, /* u32 */ +}; + #ifdef _KERNEL void pf_nl_register(void);