The branch main has been updated by kp:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=706d465dae6aa3e1b567299b9e80eb574b6c5abf

commit 706d465dae6aa3e1b567299b9e80eb574b6c5abf
Author:     Kristof Provost <[email protected]>
AuthorDate: 2024-02-26 10:20:29 +0000
Commit:     Kristof Provost <[email protected]>
CommitDate: 2024-02-28 22:26:18 +0000

    pf: convert kill/clear state to use netlink
    
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D44090
---
 contrib/pf/authpf/authpf.c |   8 +--
 lib/libpfctl/libpfctl.c    | 128 ++++++++++++++++++++++++++++++---------------
 lib/libpfctl/libpfctl.h    |   4 ++
 sbin/pfctl/pfctl.c         |  12 ++---
 sys/net/pfvar.h            |   3 ++
 sys/netpfil/pf/pf_ioctl.c  |   7 +--
 sys/netpfil/pf/pf_nl.c     |  96 +++++++++++++++++++++++++++++++++-
 sys/netpfil/pf/pf_nl.h     |  19 +++++++
 8 files changed, 221 insertions(+), 56 deletions(-)

diff --git a/contrib/pf/authpf/authpf.c b/contrib/pf/authpf/authpf.c
index 9858c1c50ced..81dbcb747f5f 100644
--- a/contrib/pf/authpf/authpf.c
+++ b/contrib/pf/authpf/authpf.c
@@ -57,6 +57,7 @@ static int    change_table(int, const char *);
 static void    authpf_kill_states(void);
 
 int    dev;                    /* pf device */
+struct pfctl_handle     *pfh;
 char   anchorname[PF_ANCHOR_NAME_SIZE] = "authpf";
 char   rulesetname[MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 2];
 char   tablename[PF_TABLE_NAME_SIZE] = "authpf_users";
@@ -135,7 +136,8 @@ main(void)
        }
        /* open the pf device */
        dev = open(PATH_DEVFILE, O_RDWR);
-       if (dev == -1) {
+       pfh = pfctl_open(PATH_DEVFILE);
+       if (dev == -1 || pfh == NULL) {
                syslog(LOG_ERR, "cannot open packet filter device (%m)");
                goto die;
        }
@@ -906,7 +908,7 @@ authpf_kill_states(void)
            sizeof(kill.src.addr.v.a.addr));
        memset(&kill.src.addr.v.a.mask, 0xff,
            sizeof(kill.src.addr.v.a.mask));
-       if (pfctl_kill_states(dev, &kill, NULL))
+       if (pfctl_kill_states_h(pfh, &kill, NULL))
                syslog(LOG_ERR, "pfctl_kill_states() failed (%m)");
 
        /* Kill all states to ipsrc */
@@ -915,7 +917,7 @@ authpf_kill_states(void)
            sizeof(kill.dst.addr.v.a.addr));
        memset(&kill.dst.addr.v.a.mask, 0xff,
            sizeof(kill.dst.addr.v.a.mask));
-       if (pfctl_kill_states(dev, &kill, NULL))
+       if (pfctl_kill_states_h(pfh, &kill, NULL))
                syslog(LOG_ERR, "pfctl_kill_states() failed (%m)");
 }
 
diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index 71546c4709c2..f12e45291fc1 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -1630,22 +1630,6 @@ pfctl_get_creatorids(struct pfctl_handle *h, uint32_t 
*creators, size_t *len)
        return (error);
 }
 
-static void
-pfctl_nv_add_state_cmp(nvlist_t *nvl, const char *name,
-    const struct pfctl_state_cmp *cmp)
-{
-       nvlist_t        *nv;
-
-       nv = nvlist_create(0);
-
-       nvlist_add_number(nv, "id", cmp->id);
-       nvlist_add_number(nv, "creatorid", htonl(cmp->creatorid));
-       nvlist_add_number(nv, "direction", cmp->direction);
-
-       nvlist_add_nvlist(nvl, name, nv);
-       nvlist_destroy(nv);
-}
-
 static inline bool
 snl_attr_get_pfaddr(struct snl_state *ss __unused, struct nlattr *nla,
     const void *arg __unused, void *target)
@@ -1848,48 +1832,110 @@ pfctl_free_states(struct pfctl_states *states)
        bzero(states, sizeof(*states));
 }
 
+struct pfctl_nl_clear_states {
+       uint32_t killed;
+};
+#define        _OUT(_field)    offsetof(struct pfctl_nl_clear_states, _field)
+static struct snl_attr_parser ap_clear_states[] = {
+       { .type = PF_CS_KILLED, .off = _OUT(killed), .cb = snl_attr_get_uint32 
},
+};
+static struct snl_field_parser fp_clear_states[] = {};
+#undef _OUT
+SNL_DECLARE_PARSER(clear_states_parser, struct genlmsghdr, fp_clear_states, 
ap_clear_states);
+
 static int
-_pfctl_clear_states(int dev, const struct pfctl_kill *kill,
-    unsigned int *killed, uint64_t ioctlval)
+_pfctl_clear_states_h(struct pfctl_handle *h, const struct pfctl_kill *kill,
+    unsigned int *killed, int cmd)
 {
-       nvlist_t        *nvl;
-       int              ret;
+       struct snl_writer nw;
+       struct snl_errmsg_data e = {};
+       struct pfctl_nl_clear_states attrs = {};
+       struct nlmsghdr *hdr;
+       uint32_t seq_id;
+       int family_id;
 
-       nvl = nvlist_create(0);
+       family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
+       if (family_id == 0)
+               return (ENOTSUP);
 
-       pfctl_nv_add_state_cmp(nvl, "cmp", &kill->cmp);
-       nvlist_add_number(nvl, "af", kill->af);
-       nvlist_add_number(nvl, "proto", kill->proto);
-       pfctl_nv_add_rule_addr(nvl, "src", &kill->src);
-       pfctl_nv_add_rule_addr(nvl, "dst", &kill->dst);
-       pfctl_nv_add_rule_addr(nvl, "rt_addr", &kill->rt_addr);
-       nvlist_add_string(nvl, "ifname", kill->ifname);
-       nvlist_add_string(nvl, "label", kill->label);
-       nvlist_add_bool(nvl, "kill_match", kill->kill_match);
-       nvlist_add_bool(nvl, "nat", kill->nat);
-
-       if ((ret = pfctl_do_ioctl(dev, ioctlval, 1024, &nvl)) != 0)
-               goto out;
+       snl_init_writer(&h->ss, &nw);
+       hdr = snl_create_genl_msg_request(&nw, family_id, cmd);
+       hdr->nlmsg_flags |= NLM_F_DUMP;
+
+       snl_add_msg_attr_u64(&nw, PF_CS_CMP_ID, kill->cmp.id);
+       snl_add_msg_attr_u32(&nw, PF_CS_CMP_CREATORID, 
htonl(kill->cmp.creatorid));
+       snl_add_msg_attr_u8(&nw, PF_CS_CMP_DIR, kill->cmp.direction);
+       snl_add_msg_attr_u8(&nw, PF_CS_AF, kill->af);
+       snl_add_msg_attr_u8(&nw, PF_CS_PROTO, kill->proto);
+       snl_add_msg_attr_rule_addr(&nw, PF_CS_SRC, &kill->src);
+       snl_add_msg_attr_rule_addr(&nw, PF_CS_DST, &kill->dst);
+       snl_add_msg_attr_rule_addr(&nw, PF_CS_RT_ADDR, &kill->rt_addr);
+       snl_add_msg_attr_string(&nw, PF_CS_IFNAME, kill->ifname);
+       snl_add_msg_attr_string(&nw, PF_CS_LABEL, kill->label);
+       snl_add_msg_attr_bool(&nw, PF_CS_KILL_MATCH, kill->kill_match);
+       snl_add_msg_attr_bool(&nw, PF_CS_NAT, kill->nat);
+
+       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, &clear_states_parser, 
&attrs))
+                       continue;
+       }
 
        if (killed)
-               *killed = nvlist_get_number(nvl, "killed");
+               *killed = attrs.killed;
+
+       return (e.error);
+}
+
+int
+pfctl_clear_states_h(struct pfctl_handle *h, const struct pfctl_kill *kill,
+    unsigned int *killed)
+{
+       return(_pfctl_clear_states_h(h, kill, killed, PFNL_CMD_CLRSTATES));
+}
+
+int
+pfctl_kill_states_h(struct pfctl_handle *h, const struct pfctl_kill *kill,
+    unsigned int *killed)
+{
+       return(_pfctl_clear_states_h(h, kill, killed, PFNL_CMD_KILLSTATES));
+}
+
+static int
+_pfctl_clear_states(int dev __unused, const struct pfctl_kill *kill,
+    unsigned int *killed, uint64_t cmd)
+{
+       struct pfctl_handle *h;
+       int ret;
+
+       h = pfctl_open(PF_DEVICE);
+       if (h == NULL)
+               return (ENODEV);
+
+       ret = _pfctl_clear_states_h(h, kill, killed, cmd);
+       pfctl_close(h);
 
-out:
-       nvlist_destroy(nvl);
        return (ret);
 }
 
 int
-pfctl_clear_states(int dev, const struct pfctl_kill *kill,
+pfctl_clear_states(int dev __unused, const struct pfctl_kill *kill,
     unsigned int *killed)
 {
-       return (_pfctl_clear_states(dev, kill, killed, DIOCCLRSTATESNV));
+       return (_pfctl_clear_states(dev, kill, killed, PFNL_CMD_CLRSTATES));
 }
 
 int
-pfctl_kill_states(int dev, const struct pfctl_kill *kill, unsigned int *killed)
+pfctl_kill_states(int dev __unused, const struct pfctl_kill *kill, unsigned 
int *killed)
 {
-       return (_pfctl_clear_states(dev, kill, killed, DIOCKILLSTATESNV));
+       return (_pfctl_clear_states(dev, kill, killed, PFNL_CMD_KILLSTATES));
 }
 
 int
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
index f05044a9a985..b16caf1f6480 100644
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -446,6 +446,10 @@ int        pfctl_clear_states(int dev, const struct 
pfctl_kill *kill,
            unsigned int *killed);
 int    pfctl_kill_states(int dev, const struct pfctl_kill *kill,
            unsigned int *killed);
+int    pfctl_clear_states_h(struct pfctl_handle *h, const struct pfctl_kill 
*kill,
+           unsigned int *killed);
+int    pfctl_kill_states_h(struct pfctl_handle *h, const struct pfctl_kill 
*kill,
+           unsigned int *killed);
 int    pfctl_clear_rules(int dev, const char *anchorname);
 int    pfctl_clear_nat(int dev, const char *anchorname);
 int    pfctl_clear_eth_rules(int dev, const char *anchorname);
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index c583279750f1..f8ecded066d2 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -545,7 +545,7 @@ pfctl_clear_iface_states(int dev, const char *iface, int 
opts)
        if (opts & PF_OPT_KILLMATCH)
                kill.kill_match = true;
 
-       if (pfctl_clear_states(dev, &kill, &killed))
+       if (pfctl_clear_states_h(pfh, &kill, &killed))
                err(1, "DIOCCLRSTATES");
        if ((opts & PF_OPT_QUIET) == 0)
                fprintf(stderr, "%d states cleared\n", killed);
@@ -801,13 +801,13 @@ pfctl_net_kill_states(int dev, const char *iface, int 
opts)
                                        errx(1, "Unknown address family %d",
                                            kill.af);
 
-                               if (pfctl_kill_states(dev, &kill, &newkilled))
+                               if (pfctl_kill_states_h(pfh, &kill, &newkilled))
                                        err(1, "DIOCKILLSTATES");
                                killed += newkilled;
                        }
                        freeaddrinfo(res[1]);
                } else {
-                       if (pfctl_kill_states(dev, &kill, &newkilled))
+                       if (pfctl_kill_states_h(pfh, &kill, &newkilled))
                                err(1, "DIOCKILLSTATES");
                        killed += newkilled;
                }
@@ -873,7 +873,7 @@ pfctl_gateway_kill_states(int dev, const char *iface, int 
opts)
                else
                        errx(1, "Unknown address family %d", kill.af);
 
-               if (pfctl_kill_states(dev, &kill, &newkilled))
+               if (pfctl_kill_states_h(pfh, &kill, &newkilled))
                        err(1, "DIOCKILLSTATES");
                killed += newkilled;
        }
@@ -907,7 +907,7 @@ pfctl_label_kill_states(int dev, const char *iface, int 
opts)
            sizeof(kill.label))
                errx(1, "label too long: %s", state_kill[1]);
 
-       if (pfctl_kill_states(dev, &kill, &killed))
+       if (pfctl_kill_states_h(pfh, &kill, &killed))
                err(1, "DIOCKILLSTATES");
 
        if ((opts & PF_OPT_QUIET) == 0)
@@ -946,7 +946,7 @@ pfctl_id_kill_states(int dev, const char *iface, int opts)
                usage();
        }
 
-       if (pfctl_kill_states(dev, &kill, &killed))
+       if (pfctl_kill_states_h(pfh, &kill, &killed))
                err(1, "DIOCKILLSTATES");
 
        if ((opts & PF_OPT_QUIET) == 0)
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index f3a808f8ad26..88fb99ead84e 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -2208,6 +2208,9 @@ extern int                         pf_state_insert(struct 
pfi_kkif *,
                                    struct pf_kstate *);
 extern struct pf_kstate                *pf_alloc_state(int);
 extern void                     pf_free_state(struct pf_kstate *);
+extern void                     pf_killstates(struct pf_kstate_kill *,
+                                   unsigned int *);
+extern unsigned int             pf_clear_states(const struct pf_kstate_kill *);
 
 static __inline void
 pf_ref_state(struct pf_kstate *s)
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index d83933cd293f..1b22d49a6255 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -227,9 +227,6 @@ struct cdev *pf_dev;
  * XXX - These are new and need to be checked when moveing to a new version
  */
 static void             pf_clear_all_states(void);
-static unsigned int     pf_clear_states(const struct pf_kstate_kill *);
-static void             pf_killstates(struct pf_kstate_kill *,
-                           unsigned int *);
 static int              pf_killstates_row(struct pf_kstate_kill *,
                            struct pf_idhash *);
 static int              pf_killstates_nv(struct pfioc_nv *);
@@ -5944,7 +5941,7 @@ on_error:
        return (error);
 }
 
-static unsigned int
+unsigned int
 pf_clear_states(const struct pf_kstate_kill *kill)
 {
        struct pf_state_key_cmp  match_key;
@@ -6013,7 +6010,7 @@ relock_DIOCCLRSTATES:
        return (killed);
 }
 
-static void
+void
 pf_killstates(struct pf_kstate_kill *kill, unsigned int *killed)
 {
        struct pf_kstate        *s;
diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c
index 120ce88f8720..e4558c156aef 100644
--- a/sys/netpfil/pf/pf_nl.c
+++ b/sys/netpfil/pf/pf_nl.c
@@ -782,6 +782,7 @@ static const struct nlattr_parser nla_p_getrules[] = {
 };
 static const struct nlfield_parser nlf_p_getrules[] = {
 };
+#undef _IN
 #undef _OUT
 NL_DECLARE_PARSER(getrules_parser, struct genlmsghdr, nlf_p_getrules, 
nla_p_getrules);
 
@@ -842,6 +843,8 @@ static const struct nlattr_parser nla_p_getrule[] = {
 };
 static const struct nlfield_parser nlf_p_getrule[] = {
 };
+#undef _IN
+#undef _OUT
 NL_DECLARE_PARSER(getrule_parser, struct genlmsghdr, nlf_p_getrule, 
nla_p_getrule);
 
 static int
@@ -1000,10 +1003,87 @@ out:
        return (error);
 }
 
+#define        _IN(_field)     offsetof(struct genlmsghdr, _field)
+#define        _OUT(_field)    offsetof(struct pf_kstate_kill, _field)
+static const struct nlattr_parser nla_p_clear_states[] = {
+       { .type = PF_CS_CMP_ID, .off = _OUT(psk_pfcmp.id), .cb = 
nlattr_get_uint64 },
+       { .type = PF_CS_CMP_CREATORID, .off = _OUT(psk_pfcmp.creatorid), .cb = 
nlattr_get_uint32 },
+       { .type = PF_CS_CMP_DIR, .off = _OUT(psk_pfcmp.direction), .cb = 
nlattr_get_uint8 },
+       { .type = PF_CS_AF, .off = _OUT(psk_af), .cb = nlattr_get_uint8 },
+       { .type = PF_CS_PROTO, .off = _OUT(psk_proto), .cb = nlattr_get_uint8 },
+       { .type = PF_CS_SRC, .off = _OUT(psk_src), .arg = &rule_addr_parser, 
.cb = nlattr_get_nested },
+       { .type = PF_CS_DST, .off = _OUT(psk_dst), .arg = &rule_addr_parser, 
.cb = nlattr_get_nested },
+       { .type = PF_CS_RT_ADDR, .off = _OUT(psk_rt_addr), .arg = 
&rule_addr_parser, .cb = nlattr_get_nested },
+       { .type = PF_CS_IFNAME, .off = _OUT(psk_ifname), .arg = (void 
*)IFNAMSIZ, .cb = nlattr_get_chara },
+       { .type = PF_CS_LABEL, .off = _OUT(psk_label), .arg = (void 
*)PF_RULE_LABEL_SIZE, .cb = nlattr_get_chara },
+       { .type = PF_CS_KILL_MATCH, .off = _OUT(psk_kill_match), .cb = 
nlattr_get_bool },
+       { .type = PF_CS_NAT, .off = _OUT(psk_nat), .cb = nlattr_get_bool },
+};
+static const struct nlfield_parser nlf_p_clear_states[] = {};
+#undef _IN
+#undef _OUT
+NL_DECLARE_PARSER(clear_states_parser, struct genlmsghdr, nlf_p_clear_states, 
nla_p_clear_states);
+
+static int
+pf_handle_killclear_states(struct nlmsghdr *hdr, struct nl_pstate *npt, int 
cmd)
+{
+       struct pf_kstate_kill            kill = {};
+       struct epoch_tracker             et;
+       struct nl_writer                *nw = npt->nw;
+       struct genlmsghdr               *ghdr_new;
+       int                              error;
+       unsigned int                     killed = 0;
+
+       error = nl_parse_nlmsg(hdr, &clear_states_parser, npt, &kill);
+       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 = cmd;
+       ghdr_new->version = 0;
+       ghdr_new->reserved = 0;
+
+       NET_EPOCH_ENTER(et);
+       if (cmd == PFNL_CMD_KILLSTATES)
+               pf_killstates(&kill, &killed);
+       else
+               killed = pf_clear_states(&kill);
+       NET_EPOCH_EXIT(et);
+
+       nlattr_add_u32(nw, PF_CS_KILLED, killed);
+
+       if (! nlmsg_end(nw)) {
+               error = ENOMEM;
+               goto out;
+       }
+
+       return (0);
+
+out:
+       nlmsg_abort(nw);
+       return (error);
+}
+
+static int
+pf_handle_clear_states(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+       return (pf_handle_killclear_states(hdr, npt, PFNL_CMD_CLRSTATES));
+}
+
+static int
+pf_handle_kill_states(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+       return (pf_handle_killclear_states(hdr, npt, PFNL_CMD_KILLSTATES));
+}
+
 static const struct nlhdr_parser *all_parsers[] = {
        &state_parser,
        &addrule_parser,
-       &getrules_parser
+       &getrules_parser,
+       &clear_states_parser,
 };
 
 static int family_id;
@@ -1058,6 +1138,20 @@ static const struct genl_cmd pf_cmds[] = {
                .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
                .cmd_priv = PRIV_NETINET_PF,
        },
+       {
+               .cmd_num = PFNL_CMD_CLRSTATES,
+               .cmd_name = "CLRSTATES",
+               .cmd_cb = pf_handle_clear_states,
+               .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | 
GENL_CMD_CAP_HASPOL,
+               .cmd_priv = PRIV_NETINET_PF,
+       },
+       {
+               .cmd_num = PFNL_CMD_KILLSTATES,
+               .cmd_name = "KILLSTATES",
+               .cmd_cb = pf_handle_kill_states,
+               .cmd_flags = GENL_CMD_CAP_DO | 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 51df8b7aece9..0ae4a9283072 100644
--- a/sys/netpfil/pf/pf_nl.h
+++ b/sys/netpfil/pf/pf_nl.h
@@ -43,6 +43,8 @@ enum {
        PFNL_CMD_ADDRULE = 5,
        PFNL_CMD_GETRULES = 6,
        PFNL_CMD_GETRULE = 7,
+       PFNL_CMD_CLRSTATES = 8,
+       PFNL_CMD_KILLSTATES = 9,
        __PFNL_CMD_MAX,
 };
 #define PFNL_CMD_MAX (__PFNL_CMD_MAX -1)
@@ -262,6 +264,23 @@ enum pf_getrules_type_t {
        PF_GR_CLEAR             = 5, /* u8 */
 };
 
+enum pf_clear_states_type_t {
+       PF_CS_UNSPEC,
+       PF_CS_CMP_ID            = 1, /* u64 */
+       PF_CS_CMP_CREATORID     = 2, /* u32 */
+       PF_CS_CMP_DIR           = 3, /* u8 */
+       PF_CS_AF                = 4, /* u8 */
+       PF_CS_PROTO             = 5, /* u8 */
+       PF_CS_SRC               = 6, /* nested, pf_addr_wrap */
+       PF_CS_DST               = 7, /* nested, pf_addr_wrap */
+       PF_CS_RT_ADDR           = 8, /* nested, pf_addr_wrap */
+       PF_CS_IFNAME            = 9, /* string */
+       PF_CS_LABEL             = 10, /* string */
+       PF_CS_KILL_MATCH        = 11, /* bool */
+       PF_CS_NAT               = 12, /* bool */
+       PF_CS_KILLED            = 13, /* u32 */
+};
+
 #ifdef _KERNEL
 
 void   pf_nl_register(void);

Reply via email to