The branch main has been updated by kp:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=1732afaa0dae9d844e341f2c1d6ed4b79c403bfb

commit 1732afaa0dae9d844e341f2c1d6ed4b79c403bfb
Author:     Kristof Provost <k...@freebsd.org>
AuthorDate: 2021-05-05 12:33:55 +0000
Commit:     Kristof Provost <k...@freebsd.org>
CommitDate: 2021-05-20 10:49:26 +0000

    pf: Add DIOCGETSTATENV
    
    Add DIOCGETSTATENV, an nvlist-based alternative to DIOCGETSTATE.
    
    MFC after:      1 week
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D30242
---
 share/man/man4/pf.4       |   4 +-
 sys/net/pfvar.h           |   1 +
 sys/netpfil/pf/pf_ioctl.c | 226 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 229 insertions(+), 2 deletions(-)

diff --git a/share/man/man4/pf.4 b/share/man/man4/pf.4
index 2fb132203908..24843535c924 100644
--- a/share/man/man4/pf.4
+++ b/share/man/man4/pf.4
@@ -326,14 +326,14 @@ struct pfioc_state {
        struct pfsync_state     state;
 };
 .Ed
-.It Dv DIOCGETSTATE Fa "struct pfioc_state *ps"
+.It Dv DIOCGETSTATENV Fa "struct pfioc_nv *nv"
 Extract the entry identified by the
 .Va id
 and
 .Va creatorid
 fields of the
 .Va state
-structure from the state table.
+nvlist from the state table.
 .It Dv DIOCKILLSTATES Fa "struct pfioc_state_kill *psk"
 Remove matching entries from the state table.
 This ioctl returns the number of killed states in
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 51c51a82b36d..1bd1ebd27449 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1257,6 +1257,7 @@ struct pfioc_iface {
 #define DIOCCLRSTATES  _IOWR('D', 18, struct pfioc_state_kill)
 #define DIOCCLRSTATESNV        _IOWR('D', 18, struct pfioc_nv)
 #define DIOCGETSTATE   _IOWR('D', 19, struct pfioc_state)
+#define DIOCGETSTATENV _IOWR('D', 19, struct pfioc_nv)
 #define DIOCSETSTATUSIF _IOWR('D', 20, struct pfioc_if)
 #define DIOCGETSTATUS  _IOWR('D', 21, struct pf_status)
 #define DIOCCLRSTATUS  _IO  ('D', 22)
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 2d13ddf1ac61..1ea7310ebebb 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -208,6 +208,7 @@ static int           pf_killstates_row(struct 
pf_kstate_kill *,
                            struct pf_idhash *);
 static int              pf_killstates_nv(struct pfioc_nv *);
 static int              pf_clearstates_nv(struct pfioc_nv *);
+static int              pf_getstate(struct pfioc_nv *);
 static int              pf_clear_tables(void);
 static void             pf_clear_srcnodes(struct pf_ksrc_node *);
 static void             pf_kill_srcnodes(struct pfioc_src_node_kill *);
@@ -2474,6 +2475,157 @@ errout:
        return (error);
 }
 
+static nvlist_t *
+pf_state_key_to_nvstate_key(const struct pf_state_key *key)
+{
+       nvlist_t        *nvl, *tmp;
+
+       nvl = nvlist_create(0);
+       if (nvl == NULL)
+               return (NULL);
+
+       for (int i = 0; i < 2; i++) {
+               tmp = pf_addr_to_nvaddr(&key->addr[i]);
+               if (tmp == NULL)
+                       goto errout;
+               nvlist_append_nvlist_array(nvl, "addr", tmp);
+               nvlist_append_number_array(nvl, "port", key->port[i]);
+       }
+       nvlist_add_number(nvl, "af", key->af);
+       nvlist_add_number(nvl, "proto", key->proto);
+
+       return (nvl);
+
+errout:
+       nvlist_destroy(nvl);
+       return (NULL);
+}
+
+static nvlist_t *
+pf_state_scrub_to_nvstate_scrub(const struct pf_state_scrub *scrub)
+{
+       nvlist_t *nvl;
+
+       nvl = nvlist_create(0);
+       if (nvl == NULL)
+               return (NULL);
+
+       nvlist_add_bool(nvl, "timestamp", scrub->pfss_flags & PFSS_TIMESTAMP);
+       nvlist_add_number(nvl, "ttl", scrub->pfss_ttl);
+       nvlist_add_number(nvl, "ts_mod", scrub->pfss_ts_mod);
+
+       return (nvl);
+}
+
+static nvlist_t *
+pf_state_peer_to_nvstate_peer(const struct pf_state_peer *peer)
+{
+       nvlist_t *nvl, *tmp;
+
+       nvl = nvlist_create(0);
+       if (nvl == NULL)
+               return (NULL);
+
+       if (peer->scrub) {
+               tmp = pf_state_scrub_to_nvstate_scrub(peer->scrub);
+               if (tmp == NULL)
+                       goto errout;
+               nvlist_add_nvlist(nvl, "scrub", tmp);
+       }
+
+       nvlist_add_number(nvl, "seqlo", peer->seqlo);
+       nvlist_add_number(nvl, "seqhi", peer->seqhi);
+       nvlist_add_number(nvl, "seqdiff", peer->seqdiff);
+       nvlist_add_number(nvl, "max_win", peer->max_win);
+       nvlist_add_number(nvl, "mss", peer->mss);
+       nvlist_add_number(nvl, "state", peer->state);
+       nvlist_add_number(nvl, "wscale", peer->wscale);
+
+       return (nvl);
+
+errout:
+       nvlist_destroy(nvl);
+       return (NULL);
+}
+
+
+static nvlist_t *
+pf_state_to_nvstate(const struct pf_state *s)
+{
+       nvlist_t        *nvl, *tmp;
+       uint32_t         expire, flags = 0;
+
+       nvl = nvlist_create(0);
+       if (nvl == NULL)
+               return (NULL);
+
+       nvlist_add_number(nvl, "id", s->id);
+       nvlist_add_string(nvl, "ifname", s->kif->pfik_name);
+
+       tmp = pf_state_key_to_nvstate_key(s->key[PF_SK_STACK]);
+       if (tmp == NULL)
+               goto errout;
+       nvlist_add_nvlist(nvl, "stack_key", tmp);
+
+       tmp = pf_state_key_to_nvstate_key(s->key[PF_SK_WIRE]);
+       if (tmp == NULL)
+               goto errout;
+       nvlist_add_nvlist(nvl, "wire_key", tmp);
+
+       tmp = pf_state_peer_to_nvstate_peer(&s->src);
+       if (tmp == NULL)
+               goto errout;
+       nvlist_add_nvlist(nvl, "src", tmp);
+
+       tmp = pf_state_peer_to_nvstate_peer(&s->dst);
+       if (tmp == NULL)
+               goto errout;
+       nvlist_add_nvlist(nvl, "dst", tmp);
+
+       tmp = pf_addr_to_nvaddr(&s->rt_addr);
+       if (tmp == NULL)
+               goto errout;
+       nvlist_add_nvlist(nvl, "rt_addr", tmp);
+
+       nvlist_add_number(nvl, "rule", s->rule.ptr ? s->rule.ptr->nr : -1);
+       nvlist_add_number(nvl, "anchor",
+           s->anchor.ptr ? s->anchor.ptr->nr : -1);
+       nvlist_add_number(nvl, "nat_rule",
+           s->nat_rule.ptr ? s->nat_rule.ptr->nr : -1);
+       nvlist_add_number(nvl, "creation", s->creation);
+
+       expire = pf_state_expires(s);
+       if (expire <= time_uptime)
+               expire = 0;
+       else
+               expire = expire - time_uptime;
+       nvlist_add_number(nvl, "expire", expire);
+
+       for (int i = 0; i < 2; i++) {
+               nvlist_append_number_array(nvl, "packets",
+                   counter_u64_fetch(s->packets[i]));
+               nvlist_append_number_array(nvl, "bytes",
+                   counter_u64_fetch(s->bytes[i]));
+       }
+
+       nvlist_add_number(nvl, "creatorid", s->creatorid);
+       nvlist_add_number(nvl, "direction", s->direction);
+       nvlist_add_number(nvl, "log", s->log);
+       nvlist_add_number(nvl, "state_flags", s->state_flags);
+       nvlist_add_number(nvl, "timeout", s->timeout);
+       if (s->src_node)
+               flags |= PFSYNC_FLAG_SRCNODE;
+       if (s->nat_src_node)
+               flags |= PFSYNC_FLAG_NATSRCNODE;
+       nvlist_add_number(nvl, "sync_flags", flags);
+
+       return (nvl);
+
+errout:
+       nvlist_destroy(nvl);
+       return (NULL);
+}
+
 static int
 pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
     uint32_t pool_ticket, const char *anchor, const char *anchor_call,
@@ -2789,6 +2941,7 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int 
flags, struct thread *td
                case DIOCGETADDRS:
                case DIOCGETADDR:
                case DIOCGETSTATE:
+               case DIOCGETSTATENV:
                case DIOCSETSTATUSIF:
                case DIOCGETSTATUS:
                case DIOCCLRSTATUS:
@@ -2844,6 +2997,7 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int 
flags, struct thread *td
                case DIOCGETADDRS:
                case DIOCGETADDR:
                case DIOCGETSTATE:
+               case DIOCGETSTATENV:
                case DIOCGETSTATUS:
                case DIOCGETSTATES:
                case DIOCGETTIMEOUT:
@@ -3504,6 +3658,11 @@ DIOCCHANGERULE_error:
                break;
        }
 
+       case DIOCGETSTATENV: {
+               error = pf_getstate((struct pfioc_nv *)addr);
+               break;
+       }
+
        case DIOCGETSTATES: {
                struct pfioc_states     *ps = (struct pfioc_states *)addr;
                struct pf_state         *s;
@@ -5684,12 +5843,79 @@ pf_clearstates_nv(struct pfioc_nv *nv)
 
        error = copyout(nvlpacked, nv->data, nv->len);
 
+#undef ERROUT
 on_error:
        nvlist_destroy(nvl);
        free(nvlpacked, M_TEMP);
        return (error);
 }
 
+static int
+pf_getstate(struct pfioc_nv *nv)
+{
+       nvlist_t        *nvl = NULL, *nvls;
+       void            *nvlpacked = NULL;
+       struct pf_state *s = NULL;
+       int              error = 0;
+       uint64_t         id, creatorid;
+
+#define ERROUT(x)      ERROUT_FUNCTION(errout, x)
+
+       if (nv->len > pf_ioctl_maxcount)
+               ERROUT(ENOMEM);
+
+       nvlpacked = malloc(nv->len, M_TEMP, M_WAITOK);
+       if (nvlpacked == NULL)
+               ERROUT(ENOMEM);
+
+       error = copyin(nv->data, nvlpacked, nv->len);
+       if (error)
+               ERROUT(error);
+
+       nvl = nvlist_unpack(nvlpacked, nv->len, 0);
+       if (nvl == NULL)
+               ERROUT(EBADMSG);
+
+       PFNV_CHK(pf_nvuint64(nvl, "id", &id));
+       PFNV_CHK(pf_nvuint64(nvl, "creatorid", &creatorid));
+
+       s = pf_find_state_byid(id, creatorid);
+       if (s == NULL)
+               ERROUT(ENOENT);
+
+       free(nvlpacked, M_TEMP);
+       nvlpacked = NULL;
+       nvlist_destroy(nvl);
+       nvl = nvlist_create(0);
+       if (nvl == NULL)
+               ERROUT(ENOMEM);
+
+       nvls = pf_state_to_nvstate(s);
+       if (nvls == NULL)
+               ERROUT(ENOMEM);
+
+       nvlist_add_nvlist(nvl, "state", nvls);
+
+       nvlpacked = nvlist_pack(nvl, &nv->len);
+       if (nvlpacked == NULL)
+               ERROUT(ENOMEM);
+
+       if (nv->size == 0)
+               ERROUT(0);
+       else if (nv->size < nv->len)
+               ERROUT(ENOSPC);
+
+       error = copyout(nvlpacked, nv->data, nv->len);
+
+#undef ERROUT
+errout:
+       if (s != NULL)
+               PF_STATE_UNLOCK(s);
+       free(nvlpacked, M_TEMP);
+       nvlist_destroy(nvl);
+       return (error);
+}
+
 /*
  * XXX - Check for version missmatch!!!
  */
_______________________________________________
dev-commits-src-main@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-main
To unsubscribe, send any mail to "dev-commits-src-main-unsubscr...@freebsd.org"

Reply via email to