git: 4bf98559d9d6 - main - pf: make contents of struct pfsync_state configurable
Date: Tue, 30 May 2023 12:29:24 UTC
The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=4bf98559d9d6fa7c3571d26ed6f2b18823e3a30b commit 4bf98559d9d6fa7c3571d26ed6f2b18823e3a30b Author: Kajetan Staszkiewicz <vegeta@tuxpowered.net> AuthorDate: 2023-05-29 13:47:23 +0000 Commit: Kristof Provost <kp@FreeBSD.org> 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 ***