The branch main has been updated by kp:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=30bad751e8bf7bea01a1756ec9112490875c4a92

commit 30bad751e8bf7bea01a1756ec9112490875c4a92
Author:     Kristof Provost <k...@freebsd.org>
AuthorDate: 2024-06-05 03:58:56 +0000
Commit:     Kristof Provost <k...@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);

Reply via email to