The branch main has been updated by kp:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=4bf98559d9d6fa7c3571d26ed6f2b18823e3a30b

commit 4bf98559d9d6fa7c3571d26ed6f2b18823e3a30b
Author:     Kajetan Staszkiewicz <[email protected]>
AuthorDate: 2023-05-29 13:47:23 +0000
Commit:     Kristof Provost <[email protected]>
CommitDate: 2023-05-30 12:28:56 +0000

    pf: make contents of struct pfsync_state configurable
    
    Make struct pfsync_state contents configurable by sending out new
    versions of the structure in separate subheader actions. Both old and
    new version of struct pfsync_state can be understood, so replication of
    states from a system running an older kernel is possible. The version
    being sent out is configured using ifconfig pfsync0 … version XXXX. The
    version is an user-friendly string - 1301 stands for FreeBSD 13.1 (I
    have checked synchronization against a host running 13.1), 1400 stands
    for 14.0.
    
    A host running an older kernel will just ignore the messages and count
    them as "packets discarded for bad action".
    
    Reviewed by:    kp
    Sponsored by:   InnoGames GmbH
    Differential Revision:  https://reviews.freebsd.org/D39392
---
 contrib/tcpdump/print-pfsync.c |  98 +++++----
 sbin/ifconfig/ifpfsync.c       |  28 ++-
 sys/net/if_pfsync.h            |  19 +-
 sys/net/pfvar.h                |  68 ++++++-
 sys/netpfil/pf/if_pfsync.c     | 445 ++++++++++++++++++++++++++++-------------
 sys/netpfil/pf/pf.c            | 193 +++++++++++++-----
 sys/netpfil/pf/pf_ioctl.c      | 132 +++++++-----
 sys/netpfil/pf/pfsync_nv.c     |   1 +
 usr.bin/netstat/if.c           |  12 +-
 9 files changed, 688 insertions(+), 308 deletions(-)

diff --git a/contrib/tcpdump/print-pfsync.c b/contrib/tcpdump/print-pfsync.c
index dc1cd039f5b0..ee13cade1b14 100644
--- a/contrib/tcpdump/print-pfsync.c
+++ b/contrib/tcpdump/print-pfsync.c
@@ -55,7 +55,7 @@ static void   pfsync_print(netdissect_options *, struct 
pfsync_header *,
 static void    print_src_dst(netdissect_options *,
                    const struct pfsync_state_peer *,
                    const struct pfsync_state_peer *, uint8_t);
-static void    print_state(netdissect_options *, struct pfsync_state *);
+static void    print_state(netdissect_options *, union pfsync_state_union *, 
int);
 
 u_int
 pfsync_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h,
@@ -100,7 +100,8 @@ struct pfsync_actions {
 };
 
 static void    pfsync_print_clr(netdissect_options *, const void *);
-static void    pfsync_print_state(netdissect_options *, const void *);
+static void    pfsync_print_state_1301(netdissect_options *, const void *);
+static void    pfsync_print_state_1400(netdissect_options *, const void *);
 static void    pfsync_print_ins_ack(netdissect_options *, const void *);
 static void    pfsync_print_upd_c(netdissect_options *, const void *);
 static void    pfsync_print_upd_req(netdissect_options *, const void *);
@@ -110,14 +111,16 @@ static void       pfsync_print_tdb(netdissect_options *, 
const void *);
 
 struct pfsync_actions actions[] = {
        { "clear all", sizeof(struct pfsync_clr),       pfsync_print_clr },
-       { "insert", sizeof(struct pfsync_state),        pfsync_print_state },
+       { "insert 13.1", sizeof(struct pfsync_state_1301),
+                                                       pfsync_print_state_1301 
},
        { "insert ack", sizeof(struct pfsync_ins_ack),  pfsync_print_ins_ack },
-       { "update", sizeof(struct pfsync_ins_ack),      pfsync_print_state },
+       { "update 13.1", sizeof(struct pfsync_state_1301),
+                                                       pfsync_print_state_1301 
},
        { "update compressed", sizeof(struct pfsync_upd_c),
                                                        pfsync_print_upd_c },
        { "request uncompressed", sizeof(struct pfsync_upd_req),
                                                        pfsync_print_upd_req },
-       { "delete", sizeof(struct pfsync_state),        pfsync_print_state },
+       { "delete", sizeof(struct pfsync_state_1301),   pfsync_print_state_1301 
},
        { "delete compressed", sizeof(struct pfsync_del_c),
                                                        pfsync_print_del_c },
        { "frag insert", 0,                             NULL },
@@ -126,6 +129,8 @@ struct pfsync_actions actions[] = {
                                                        pfsync_print_bus },
        { "tdb", 0,                                     pfsync_print_tdb },
        { "eof", 0,                                     NULL },
+       { "insert", sizeof(struct pfsync_state_1400),   pfsync_print_state_1400 
},
+       { "update", sizeof(struct pfsync_state_1400),   pfsync_print_state_1400 
},
 };
 
 static void
@@ -212,12 +217,21 @@ pfsync_print_clr(netdissect_options *ndo, const void *bp)
 }
 
 static void
-pfsync_print_state(netdissect_options *ndo, const void *bp)
+pfsync_print_state_1301(netdissect_options *ndo, const void *bp)
 {
-       struct pfsync_state *st = (struct pfsync_state *)bp;
+       struct pfsync_state_1301 *st = (struct pfsync_state_1301 *)bp;
 
        safeputchar(ndo, '\n');
-       print_state(ndo, st);
+       print_state(ndo, (union pfsync_state_union *)st, 
PFSYNC_MSG_VERSION_1301);
+}
+
+static void
+pfsync_print_state_1400(netdissect_options *ndo, const void *bp)
+{
+       struct pfsync_state_1301 *st = (struct pfsync_state_1301 *)bp;
+
+       safeputchar(ndo, '\n');
+       print_state(ndo, (union pfsync_state_union *)st, 
PFSYNC_MSG_VERSION_1400);
 }
 
 static void
@@ -374,56 +388,56 @@ print_src_dst(netdissect_options *ndo, const struct 
pfsync_state_peer *src,
 }
 
 static void
-print_state(netdissect_options *ndo, struct pfsync_state *s)
+print_state(netdissect_options *ndo, union pfsync_state_union *s, int version)
 {
        struct pfsync_state_peer *src, *dst;
        struct pfsync_state_key *sk, *nk;
        int min, sec;
 
-       if (s->direction == PF_OUT) {
-               src = &s->src;
-               dst = &s->dst;
-               sk = &s->key[PF_SK_STACK];
-               nk = &s->key[PF_SK_WIRE];
-               if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6)
+       if (s->pfs_1301.direction == PF_OUT) {
+               src = &s->pfs_1301.src;
+               dst = &s->pfs_1301.dst;
+               sk = &s->pfs_1301.key[PF_SK_STACK];
+               nk = &s->pfs_1301.key[PF_SK_WIRE];
+               if (s->pfs_1301.proto == IPPROTO_ICMP || s->pfs_1301.proto == 
IPPROTO_ICMPV6)
                        sk->port[0] = nk->port[0];
        } else {
-               src = &s->dst;
-               dst = &s->src;
-               sk = &s->key[PF_SK_WIRE];
-               nk = &s->key[PF_SK_STACK];
-               if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6)
+               src = &s->pfs_1301.dst;
+               dst = &s->pfs_1301.src;
+               sk = &s->pfs_1301.key[PF_SK_WIRE];
+               nk = &s->pfs_1301.key[PF_SK_STACK];
+               if (s->pfs_1301.proto == IPPROTO_ICMP || s->pfs_1301.proto == 
IPPROTO_ICMPV6)
                        sk->port[1] = nk->port[1];
        }
-       ND_PRINT((ndo, "\t%s ", s->ifname));
-       ND_PRINT((ndo, "proto %u ", s->proto));
+       ND_PRINT((ndo, "\t%s ", s->pfs_1301.ifname));
+       ND_PRINT((ndo, "proto %u ", s->pfs_1301.proto));
 
-       print_host(ndo, &nk->addr[1], nk->port[1], s->af, NULL);
-       if (PF_ANEQ(&nk->addr[1], &sk->addr[1], s->af) ||
+       print_host(ndo, &nk->addr[1], nk->port[1], s->pfs_1301.af, NULL);
+       if (PF_ANEQ(&nk->addr[1], &sk->addr[1], s->pfs_1301.af) ||
            nk->port[1] != sk->port[1]) {
                ND_PRINT((ndo, " ("));
-               print_host(ndo, &sk->addr[1], sk->port[1], s->af, NULL);
+               print_host(ndo, &sk->addr[1], sk->port[1], s->pfs_1301.af, 
NULL);
                ND_PRINT((ndo, ")"));
        }
-       if (s->direction == PF_OUT)
+       if (s->pfs_1301.direction == PF_OUT)
                ND_PRINT((ndo, " -> "));
        else
                ND_PRINT((ndo, " <- "));
-       print_host(ndo, &nk->addr[0], nk->port[0], s->af, NULL);
-       if (PF_ANEQ(&nk->addr[0], &sk->addr[0], s->af) ||
+       print_host(ndo, &nk->addr[0], nk->port[0], s->pfs_1301.af, NULL);
+       if (PF_ANEQ(&nk->addr[0], &sk->addr[0], s->pfs_1301.af) ||
            nk->port[0] != sk->port[0]) {
                ND_PRINT((ndo, " ("));
-               print_host(ndo, &sk->addr[0], sk->port[0], s->af, NULL);
+               print_host(ndo, &sk->addr[0], sk->port[0], s->pfs_1301.af, 
NULL);
                ND_PRINT((ndo, ")"));
        }
 
-       print_src_dst(ndo, src, dst, s->proto);
+       print_src_dst(ndo, src, dst, s->pfs_1301.proto);
 
        if (ndo->ndo_vflag > 1) {
                uint64_t packets[2];
                uint64_t bytes[2];
-               uint32_t creation = ntohl(s->creation);
-               uint32_t expire = ntohl(s->expire);
+               uint32_t creation = ntohl(s->pfs_1301.creation);
+               uint32_t expire = ntohl(s->pfs_1301.expire);
 
                sec = creation % 60;
                creation /= 60;
@@ -436,23 +450,23 @@ print_state(netdissect_options *ndo, struct pfsync_state 
*s)
                expire /= 60;
                ND_PRINT((ndo, ", expires in %.2u:%.2u:%.2u", expire, min, 
sec));
 
-               bcopy(s->packets[0], &packets[0], sizeof(uint64_t));
-               bcopy(s->packets[1], &packets[1], sizeof(uint64_t));
-               bcopy(s->bytes[0], &bytes[0], sizeof(uint64_t));
-               bcopy(s->bytes[1], &bytes[1], sizeof(uint64_t));
+               bcopy(s->pfs_1301.packets[0], &packets[0], sizeof(uint64_t));
+               bcopy(s->pfs_1301.packets[1], &packets[1], sizeof(uint64_t));
+               bcopy(s->pfs_1301.bytes[0], &bytes[0], sizeof(uint64_t));
+               bcopy(s->pfs_1301.bytes[1], &bytes[1], sizeof(uint64_t));
                ND_PRINT((ndo, ", %ju:%ju pkts, %ju:%ju bytes",
                    be64toh(packets[0]), be64toh(packets[1]),
                    be64toh(bytes[0]), be64toh(bytes[1])));
-               if (s->anchor != ntohl(-1))
-                       ND_PRINT((ndo, ", anchor %u", ntohl(s->anchor)));
-               if (s->rule != ntohl(-1))
-                       ND_PRINT((ndo, ", rule %u", ntohl(s->rule)));
+               if (s->pfs_1301.anchor != ntohl(-1))
+                       ND_PRINT((ndo, ", anchor %u", 
ntohl(s->pfs_1301.anchor)));
+               if (s->pfs_1301.rule != ntohl(-1))
+                       ND_PRINT((ndo, ", rule %u", ntohl(s->pfs_1301.rule)));
        }
        if (ndo->ndo_vflag > 1) {
                uint64_t id;
 
-               bcopy(&s->id, &id, sizeof(uint64_t));
+               bcopy(&s->pfs_1301.id, &id, sizeof(uint64_t));
                ND_PRINT((ndo, "\n\tid: %016jx creatorid: %08x",
-                   (uintmax_t )be64toh(id), ntohl(s->creatorid)));
+                   (uintmax_t )be64toh(id), ntohl(s->pfs_1301.creatorid)));
        }
 }
diff --git a/sbin/ifconfig/ifpfsync.c b/sbin/ifconfig/ifpfsync.c
index 8fd15962c2d0..de2a2445afb4 100644
--- a/sbin/ifconfig/ifpfsync.c
+++ b/sbin/ifconfig/ifpfsync.c
@@ -309,6 +309,27 @@ setpfsync_defer(if_ctx *ctx, const char *val, int d)
        nvlist_destroy(nvl);
 }
 
+static void
+setpfsync_version(if_ctx *ctx, const char *val, int dummy __unused)
+{
+       int version;
+       nvlist_t *nvl = nvlist_create(0);
+
+       /* Don't verify, kernel knows which versions are supported.*/
+       version = atoi(val);
+
+       if (pfsync_do_ioctl(ctx->io_s, SIOCGETPFSYNCNV, &nvl) == -1)
+               err(1, "SIOCGETPFSYNCNV");
+
+       nvlist_free_number(nvl, "version");
+       nvlist_add_number(nvl, "version", version);
+
+       if (pfsync_do_ioctl(ctx->io_s, SIOCSETPFSYNCNV, &nvl) == -1)
+               err(1, "SIOCSETPFSYNCNV");
+
+       nvlist_destroy(nvl);
+}
+
 static void
 pfsync_status(if_ctx *ctx)
 {
@@ -318,6 +339,7 @@ pfsync_status(if_ctx *ctx)
        struct sockaddr_storage syncpeer;
        int maxupdates = 0;
        int flags = 0;
+       int version;
        int error;
 
        nvl = nvlist_create(0);
@@ -333,6 +355,8 @@ pfsync_status(if_ctx *ctx)
                    IFNAMSIZ);
        if (nvlist_exists_number(nvl, "maxupdates"))
                maxupdates = nvlist_get_number(nvl, "maxupdates");
+       if (nvlist_exists_number(nvl, "version"))
+               version = nvlist_get_number(nvl, "version");
        if (nvlist_exists_number(nvl, "flags"))
                flags = nvlist_get_number(nvl, "flags");
        if (nvlist_exists_nvlist(nvl, "syncpeer")) {
@@ -363,7 +387,8 @@ pfsync_status(if_ctx *ctx)
        }
 
        printf("maxupd: %d ", maxupdates);
-       printf("defer: %s\n", (flags & PFSYNCF_DEFER) ? "on" : "off");
+       printf("defer: %s ", (flags & PFSYNCF_DEFER) ? "on" : "off");
+       printf("version: %d\n", version);
        printf("\tsyncok: %d\n", (flags & PFSYNCF_OK) ? 1 : 0);
 }
 
@@ -377,6 +402,7 @@ static struct cmd pfsync_cmds[] = {
        DEF_CMD_ARG("maxupd",           setpfsync_maxupd),
        DEF_CMD("defer",        1,      setpfsync_defer),
        DEF_CMD("-defer",       0,      setpfsync_defer),
+       DEF_CMD_ARG("version",          setpfsync_version),
 };
 static struct afswtch af_pfsync = {
        .af_name        = "af_pfsync",
diff --git a/sys/net/if_pfsync.h b/sys/net/if_pfsync.h
index a13e26fd3bdf..ef5c26285781 100644
--- a/sys/net/if_pfsync.h
+++ b/sys/net/if_pfsync.h
@@ -59,10 +59,18 @@
 #define        PFSYNC_VERSION          5
 #define        PFSYNC_DFLTTL           255
 
+enum pfsync_msg_versions {
+       PFSYNC_MSG_VERSION_UNSPECIFIED = 0,
+       PFSYNC_MSG_VERSION_1301 = 1301,
+       PFSYNC_MSG_VERSION_1400 = 1400,
+};
+
+#define PFSYNC_MSG_VERSION_DEFAULT PFSYNC_MSG_VERSION_1400
+
 #define        PFSYNC_ACT_CLR          0       /* clear all states */
-#define        PFSYNC_ACT_INS          1       /* insert state */
+#define        PFSYNC_ACT_INS_1301     1       /* insert state */
 #define        PFSYNC_ACT_INS_ACK      2       /* ack of inserted state */
-#define        PFSYNC_ACT_UPD          3       /* update state */
+#define        PFSYNC_ACT_UPD_1301     3       /* update state */
 #define        PFSYNC_ACT_UPD_C        4       /* "compressed" update state */
 #define        PFSYNC_ACT_UPD_REQ      5       /* request "uncompressed" state 
*/
 #define        PFSYNC_ACT_DEL          6       /* delete state */
@@ -72,7 +80,9 @@
 #define        PFSYNC_ACT_BUS          10      /* bulk update status */
 #define        PFSYNC_ACT_TDB          11      /* TDB replay counter update */
 #define        PFSYNC_ACT_EOF          12      /* end of frame */
-#define        PFSYNC_ACT_MAX          13
+#define PFSYNC_ACT_INS_1400    13      /* insert state */
+#define PFSYNC_ACT_UPD_1400    14      /* update state */
+#define        PFSYNC_ACT_MAX          15
 
 /*
  * A pfsync frame is built from a header followed by several sections which
@@ -251,6 +261,7 @@ struct pfsync_kstatus {
        char                    syncdev[IFNAMSIZ];
        struct sockaddr_storage syncpeer;
        int                     maxupdates;
+       int                     version;
        int                     flags;
 };
 
@@ -269,13 +280,13 @@ struct pfsyncioc_nv {
 
 /*
  * this shows where a pf state is with respect to the syncing.
+ * pf_kstate->sync_state
  */
 #define        PFSYNC_S_INS    0x00
 #define        PFSYNC_S_IACK   0x01
 #define        PFSYNC_S_UPD    0x02
 #define        PFSYNC_S_UPD_C  0x03
 #define        PFSYNC_S_DEL_C  0x04
-#define        PFSYNC_S_COUNT  0x05
 
 #define        PFSYNC_S_DEFER  0xfe
 #define        PFSYNC_S_NONE   0xff
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 4bdfa22b58ab..c5923bc9abdf 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -641,6 +641,7 @@ struct pf_rule_actions {
        uint16_t         dnpipe;
        uint16_t         dnrpipe;       /* Reverse direction pipe */
        uint32_t         flags;
+       uint8_t          set_prio[2];
 };
 
 union pf_keth_rule_ptr {
@@ -1057,12 +1058,14 @@ struct pf_kstate {
        u_int8_t                 min_ttl;
        u_int8_t                 set_tos;
        u_int16_t                max_mss;
+       u_int8_t                 rt;
+       u_int8_t                 set_prio[2];
 };
 
 /*
- * Size <= fits 12 objects per page on LP64. Try to not grow the struct beyond 
that.
+ * Size <= fits 11 objects per page on LP64. Try to not grow the struct beyond 
that.
  */
-_Static_assert(sizeof(struct pf_kstate) <= 336, "pf_kstate size crosses 336 
bytes");
+_Static_assert(sizeof(struct pf_kstate) <= 368, "pf_kstate size crosses 368 
bytes");
 #endif
 
 /*
@@ -1094,7 +1097,34 @@ struct pfsync_state_key {
        u_int16_t        port[2];
 };
 
-struct pfsync_state {
+struct pfsync_state_1301 {
+       u_int64_t        id;
+       char             ifname[IFNAMSIZ];
+       struct pfsync_state_key key[2];
+       struct pfsync_state_peer src;
+       struct pfsync_state_peer dst;
+       struct pf_addr   rt_addr;
+       u_int32_t        rule;
+       u_int32_t        anchor;
+       u_int32_t        nat_rule;
+       u_int32_t        creation;
+       u_int32_t        expire;
+       u_int32_t        packets[2][2];
+       u_int32_t        bytes[2][2];
+       u_int32_t        creatorid;
+       sa_family_t      af;
+       u_int8_t         proto;
+       u_int8_t         direction;
+       u_int8_t         __spare[2];
+       u_int8_t         log;
+       u_int8_t         state_flags;
+       u_int8_t         timeout;
+       u_int8_t         sync_flags;
+       u_int8_t         updates;
+} __packed;
+
+struct pfsync_state_1400 {
+       /* The beginning of the struct is compatible with previous versions */
        u_int64_t        id;
        char             ifname[IFNAMSIZ];
        struct pfsync_state_key key[2];
@@ -1114,15 +1144,33 @@ struct pfsync_state {
        u_int8_t         direction;
        u_int16_t        state_flags;
        u_int8_t         log;
-       u_int8_t         state_flags_compat;
+       u_int8_t         __spare;
        u_int8_t         timeout;
        u_int8_t         sync_flags;
        u_int8_t         updates;
+       /* The rest is not */
+       u_int16_t        qid;
+       u_int16_t        pqid;
+       u_int16_t        dnpipe;
+       u_int16_t        dnrpipe;
+       int32_t          rtableid;
+       u_int8_t         min_ttl;
+       u_int8_t         set_tos;
+       u_int16_t        max_mss;
+       u_int8_t         set_prio[2];
+       u_int8_t         rt;
+       char             rt_ifname[IFNAMSIZ];
+
+} __packed;
+
+union pfsync_state_union {
+       struct pfsync_state_1301 pfs_1301;
+       struct pfsync_state_1400 pfs_1400;
 } __packed;
 
 #ifdef _KERNEL
 /* pfsync */
-typedef int            pfsync_state_import_t(struct pfsync_state *, int);
+typedef int            pfsync_state_import_t(union pfsync_state_union *, int, 
int);
 typedef        void            pfsync_insert_state_t(struct pf_kstate *);
 typedef        void            pfsync_update_state_t(struct pf_kstate *);
 typedef        void            pfsync_delete_state_t(struct pf_kstate *);
@@ -1144,8 +1192,8 @@ VNET_DECLARE(pfsync_defer_t *, pfsync_defer_ptr);
 #define V_pfsync_defer_ptr             VNET(pfsync_defer_ptr)
 extern pfsync_detach_ifnet_t   *pfsync_detach_ifnet_ptr;
 
-void                   pfsync_state_export(struct pfsync_state *,
-                           struct pf_kstate *);
+void                   pfsync_state_export(union pfsync_state_union *,
+                           struct pf_kstate *, int);
 void                   pf_state_export(struct pf_state_export *,
                            struct pf_kstate *);
 
@@ -1665,7 +1713,7 @@ struct pfioc_natlook {
 };
 
 struct pfioc_state {
-       struct pfsync_state     state;
+       struct pfsync_state_1301        state;
 };
 
 struct pfioc_src_node_kill {
@@ -1704,8 +1752,8 @@ struct pfioc_state_kill {
 struct pfioc_states {
        int     ps_len;
        union {
-               void                    *ps_buf;
-               struct pfsync_state     *ps_states;
+               void                            *ps_buf;
+               struct pfsync_state_1301        *ps_states;
        };
 };
 
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
index f53479283ecd..67f986e6abd2 100644
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -122,23 +122,23 @@ union inet_template {
 
 static int     pfsync_upd_tcp(struct pf_kstate *, struct pfsync_state_peer *,
                    struct pfsync_state_peer *);
-static int     pfsync_in_clr(struct mbuf *, int, int, int);
-static int     pfsync_in_ins(struct mbuf *, int, int, int);
-static int     pfsync_in_iack(struct mbuf *, int, int, int);
-static int     pfsync_in_upd(struct mbuf *, int, int, int);
-static int     pfsync_in_upd_c(struct mbuf *, int, int, int);
-static int     pfsync_in_ureq(struct mbuf *, int, int, int);
-static int     pfsync_in_del_c(struct mbuf *, int, int, int);
-static int     pfsync_in_bus(struct mbuf *, int, int, int);
-static int     pfsync_in_tdb(struct mbuf *, int, int, int);
-static int     pfsync_in_eof(struct mbuf *, int, int, int);
-static int     pfsync_in_error(struct mbuf *, int, int, int);
-
-static int (*pfsync_acts[])(struct mbuf *, int, int, int) = {
+static int     pfsync_in_clr(struct mbuf *, int, int, int, int);
+static int     pfsync_in_ins(struct mbuf *, int, int, int, int);
+static int     pfsync_in_iack(struct mbuf *, int, int, int, int);
+static int     pfsync_in_upd(struct mbuf *, int, int, int, int);
+static int     pfsync_in_upd_c(struct mbuf *, int, int, int, int);
+static int     pfsync_in_ureq(struct mbuf *, int, int, int, int);
+static int     pfsync_in_del_c(struct mbuf *, int, int, int, int);
+static int     pfsync_in_bus(struct mbuf *, int, int, int, int);
+static int     pfsync_in_tdb(struct mbuf *, int, int, int, int);
+static int     pfsync_in_eof(struct mbuf *, int, int, int, int);
+static int     pfsync_in_error(struct mbuf *, int, int, int, int);
+
+static int (*pfsync_acts[])(struct mbuf *, int, int, int, int) = {
        pfsync_in_clr,                  /* PFSYNC_ACT_CLR */
-       pfsync_in_ins,                  /* PFSYNC_ACT_INS */
+       pfsync_in_ins,                  /* PFSYNC_ACT_INS_1301 */
        pfsync_in_iack,                 /* PFSYNC_ACT_INS_ACK */
-       pfsync_in_upd,                  /* PFSYNC_ACT_UPD */
+       pfsync_in_upd,                  /* PFSYNC_ACT_UPD_1301 */
        pfsync_in_upd_c,                /* PFSYNC_ACT_UPD_C */
        pfsync_in_ureq,                 /* PFSYNC_ACT_UPD_REQ */
        pfsync_in_error,                /* PFSYNC_ACT_DEL */
@@ -147,7 +147,9 @@ static int (*pfsync_acts[])(struct mbuf *, int, int, int) = 
{
        pfsync_in_error,                /* PFSYNC_ACT_DEL_F */
        pfsync_in_bus,                  /* PFSYNC_ACT_BUS */
        pfsync_in_tdb,                  /* PFSYNC_ACT_TDB */
-       pfsync_in_eof                   /* PFSYNC_ACT_EOF */
+       pfsync_in_eof,                  /* PFSYNC_ACT_EOF */
+       pfsync_in_ins,                  /* PFSYNC_ACT_INS_1400 */
+       pfsync_in_upd,                  /* PFSYNC_ACT_UPD_1400 */
 };
 
 struct pfsync_q {
@@ -156,21 +158,51 @@ struct pfsync_q {
        u_int8_t        action;
 };
 
-/* we have one of these for every PFSYNC_S_ */
-static void    pfsync_out_state(struct pf_kstate *, void *);
+/* We have the following sync queues */
+enum pfsync_q_id {
+       PFSYNC_Q_INS_1301,
+       PFSYNC_Q_INS_1400,
+       PFSYNC_Q_IACK,
+       PFSYNC_Q_UPD_1301,
+       PFSYNC_Q_UPD_1400,
+       PFSYNC_Q_UPD_C,
+       PFSYNC_Q_DEL_C,
+       PFSYNC_Q_COUNT,
+};
+
+/* Functions for building messages for given queue */
+static void    pfsync_out_state_1301(struct pf_kstate *, void *);
+static void    pfsync_out_state_1400(struct pf_kstate *, void *);
 static void    pfsync_out_iack(struct pf_kstate *, void *);
 static void    pfsync_out_upd_c(struct pf_kstate *, void *);
 static void    pfsync_out_del_c(struct pf_kstate *, void *);
 
+/* Attach those functions to queue */
 static struct pfsync_q pfsync_qs[] = {
-       { pfsync_out_state, sizeof(struct pfsync_state),   PFSYNC_ACT_INS },
-       { pfsync_out_iack,  sizeof(struct pfsync_ins_ack), PFSYNC_ACT_INS_ACK },
-       { pfsync_out_state, sizeof(struct pfsync_state),   PFSYNC_ACT_UPD },
-       { pfsync_out_upd_c, sizeof(struct pfsync_upd_c),   PFSYNC_ACT_UPD_C },
-       { pfsync_out_del_c, sizeof(struct pfsync_del_c),   PFSYNC_ACT_DEL_C }
+       { pfsync_out_state_1301, sizeof(struct pfsync_state_1301), 
PFSYNC_ACT_INS_1301 },
+       { pfsync_out_state_1400, sizeof(struct pfsync_state_1400), 
PFSYNC_ACT_INS_1400 },
+       { pfsync_out_iack,       sizeof(struct pfsync_ins_ack),    
PFSYNC_ACT_INS_ACK },
+       { pfsync_out_state_1301, sizeof(struct pfsync_state_1301), 
PFSYNC_ACT_UPD_1301 },
+       { pfsync_out_state_1400, sizeof(struct pfsync_state_1400), 
PFSYNC_ACT_UPD_1400 },
+       { pfsync_out_upd_c,      sizeof(struct pfsync_upd_c),      
PFSYNC_ACT_UPD_C },
+       { pfsync_out_del_c,      sizeof(struct pfsync_del_c),      
PFSYNC_ACT_DEL_C }
+};
+
+/* Map queue to pf_kstate->sync_state */
+static u_int8_t pfsync_qid_sstate[] = {
+       PFSYNC_S_INS,   /* PFSYNC_Q_INS_1301 */
+       PFSYNC_S_INS,   /* PFSYNC_Q_INS_1400 */
+       PFSYNC_S_IACK,  /* PFSYNC_Q_IACK */
+       PFSYNC_S_UPD,   /* PFSYNC_Q_UPD_1301 */
+       PFSYNC_S_UPD,   /* PFSYNC_Q_UPD_1400 */
+       PFSYNC_S_UPD_C, /* PFSYNC_Q_UPD_C */
+       PFSYNC_S_DEL_C, /* PFSYNC_Q_DEL_C */
 };
 
-static void    pfsync_q_ins(struct pf_kstate *, int, bool);
+/* Map pf_kstate->sync_state to queue */
+static enum pfsync_q_id pfsync_sstate_to_qid(u_int8_t);
+
+static void    pfsync_q_ins(struct pf_kstate *, int sync_state, bool);
 static void    pfsync_q_del(struct pf_kstate *, bool, struct pfsync_bucket *);
 
 static void    pfsync_update_state(struct pf_kstate *);
@@ -200,7 +232,7 @@ struct pfsync_bucket
 #define        PFSYNCF_BUCKET_PUSH     0x00000001
 
        size_t                  b_len;
-       TAILQ_HEAD(, pf_kstate)                 b_qs[PFSYNC_S_COUNT];
+       TAILQ_HEAD(, pf_kstate)                 b_qs[PFSYNC_Q_COUNT];
        TAILQ_HEAD(, pfsync_upd_req_item)       b_upd_req_list;
        TAILQ_HEAD(, pfsync_deferral)           b_deferrals;
        u_int                   b_deferred;
@@ -220,6 +252,7 @@ struct pfsync_softc {
        uint8_t                 sc_maxupdates;
        union inet_template     sc_template;
        struct mtx              sc_mtx;
+       uint32_t                sc_version;
 
        /* Queued data */
        struct pfsync_bucket    *sc_buckets;
@@ -336,7 +369,8 @@ pfsync_clone_create(struct if_clone *ifc, int unit, caddr_t 
param)
        struct pfsync_softc *sc;
        struct ifnet *ifp;
        struct pfsync_bucket *b;
-       int c, q;
+       int c;
+       enum pfsync_q_id q;
 
        if (unit != 0)
                return (EINVAL);
@@ -347,6 +381,7 @@ pfsync_clone_create(struct if_clone *ifc, int unit, caddr_t 
param)
        sc = malloc(sizeof(struct pfsync_softc), M_PFSYNC, M_WAITOK | M_ZERO);
        sc->sc_flags |= PFSYNCF_OK;
        sc->sc_maxupdates = 128;
+       sc->sc_version = PFSYNC_MSG_VERSION_DEFAULT;
 
        ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC);
        if (ifp == NULL) {
@@ -379,7 +414,7 @@ pfsync_clone_create(struct if_clone *ifc, int unit, caddr_t 
param)
                b->b_sc = sc;
                b->b_len = PFSYNC_MINPKT;
 
-               for (q = 0; q < PFSYNC_S_COUNT; q++)
+               for (q = 0; q < PFSYNC_Q_COUNT; q++)
                        TAILQ_INIT(&b->b_qs[q]);
 
                TAILQ_INIT(&b->b_upd_req_list);
@@ -465,7 +500,7 @@ pfsync_alloc_scrub_memory(struct pfsync_state_peer *s,
 }
 
 static int
-pfsync_state_import(struct pfsync_state *sp, int flags)
+pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
 {
        struct pfsync_softc *sc = V_pfsyncif;
 #ifndef        __NO_STRICT_ALIGNMENT
@@ -480,17 +515,17 @@ pfsync_state_import(struct pfsync_state *sp, int flags)
 
        PF_RULES_RASSERT();
 
-       if (sp->creatorid == 0) {
+       if (sp->pfs_1301.creatorid == 0) {
                if (V_pf_status.debug >= PF_DEBUG_MISC)
                        printf("%s: invalid creator id: %08x\n", __func__,
-                           ntohl(sp->creatorid));
+                           ntohl(sp->pfs_1301.creatorid));
                return (EINVAL);
        }
 
-       if ((kif = pfi_kkif_find(sp->ifname)) == NULL) {
+       if ((kif = pfi_kkif_find(sp->pfs_1301.ifname)) == NULL) {
                if (V_pf_status.debug >= PF_DEBUG_MISC)
                        printf("%s: unknown interface: %s\n", __func__,
-                           sp->ifname);
+                           sp->pfs_1301.ifname);
                if (flags & PFSYNC_SI_IOCTL)
                        return (EINVAL);
                return (0);     /* skip this state */
@@ -500,11 +535,11 @@ pfsync_state_import(struct pfsync_state *sp, int flags)
         * If the ruleset checksums match or the state is coming from the ioctl,
         * it's safe to associate the state with the rule of that number.
         */
-       if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) &&
-           (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) <
+       if (sp->pfs_1301.rule != htonl(-1) && sp->pfs_1301.anchor == htonl(-1) 
&&
+           (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && 
ntohl(sp->pfs_1301.rule) <
            pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount)
                r = pf_main_ruleset.rules[
-                   PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)];
+                   
PF_RULESET_FILTER].active.ptr_array[ntohl(sp->pfs_1301.rule)];
        else
                r = &V_pf_default_rule;
 
@@ -523,16 +558,16 @@ pfsync_state_import(struct pfsync_state *sp, int flags)
                goto cleanup;
 
 #ifndef        __NO_STRICT_ALIGNMENT
-       bcopy(&sp->key, key, sizeof(struct pfsync_state_key) * 2);
+       bcopy(&sp->pfs_1301.key, key, sizeof(struct pfsync_state_key) * 2);
        kw = &key[PF_SK_WIRE];
        ks = &key[PF_SK_STACK];
 #else
-       kw = &sp->key[PF_SK_WIRE];
-       ks = &sp->key[PF_SK_STACK];
+       kw = &sp->pfs_1301.key[PF_SK_WIRE];
+       ks = &sp->pfs_1301.key[PF_SK_STACK];
 #endif
 
-       if (PF_ANEQ(&kw->addr[0], &ks->addr[0], sp->af) ||
-           PF_ANEQ(&kw->addr[1], &ks->addr[1], sp->af) ||
+       if (PF_ANEQ(&kw->addr[0], &ks->addr[0], sp->pfs_1301.af) ||
+           PF_ANEQ(&kw->addr[1], &ks->addr[1], sp->pfs_1301.af) ||
            kw->port[0] != ks->port[0] ||
            kw->port[1] != ks->port[1]) {
                sks = uma_zalloc(V_pf_state_key_z, M_NOWAIT);
@@ -542,8 +577,8 @@ pfsync_state_import(struct pfsync_state *sp, int flags)
                sks = skw;
 
        /* allocate memory for scrub info */
-       if (pfsync_alloc_scrub_memory(&sp->src, &st->src) ||
-           pfsync_alloc_scrub_memory(&sp->dst, &st->dst))
+       if (pfsync_alloc_scrub_memory(&sp->pfs_1301.src, &st->src) ||
+           pfsync_alloc_scrub_memory(&sp->pfs_1301.dst, &st->dst))
                goto cleanup;
 
        /* Copy to state key(s). */
@@ -551,69 +586,110 @@ pfsync_state_import(struct pfsync_state *sp, int flags)
        skw->addr[1] = kw->addr[1];
        skw->port[0] = kw->port[0];
        skw->port[1] = kw->port[1];
-       skw->proto = sp->proto;
-       skw->af = sp->af;
+       skw->proto = sp->pfs_1301.proto;
+       skw->af = sp->pfs_1301.af;
        if (sks != skw) {
                sks->addr[0] = ks->addr[0];
                sks->addr[1] = ks->addr[1];
                sks->port[0] = ks->port[0];
                sks->port[1] = ks->port[1];
-               sks->proto = sp->proto;
-               sks->af = sp->af;
+               sks->proto = sp->pfs_1301.proto;
+               sks->af = sp->pfs_1301.af;
        }
 
        /* copy to state */
-       bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr));
-       st->creation = time_uptime - ntohl(sp->creation);
+       bcopy(&sp->pfs_1301.rt_addr, &st->rt_addr, sizeof(st->rt_addr));
+       st->creation = time_uptime - ntohl(sp->pfs_1301.creation);
        st->expire = time_uptime;
-       if (sp->expire) {
+       if (sp->pfs_1301.expire) {
                uint32_t timeout;
 
-               timeout = r->timeout[sp->timeout];
+               timeout = r->timeout[sp->pfs_1301.timeout];
                if (!timeout)
-                       timeout = V_pf_default_rule.timeout[sp->timeout];
+                       timeout = 
V_pf_default_rule.timeout[sp->pfs_1301.timeout];
 
                /* sp->expire may have been adaptively scaled by export. */
-               st->expire -= timeout - ntohl(sp->expire);
+               st->expire -= timeout - ntohl(sp->pfs_1301.expire);
        }
 
-       st->direction = sp->direction;
-       st->log = sp->log;
-       st->timeout = sp->timeout;
-       /* 8 from old peers, 16 bits from new peers */
-       st->state_flags = sp->state_flags_compat | ntohs(sp->state_flags);
+       st->direction = sp->pfs_1301.direction;
+       st->log = sp->pfs_1301.log;
+       st->timeout = sp->pfs_1301.timeout;
 
-       if (r == &V_pf_default_rule) {
-               /* ToS and Prio are not sent over struct pfsync_state */
-               st->state_flags &= ~PFSTATE_SETMASK;
-       } else {
-               /* Most actions are applied form state, not from rule. Until
-                * pfsync can forward all those actions and their parameters we
-                * must relay on restoring them from the found rule.
-                * It's a copy of pf_rule_to_actions() */
-               st->qid = r->qid;
-               st->pqid = r->pqid;
-               st->rtableid = r->rtableid;
-               if (r->scrub_flags & PFSTATE_SETTOS)
-                       st->set_tos = r->set_tos;
-               st->min_ttl = r->min_ttl;
-               st->max_mss = r->max_mss;
-               st->state_flags |= (r->scrub_flags & 
(PFSTATE_NODF|PFSTATE_RANDOMID|
-                   PFSTATE_SETTOS|PFSTATE_SCRUB_TCP|PFSTATE_SETPRIO));
-               st->dnpipe = r->dnpipe;
-               st->dnrpipe = r->dnrpipe;
-               /* FIXME: dnflags are not part of state, can't update them */
-       }
-
-       st->id = sp->id;
-       st->creatorid = sp->creatorid;
-       pf_state_peer_ntoh(&sp->src, &st->src);
-       pf_state_peer_ntoh(&sp->dst, &st->dst);
+       switch (msg_version) {
+               case PFSYNC_MSG_VERSION_1301:
+                       st->state_flags = sp->pfs_1301.state_flags;
+                       /*
+                        * In FreeBSD 13 pfsync lacks many attributes. Copy them
+                        * from the rule if possible. If rule can't be matched
+                        * clear any set options as we can't recover their
+                        * parameters.
+                       */
+                       if (r == &V_pf_default_rule) {
+                               st->state_flags &= ~PFSTATE_SETMASK;
+                       } else {
+                               /*
+                                * Similar to pf_rule_to_actions(). This code
+                                * won't set the actions properly if they come
+                                * from multiple "match" rules as only rule
+                                * creating the state is send over pfsync.
+                                */
+                               st->qid = r->qid;
+                               st->pqid = r->pqid;
+                               st->rtableid = r->rtableid;
+                               if (r->scrub_flags & PFSTATE_SETTOS)
+                                       st->set_tos = r->set_tos;
+                               st->min_ttl = r->min_ttl;
+                               st->max_mss = r->max_mss;
+                               st->state_flags |= (r->scrub_flags &
+                                   (PFSTATE_NODF|PFSTATE_RANDOMID|
+                                   PFSTATE_SETTOS|PFSTATE_SCRUB_TCP|
+                                   PFSTATE_SETPRIO));
+                               if (r->dnpipe || r->dnrpipe) {
+                                       if (r->free_flags & PFRULE_DN_IS_PIPE)
+                                               st->state_flags |= 
PFSTATE_DN_IS_PIPE;
+                                       else
+                                               st->state_flags &= 
~PFSTATE_DN_IS_PIPE;
+                               }
+                               st->dnpipe = r->dnpipe;
+                               st->dnrpipe = r->dnrpipe;
+                       }
+                       break;
+               case PFSYNC_MSG_VERSION_1400:
+                       st->state_flags = ntohs(sp->pfs_1400.state_flags);
+                       st->qid = ntohs(sp->pfs_1400.qid);
+                       st->pqid = ntohs(sp->pfs_1400.pqid);
+                       st->dnpipe = ntohs(sp->pfs_1400.dnpipe);
+                       st->dnrpipe = ntohs(sp->pfs_1400.dnrpipe);
+                       st->rtableid = ntohl(sp->pfs_1400.rtableid);
+                       st->min_ttl = sp->pfs_1400.min_ttl;
+                       st->set_tos = sp->pfs_1400.set_tos;
+                       st->max_mss = ntohs(sp->pfs_1400.max_mss);
+                       st->set_prio[0] = sp->pfs_1400.set_prio[0];
+                       st->set_prio[1] = sp->pfs_1400.set_prio[1];
+                       st->rt = sp->pfs_1400.rt;
+                       if (st->rt && (st->rt_kif = 
pfi_kkif_find(sp->pfs_1400.rt_ifname)) == NULL) {
+                               if (V_pf_status.debug >= PF_DEBUG_MISC)
+                                       printf("%s: unknown route interface: 
%s\n",
+                                           __func__, sp->pfs_1400.rt_ifname);
+                               if (flags & PFSYNC_SI_IOCTL)
+                                       return (EINVAL);
+                               return (0);     /* skip this state */
+                       }
+                       break;
+               default:
+                       panic("%s: Unsupported pfsync_msg_version %d",
+                           __func__, msg_version);
+       }
+
+       st->id = sp->pfs_1301.id;
+       st->creatorid = sp->pfs_1301.creatorid;
+       pf_state_peer_ntoh(&sp->pfs_1301.src, &st->src);
+       pf_state_peer_ntoh(&sp->pfs_1301.dst, &st->dst);
 
        st->rule.ptr = r;
        st->nat_rule.ptr = NULL;
        st->anchor.ptr = NULL;
-       st->rt_kif = NULL;
 
        st->pfsync_time = time_uptime;
        st->sync_state = PFSYNC_S_NONE;
@@ -745,7 +821,7 @@ pfsync_input(struct mbuf **mp, int *offp __unused, int 
proto __unused)
 
                count = ntohs(subh.count);
                V_pfsyncstats.pfsyncs_iacts[subh.action] += count;
-               rv = (*pfsync_acts[subh.action])(m, offset, count, flags);
+               rv = (*pfsync_acts[subh.action])(m, offset, count, flags, 
subh.action);
                if (rv == -1) {
                        PF_RULES_RUNLOCK();
                        return (IPPROTO_DONE);
@@ -762,7 +838,7 @@ done:
 #endif
 
 static int
-pfsync_in_clr(struct mbuf *m, int offset, int count, int flags)
+pfsync_in_clr(struct mbuf *m, int offset, int count, int flags, int action)
 {
        struct pfsync_clr *clr;
        struct mbuf *mp;
@@ -804,36 +880,50 @@ relock:
 }
 
 static int
-pfsync_in_ins(struct mbuf *m, int offset, int count, int flags)
+pfsync_in_ins(struct mbuf *m, int offset, int count, int flags, int action)
 {
        struct mbuf *mp;
-       struct pfsync_state *sa, *sp;
-       int len = sizeof(*sp) * count;
-       int i, offp;
+       union pfsync_state_union *sa, *sp;
+       int i, offp, len, msg_version;
+
+       switch (action) {
+               case PFSYNC_ACT_INS_1301:
+                       len = sizeof(struct pfsync_state_1301) * count;
+                       msg_version = PFSYNC_MSG_VERSION_1301;
+                       break;
+               case PFSYNC_ACT_INS_1400:
+                       len = sizeof(struct pfsync_state_1400) * count;
+                       msg_version = PFSYNC_MSG_VERSION_1400;
+                       break;
+               default:
+                       V_pfsyncstats.pfsyncs_badact++;
+                       return (-1);
+       }
 
        mp = m_pulldown(m, offset, len, &offp);
        if (mp == NULL) {
                V_pfsyncstats.pfsyncs_badlen++;
                return (-1);
        }
-       sa = (struct pfsync_state *)(mp->m_data + offp);
+       sa = (union pfsync_state_union *)(mp->m_data + offp);
 
        for (i = 0; i < count; i++) {
                sp = &sa[i];
 
                /* Check for invalid values. */
-               if (sp->timeout >= PFTM_MAX ||
-                   sp->src.state > PF_TCPS_PROXY_DST ||
-                   sp->dst.state > PF_TCPS_PROXY_DST ||
-                   sp->direction > PF_OUT ||
-                   (sp->af != AF_INET && sp->af != AF_INET6)) {
+               if (sp->pfs_1301.timeout >= PFTM_MAX ||
+                   sp->pfs_1301.src.state > PF_TCPS_PROXY_DST ||
+                   sp->pfs_1301.dst.state > PF_TCPS_PROXY_DST ||
+                   sp->pfs_1301.direction > PF_OUT ||
+                   (sp->pfs_1301.af != AF_INET &&
+                   sp->pfs_1301.af != AF_INET6)) {
                        if (V_pf_status.debug >= PF_DEBUG_MISC)
                                printf("%s: invalid value\n", __func__);
                        V_pfsyncstats.pfsyncs_badval++;
                        continue;
                }
 
-               if (pfsync_state_import(sp, flags) == ENOMEM)
+               if (pfsync_state_import(sp, flags, msg_version) == ENOMEM)
                        /* Drop out, but process the rest of the actions. */
                        break;
        }
@@ -842,7 +932,7 @@ pfsync_in_ins(struct mbuf *m, int offset, int count, int 
flags)
 }
 
 static int
-pfsync_in_iack(struct mbuf *m, int offset, int count, int flags)
+pfsync_in_iack(struct mbuf *m, int offset, int count, int flags, int action)
 {
        struct pfsync_ins_ack *ia, *iaa;
        struct pf_kstate *st;
@@ -913,31 +1003,42 @@ pfsync_upd_tcp(struct pf_kstate *st, struct 
pfsync_state_peer *src,
 }
 
 static int
-pfsync_in_upd(struct mbuf *m, int offset, int count, int flags)
+pfsync_in_upd(struct mbuf *m, int offset, int count, int flags, int action)
 {
        struct pfsync_softc *sc = V_pfsyncif;
-       struct pfsync_state *sa, *sp;
+       union pfsync_state_union *sa, *sp;
        struct pf_kstate *st;
-       int sync;
-
        struct mbuf *mp;
-       int len = count * sizeof(*sp);
-       int offp, i;
+       int sync, offp, i, len, msg_version;
+
+       switch (action) {
*** 1017 LINES SKIPPED ***

Reply via email to