Page MenuHomeFreeBSD

D52176.id.diff
No OneTemporary

D52176.id.diff

diff --git a/contrib/tcpdump/print-pfsync.c b/contrib/tcpdump/print-pfsync.c
--- a/contrib/tcpdump/print-pfsync.c
+++ b/contrib/tcpdump/print-pfsync.c
@@ -102,6 +102,7 @@
static void pfsync_print_clr(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_state_1500(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 *);
@@ -131,6 +132,8 @@
{ "eof", 0, NULL },
{ "insert", sizeof(struct pfsync_state_1400), pfsync_print_state_1400 },
{ "update", sizeof(struct pfsync_state_1400), pfsync_print_state_1400 },
+ { "insert", sizeof(struct pfsync_state_1500), pfsync_print_state_1500 },
+ { "update", sizeof(struct pfsync_state_1500), pfsync_print_state_1500 },
};
static void
@@ -228,12 +231,21 @@
static void
pfsync_print_state_1400(netdissect_options *ndo, const void *bp)
{
- struct pfsync_state_1301 *st = (struct pfsync_state_1301 *)bp;
+ struct pfsync_state_1400 *st = (struct pfsync_state_1400 *)bp;
fn_print_char(ndo, '\n');
print_state(ndo, (union pfsync_state_union *)st, PFSYNC_MSG_VERSION_1400);
}
+static void
+pfsync_print_state_1500(netdissect_options *ndo, const void *bp)
+{
+ struct pfsync_state_1500 *st = (struct pfsync_state_1500 *)bp;
+
+ fn_print_char(ndo, '\n');
+ print_state(ndo, (union pfsync_state_union *)st, PFSYNC_MSG_VERSION_1500);
+}
+
static void
pfsync_print_ins_ack(netdissect_options *ndo, const void *bp)
{
diff --git a/share/man/man4/pfsync.4 b/share/man/man4/pfsync.4
--- a/share/man/man4/pfsync.4
+++ b/share/man/man4/pfsync.4
@@ -162,6 +162,8 @@
Compatibility with FreeBSD 13.1 has been verified.
.It Cm 1400
FreeBSD release 14.0.
+.It Cm 1500
+FreeBSD release 15.0.
.El
.Sh SYSCTL VARIABLES
The following variables can be entered at the
diff --git a/sys/net/if_pfsync.h b/sys/net/if_pfsync.h
--- a/sys/net/if_pfsync.h
+++ b/sys/net/if_pfsync.h
@@ -62,9 +62,10 @@
PFSYNC_MSG_VERSION_UNSPECIFIED = 0,
PFSYNC_MSG_VERSION_1301 = 1301,
PFSYNC_MSG_VERSION_1400 = 1400,
+ PFSYNC_MSG_VERSION_1500 = 1500,
};
-#define PFSYNC_MSG_VERSION_DEFAULT PFSYNC_MSG_VERSION_1400
+#define PFSYNC_MSG_VERSION_DEFAULT PFSYNC_MSG_VERSION_1500
#define PFSYNC_ACT_CLR 0 /* clear all states */
#define PFSYNC_ACT_INS_1301 1 /* insert state */
@@ -81,7 +82,9 @@
#define PFSYNC_ACT_EOF 12 /* end of frame */
#define PFSYNC_ACT_INS_1400 13 /* insert state */
#define PFSYNC_ACT_UPD_1400 14 /* update state */
-#define PFSYNC_ACT_MAX 15
+#define PFSYNC_ACT_INS_1500 15 /* insert state */
+#define PFSYNC_ACT_UPD_1500 16 /* update state */
+#define PFSYNC_ACT_MAX 17
/*
* A pfsync frame is built from a header followed by several sections which
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -452,6 +452,16 @@
#define PF_RULES_RASSERT() rm_assert(&V_pf_rules_lock, RA_RLOCKED)
#define PF_RULES_WASSERT() rm_assert(&V_pf_rules_lock, RA_WLOCKED)
+VNET_DECLARE(struct rmlock, pf_tags_lock);
+#define V_pf_tags_lock VNET(pf_tags_lock)
+
+#define PF_TAGS_RLOCK_TRACKER struct rm_priotracker _pf_tags_tracker
+#define PF_TAGS_RLOCK() rm_rlock(&V_pf_tags_lock, &_pf_tags_tracker)
+#define PF_TAGS_RUNLOCK() rm_runlock(&V_pf_tags_lock, &_pf_tags_tracker)
+#define PF_TAGS_WLOCK() rm_wlock(&V_pf_tags_lock)
+#define PF_TAGS_WUNLOCK() rm_wunlock(&V_pf_tags_lock)
+#define PF_TAGS_WASSERT() rm_assert(&V_pf_tags_lock, RA_WLOCKED)
+
extern struct mtx_padalign pf_table_stats_lock;
#define PF_TABLE_STATS_LOCK() mtx_lock(&pf_table_stats_lock)
#define PF_TABLE_STATS_UNLOCK() mtx_unlock(&pf_table_stats_lock)
@@ -1209,11 +1219,11 @@
u_int8_t state_flags;
u_int8_t timeout;
u_int8_t sync_flags;
- u_int8_t updates;
+ u_int8_t updates; /* unused */
} __packed;
struct pfsync_state_1400 {
- /* The beginning of the struct is compatible with previous versions */
+ /* The beginning of the struct is compatible with pfsync_state_1301 */
u_int64_t id;
char ifname[IFNAMSIZ];
struct pfsync_state_key key[2];
@@ -1236,7 +1246,7 @@
u_int8_t __spare;
u_int8_t timeout;
u_int8_t sync_flags;
- u_int8_t updates;
+ u_int8_t updates; /* unused */
/* The rest is not */
u_int16_t qid;
u_int16_t pqid;
@@ -1249,12 +1259,54 @@
u_int8_t set_prio[2];
u_int8_t rt;
char rt_ifname[IFNAMSIZ];
+} __packed;
+struct pfsync_state_1500 {
+ /* The beginning of the struct is compatible with pfsync_state_1301 */
+ u_int64_t id;
+ char ifname[IFNAMSIZ];
+ struct pfsync_state_key key[2];
+ struct pf_state_peer_export src;
+ struct pf_state_peer_export 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;
+ /* The rest is not, use the opportunity to fix alignment */
+ char tagname[PF_TAG_NAME_SIZE];
+ char rt_ifname[IFNAMSIZ];
+ char orig_ifname[IFNAMSIZ];
+ int32_t rtableid;
+ u_int16_t state_flags;
+ u_int16_t qid;
+ u_int16_t pqid;
+ u_int16_t dnpipe;
+ u_int16_t dnrpipe;
+ u_int16_t max_mss;
+ sa_family_t wire_af;
+ sa_family_t stack_af;
+ sa_family_t rt_af;
+ u_int8_t wire_proto;
+ u_int8_t stack_proto;
+ u_int8_t log;
+ u_int8_t timeout;
+ u_int8_t direction;
+ u_int8_t rt;
+ u_int8_t min_ttl;
+ u_int8_t set_tos;
+ u_int8_t set_prio[2];
+ u_int8_t spare[3]; /* Improve struct alignment */
} __packed;
union pfsync_state_union {
struct pfsync_state_1301 pfs_1301;
struct pfsync_state_1400 pfs_1400;
+ struct pfsync_state_1500 pfs_1500;
} __packed;
#ifdef _KERNEL
@@ -2462,6 +2514,10 @@
struct pf_addr *, u_int16_t, u_int16_t, int);
int pf_translate_af(struct pf_pdesc *);
bool pf_init_threshold(struct pf_kthreshold *, uint32_t, uint32_t);
+uint16_t pf_tagname2tag(const char *);
+#ifdef ALTQ
+uint16_t pf_qname2qid(const char *, bool);
+#endif /* ALTQ */
void pfr_initialize(void);
void pfr_cleanup(void);
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -153,6 +153,8 @@
pfsync_in_eof, /* PFSYNC_ACT_EOF */
pfsync_in_ins, /* PFSYNC_ACT_INS_1400 */
pfsync_in_upd, /* PFSYNC_ACT_UPD_1400 */
+ pfsync_in_ins, /* PFSYNC_ACT_INS_1500 */
+ pfsync_in_upd, /* PFSYNC_ACT_UPD_1500 */
};
struct pfsync_q {
@@ -165,9 +167,11 @@
enum pfsync_q_id {
PFSYNC_Q_INS_1301,
PFSYNC_Q_INS_1400,
+ PFSYNC_Q_INS_1500,
PFSYNC_Q_IACK,
PFSYNC_Q_UPD_1301,
PFSYNC_Q_UPD_1400,
+ PFSYNC_Q_UPD_1500,
PFSYNC_Q_UPD_C,
PFSYNC_Q_DEL_C,
PFSYNC_Q_COUNT,
@@ -176,6 +180,7 @@
/* 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_state_1500(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 *);
@@ -184,9 +189,11 @@
static struct pfsync_q pfsync_qs[] = {
{ 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_state_1500, sizeof(struct pfsync_state_1500), PFSYNC_ACT_INS_1500 },
{ 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_state_1500, sizeof(struct pfsync_state_1500), PFSYNC_ACT_UPD_1500 },
{ 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 }
};
@@ -195,9 +202,11 @@
static u_int8_t pfsync_qid_sstate[] = {
PFSYNC_S_INS, /* PFSYNC_Q_INS_1301 */
PFSYNC_S_INS, /* PFSYNC_Q_INS_1400 */
+ PFSYNC_S_INS, /* PFSYNC_Q_INS_1500 */
PFSYNC_S_IACK, /* PFSYNC_Q_IACK */
PFSYNC_S_UPD, /* PFSYNC_Q_UPD_1301 */
PFSYNC_S_UPD, /* PFSYNC_Q_UPD_1400 */
+ PFSYNC_S_UPD, /* PFSYNC_Q_UPD_1500 */
PFSYNC_S_UPD_C, /* PFSYNC_Q_UPD_C */
PFSYNC_S_DEL_C, /* PFSYNC_Q_DEL_C */
};
@@ -525,13 +534,15 @@
struct pf_kstate *st = NULL;
struct pf_state_key *skw = NULL, *sks = NULL;
struct pf_krule *r = NULL;
- struct pfi_kkif *kif;
+ struct pfi_kkif *kif, *orig_kif;
struct pfi_kkif *rt_kif = NULL;
struct pf_kpooladdr *rpool_first;
int error;
+ int n = 0;
sa_family_t rt_af = 0;
uint8_t rt = 0;
- int n = 0;
+ sa_family_t wire_af, stack_af;
+ u_int8_t wire_proto, stack_proto;
PF_RULES_RASSERT();
@@ -542,7 +553,11 @@
return (EINVAL);
}
- if ((kif = pfi_kkif_find(sp->pfs_1301.ifname)) == NULL) {
+ /*
+ * Check interfaces early on. Do it before allocating memory etc.
+ * Because there is a high chance there will be a lot more such states.
+ */
+ if ((kif = orig_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->pfs_1301.ifname);
@@ -551,6 +566,30 @@
return (0); /* skip this state */
}
+ /*
+ * States created with floating interface policy can be synchronized to
+ * hosts with different interfaces, because they are bound to V_pfi_all.
+ * But s->orig_kif still points to a real interface. Don't abort
+ * importing the state if orig_kif does not exists on the importing host
+ * but the state is not interface-bound.
+ */
+ if (msg_version == PFSYNC_MSG_VERSION_1500) {
+ orig_kif = pfi_kkif_find(sp->pfs_1500.orig_ifname);
+ if (orig_kif == NULL) {
+ if (kif == V_pfi_all) {
+ orig_kif = kif;
+ } else {
+ if (V_pf_status.debug >= PF_DEBUG_MISC)
+ printf("%s: unknown original interface:"
+ " %s\n", __func__,
+ sp->pfs_1500.orig_ifname);
+ if (flags & PFSYNC_SI_IOCTL)
+ return (EINVAL);
+ return (0); /* skip this state */
+ }
+ }
+ }
+
/*
* 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.
@@ -565,10 +604,6 @@
} else
r = &V_pf_default_rule;
- /*
- * Check routing interface early on. Do it before allocating memory etc.
- * because there is a high chance there will be a lot more such states.
- */
switch (msg_version) {
case PFSYNC_MSG_VERSION_1301:
/*
@@ -619,10 +654,12 @@
"because of different ruleset", __func__);
return ((flags & PFSYNC_SI_IOCTL) ? EINVAL : 0);
}
+ wire_af = stack_af = sp->pfs_1301.af;
+ wire_proto = stack_proto = sp->pfs_1301.proto;
break;
case PFSYNC_MSG_VERSION_1400:
/*
- * On FreeBSD 14 and above we're not taking any chances.
+ * On FreeBSD 14 we're not taking any chances.
* We use the information synced to us.
*/
if (sp->pfs_1400.rt) {
@@ -641,6 +678,29 @@
*/
rt_af = sp->pfs_1400.af;
}
+ wire_af = stack_af = sp->pfs_1400.af;
+ wire_proto = stack_proto = sp->pfs_1400.proto;
+ break;
+ case PFSYNC_MSG_VERSION_1500:
+ /*
+ * On FreeBSD 15 and above we're not taking any chances.
+ * We use the information synced to us.
+ */
+ if (sp->pfs_1500.rt) {
+ rt_kif = pfi_kkif_find(sp->pfs_1500.rt_ifname);
+ if (rt_kif == NULL) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ "%s: unknown route interface: %s",
+ __func__, sp->pfs_1500.rt_ifname);
+ return ((flags & PFSYNC_SI_IOCTL) ? EINVAL : 0);
+ }
+ rt = sp->pfs_1500.rt;
+ rt_af = sp->pfs_1500.rt_af;
+ }
+ wire_af = sp->pfs_1500.wire_af;
+ stack_af = sp->pfs_1500.stack_af;
+ wire_proto = sp->pfs_1500.wire_proto;
+ stack_proto = sp->pfs_1500.stack_proto;
break;
}
@@ -667,8 +727,9 @@
ks = &sp->pfs_1301.key[PF_SK_STACK];
#endif
- 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) ||
+ if (wire_af != stack_af ||
+ PF_ANEQ(&kw->addr[0], &ks->addr[0], wire_af) ||
+ PF_ANEQ(&kw->addr[1], &ks->addr[1], wire_af) ||
kw->port[0] != ks->port[0] ||
kw->port[1] != ks->port[1]) {
sks = uma_zalloc(V_pf_state_key_z, M_NOWAIT);
@@ -687,36 +748,19 @@
skw->addr[1] = kw->addr[1];
skw->port[0] = kw->port[0];
skw->port[1] = kw->port[1];
- skw->proto = sp->pfs_1301.proto;
- skw->af = sp->pfs_1301.af;
+ skw->proto = wire_proto;
+ skw->af = wire_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->pfs_1301.proto;
- sks->af = sp->pfs_1301.af;
+ sks->proto = stack_proto;
+ sks->af = stack_af;
}
/* copy to state */
- bcopy(&sp->pfs_1301.rt_addr, &st->act.rt_addr, sizeof(st->act.rt_addr));
st->creation = (time_uptime - ntohl(sp->pfs_1301.creation)) * 1000;
- st->expire = pf_get_uptime();
- if (sp->pfs_1301.expire) {
- uint32_t timeout;
-
- timeout = r->timeout[sp->pfs_1301.timeout];
- if (!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->pfs_1301.expire)) * 1000;
- }
-
- st->direction = sp->pfs_1301.direction;
- st->act.log = sp->pfs_1301.log;
- st->timeout = sp->pfs_1301.timeout;
-
st->act.rt = rt;
st->act.rt_kif = rt_kif;
st->act.rt_af = rt_af;
@@ -724,6 +768,12 @@
switch (msg_version) {
case PFSYNC_MSG_VERSION_1301:
st->state_flags = sp->pfs_1301.state_flags;
+ st->direction = sp->pfs_1301.direction;
+ st->act.log = sp->pfs_1301.log;
+ st->timeout = sp->pfs_1301.timeout;
+ if (rt)
+ bcopy(&sp->pfs_1301.rt_addr, &st->act.rt_addr,
+ sizeof(st->act.rt_addr));
/*
* In FreeBSD 13 pfsync lacks many attributes. Copy them
* from the rule if possible. If rule can't be matched
@@ -762,6 +812,9 @@
break;
case PFSYNC_MSG_VERSION_1400:
st->state_flags = ntohs(sp->pfs_1400.state_flags);
+ st->direction = sp->pfs_1400.direction;
+ st->act.log = sp->pfs_1400.log;
+ st->timeout = sp->pfs_1400.timeout;
st->act.qid = ntohs(sp->pfs_1400.qid);
st->act.pqid = ntohs(sp->pfs_1400.pqid);
st->act.dnpipe = ntohs(sp->pfs_1400.dnpipe);
@@ -772,12 +825,47 @@
st->act.max_mss = ntohs(sp->pfs_1400.max_mss);
st->act.set_prio[0] = sp->pfs_1400.set_prio[0];
st->act.set_prio[1] = sp->pfs_1400.set_prio[1];
+ if (rt)
+ bcopy(&sp->pfs_1400.rt_addr, &st->act.rt_addr,
+ sizeof(st->act.rt_addr));
+ break;
+ case PFSYNC_MSG_VERSION_1500:
+ st->state_flags = ntohs(sp->pfs_1500.state_flags);
+ st->direction = sp->pfs_1500.direction;
+ st->act.log = sp->pfs_1500.log;
+ st->timeout = sp->pfs_1500.timeout;
+ st->act.qid = ntohs(sp->pfs_1500.qid);
+ st->act.pqid = ntohs(sp->pfs_1500.pqid);
+ st->act.dnpipe = ntohs(sp->pfs_1500.dnpipe);
+ st->act.dnrpipe = ntohs(sp->pfs_1500.dnrpipe);
+ st->act.rtableid = ntohl(sp->pfs_1500.rtableid);
+ st->act.min_ttl = sp->pfs_1500.min_ttl;
+ st->act.set_tos = sp->pfs_1500.set_tos;
+ st->act.max_mss = ntohs(sp->pfs_1500.max_mss);
+ st->act.set_prio[0] = sp->pfs_1500.set_prio[0];
+ st->act.set_prio[1] = sp->pfs_1500.set_prio[1];
+ if (rt)
+ bcopy(&sp->pfs_1500.rt_addr, &st->act.rt_addr,
+ sizeof(st->act.rt_addr));
+ if (sp->pfs_1500.tagname[0] != 0)
+ st->tag = pf_tagname2tag(sp->pfs_1500.tagname);
break;
default:
panic("%s: Unsupported pfsync_msg_version %d",
__func__, msg_version);
}
+ st->expire = pf_get_uptime();
+ if (sp->pfs_1301.expire) {
+ uint32_t timeout;
+ timeout = r->timeout[st->timeout];
+ if (!timeout)
+ timeout = V_pf_default_rule.timeout[st->timeout];
+
+ /* sp->expire may have been adaptively scaled by export. */
+ st->expire -= (timeout - ntohl(sp->pfs_1301.expire)) * 1000;
+ }
+
if (! (st->act.rtableid == -1 ||
(st->act.rtableid >= 0 && st->act.rtableid < rt_numfibs)))
goto cleanup;
@@ -797,7 +885,7 @@
if (!(flags & PFSYNC_SI_IOCTL))
st->state_flags |= PFSTATE_NOSYNC;
- if ((error = pf_state_insert(kif, kif, skw, sks, st)) != 0)
+ if ((error = pf_state_insert(kif, orig_kif, skw, sks, st)) != 0)
goto cleanup_state;
/* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */
@@ -1089,23 +1177,29 @@
struct mbuf *mp;
union pfsync_state_union *sa, *sp;
int i, offp, total_len, msg_version, msg_len;
+ u_int8_t timeout, direction;
+ sa_family_t af;
switch (action) {
case PFSYNC_ACT_INS_1301:
msg_len = sizeof(struct pfsync_state_1301);
- total_len = msg_len * count;
msg_version = PFSYNC_MSG_VERSION_1301;
break;
case PFSYNC_ACT_INS_1400:
msg_len = sizeof(struct pfsync_state_1400);
- total_len = msg_len * count;
msg_version = PFSYNC_MSG_VERSION_1400;
break;
+ case PFSYNC_ACT_INS_1500:
+ msg_len = sizeof(struct pfsync_state_1500);
+ msg_version = PFSYNC_MSG_VERSION_1500;
+ break;
default:
V_pfsyncstats.pfsyncs_badver++;
return (-1);
}
+ total_len = msg_len * count;
+
mp = m_pulldown(m, offset, total_len, &offp);
if (mp == NULL) {
V_pfsyncstats.pfsyncs_badlen++;
@@ -1116,13 +1210,26 @@
for (i = 0; i < count; i++) {
sp = (union pfsync_state_union *)((char *)sa + msg_len * i);
+ switch (msg_version) {
+ case PFSYNC_MSG_VERSION_1301:
+ case PFSYNC_MSG_VERSION_1400:
+ af = sp->pfs_1301.af;
+ timeout = sp->pfs_1301.timeout;
+ direction = sp->pfs_1301.direction;
+ break;
+ case PFSYNC_MSG_VERSION_1500:
+ af = sp->pfs_1500.wire_af;
+ timeout = sp->pfs_1500.timeout;
+ direction = sp->pfs_1500.direction;
+ break;
+ }
+
/* Check for invalid values. */
- if (sp->pfs_1301.timeout >= PFTM_MAX ||
+ if (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)) {
+ direction > PF_OUT ||
+ (af != AF_INET && af != AF_INET6)) {
if (V_pf_status.debug >= PF_DEBUG_MISC)
printf("%s: invalid value\n", __func__);
V_pfsyncstats.pfsyncs_badval++;
@@ -1215,23 +1322,28 @@
struct pf_kstate *st;
struct mbuf *mp;
int sync, offp, i, total_len, msg_len, msg_version;
+ u_int8_t timeout;
switch (action) {
case PFSYNC_ACT_UPD_1301:
msg_len = sizeof(struct pfsync_state_1301);
- total_len = msg_len * count;
msg_version = PFSYNC_MSG_VERSION_1301;
break;
case PFSYNC_ACT_UPD_1400:
msg_len = sizeof(struct pfsync_state_1400);
- total_len = msg_len * count;
msg_version = PFSYNC_MSG_VERSION_1400;
break;
+ case PFSYNC_ACT_UPD_1500:
+ msg_len = sizeof(struct pfsync_state_1500);
+ msg_version = PFSYNC_MSG_VERSION_1500;
+ break;
default:
V_pfsyncstats.pfsyncs_badact++;
return (-1);
}
+ total_len = msg_len * count;
+
mp = m_pulldown(m, offset, total_len, &offp);
if (mp == NULL) {
V_pfsyncstats.pfsyncs_badlen++;
@@ -1242,8 +1354,18 @@
for (i = 0; i < count; i++) {
sp = (union pfsync_state_union *)((char *)sa + msg_len * i);
+ switch (msg_version) {
+ case PFSYNC_MSG_VERSION_1301:
+ case PFSYNC_MSG_VERSION_1400:
+ timeout = sp->pfs_1301.timeout;
+ break;
+ case PFSYNC_MSG_VERSION_1500:
+ timeout = sp->pfs_1500.timeout;
+ break;
+ }
+
/* check for invalid values */
- if (sp->pfs_1301.timeout >= PFTM_MAX ||
+ if (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) {
@@ -1288,7 +1410,7 @@
pfsync_alloc_scrub_memory(&sp->pfs_1301.dst, &st->dst);
pf_state_peer_ntoh(&sp->pfs_1301.dst, &st->dst);
st->expire = pf_get_uptime();
- st->timeout = sp->pfs_1301.timeout;
+ st->timeout = timeout;
}
st->pfsync_time = time_uptime;
@@ -1788,6 +1910,14 @@
pfsync_state_export(sp, st, PFSYNC_MSG_VERSION_1400);
}
+static void
+pfsync_out_state_1500(struct pf_kstate *st, void *buf)
+{
+ union pfsync_state_union *sp = buf;
+
+ pfsync_state_export(sp, st, PFSYNC_MSG_VERSION_1500);
+}
+
static void
pfsync_out_iack(struct pf_kstate *st, void *buf)
{
@@ -2455,6 +2585,8 @@
return PFSYNC_Q_INS_1301;
case PFSYNC_MSG_VERSION_1400:
return PFSYNC_Q_INS_1400;
+ case PFSYNC_MSG_VERSION_1500:
+ return PFSYNC_Q_INS_1500;
}
break;
case PFSYNC_S_IACK:
@@ -2465,6 +2597,8 @@
return PFSYNC_Q_UPD_1301;
case PFSYNC_MSG_VERSION_1400:
return PFSYNC_Q_UPD_1400;
+ case PFSYNC_MSG_VERSION_1500:
+ return PFSYNC_Q_UPD_1500;
}
break;
case PFSYNC_S_UPD_C:
@@ -3021,6 +3155,7 @@
break;
case PFSYNC_MSG_VERSION_1301:
case PFSYNC_MSG_VERSION_1400:
+ case PFSYNC_MSG_VERSION_1500:
sc->sc_version = status->version;
break;
default:
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -116,7 +116,6 @@
static int pf_commit_altq(u_int32_t);
static int pf_enable_altq(struct pf_altq *);
static int pf_disable_altq(struct pf_altq *);
-static uint16_t pf_qname2qid(const char *);
static void pf_qid_unref(uint16_t);
#endif /* ALTQ */
static int pf_begin_rules(u_int32_t *, int, const char *);
@@ -214,8 +213,7 @@
static void pf_cleanup_tagset(struct pf_tagset *);
static uint16_t tagname2hashindex(const struct pf_tagset *, const char *);
static uint16_t tag2hashindex(const struct pf_tagset *, uint16_t);
-static u_int16_t tagname2tag(struct pf_tagset *, const char *);
-static u_int16_t pf_tagname2tag(const char *);
+static u_int16_t tagname2tag(struct pf_tagset *, const char *, bool);
static void tag_unref(struct pf_tagset *, u_int16_t);
struct cdev *pf_dev;
@@ -286,6 +284,7 @@
struct proc *pf_purge_proc;
VNET_DEFINE(struct rmlock, pf_rules_lock);
+VNET_DEFINE(struct rmlock, pf_tags_lock);
VNET_DEFINE_STATIC(struct sx, pf_ioctl_lock);
#define V_pf_ioctl_lock VNET(pf_ioctl_lock)
struct sx pf_end_lock;
@@ -687,19 +686,50 @@
}
static u_int16_t
-tagname2tag(struct pf_tagset *ts, const char *tagname)
+tagname2tag(struct pf_tagset *ts, const char *tagname, bool add_new)
{
struct pf_tagname *tag;
u_int32_t index;
u_int16_t new_tagid;
- PF_RULES_WASSERT();
+ PF_TAGS_RLOCK_TRACKER;
+
+ PF_TAGS_RLOCK();
index = tagname2hashindex(ts, tagname);
TAILQ_FOREACH(tag, &ts->namehash[index], namehash_entries)
if (strcmp(tagname, tag->name) == 0) {
tag->ref++;
- return (tag->tag);
+ new_tagid = tag->tag;
+ PF_TAGS_RUNLOCK();
+ return (new_tagid);
+ }
+
+ /*
+ * When used for pfsync with queues we must not create new entries.
+ * Pf tags can be created just fine by this function, but queues
+ * require additional configuration. If they are missing on the target
+ * system we just ignore them
+ */
+ if (add_new == false) {
+ printf("%s: Not creating a new tag\n", __func__);
+ PF_TAGS_RUNLOCK();
+ return (0);
+ }
+
+ /*
+ * If a new entry must be created do it under a write lock.
+ * But first search again, somebody could have created the tag
+ * between unlocking the read lock and locking the write lock.
+ */
+ PF_TAGS_RUNLOCK();
+ PF_TAGS_WLOCK();
+ TAILQ_FOREACH(tag, &ts->namehash[index], namehash_entries)
+ if (strcmp(tagname, tag->name) == 0) {
+ tag->ref++;
+ new_tagid = tag->tag;
+ PF_TAGS_WUNLOCK();
+ return (new_tagid);
}
/*
@@ -716,16 +746,20 @@
* to rounding of the number of bits in the vector up to a multiple
* of the vector word size at declaration/allocation time.
*/
- if ((new_tagid == 0) || (new_tagid > TAGID_MAX))
+ if ((new_tagid == 0) || (new_tagid > TAGID_MAX)) {
+ PF_TAGS_WUNLOCK();
return (0);
+ }
/* Mark the tag as in use. Bits are 0-based for BIT_CLR() */
BIT_CLR(TAGID_MAX, new_tagid - 1, &ts->avail);
/* allocate and fill new struct pf_tagname */
tag = uma_zalloc(V_pf_tag_z, M_NOWAIT);
- if (tag == NULL)
+ if (tag == NULL) {
+ PF_TAGS_WUNLOCK();
return (0);
+ }
strlcpy(tag->name, tagname, sizeof(tag->name));
tag->tag = new_tagid;
tag->ref = 1;
@@ -737,7 +771,29 @@
index = tag2hashindex(ts, new_tagid);
TAILQ_INSERT_TAIL(&ts->taghash[index], tag, taghash_entries);
- return (tag->tag);
+ PF_TAGS_WUNLOCK();
+ return (new_tagid);
+}
+
+static char *
+tag2tagname(struct pf_tagset *ts, u_int16_t tag)
+{
+ struct pf_tagname *t;
+ uint16_t index;
+
+ PF_TAGS_RLOCK_TRACKER;
+
+ PF_TAGS_RLOCK();
+
+ index = tag2hashindex(ts, tag);
+ TAILQ_FOREACH(t, &ts->taghash[index], taghash_entries)
+ if (tag == t->tag) {
+ PF_TAGS_RUNLOCK();
+ return (t->name);
+ }
+
+ PF_TAGS_RUNLOCK();
+ return (NULL);
}
static void
@@ -746,7 +802,7 @@
struct pf_tagname *t;
uint16_t index;
- PF_RULES_WASSERT();
+ PF_TAGS_WLOCK();
index = tag2hashindex(ts, tag);
TAILQ_FOREACH(t, &ts->taghash[index], taghash_entries)
@@ -763,12 +819,20 @@
}
break;
}
+
+ PF_TAGS_WUNLOCK();
}
-static uint16_t
+uint16_t
pf_tagname2tag(const char *tagname)
{
- return (tagname2tag(&V_pf_tags, tagname));
+ return (tagname2tag(&V_pf_tags, tagname, true));
+}
+
+static const char *
+pf_tag2tagname(uint16_t tag)
+{
+ return (tag2tagname(&V_pf_tags, tag));
}
static int
@@ -899,10 +963,16 @@
}
#ifdef ALTQ
-static uint16_t
-pf_qname2qid(const char *qname)
+uint16_t
+pf_qname2qid(const char *qname, bool add_new)
+{
+ return (tagname2tag(&V_pf_qids, qname, add_new));
+}
+
+static const char *
+pf_qid2qname(uint16_t qid)
{
- return (tagname2tag(&V_pf_qids, qname));
+ return (tag2tagname(&V_pf_qids, qid));
}
static void
@@ -1151,7 +1221,7 @@
}
bcopy(a1, a2, sizeof(struct pf_altq));
- if ((a2->qid = pf_qname2qid(a2->qname)) == 0) {
+ if ((a2->qid = pf_qname2qid(a2->qname, true)) == 0) {
error = EBUSY;
free(a2, M_PFALTQ);
break;
@@ -1606,7 +1676,7 @@
#define ASSIGN_OPT(x) exported_q->pq_u.hfsc_opts.x = q->pq_u.hfsc_opts.x
#define ASSIGN_OPT_SATU32(x) exported_q->pq_u.hfsc_opts.x = \
SATU32(q->pq_u.hfsc_opts.x)
-
+
ASSIGN_OPT_SATU32(rtsc_m1);
ASSIGN_OPT(rtsc_d);
ASSIGN_OPT_SATU32(rtsc_m2);
@@ -1620,7 +1690,7 @@
ASSIGN_OPT_SATU32(ulsc_m2);
ASSIGN_OPT(flags);
-
+
#undef ASSIGN_OPT
#undef ASSIGN_OPT_SATU32
} else
@@ -1728,7 +1798,7 @@
ASSIGN_OPT(ulsc_m2);
ASSIGN_OPT(flags);
-
+
#undef ASSIGN_OPT
} else
COPY(pq_u);
@@ -1760,7 +1830,7 @@
ASSIGN(qid);
break;
}
- default:
+ default:
panic("%s: unhandled struct pfioc_altq version", __func__);
break;
}
@@ -2191,11 +2261,11 @@
#ifdef ALTQ
/* set queue IDs */
if (rule->qname[0] != 0) {
- if ((rule->qid = pf_qname2qid(rule->qname)) == 0)
+ if ((rule->qid = pf_qname2qid(rule->qname, true)) == 0)
ERROUT(EBUSY);
else if (rule->pqname[0] != 0) {
if ((rule->pqid =
- pf_qname2qid(rule->pqname)) == 0)
+ pf_qname2qid(rule->pqname, true)) == 0)
ERROUT(EBUSY);
} else
rule->pqid = rule->qid;
@@ -3314,7 +3384,7 @@
#ifdef ALTQ
/* set queue IDs */
if (rule->qname[0] != 0) {
- if ((rule->qid = pf_qname2qid(rule->qname)) == 0)
+ if ((rule->qid = pf_qname2qid(rule->qname, true)) == 0)
error = EBUSY;
else
rule->qid = rule->qid;
@@ -3865,11 +3935,11 @@
/* set queue IDs */
if (newrule->qname[0] != 0) {
if ((newrule->qid =
- pf_qname2qid(newrule->qname)) == 0)
+ pf_qname2qid(newrule->qname, true)) == 0)
error = EBUSY;
else if (newrule->pqname[0] != 0) {
if ((newrule->pqid =
- pf_qname2qid(newrule->pqname)) == 0)
+ pf_qname2qid(newrule->pqname, true)) == 0)
error = EBUSY;
} else
newrule->pqid = newrule->qid;
@@ -4400,7 +4470,7 @@
* copy the necessary fields
*/
if (altq->qname[0] != 0) {
- if ((altq->qid = pf_qname2qid(altq->qname)) == 0) {
+ if ((altq->qid = pf_qname2qid(altq->qname, true)) == 0) {
PF_RULES_WUNLOCK();
error = EBUSY;
free(altq, M_PFALTQ);
@@ -5723,6 +5793,7 @@
void
pfsync_state_export(union pfsync_state_union *sp, struct pf_kstate *st, int msg_version)
{
+ const char *tagname;
bzero(sp, sizeof(union pfsync_state_union));
/* copy from state key */
@@ -5734,8 +5805,6 @@
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->pfs_1301.ifname, st->kif->pfik_name, sizeof(sp->pfs_1301.ifname));
@@ -5747,16 +5816,31 @@
else
sp->pfs_1301.expire = htonl(sp->pfs_1301.expire - time_uptime);
- sp->pfs_1301.direction = st->direction;
- sp->pfs_1301.log = st->act.log;
- sp->pfs_1301.timeout = st->timeout;
-
switch (msg_version) {
case PFSYNC_MSG_VERSION_1301:
sp->pfs_1301.state_flags = st->state_flags;
+ sp->pfs_1301.direction = st->direction;
+ sp->pfs_1301.log = st->act.log;
+ sp->pfs_1301.timeout = st->timeout;
+ sp->pfs_1301.proto = st->key[PF_SK_WIRE]->proto;
+ sp->pfs_1301.af = st->key[PF_SK_WIRE]->af;
+ /*
+ * XXX Why do we bother pfsyncing source node information if source
+ * nodes are not synced? Showing users that there is source tracking
+ * when there is none seems useless.
+ */
+ if (st->sns[PF_SN_LIMIT] != NULL)
+ sp->pfs_1301.sync_flags |= PFSYNC_FLAG_SRCNODE;
+ if (st->sns[PF_SN_NAT] != NULL || st->sns[PF_SN_ROUTE])
+ sp->pfs_1301.sync_flags |= PFSYNC_FLAG_NATSRCNODE;
break;
case PFSYNC_MSG_VERSION_1400:
sp->pfs_1400.state_flags = htons(st->state_flags);
+ sp->pfs_1400.direction = st->direction;
+ sp->pfs_1400.log = st->act.log;
+ sp->pfs_1400.timeout = st->timeout;
+ sp->pfs_1400.proto = st->key[PF_SK_WIRE]->proto;
+ sp->pfs_1400.af = st->key[PF_SK_WIRE]->af;
sp->pfs_1400.qid = htons(st->act.qid);
sp->pfs_1400.pqid = htons(st->act.pqid);
sp->pfs_1400.dnpipe = htons(st->act.dnpipe);
@@ -5772,22 +5856,53 @@
strlcpy(sp->pfs_1400.rt_ifname,
st->act.rt_kif->pfik_name,
sizeof(sp->pfs_1400.rt_ifname));
+ /*
+ * XXX Why do we bother pfsyncing source node information if source
+ * nodes are not synced? Showing users that there is source tracking
+ * when there is none seems useless.
+ */
+ if (st->sns[PF_SN_LIMIT] != NULL)
+ sp->pfs_1400.sync_flags |= PFSYNC_FLAG_SRCNODE;
+ if (st->sns[PF_SN_NAT] != NULL || st->sns[PF_SN_ROUTE])
+ sp->pfs_1400.sync_flags |= PFSYNC_FLAG_NATSRCNODE;
+ break;
+ case PFSYNC_MSG_VERSION_1500:
+ sp->pfs_1500.state_flags = htons(st->state_flags);
+ sp->pfs_1500.direction = st->direction;
+ sp->pfs_1500.log = st->act.log;
+ sp->pfs_1500.timeout = st->timeout;
+ sp->pfs_1500.wire_proto = st->key[PF_SK_WIRE]->proto;
+ sp->pfs_1500.wire_af = st->key[PF_SK_WIRE]->af;
+ sp->pfs_1500.stack_proto = st->key[PF_SK_STACK]->proto;
+ sp->pfs_1500.stack_af = st->key[PF_SK_STACK]->af;
+ sp->pfs_1500.qid = htons(st->act.qid);
+ sp->pfs_1500.pqid = htons(st->act.pqid);
+ sp->pfs_1500.dnpipe = htons(st->act.dnpipe);
+ sp->pfs_1500.dnrpipe = htons(st->act.dnrpipe);
+ sp->pfs_1500.rtableid = htonl(st->act.rtableid);
+ sp->pfs_1500.min_ttl = st->act.min_ttl;
+ sp->pfs_1500.set_tos = st->act.set_tos;
+ sp->pfs_1500.max_mss = htons(st->act.max_mss);
+ sp->pfs_1500.set_prio[0] = st->act.set_prio[0];
+ sp->pfs_1500.set_prio[1] = st->act.set_prio[1];
+ sp->pfs_1500.rt = st->act.rt;
+ sp->pfs_1500.rt_af = st->act.rt_af;
+ if (st->act.rt_kif)
+ strlcpy(sp->pfs_1500.rt_ifname,
+ st->act.rt_kif->pfik_name,
+ sizeof(sp->pfs_1500.rt_ifname));
+ strlcpy(sp->pfs_1500.orig_ifname,
+ st->orig_kif->pfik_name,
+ sizeof(sp->pfs_1500.orig_ifname));
+ if ((tagname = pf_tag2tagname(st->tag)) != NULL)
+ strlcpy(sp->pfs_1500.tagname, tagname,
+ sizeof(sp->pfs_1500.tagname));
break;
default:
panic("%s: Unsupported pfsync_msg_version %d",
__func__, msg_version);
}
- /*
- * XXX Why do we bother pfsyncing source node information if source
- * nodes are not synced? Showing users that there is source tracking
- * when there is none seems useless.
- */
- if (st->sns[PF_SN_LIMIT] != NULL)
- sp->pfs_1301.sync_flags |= PFSYNC_FLAG_SRCNODE;
- if (st->sns[PF_SN_NAT] != NULL || st->sns[PF_SN_ROUTE])
- sp->pfs_1301.sync_flags |= PFSYNC_FLAG_NATSRCNODE;
-
sp->pfs_1301.id = st->id;
sp->pfs_1301.creatorid = st->creatorid;
pf_state_peer_hton(&st->src, &sp->pfs_1301.src);
@@ -6842,6 +6957,7 @@
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
rm_init_flags(&V_pf_rules_lock, "pf rulesets", RM_RECURSE);
+ rm_init_flags(&V_pf_tags_lock, "pf tags and queues", RM_RECURSE);
sx_init(&V_pf_ioctl_lock, "pf ioctl");
pf_init_tagset(&V_pf_tags, &pf_rule_tag_hashsize,
@@ -6993,7 +7109,7 @@
pf_load_vnet();
}
-VNET_SYSINIT(vnet_pf_init, SI_SUB_PROTO_FIREWALL, SI_ORDER_THIRD,
+VNET_SYSINIT(vnet_pf_init, SI_SUB_PROTO_FIREWALL, SI_ORDER_THIRD,
vnet_pf_init, NULL);
static void
@@ -7001,7 +7117,7 @@
{
pf_unload_vnet();
-}
+}
SYSUNINIT(pf_unload, SI_SUB_PROTO_FIREWALL, SI_ORDER_SECOND, pf_unload, NULL);
VNET_SYSUNINIT(vnet_pf_uninit, SI_SUB_PROTO_FIREWALL, SI_ORDER_THIRD,
vnet_pf_uninit, NULL);
diff --git a/tests/sys/netpfil/pf/pfsync.sh b/tests/sys/netpfil/pf/pfsync.sh
--- a/tests/sys/netpfil/pf/pfsync.sh
+++ b/tests/sys/netpfil/pf/pfsync.sh
@@ -921,6 +921,8 @@
route_to_common_head()
{
+ # TODO: Extend setup_router_server_nat64 to create a 2nd router
+
pfsync_version=$1
shift
@@ -937,11 +939,16 @@
# pfsync interface
jexec one ifconfig ${epair_sync}a 192.0.2.1/24 up
- jexec one ifconfig ${epair_one}a 198.51.100.1/24 up
+ jexec one ifconfig ${epair_one}a 198.51.100.1/28 up
+ jexec one ifconfig ${epair_one}a inet6 2001:db8:4211::1/64 no_dad
+ jexec one ifconfig ${epair_one}a name inif
jexec one ifconfig ${epair_out_one}a 203.0.113.1/24 up
+ jexec one ifconfig ${epair_out_one}a inet6 2001:db8:4200::1/64 no_dad
jexec one ifconfig ${epair_out_one}a name outif
jexec one sysctl net.inet.ip.forwarding=1
- jexec one arp -s 203.0.113.254 00:01:02:03:04:05
+ jexec one sysctl net.inet6.ip6.forwarding=1
+ jexec one arp -s 203.0.113.254 00:01:02:00:00:04
+ jexec one ndp -s 2001:db8:4200::fe 00:01:02:00:00:06
jexec one ifconfig pfsync0 \
syncdev ${epair_sync}a \
maxupd 1 \
@@ -949,20 +956,30 @@
up
jexec two ifconfig ${epair_sync}b 192.0.2.2/24 up
- jexec two ifconfig ${epair_two}a 198.51.100.2/24 up
- jexec two ifconfig ${epair_out_two}a 203.0.113.2/24 up
+ jexec two ifconfig ${epair_two}a 198.51.100.17/28 up
+ jexec two ifconfig ${epair_two}a inet6 2001:db8:4212::1/64 no_dad
+ jexec two ifconfig ${epair_two}a name inif
+ jexec two ifconfig ${epair_out_two}a 203.0.113.1/24 up
+ jexec two ifconfig ${epair_out_two}a inet6 2001:db8:4200::2/64 no_dad
jexec two ifconfig ${epair_out_two}a name outif
jexec two sysctl net.inet.ip.forwarding=1
- jexec two arp -s 203.0.113.254 00:01:02:03:04:05
+ jexec two sysctl net.inet6.ip6.forwarding=1
+ jexec two arp -s 203.0.113.254 00:01:02:00:00:04
+ jexec two ndp -s 2001:db8:4200::fe 00:01:02:00:00:06
jexec two ifconfig pfsync0 \
syncdev ${epair_sync}b \
maxupd 1 \
version $pfsync_version \
up
- ifconfig ${epair_one}b 198.51.100.254/24 up
- ifconfig ${epair_two}b 198.51.100.253/24 up
+ ifconfig ${epair_one}b 198.51.100.2/28 up
+ ifconfig ${epair_one}b inet6 2001:db8:4211::2/64 no_dad
+ ifconfig ${epair_two}b 198.51.100.18/28 up
+ ifconfig ${epair_two}b inet6 2001:db8:4212::2/64 no_dad
+ # Target is behind router "one"
route add -net 203.0.113.0/24 198.51.100.1
+ route add -inet6 -net 64:ff9b::/96 2001:db8:4211::1
+
ifconfig ${epair_two}b up
ifconfig ${epair_out_one}b up
ifconfig ${epair_out_two}b up
@@ -1206,6 +1223,435 @@
pfsynct_cleanup
}
+atf_test_case "af_to_in_floating" "cleanup"
+af_to_in_floating_head()
+{
+ atf_set descr 'Test syncing of states created by inbound af-to rules with floating states'
+ atf_set require.user root
+ atf_set require.progs python3 scapy
+}
+
+af_to_in_floating_body()
+{
+ route_to_common_head 1500
+
+ jexec one pfctl -e
+ pft_set_rules one \
+ "set state-policy floating" \
+ "set skip on ${epair_sync}a" \
+ "block" \
+ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv } keep state (no-sync)" \
+ "pass in on inif to 64:ff9b::/96 af-to inet from (outif) keep state"
+
+ jexec two pfctl -e
+ pft_set_rules two \
+ "set skip on ${epair_sync}b" \
+ "block" \
+ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv } keep state (no-sync)"
+
+ # ptf_ping can't deal with nat64, this test will fail but generate states
+ atf_check -s exit:1 env PYTHONPATH=${common_dir} \
+ ${common_dir}/pft_ping.py \
+ --sendif ${epair_one}b \
+ --fromaddr 2001:db8:4201::fe \
+ --to 64:ff9b::203.0.113.254 \
+ --recvif ${epair_out_one}b
+
+ # Allow time for sync
+ sleep 2
+
+ states_one=$(mktemp)
+ states_two=$(mktemp)
+ jexec one pfctl -qvvss | normalize_pfctl_s > $states_one
+ jexec two pfctl -qvvss | normalize_pfctl_s > $states_two
+
+ # Sanity check
+ grep -qE 'all ipv6-icmp 203.0.113.1 \(2001:db8:4201::fe\) -> 203.0.113.254:8 \(64:ff9b::cb00:71fe) .* rule 3 .* origif: inif' $states_one ||
+ atf_fail "State missing on router one"
+
+ grep -qE 'all ipv6-icmp 203.0.113.1 \(2001:db8:4201::fe\) -> 203.0.113.254:8 \(64:ff9b::cb00:71fe) .* origif: inif' $states_two ||
+ atf_fail "State missing on router two"
+}
+
+af_to_in_floating_cleanup()
+{
+ pfsynct_cleanup
+}
+
+atf_test_case "af_to_in_if_bound" "cleanup"
+af_to_in_if_bound_head()
+{
+ atf_set descr 'Test syncing of states created by inbound af-to rules with if-bound states'
+ atf_set require.user root
+ atf_set require.progs python3 scapy
+}
+
+af_to_in_if_bound_body()
+{
+ route_to_common_head 1500
+
+ jexec one pfctl -e
+ pft_set_rules one \
+ "set state-policy if-bound" \
+ "set skip on ${epair_sync}a" \
+ "block" \
+ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv } keep state (no-sync)" \
+ "pass in on inif to 64:ff9b::/96 af-to inet from (outif) keep state"
+
+ jexec two pfctl -e
+ pft_set_rules two \
+ "set skip on ${epair_sync}b" \
+ "block" \
+ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv } keep state (no-sync)"
+
+ # ptf_ping can't deal with nat64, this test will fail but generate states
+ atf_check -s exit:1 env PYTHONPATH=${common_dir} \
+ ${common_dir}/pft_ping.py \
+ --sendif ${epair_one}b \
+ --fromaddr 2001:db8:4201::fe \
+ --to 64:ff9b::203.0.113.254 \
+ --recvif ${epair_out_one}b
+
+ # Allow time for sync
+ sleep 2
+
+ states_one=$(mktemp)
+ states_two=$(mktemp)
+ jexec one pfctl -qvvss | normalize_pfctl_s > $states_one
+ jexec two pfctl -qvvss | normalize_pfctl_s > $states_two
+
+ # Sanity check
+ grep -qE 'outif ipv6-icmp 203.0.113.1 \(2001:db8:4201::fe\) -> 203.0.113.254:8 \(64:ff9b::cb00:71fe) .* rule 3 .* origif: inif' $states_one ||
+ atf_fail "State missing on router one"
+
+ grep -qE 'outif ipv6-icmp 203.0.113.1 \(2001:db8:4201::fe\) -> 203.0.113.254:8 \(64:ff9b::cb00:71fe) .* origif: inif' $states_two ||
+ atf_fail "State missing on router two"
+}
+
+af_to_in_if_bound_cleanup()
+{
+ pfsynct_cleanup
+}
+
+atf_test_case "af_to_out_if_bound" "cleanup"
+af_to_out_if_bound_head()
+{
+ atf_set descr 'Test syncing of states created by outbound af-to rules with if-bound states'
+ atf_set require.user root
+ atf_set require.progs python3 scapy
+}
+
+af_to_out_if_bound_body()
+{
+ route_to_common_head 1500
+
+ jexec one route add -inet6 -net 64:ff9b::/96 -iface outif
+ jexec one sysctl net.inet6.ip6.forwarding=1
+
+ jexec one pfctl -e
+ pft_set_rules one \
+ "set state-policy if-bound" \
+ "set skip on ${epair_sync}a" \
+ "block" \
+ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv } keep state (no-sync)" \
+ "pass in on inif to 64:ff9b::/96 keep state" \
+ "pass out on outif to 64:ff9b::/96 af-to inet from (outif) keep state"
+
+ jexec two pfctl -e
+ pft_set_rules two \
+ "set skip on ${epair_sync}b" \
+ "block" \
+ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv } keep state (no-sync)"
+
+ # ptf_ping can't deal with nat64, this test will fail but generate states
+ atf_check -s exit:1 env PYTHONPATH=${common_dir} \
+ ${common_dir}/pft_ping.py \
+ --sendif ${epair_one}b \
+ --fromaddr 2001:db8:4201::fe \
+ --to 64:ff9b::203.0.113.254 \
+ --recvif ${epair_out_one}b
+
+ # Allow time for sync
+ sleep 2
+
+ states_one=$(mktemp)
+ states_two=$(mktemp)
+ jexec one pfctl -qvvss | normalize_pfctl_s > $states_one
+ jexec two pfctl -qvvss | normalize_pfctl_s > $states_two
+
+ # Sanity check
+ # st->orig_kif is the same as st->kif, so st->orig_kif is not printed.
+ for state_regexp in \
+ "inif ipv6-icmp 64:ff9b::cb00:71fe\[128\] <- 2001:db8:4201::fe .* rule 3 .* creatorid: [0-9a-f]+" \
+ "outif icmp 203.0.113.1 \(64:ff9b::cb00:71fe\[8\]\) -> 203.0.113.254:8 \(2001:db8:4201::fe\) .* rule 4 .* creatorid: [0-9a-f]+" \
+ ; do
+ grep -qE "${state_regexp}" $states_one || atf_fail "State not found for '${state_regexp}'"
+ done
+
+ for state_regexp in \
+ "inif ipv6-icmp 64:ff9b::cb00:71fe\[128\] <- 2001:db8:4201::fe .* creatorid: [0-9a-f]+" \
+ "outif icmp 203.0.113.1 \(64:ff9b::cb00:71fe\[8\]\) -> 203.0.113.254:8 \(2001:db8:4201::fe\) .* creatorid: [0-9a-f]+" \
+ ; do
+ grep -qE "${state_regexp}" $states_two || atf_fail "State not found for '${state_regexp}'"
+ done
+}
+
+af_to_out_if_bound_cleanup()
+{
+ pfsynct_cleanup
+}
+
+atf_test_case "tag" "cleanup"
+tag_head()
+{
+ atf_set descr 'Test if the pf tag is synced'
+ atf_set require.user root
+ atf_set require.progs python3 scapy
+}
+
+tag_body()
+{
+ route_to_common_head 1500
+
+ jexec one pfctl -e
+ pft_set_rules one \
+ "set skip on ${epair_sync}a" \
+ "block" \
+ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv } keep state (no-sync)" \
+ "pass in on inif inet proto udp tag sometag keep state" \
+ "pass out on outif tagged sometag keep state (no-sync)"
+
+ jexec two pfctl -e
+ pft_set_rules two \
+ "set debug loud" \
+ "set skip on ${epair_sync}b" \
+ "block" \
+ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv } keep state (no-sync)" \
+ "block tagged othertag" \
+ "pass out on outif tagged sometag keep state (no-sync)"
+
+ atf_check -s exit:0 env PYTHONPATH=${common_dir} \
+ ${common_dir}/pft_ping.py \
+ --ping-type=udp \
+ --sendif ${epair_one}b \
+ --fromaddr 198.51.100.254 \
+ --to 203.0.113.254 \
+ --recvif ${epair_out_one}b
+
+ # Allow time for sync
+ sleep 2
+
+ # Force the next request to go through the 2nd router
+ route change -net 203.0.113.0/24 198.51.100.17
+
+ atf_check -s exit:0 env PYTHONPATH=${common_dir} \
+ ${common_dir}/pft_ping.py \
+ --ping-type=udp \
+ --sendif ${epair_two}b \
+ --fromaddr 198.51.100.254 \
+ --to 203.0.113.254 \
+ --recvif ${epair_out_two}b
+}
+
+tag_cleanup()
+{
+ pfsynct_cleanup
+}
+
+atf_test_case "altq_queues" "cleanup"
+altq_queues_head()
+{
+ atf_set descr 'Test if the altq queues are synced'
+ atf_set require.user root
+ atf_set require.progs python3 scapy
+}
+
+altq_queues_body()
+{
+ route_to_common_head 1500
+ altq_init
+ is_altq_supported hfsc
+
+ jexec one pfctl -e
+ pft_set_rules one \
+ "set skip on ${epair_sync}a" \
+ "altq on outif bandwidth 30000b hfsc queue { default other1 other2 }" \
+ "queue default hfsc(linkshare 10000b default)" \
+ "queue other1 hfsc(linkshare 10000b)" \
+ "queue other2 hfsc(linkshare 10000b)" \
+ "block" \
+ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv } keep state (no-sync)" \
+ "pass in on inif inet proto udp queue other1 keep state" \
+ "pass out on outif inet proto udp keep state"
+
+ jexec two pfctl -e
+ pft_set_rules two \
+ "set debug loud" \
+ "set skip on ${epair_sync}b" \
+ "altq on outif bandwidth 30000b hfsc queue { default other2 other1 }" \
+ "queue default hfsc(linkshare 10000b default)" \
+ "queue other2 hfsc(linkshare 10000b)" \
+ "queue other1 hfsc(linkshare 10000b)" \
+ "block" \
+ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv } keep state (no-sync)" \
+ "pass out on outif inet proto udp keep state"
+
+ atf_check -s exit:0 env PYTHONPATH=${common_dir} \
+ ${common_dir}/pft_ping.py \
+ --ping-type=udp \
+ --sendif ${epair_one}b \
+ --fromaddr 198.51.100.254 \
+ --to 203.0.113.254 \
+ --recvif ${epair_out_one}b
+
+ queues_one=$(mktemp)
+ jexec one pfctl -qvsq | normalize_pfctl_s > $queues_one
+ echo " === queues one === "
+ cat $queues_one
+ grep -qE 'queue other1 on outif .* pkts: 1 ' $queues_one || atf_fail 'Packets not sent through queue "other1"'
+
+ # Allow time for sync
+ sleep 2
+
+ # Force the next request to go through the 2nd router
+ route change -net 203.0.113.0/24 198.51.100.17
+
+ # Send a packet through router "two". It lacks the inbound rule
+ # but the inbound state should have been pfsynced from router "one"
+ # including altq queuing information. However the queues are created
+ # on router "two" in different order and we only sync queue index,
+ # so the packet ends up in a different queue. One must have identical
+ # queue set on both routers!
+ atf_check -s exit:0 env PYTHONPATH=${common_dir} \
+ ${common_dir}/pft_ping.py \
+ --ping-type=udp \
+ --sendif ${epair_two}b \
+ --fromaddr 198.51.100.254 \
+ --to 203.0.113.254 \
+ --recvif ${epair_out_two}b
+
+ queues_two=$(mktemp)
+ jexec two pfctl -qvsq | normalize_pfctl_s > $queues_two
+ echo " === queues two === "
+ cat $queues_two
+ grep -qE 'queue other2 on outif .* pkts: 1 ' $queues_two || atf_fail 'Packets not sent through queue "other2"'
+}
+
+altq_queues_cleanup()
+{
+ # Interface detaching seems badly broken in altq. If interfaces are
+ # destroyed when shutting down the vnet and then pf is unloaded, it will
+ # cause a kernel crash. Work around the issue by first flushing the
+ # pf rulesets
+ jexec one pfctl -F all
+ jexec two pfctl -F all
+ pfsynct_cleanup
+}
+
+atf_test_case "rt_af" "cleanup"
+rt_af_head()
+{
+ atf_set descr 'Test if the rt_af is synced'
+ atf_set require.user root
+ atf_set require.progs python3 scapy
+}
+
+rt_af_body()
+{
+ route_to_common_head 1500
+
+ jexec one pfctl -e
+ pft_set_rules one \
+ "set skip on ${epair_sync}a" \
+ "block" \
+ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv } keep state (no-sync)" \
+ "pass in on inif \
+ route-to (outif 203.0.113.254) prefer-ipv6-nexthop \
+ inet proto udp \
+ to 203.0.113.241 \
+ keep state" \
+ "pass in on inif \
+ route-to (outif 2001:db8:4200::fe) prefer-ipv6-nexthop \
+ inet proto udp \
+ to 203.0.113.242 \
+ keep state" \
+ "pass in on inif \
+ route-to (outif 2001:db8:4200::fe) prefer-ipv6-nexthop \
+ inet6 proto udp \
+ to 2001:db8:4200::f3 \
+ keep state" \
+ "pass out on outif inet proto udp keep state (no-sync)" \
+ "pass out on outif inet6 proto udp keep state (no-sync)"
+
+ jexec two pfctl -e
+ pft_set_rules two \
+ "set debug loud" \
+ "set skip on ${epair_sync}b" \
+ "block" \
+ "pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv } keep state (no-sync)" \
+
+ # IPv4 packet over IPv4 gateway
+ atf_check -s exit:0 env PYTHONPATH=${common_dir} \
+ ${common_dir}/pft_ping.py \
+ --ping-type=udp \
+ --sendif ${epair_one}b \
+ --fromaddr 198.51.100.254 \
+ --to 203.0.113.241 \
+ --recvif ${epair_out_one}b
+
+ # FIXME: Routing IPv4 packets over IPv6 gateways with gateway added
+ # with `ndp -s` causes the static NDP entry to become expired.
+ # Pfsync tests don't use "servers" which can reply to ARP and NDP,
+ # but such static entry for gateway and only check if a stateless
+ # ICMP or UDP packet is forward through.
+ #
+ # IPv4 packert over IPv6 gateway
+ #atf_check -s exit:0 env PYTHONPATH=${common_dir} \
+ # ${common_dir}/pft_ping.py \
+ # --ping-type=udp \
+ # --sendif ${epair_one}b \
+ # --fromaddr 198.51.100.254 \
+ # --to 203.0.113.242 \
+ # --recvif ${epair_out_one}b
+
+ # IPv6 packet over IPv6 gateway
+ atf_check -s exit:0 env PYTHONPATH=${common_dir} \
+ ${common_dir}/pft_ping.py \
+ --ping-type=udp \
+ --sendif ${epair_one}b \
+ --fromaddr 2001:db8:4211::fe \
+ --to 2001:db8:4200::f3 \
+ --recvif ${epair_out_one}b
+
+ sleep 5 # Wait for pfsync
+
+ states_one=$(mktemp)
+ states_two=$(mktemp)
+ jexec one pfctl -qvvss | normalize_pfctl_s > $states_one
+ jexec two pfctl -qvvss | normalize_pfctl_s > $states_two
+
+ echo " === states one === "
+ cat $states_one
+ echo " === states two === "
+ cat $states_two
+
+ for state_regexp in \
+ "all udp 203.0.113.241:9 <- 198.51.100.254 .* route-to: 203.0.113.254@outif origif: inif" \
+ "all udp 2001:db8:4200::f3\[9\] <- 2001:db8:4211::fe .* route-to: 2001:db8:4200::fe@outif origif: inif" \
+ ; do
+ grep -qE "${state_regexp}" $states_two || atf_fail "State not found for '${state_regexp}' on router two"
+ done
+}
+
+rt_af_cleanup()
+{
+ jexec one pfctl -qvvsr
+ jexec one pfctl -qvvss
+ jexec one arp -an
+ jexec one ndp -an
+ pfsynct_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "basic"
@@ -1224,4 +1670,10 @@
atf_add_test_case "route_to_1301_bad_rpool"
atf_add_test_case "route_to_1400_bad_ruleset"
atf_add_test_case "route_to_1400_bad_ifname"
+ atf_add_test_case "af_to_in_floating"
+ atf_add_test_case "af_to_in_if_bound"
+ atf_add_test_case "af_to_out_if_bound"
+ atf_add_test_case "tag"
+ atf_add_test_case "altq_queues"
+ atf_add_test_case "rt_af"
}
diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c
--- a/usr.bin/netstat/if.c
+++ b/usr.bin/netstat/if.c
@@ -84,8 +84,10 @@
/* 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",
+ /* PFSYNC_ACT_INS_1400 */ "14.0 state insert",
+ /* PFSYNC_ACT_UPD_1400 */ "14.0 state update",
+ /* PFSYNC_ACT_INS_1500 */ "state insert",
+ /* PFSYNC_ACT_UPD_1500 */ "state update",
};
static const char* pfsyncacts_name[] = {
@@ -102,8 +104,10 @@
/* 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",
+ /* PFSYNC_ACT_INS_1400 */ "state-insert-1400",
+ /* PFSYNC_ACT_UPD_1400 */ "state-update-1400",
+ /* PFSYNC_ACT_INS_1500 */ "state-insert",
+ /* PFSYNC_ACT_UPD_1500 */ "state-update",
};
static void

File Metadata

Mime Type
text/plain
Expires
Mon, Jan 26, 6:16 PM (20 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28042133
Default Alt Text
D52176.id.diff (49 KB)

Event Timeline