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
This commit is contained in:
Kajetan Staszkiewicz 2023-05-29 15:47:23 +02:00 committed by Kristof Provost
parent 153145efcd
commit 4bf98559d9
9 changed files with 689 additions and 309 deletions

View file

@ -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)));
}
}

View file

@ -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",

View file

@ -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

View file

@ -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;
};
};

View file

@ -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_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) = {
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 }
};
static void pfsync_q_ins(struct pf_kstate *, int, bool);
/* 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 */
};
/* 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 */
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->id;
st->creatorid = sp->creatorid;
pf_state_peer_ntoh(&sp->src, &st->src);
pf_state_peer_ntoh(&sp->dst, &st->dst);
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) {
case PFSYNC_ACT_UPD_1301:
len = sizeof(struct pfsync_state_1301) * count;
msg_version = PFSYNC_MSG_VERSION_1301;
break;
case PFSYNC_ACT_UPD_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) {
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) {
if (V_pf_status.debug >= PF_DEBUG_MISC) {
printf("pfsync_input: PFSYNC_ACT_UPD: "
"invalid value\n");
@ -946,10 +1047,10 @@ pfsync_in_upd(struct mbuf *m, int offset, int count, int flags)
continue;
}
st = pf_find_state_byid(sp->id, sp->creatorid);
st = pf_find_state_byid(sp->pfs_1301.id, sp->pfs_1301.creatorid);
if (st == NULL) {
/* insert the update */
if (pfsync_state_import(sp, flags))
if (pfsync_state_import(sp, flags, msg_version))
V_pfsyncstats.pfsyncs_badstate++;
continue;
}
@ -959,7 +1060,7 @@ pfsync_in_upd(struct mbuf *m, int offset, int count, int flags)
}
if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP)
sync = pfsync_upd_tcp(st, &sp->src, &sp->dst);
sync = pfsync_upd_tcp(st, &sp->pfs_1301.src, &sp->pfs_1301.dst);
else {
sync = 0;
@ -967,20 +1068,20 @@ pfsync_in_upd(struct mbuf *m, int offset, int count, int flags)
* Non-TCP protocol state machine always go
* forwards
*/
if (st->src.state > sp->src.state)
if (st->src.state > sp->pfs_1301.src.state)
sync++;
else
pf_state_peer_ntoh(&sp->src, &st->src);
if (st->dst.state > sp->dst.state)
pf_state_peer_ntoh(&sp->pfs_1301.src, &st->src);
if (st->dst.state > sp->pfs_1301.dst.state)
sync++;
else
pf_state_peer_ntoh(&sp->dst, &st->dst);
pf_state_peer_ntoh(&sp->pfs_1301.dst, &st->dst);
}
if (sync < 2) {
pfsync_alloc_scrub_memory(&sp->dst, &st->dst);
pf_state_peer_ntoh(&sp->dst, &st->dst);
pfsync_alloc_scrub_memory(&sp->pfs_1301.dst, &st->dst);
pf_state_peer_ntoh(&sp->pfs_1301.dst, &st->dst);
st->expire = time_uptime;
st->timeout = sp->timeout;
st->timeout = sp->pfs_1301.timeout;
}
st->pfsync_time = time_uptime;
@ -999,7 +1100,7 @@ pfsync_in_upd(struct mbuf *m, int offset, int count, int flags)
}
static int
pfsync_in_upd_c(struct mbuf *m, int offset, int count, int flags)
pfsync_in_upd_c(struct mbuf *m, int offset, int count, int flags, int action)
{
struct pfsync_softc *sc = V_pfsyncif;
struct pfsync_upd_c *ua, *up;
@ -1086,7 +1187,7 @@ pfsync_in_upd_c(struct mbuf *m, int offset, int count, int flags)
}
static int
pfsync_in_ureq(struct mbuf *m, int offset, int count, int flags)
pfsync_in_ureq(struct mbuf *m, int offset, int count, int flags, int action)
{
struct pfsync_upd_req *ur, *ura;
struct mbuf *mp;
@ -1127,7 +1228,7 @@ pfsync_in_ureq(struct mbuf *m, int offset, int count, int flags)
}
static int
pfsync_in_del_c(struct mbuf *m, int offset, int count, int flags)
pfsync_in_del_c(struct mbuf *m, int offset, int count, int flags, int action)
{
struct mbuf *mp;
struct pfsync_del_c *sa, *sp;
@ -1159,7 +1260,7 @@ pfsync_in_del_c(struct mbuf *m, int offset, int count, int flags)
}
static int
pfsync_in_bus(struct mbuf *m, int offset, int count, int flags)
pfsync_in_bus(struct mbuf *m, int offset, int count, int flags, int action)
{
struct pfsync_softc *sc = V_pfsyncif;
struct pfsync_bus *bus;
@ -1188,7 +1289,7 @@ pfsync_in_bus(struct mbuf *m, int offset, int count, int flags)
callout_reset(&sc->sc_bulkfail_tmo, 4 * hz +
V_pf_limits[PF_LIMIT_STATES].limit /
((sc->sc_ifp->if_mtu - PFSYNC_MINPKT) /
sizeof(struct pfsync_state)),
sizeof(union pfsync_state_union)),
pfsync_bulk_fail, sc);
if (V_pf_status.debug >= PF_DEBUG_MISC)
printf("pfsync: received bulk update start\n");
@ -1221,7 +1322,7 @@ pfsync_in_bus(struct mbuf *m, int offset, int count, int flags)
}
static int
pfsync_in_tdb(struct mbuf *m, int offset, int count, int flags)
pfsync_in_tdb(struct mbuf *m, int offset, int count, int flags, int action)
{
int len = count * sizeof(struct pfsync_tdb);
@ -1286,7 +1387,7 @@ bad:
#endif
static int
pfsync_in_eof(struct mbuf *m, int offset, int count, int flags)
pfsync_in_eof(struct mbuf *m, int offset, int count, int flags, int action)
{
/* check if we are at the right place in the packet */
if (offset != m->m_pkthdr.len)
@ -1298,7 +1399,7 @@ pfsync_in_eof(struct mbuf *m, int offset, int count, int flags)
}
static int
pfsync_in_error(struct mbuf *m, int offset, int count, int flags)
pfsync_in_error(struct mbuf *m, int offset, int count, int flags, int action)
{
V_pfsyncstats.pfsyncs_badact++;
@ -1379,6 +1480,7 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
nvlist_add_string(nvl, "syncdev", sc->sc_sync_if->if_xname);
nvlist_add_number(nvl, "maxupdates", sc->sc_maxupdates);
nvlist_add_number(nvl, "flags", sc->sc_flags);
nvlist_add_number(nvl, "version", sc->sc_version);
if ((nvl_syncpeer = pfsync_sockaddr_to_syncpeer_nvlist(&sc->sc_sync_peer)) != NULL)
nvlist_add_nvlist(nvl, "syncpeer", nvl_syncpeer);
@ -1464,11 +1566,19 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
}
static void
pfsync_out_state(struct pf_kstate *st, void *buf)
pfsync_out_state_1301(struct pf_kstate *st, void *buf)
{
struct pfsync_state *sp = buf;
union pfsync_state_union *sp = buf;
pfsync_state_export(sp, st);
pfsync_state_export(sp, st, PFSYNC_MSG_VERSION_1301);
}
static void
pfsync_out_state_1400(struct pf_kstate *st, void *buf)
{
union pfsync_state_union *sp = buf;
pfsync_state_export(sp, st, PFSYNC_MSG_VERSION_1400);
}
static void
@ -1509,16 +1619,17 @@ pfsync_drop(struct pfsync_softc *sc)
struct pf_kstate *st, *next;
struct pfsync_upd_req_item *ur;
struct pfsync_bucket *b;
int c, q;
int c;
enum pfsync_q_id q;
for (c = 0; c < pfsync_buckets; c++) {
b = &sc->sc_buckets[c];
for (q = 0; q < PFSYNC_S_COUNT; q++) {
for (q = 0; q < PFSYNC_Q_COUNT; q++) {
if (TAILQ_EMPTY(&b->b_qs[q]))
continue;
TAILQ_FOREACH_SAFE(st, &b->b_qs[q], sync_list, next) {
KASSERT(st->sync_state == q,
KASSERT(st->sync_state == pfsync_qid_sstate[q],
("%s: st->sync_state == q",
__func__));
st->sync_state = PFSYNC_S_NONE;
@ -1548,8 +1659,8 @@ pfsync_sendout(int schedswi, int c)
struct pf_kstate *st, *st_next;
struct pfsync_upd_req_item *ur;
struct pfsync_bucket *b = &sc->sc_buckets[c];
int aflen, offset;
int q, count = 0;
int aflen, offset, count = 0;
enum pfsync_q_id q;
KASSERT(sc != NULL, ("%s: null sc", __func__));
KASSERT(b->b_len > PFSYNC_MINPKT,
@ -1591,7 +1702,6 @@ pfsync_sendout(int schedswi, int c)
return;
}
/* build the pfsync header */
ph = (struct pfsync_header *)(m->m_data + offset);
bzero(ph, sizeof(*ph));
@ -1602,7 +1712,7 @@ pfsync_sendout(int schedswi, int c)
bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH);
/* walk the queues */
for (q = 0; q < PFSYNC_S_COUNT; q++) {
for (q = 0; q < PFSYNC_Q_COUNT; q++) {
if (TAILQ_EMPTY(&b->b_qs[q]))
continue;
@ -1611,7 +1721,7 @@ pfsync_sendout(int schedswi, int c)
count = 0;
TAILQ_FOREACH_SAFE(st, &b->b_qs[q], sync_list, st_next) {
KASSERT(st->sync_state == q,
KASSERT(st->sync_state == pfsync_qid_sstate[q],
("%s: st->sync_state == q",
__func__));
/*
@ -2015,7 +2125,7 @@ pfsync_update_state_req(struct pf_kstate *st)
panic("%s: unexpected sync state %d", __func__, st->sync_state);
}
if ((sc->sc_ifp->if_mtu - b->b_len) < sizeof(struct pfsync_state))
if ((sc->sc_ifp->if_mtu - b->b_len) < sizeof(union pfsync_state_union))
full = true;
PFSYNC_BUCKET_UNLOCK(b);
@ -2087,10 +2197,48 @@ pfsync_clear_states(u_int32_t creatorid, const char *ifname)
pfsync_send_plus(&r, sizeof(r));
}
static void
pfsync_q_ins(struct pf_kstate *st, int q, bool ref)
static enum pfsync_q_id
pfsync_sstate_to_qid(u_int8_t sync_state)
{
struct pfsync_softc *sc = V_pfsyncif;
switch (sync_state) {
case PFSYNC_S_INS:
switch (sc->sc_version) {
case PFSYNC_MSG_VERSION_1301:
return PFSYNC_Q_INS_1301;
case PFSYNC_MSG_VERSION_1400:
return PFSYNC_Q_INS_1400;
}
break;
case PFSYNC_S_IACK:
return PFSYNC_Q_IACK;
case PFSYNC_S_UPD:
switch (sc->sc_version) {
case PFSYNC_MSG_VERSION_1301:
return PFSYNC_Q_UPD_1301;
case PFSYNC_MSG_VERSION_1400:
return PFSYNC_Q_UPD_1400;
}
break;
case PFSYNC_S_UPD_C:
return PFSYNC_Q_UPD_C;
case PFSYNC_S_DEL_C:
return PFSYNC_Q_DEL_C;
default:
panic("%s: Unsupported st->sync_state 0x%02x",
__func__, sync_state);
}
panic("%s: Unsupported pfsync_msg_version %d",
__func__, sc->sc_version);
}
static void
pfsync_q_ins(struct pf_kstate *st, int sync_state, bool ref)
{
enum pfsync_q_id q = pfsync_sstate_to_qid(sync_state);
struct pfsync_softc *sc = V_pfsyncif;
size_t nlen = pfsync_qs[q].len;
struct pfsync_bucket *b = pfsync_get_bucket(sc, st);
@ -2112,7 +2260,7 @@ pfsync_q_ins(struct pf_kstate *st, int q, bool ref)
b->b_len += nlen;
TAILQ_INSERT_TAIL(&b->b_qs[q], st, sync_list);
st->sync_state = q;
st->sync_state = pfsync_qid_sstate[q];
if (ref)
pf_ref_state(st);
}
@ -2120,12 +2268,13 @@ pfsync_q_ins(struct pf_kstate *st, int q, bool ref)
static void
pfsync_q_del(struct pf_kstate *st, bool unref, struct pfsync_bucket *b)
{
int q = st->sync_state;
enum pfsync_q_id q;
PFSYNC_BUCKET_LOCK_ASSERT(b);
KASSERT(st->sync_state != PFSYNC_S_NONE,
("%s: st->sync_state != PFSYNC_S_NONE", __func__));
q = pfsync_sstate_to_qid(st->sync_state);
b->b_len -= pfsync_qs[q].len;
TAILQ_REMOVE(&b->b_qs[q], st, sync_list);
st->sync_state = PFSYNC_S_NONE;
@ -2522,6 +2671,20 @@ pfsync_kstatus_to_softc(struct pfsync_kstatus *status, struct pfsync_softc *sc)
imf = ip_mfilter_alloc(M_WAITOK, 0, 0);
PFSYNC_LOCK(sc);
switch (status->version) {
case PFSYNC_MSG_VERSION_UNSPECIFIED:
sc->sc_version = PFSYNC_MSG_VERSION_DEFAULT;
break;
case PFSYNC_MSG_VERSION_1301:
case PFSYNC_MSG_VERSION_1400:
sc->sc_version = status->version;
break;
default:
PFSYNC_UNLOCK(sc);
return (EINVAL);
}
struct sockaddr_in *sc_sin = (struct sockaddr_in *)&sc->sc_sync_peer;
sc_sin->sin_family = AF_INET;
sc_sin->sin_len = sizeof(*sc_sin);

View file

@ -3592,6 +3592,8 @@ pf_addr_inc(struct pf_addr *addr, sa_family_t af)
void
pf_rule_to_actions(struct pf_krule *r, struct pf_rule_actions *a)
{
a->flags |= (r->scrub_flags & (PFSTATE_NODF|PFSTATE_RANDOMID|
PFSTATE_SETTOS|PFSTATE_SCRUB_TCP|PFSTATE_SETPRIO));
if (r->qid)
a->qid = r->qid;
if (r->pqid)
@ -3599,14 +3601,12 @@ pf_rule_to_actions(struct pf_krule *r, struct pf_rule_actions *a)
if (r->rtableid >= 0)
a->rtableid = r->rtableid;
a->log |= r->log;
if (r->scrub_flags & PFSTATE_SETTOS)
if (a->flags & PFSTATE_SETTOS)
a->set_tos = r->set_tos;
if (r->min_ttl)
a->min_ttl = r->min_ttl;
if (r->max_mss)
a->max_mss = r->max_mss;
a->flags |= (r->scrub_flags & (PFSTATE_NODF|PFSTATE_RANDOMID|
PFSTATE_SETTOS|PFSTATE_SCRUB_TCP|PFSTATE_SETPRIO));
if (r->dnpipe)
a->dnpipe = r->dnpipe;
if (r->dnrpipe)
@ -3617,6 +3617,10 @@ pf_rule_to_actions(struct pf_krule *r, struct pf_rule_actions *a)
else
a->flags &= ~PFSTATE_DN_IS_PIPE;
}
if (a->flags & PFSTATE_SETPRIO) {
a->set_prio[0] = r->set_prio[0];
a->set_prio[1] = r->set_prio[1];
}
}
int
@ -4638,6 +4642,8 @@ pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a,
s->pqid = pd->act.pqid;
s->dnpipe = pd->act.dnpipe;
s->dnrpipe = pd->act.dnrpipe;
s->set_prio[0] = pd->act.set_prio[0];
s->set_prio[1] = pd->act.set_prio[1];
s->state_flags |= pd->act.flags;
if (nr != NULL)
s->log |= nr->log & PF_LOG_ALL;
@ -4706,6 +4712,7 @@ pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a,
goto csfailed;
}
s->rt_kif = r->rpool.cur->kif;
s->rt = r->rt;
}
s->creation = time_uptime;
@ -6441,9 +6448,20 @@ pf_route(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp,
struct pf_ksrc_node *sn = NULL;
int error = 0;
uint16_t ip_len, ip_off;
int r_rt, r_dir;
KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__));
KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: invalid direction",
if (s) {
r_rt = s->rt;
r_dir = s->direction;
} else {
r_rt = r->rt;
r_dir = r->direction;
}
KASSERT(dir == PF_IN || dir == PF_OUT ||
r_dir == PF_IN || r_dir == PF_OUT, ("%s: invalid direction",
__func__));
if ((pd->pf_mtag == NULL &&
@ -6454,7 +6472,7 @@ pf_route(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp,
goto bad_locked;
}
if (r->rt == PF_DUPTO) {
if (r_rt == PF_DUPTO) {
if ((pd->pf_mtag->flags & PF_DUPLICATED)) {
if (s == NULL) {
ifp = r->rpool.cur->kif ?
@ -6484,7 +6502,7 @@ pf_route(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp,
}
}
} else {
if ((r->rt == PF_REPLYTO) == (r->direction == dir)) {
if ((r_rt == PF_REPLYTO) == (r_dir == dir)) {
pf_dummynet(pd, dir, s, r, m);
if (s)
PF_STATE_UNLOCK(s);
@ -6583,7 +6601,7 @@ pf_route(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp,
if ((ip_off & IP_DF) || (m0->m_pkthdr.csum_flags & CSUM_TSO)) {
error = EMSGSIZE;
KMOD_IPSTAT_INC(ips_cantfrag);
if (r->rt != PF_DUPTO) {
if (r_rt != PF_DUPTO) {
if (s && pd->nat_rule != NULL)
PACKET_UNDO_NAT(m0, pd,
(ip->ip_hl << 2) + (ip_off & IP_OFFMASK),
@ -6619,7 +6637,7 @@ pf_route(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp,
KMOD_IPSTAT_INC(ips_fragmented);
done:
if (r->rt != PF_DUPTO)
if (r_rt != PF_DUPTO)
*m = NULL;
return;
@ -6643,9 +6661,20 @@ pf_route6(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp,
struct ifnet *ifp = NULL;
struct pf_addr naddr;
struct pf_ksrc_node *sn = NULL;
int r_rt, r_dir;
KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__));
KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: invalid direction",
if (s) {
r_rt = s->rt;
r_dir = s->direction;
} else {
r_rt = r->rt;
r_dir = r->direction;
}
KASSERT(dir == PF_IN || dir == PF_OUT ||
r_dir == PF_IN || r_dir == PF_OUT, ("%s: invalid direction",
__func__));
if ((pd->pf_mtag == NULL &&
@ -6656,7 +6685,7 @@ pf_route6(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp,
goto bad_locked;
}
if (r->rt == PF_DUPTO) {
if (r_rt == PF_DUPTO) {
if ((pd->pf_mtag->flags & PF_DUPLICATED)) {
if (s == NULL) {
ifp = r->rpool.cur->kif ?
@ -6686,7 +6715,7 @@ pf_route6(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp,
}
}
} else {
if ((r->rt == PF_REPLYTO) == (r->direction == dir)) {
if ((r_rt == PF_REPLYTO) == (r_dir == dir)) {
pf_dummynet(pd, dir, s, r, m);
if (s)
PF_STATE_UNLOCK(s);
@ -6770,7 +6799,7 @@ pf_route6(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp,
}
else {
in6_ifstat_inc(ifp, ifs6_in_toobig);
if (r->rt != PF_DUPTO) {
if (r_rt != PF_DUPTO) {
if (s && pd->nat_rule != NULL)
PACKET_UNDO_NAT(m0, pd,
((caddr_t)ip6 - m0->m_data) +
@ -6782,7 +6811,7 @@ pf_route6(struct mbuf **m, struct pf_krule *r, int dir, struct ifnet *oifp,
}
done:
if (r->rt != PF_DUPTO)
if (r_rt != PF_DUPTO)
*m = NULL;
return;
@ -7102,7 +7131,18 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *
struct pf_kstate *s = NULL;
struct pf_kruleset *ruleset = NULL;
struct pf_pdesc pd;
int off, dirndx, pqid = 0;
int off, dirndx;
uint16_t scrub_flags;
#ifdef ALTQ
uint16_t qid;
#endif
uint16_t pqid;
uint16_t tag;
int32_t rtableid;
uint8_t min_ttl;
uint8_t set_tos;
uint8_t rt;
uint8_t set_prio[2];
PF_RULES_RLOCK_TRACKER;
KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: bad direction %d\n", __func__, dir));
@ -7394,36 +7434,47 @@ done:
}
if (s) {
pf_scrub_ip(&m, s->state_flags, s->min_ttl, s->set_tos);
if (s->rtableid >= 0)
M_SETFIB(m, s->rtableid);
scrub_flags = s->state_flags;
min_ttl = s->min_ttl;
set_tos = s->set_tos;
rtableid = s->rtableid;
pqid = s->pqid;
#ifdef ALTQ
if (s->qid) {
pd.act.pqid = s->pqid;
pd.act.qid = s->qid;
}
qid = s->qid;
#endif
tag = s->tag;
rt = s->rt;
set_prio[0] = s->set_prio[0];
set_prio[1] = s->set_prio[1];
} else {
pf_scrub_ip(&m, r->scrub_flags, r->min_ttl, r->set_tos);
if (r->rtableid >= 0)
M_SETFIB(m, r->rtableid);
scrub_flags = r->scrub_flags;
min_ttl = r->min_ttl;
set_tos = r->set_tos;
rtableid = r->rtableid;
pqid = r->pqid;
#ifdef ALTQ
if (r->qid) {
pd.act.pqid = r->pqid;
pd.act.qid = r->qid;
}
qid = r->qid;
#endif
tag = r->tag;
rt = r->rt;
set_prio[0] = r->set_prio[0];
set_prio[1] = r->set_prio[1];
}
if (s && s->tag > 0 && pf_tag_packet(m, &pd, s->tag)) {
if (tag > 0 && pf_tag_packet(m, &pd, tag)) {
action = PF_DROP;
REASON_SET(&reason, PFRES_MEMORY);
}
if (r->scrub_flags & PFSTATE_SETPRIO) {
pf_scrub_ip(&m, scrub_flags, min_ttl, set_tos);
if (rtableid >= 0)
M_SETFIB(m, rtableid);
if (scrub_flags & PFSTATE_SETPRIO) {
if (pd.tos & IPTOS_LOWDELAY)
pqid = 1;
if (vlan_set_pcp(m, r->set_prio[pqid])) {
if (vlan_set_pcp(m, set_prio[pqid])) {
action = PF_DROP;
REASON_SET(&reason, PFRES_MEMORY);
log = PF_LOG_FORCE;
@ -7433,6 +7484,11 @@ done:
}
#ifdef ALTQ
if (qid) {
pd.act.pqid = pqid;
pd.act.qid = qid;
}
if (action == PF_PASS && pd.act.qid) {
if (pd.pf_mtag == NULL &&
((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
@ -7604,7 +7660,7 @@ done:
break;
default:
/* pf_route() returns unlocked. */
if (r->rt) {
if (rt) {
pf_route(m0, r, dir, kif->pfik_ifp, s, &pd, inp);
return (action);
}
@ -7637,7 +7693,18 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb
struct pf_kstate *s = NULL;
struct pf_kruleset *ruleset = NULL;
struct pf_pdesc pd;
int off, terminal = 0, dirndx, rh_cnt = 0, pqid = 0;
int off, terminal = 0, dirndx, rh_cnt = 0;
uint16_t scrub_flags;
#ifdef ALTQ
uint16_t qid;
#endif
uint16_t pqid;
uint16_t tag;
int32_t rtableid;
uint8_t min_ttl;
uint8_t set_tos;
uint8_t rt;
uint8_t set_prio[2];
PF_RULES_RLOCK_TRACKER;
KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: bad direction %d\n", __func__, dir));
@ -7925,37 +7992,48 @@ done:
("pf: dropping packet with dangerous v6 headers\n"));
}
if (s && s->tag > 0 && pf_tag_packet(m, &pd, s->tag)) {
if (s) {
scrub_flags = s->state_flags;
min_ttl = s->min_ttl;
set_tos = s->set_tos;
rtableid = s->rtableid;
pqid = s->pqid;
#ifdef ALTQ
qid = s->qid;
#endif
tag = s->tag;
rt = s->rt;
set_prio[0] = s->set_prio[0];
set_prio[1] = s->set_prio[1];
} else {
scrub_flags = r->scrub_flags;
min_ttl = r->min_ttl;
set_tos = r->set_tos;
rtableid = r->rtableid;
pqid = r->pqid;
#ifdef ALTQ
qid = r->qid;
#endif
tag = r->tag;
rt = r->rt;
set_prio[0] = r->set_prio[0];
set_prio[1] = r->set_prio[1];
}
if (tag > 0 && pf_tag_packet(m, &pd, tag)) {
action = PF_DROP;
REASON_SET(&reason, PFRES_MEMORY);
}
if (s) {
pf_scrub_ip6(&m, s->state_flags, s->min_ttl, s->set_tos);
if (s->rtableid >= 0)
M_SETFIB(m, s->rtableid);
#ifdef ALTQ
if (s->qid) {
pd.act.pqid = s->pqid;
pd.act.qid = s->qid;
}
#endif
} else {
pf_scrub_ip6(&m, r->scrub_flags, r->min_ttl, r->set_tos);
if (r->rtableid >= 0)
M_SETFIB(m, r->rtableid);
#ifdef ALTQ
if (r->qid) {
pd.act.pqid = r->pqid;
pd.act.qid = r->qid;
}
#endif
}
pf_scrub_ip6(&m, scrub_flags, min_ttl, set_tos);
if (r->scrub_flags & PFSTATE_SETPRIO) {
if (rtableid >= 0)
M_SETFIB(m, rtableid);
if (scrub_flags & PFSTATE_SETPRIO) {
if (pd.tos & IPTOS_LOWDELAY)
pqid = 1;
if (vlan_set_pcp(m, r->set_prio[pqid])) {
if (vlan_set_pcp(m, set_prio[pqid])) {
action = PF_DROP;
REASON_SET(&reason, PFRES_MEMORY);
log = PF_LOG_FORCE;
@ -7965,6 +8043,11 @@ done:
}
#ifdef ALTQ
if (qid) {
pd.act.pqid = pqid;
pd.act.qid = qid;
}
if (action == PF_PASS && pd.act.qid) {
if (pd.pf_mtag == NULL &&
((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
@ -8084,7 +8167,7 @@ done:
break;
default:
/* pf_route6() returns unlocked. */
if (r->rt) {
if (rt) {
pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd, inp);
return (action);
}

View file

@ -3720,8 +3720,8 @@ DIOCCHANGERULE_error:
}
case DIOCADDSTATE: {
struct pfioc_state *ps = (struct pfioc_state *)addr;
struct pfsync_state *sp = &ps->state;
struct pfioc_state *ps = (struct pfioc_state *)addr;
struct pfsync_state_1301 *sp = &ps->state;
if (sp->timeout >= PFTM_MAX) {
error = EINVAL;
@ -3729,7 +3729,9 @@ DIOCCHANGERULE_error:
}
if (V_pfsync_state_import_ptr != NULL) {
PF_RULES_RLOCK();
error = V_pfsync_state_import_ptr(sp, PFSYNC_SI_IOCTL);
error = V_pfsync_state_import_ptr(
(union pfsync_state_union *)sp, PFSYNC_SI_IOCTL,
PFSYNC_MSG_VERSION_1301);
PF_RULES_RUNLOCK();
} else
error = EOPNOTSUPP;
@ -3746,7 +3748,8 @@ DIOCCHANGERULE_error:
break;
}
pfsync_state_export(&ps->state, s);
pfsync_state_export((union pfsync_state_union*)&ps->state,
s, PFSYNC_MSG_VERSION_1301);
PF_STATE_UNLOCK(s);
break;
}
@ -3759,20 +3762,20 @@ DIOCCHANGERULE_error:
case DIOCGETSTATES: {
struct pfioc_states *ps = (struct pfioc_states *)addr;
struct pf_kstate *s;
struct pfsync_state *pstore, *p;
struct pfsync_state_1301 *pstore, *p;
int i, nr;
size_t slice_count = 16, count;
void *out;
if (ps->ps_len <= 0) {
nr = uma_zone_get_cur(V_pf_state_z);
ps->ps_len = sizeof(struct pfsync_state) * nr;
ps->ps_len = sizeof(struct pfsync_state_1301) * nr;
break;
}
out = ps->ps_states;
pstore = mallocarray(slice_count,
sizeof(struct pfsync_state), M_TEMP, M_WAITOK | M_ZERO);
sizeof(struct pfsync_state_1301), M_TEMP, M_WAITOK | M_ZERO);
nr = 0;
for (i = 0; i <= pf_hashmask; i++) {
@ -3797,7 +3800,7 @@ DIOCGETSTATES_retry:
free(pstore, M_TEMP);
slice_count = count * 2;
pstore = mallocarray(slice_count,
sizeof(struct pfsync_state), M_TEMP,
sizeof(struct pfsync_state_1301), M_TEMP,
M_WAITOK | M_ZERO);
goto DIOCGETSTATES_retry;
}
@ -3811,19 +3814,20 @@ DIOCGETSTATES_retry:
if (s->timeout == PFTM_UNLINKED)
continue;
pfsync_state_export(p, s);
pfsync_state_export((union pfsync_state_union*)p,
s, PFSYNC_MSG_VERSION_1301);
p++;
nr++;
}
PF_HASHROW_UNLOCK(ih);
error = copyout(pstore, out,
sizeof(struct pfsync_state) * count);
sizeof(struct pfsync_state_1301) * count);
if (error)
break;
out = ps->ps_states + nr;
}
DIOCGETSTATES_full:
ps->ps_len = sizeof(struct pfsync_state) * nr;
ps->ps_len = sizeof(struct pfsync_state_1301) * nr;
free(pstore, M_TEMP);
break;
@ -5663,64 +5667,90 @@ fail:
}
void
pfsync_state_export(struct pfsync_state *sp, struct pf_kstate *st)
pfsync_state_export(union pfsync_state_union *sp, struct pf_kstate *st, int msg_version)
{
bzero(sp, sizeof(struct pfsync_state));
bzero(sp, sizeof(union pfsync_state_union));
/* copy from state key */
sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0];
sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1];
sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0];
sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1];
sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0];
sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1];
sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0];
sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1];
sp->proto = st->key[PF_SK_WIRE]->proto;
sp->af = st->key[PF_SK_WIRE]->af;
sp->pfs_1301.key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0];
sp->pfs_1301.key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1];
sp->pfs_1301.key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0];
sp->pfs_1301.key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1];
sp->pfs_1301.key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0];
sp->pfs_1301.key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1];
sp->pfs_1301.key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0];
sp->pfs_1301.key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1];
sp->pfs_1301.proto = st->key[PF_SK_WIRE]->proto;
sp->pfs_1301.af = st->key[PF_SK_WIRE]->af;
/* copy from state */
strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));
bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
sp->creation = htonl(time_uptime - st->creation);
sp->expire = pf_state_expires(st);
if (sp->expire <= time_uptime)
sp->expire = htonl(0);
strlcpy(sp->pfs_1301.ifname, st->kif->pfik_name, sizeof(sp->pfs_1301.ifname));
bcopy(&st->rt_addr, &sp->pfs_1301.rt_addr, sizeof(sp->pfs_1301.rt_addr));
sp->pfs_1301.creation = htonl(time_uptime - st->creation);
sp->pfs_1301.expire = pf_state_expires(st);
if (sp->pfs_1301.expire <= time_uptime)
sp->pfs_1301.expire = htonl(0);
else
sp->expire = htonl(sp->expire - time_uptime);
sp->pfs_1301.expire = htonl(sp->pfs_1301.expire - time_uptime);
sp->pfs_1301.direction = st->direction;
sp->pfs_1301.log = st->log;
sp->pfs_1301.timeout = st->timeout;
switch (msg_version) {
case PFSYNC_MSG_VERSION_1301:
sp->pfs_1301.state_flags = st->state_flags;
break;
case PFSYNC_MSG_VERSION_1400:
sp->pfs_1400.state_flags = htons(st->state_flags);
sp->pfs_1400.qid = htons(st->qid);
sp->pfs_1400.pqid = htons(st->pqid);
sp->pfs_1400.dnpipe = htons(st->dnpipe);
sp->pfs_1400.dnrpipe = htons(st->dnrpipe);
sp->pfs_1400.rtableid = htonl(st->rtableid);
sp->pfs_1400.min_ttl = st->min_ttl;
sp->pfs_1400.set_tos = st->set_tos;
sp->pfs_1400.max_mss = htons(st->max_mss);
sp->pfs_1400.set_prio[0] = st->set_prio[0];
sp->pfs_1400.set_prio[1] = st->set_prio[1];
sp->pfs_1400.rt = st->rt;
if (st->rt_kif)
strlcpy(sp->pfs_1400.rt_ifname,
st->rt_kif->pfik_name,
sizeof(sp->pfs_1400.rt_ifname));
break;
default:
panic("%s: Unsupported pfsync_msg_version %d",
__func__, msg_version);
}
sp->direction = st->direction;
sp->log = st->log;
sp->timeout = st->timeout;
sp->state_flags_compat = st->state_flags;
sp->state_flags = htons(st->state_flags);
if (st->src_node)
sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
sp->pfs_1301.sync_flags |= PFSYNC_FLAG_SRCNODE;
if (st->nat_src_node)
sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE;
sp->pfs_1301.sync_flags |= PFSYNC_FLAG_NATSRCNODE;
sp->id = st->id;
sp->creatorid = st->creatorid;
pf_state_peer_hton(&st->src, &sp->src);
pf_state_peer_hton(&st->dst, &sp->dst);
sp->pfs_1301.id = st->id;
sp->pfs_1301.creatorid = st->creatorid;
pf_state_peer_hton(&st->src, &sp->pfs_1301.src);
pf_state_peer_hton(&st->dst, &sp->pfs_1301.dst);
if (st->rule.ptr == NULL)
sp->rule = htonl(-1);
sp->pfs_1301.rule = htonl(-1);
else
sp->rule = htonl(st->rule.ptr->nr);
sp->pfs_1301.rule = htonl(st->rule.ptr->nr);
if (st->anchor.ptr == NULL)
sp->anchor = htonl(-1);
sp->pfs_1301.anchor = htonl(-1);
else
sp->anchor = htonl(st->anchor.ptr->nr);
sp->pfs_1301.anchor = htonl(st->anchor.ptr->nr);
if (st->nat_rule.ptr == NULL)
sp->nat_rule = htonl(-1);
sp->pfs_1301.nat_rule = htonl(-1);
else
sp->nat_rule = htonl(st->nat_rule.ptr->nr);
sp->pfs_1301.nat_rule = htonl(st->nat_rule.ptr->nr);
pf_state_counter_hton(st->packets[0], sp->packets[0]);
pf_state_counter_hton(st->packets[1], sp->packets[1]);
pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
pf_state_counter_hton(st->bytes[1], sp->bytes[1]);
pf_state_counter_hton(st->packets[0], sp->pfs_1301.packets[0]);
pf_state_counter_hton(st->packets[1], sp->pfs_1301.packets[1]);
pf_state_counter_hton(st->bytes[0], sp->pfs_1301.bytes[0]);
pf_state_counter_hton(st->bytes[1], sp->pfs_1301.bytes[1]);
}
void

View file

@ -130,6 +130,7 @@ pfsync_nvstatus_to_kstatus(const nvlist_t *nvl, struct pfsync_kstatus *status)
return (EINVAL);
status->maxupdates = nvlist_get_number(nvl, "maxupdates");
status->version = nvlist_get_number(nvl, "version");
status->flags = nvlist_get_number(nvl, "flags");
if (nvlist_exists_string(nvl, "syncdev"))

View file

@ -81,9 +81,9 @@ static void sidewaysintpr(void);
#ifdef PF
static const char* pfsyncacts[] = {
/* PFSYNC_ACT_CLR */ "clear all request",
/* PFSYNC_ACT_INS */ "state insert",
/* PFSYNC_ACT_INS_1301 */ "13.1 state insert",
/* PFSYNC_ACT_INS_ACK */ "state inserted ack",
/* PFSYNC_ACT_UPD */ "state update",
/* PFSYNC_ACT_UPD_1301 */ "13.1 state update",
/* PFSYNC_ACT_UPD_C */ "compressed state update",
/* PFSYNC_ACT_UPD_REQ */ "uncompressed state request",
/* PFSYNC_ACT_DEL */ "state delete",
@ -93,13 +93,15 @@ static const char* pfsyncacts[] = {
/* PFSYNC_ACT_BUS */ "bulk update mark",
/* PFSYNC_ACT_TDB */ "TDB replay counter update",
/* PFSYNC_ACT_EOF */ "end of frame mark",
/* PFSYNC_ACT_INS_1400 */ "state insert",
/* PFSYNC_ACT_UPD_1400 */ "state update",
};
static const char* pfsyncacts_name[] = {
/* PFSYNC_ACT_CLR */ "clear-all-request",
/* PFSYNC_ACT_INS */ "state-insert",
/* PFSYNC_ACT_INS_1301 */ "state-insert-1301",
/* PFSYNC_ACT_INS_ACK */ "state-inserted-ack",
/* PFSYNC_ACT_UPD */ "state-update",
/* PFSYNC_ACT_UPD_1301 */ "state-update-1301",
/* PFSYNC_ACT_UPD_C */ "compressed-state-update",
/* PFSYNC_ACT_UPD_REQ */ "uncompressed-state-request",
/* PFSYNC_ACT_DEL */ "state-delete",
@ -109,6 +111,8 @@ static const char* pfsyncacts_name[] = {
/* PFSYNC_ACT_BUS */ "bulk-update-mark",
/* PFSYNC_ACT_TDB */ "TDB-replay-counter-update",
/* PFSYNC_ACT_EOF */ "end-of-frame-mark",
/* PFSYNC_ACT_INS_1400 */ "state-insert",
/* PFSYNC_ACT_UPD_1400 */ "state-update",
};
static void