mirror of
https://git.freebsd.org/src.git
synced 2026-01-11 19:57:22 +00:00
pf: Add pfsync protocol for FreeBSD 15
A new version of pfsync packet is introduced: 1500. This version solves the issues with data alignment introduced in version 1400 and adds syncing of information needed to sync states created by rules with af-to (original interface, af and proto separate for wire and stack keys), of rt_af needed for prefer-ipv6-nexthop, and of tag names. Reviewed by: kp Sponsored by: InnoGames GmbH Differential Revision: https://reviews.freebsd.org/D52176
This commit is contained in:
parent
42441d3420
commit
99475087d6
8 changed files with 883 additions and 103 deletions
|
|
@ -102,6 +102,7 @@ struct pfsync_actions {
|
|||
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 @@ struct pfsync_actions actions[] = {
|
|||
{ "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 @@ pfsync_print_state_1301(netdissect_options *ndo, const void *bp)
|
|||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -162,6 +162,8 @@ FreeBSD releases 13.2 and older.
|
|||
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
|
||||
|
|
|
|||
|
|
@ -62,9 +62,10 @@ enum pfsync_msg_versions {
|
|||
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 @@ enum pfsync_msg_versions {
|
|||
#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
|
||||
|
|
|
|||
|
|
@ -452,6 +452,16 @@ VNET_DECLARE(struct rmlock, pf_rules_lock);
|
|||
#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 @@ struct pfsync_state_1301 {
|
|||
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 @@ struct pfsync_state_1400 {
|
|||
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 @@ struct pfsync_state_1400 {
|
|||
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 @@ int pf_translate(struct pf_pdesc *, struct pf_addr *, u_int16_t,
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -153,6 +153,8 @@ static int (*pfsync_acts[])(struct mbuf *, int, int, int, int) = {
|
|||
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 @@ struct pfsync_q {
|
|||
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 @@ enum pfsync_q_id {
|
|||
/* 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 void pfsync_out_del_c(struct pf_kstate *, void *);
|
|||
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 struct pfsync_q pfsync_qs[] = {
|
|||
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 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
|
|||
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 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
|
|||
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 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
|
|||
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 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
|
|||
} 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 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
|
|||
"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 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
|
|||
*/
|
||||
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 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
|
|||
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 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
|
|||
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 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
|
|||
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 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
|
|||
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 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
|
|||
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 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
|
|||
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 @@ pfsync_in_ins(struct mbuf *m, int offset, int count, int flags, int action)
|
|||
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 @@ pfsync_in_ins(struct mbuf *m, int offset, int count, int flags, int action)
|
|||
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 @@ pfsync_in_upd(struct mbuf *m, int offset, int count, int flags, int action)
|
|||
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 @@ pfsync_in_upd(struct mbuf *m, int offset, int count, int flags, int action)
|
|||
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_in_upd(struct mbuf *m, int offset, int count, int flags, int action)
|
|||
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_out_state_1400(struct pf_kstate *st, void *buf)
|
|||
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 @@ pfsync_sstate_to_qid(u_int8_t sync_state)
|
|||
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 @@ pfsync_sstate_to_qid(u_int8_t sync_state)
|
|||
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 @@ pfsync_kstatus_to_softc(struct pfsync_kstatus *status, struct pfsync_softc *sc)
|
|||
break;
|
||||
case PFSYNC_MSG_VERSION_1301:
|
||||
case PFSYNC_MSG_VERSION_1400:
|
||||
case PFSYNC_MSG_VERSION_1500:
|
||||
sc->sc_version = status->version;
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -116,7 +116,6 @@ static int pf_rollback_altq(u_int32_t);
|
|||
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_init_tagset(struct pf_tagset *, unsigned int *,
|
|||
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 @@ int pf_end_threads;
|
|||
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 @@ tag2hashindex(const struct pf_tagset *ts, uint16_t tag)
|
|||
}
|
||||
|
||||
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 @@ tagname2tag(struct pf_tagset *ts, const char *tagname)
|
|||
* 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 @@ tagname2tag(struct pf_tagset *ts, const char *tagname)
|
|||
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 @@ tag_unref(struct pf_tagset *ts, u_int16_t tag)
|
|||
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 @@ tag_unref(struct pf_tagset *ts, u_int16_t tag)
|
|||
}
|
||||
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 @@ pf_commit_eth(uint32_t ticket, const char *anchor)
|
|||
}
|
||||
|
||||
#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));
|
||||
return (tagname2tag(&V_pf_qids, qname, add_new));
|
||||
}
|
||||
|
||||
static const char *
|
||||
pf_qid2qname(uint16_t qid)
|
||||
{
|
||||
return (tag2tagname(&V_pf_qids, qid));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1151,7 +1221,7 @@ pf_altq_ifnet_event(struct ifnet *ifp, int remove)
|
|||
}
|
||||
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 @@ pf_export_kaltq(struct pf_altq *q, struct pfioc_altq_v1 *pa, size_t ioc_size)
|
|||
#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 @@ pf_export_kaltq(struct pf_altq *q, struct pfioc_altq_v1 *pa, size_t ioc_size)
|
|||
ASSIGN_OPT_SATU32(ulsc_m2);
|
||||
|
||||
ASSIGN_OPT(flags);
|
||||
|
||||
|
||||
#undef ASSIGN_OPT
|
||||
#undef ASSIGN_OPT_SATU32
|
||||
} else
|
||||
|
|
@ -1728,7 +1798,7 @@ pf_import_kaltq(struct pfioc_altq_v1 *pa, struct pf_altq *q, size_t ioc_size)
|
|||
ASSIGN_OPT(ulsc_m2);
|
||||
|
||||
ASSIGN_OPT(flags);
|
||||
|
||||
|
||||
#undef ASSIGN_OPT
|
||||
} else
|
||||
COPY(pq_u);
|
||||
|
|
@ -1760,7 +1830,7 @@ pf_import_kaltq(struct pfioc_altq_v1 *pa, struct pf_altq *q, size_t ioc_size)
|
|||
ASSIGN(qid);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
default:
|
||||
panic("%s: unhandled struct pfioc_altq version", __func__);
|
||||
break;
|
||||
}
|
||||
|
|
@ -2191,11 +2261,11 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
|
|||
#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 @@ DIOCGETETHRULE_error:
|
|||
#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 @@ DIOCGETRULENV_error:
|
|||
/* 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 @@ DIOCGETSTATESV2_full:
|
|||
* 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 @@ fail:
|
|||
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 @@ pfsync_state_export(union pfsync_state_union *sp, struct pf_kstate *st, int msg_
|
|||
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 @@ pfsync_state_export(union pfsync_state_union *sp, struct pf_kstate *st, int msg_
|
|||
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 @@ pfsync_state_export(union pfsync_state_union *sp, struct pf_kstate *st, int msg_
|
|||
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 @@ pf_load_vnet(void)
|
|||
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 @@ vnet_pf_init(void *unused __unused)
|
|||
|
||||
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 @@ vnet_pf_uninit(const void *unused __unused)
|
|||
{
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -921,6 +921,8 @@ rtable_cleanup()
|
|||
|
||||
route_to_common_head()
|
||||
{
|
||||
# TODO: Extend setup_router_server_nat64 to create a 2nd router
|
||||
|
||||
pfsync_version=$1
|
||||
shift
|
||||
|
||||
|
|
@ -937,11 +939,16 @@ route_to_common_head()
|
|||
|
||||
# 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 @@ route_to_common_head()
|
|||
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 @@ route_to_1400_bad_ifname_cleanup()
|
|||
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_init_test_cases()
|
|||
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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,8 +84,10 @@ 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",
|
||||
/* 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 @@ 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",
|
||||
/* 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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue