diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -172,7 +172,8 @@ PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN, PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES, PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK, - PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, }; + PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, + PF_STATE_OPT_PFLOW }; enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE }; @@ -512,7 +513,7 @@ %token DNPIPE DNQUEUE RIDENTIFIER %token LOAD RULESET_OPTIMIZATION PRIO %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE -%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY +%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW %token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS %token DIVERTTO DIVERTREPLY BRIDGE_TO %token STRING @@ -2615,6 +2616,14 @@ } r.rule_flag |= PFRULE_STATESLOPPY; break; + case PF_STATE_OPT_PFLOW: + if (r.rule_flag & PFRULE_PFLOW) { + yyerror("state pflow option: " + "multiple definitions"); + YYERROR; + } + r.rule_flag |= PFRULE_PFLOW; + break; case PF_STATE_OPT_TIMEOUT: if (o->data.timeout.number == PFTM_ADAPTIVE_START || @@ -4368,6 +4377,14 @@ $$->next = NULL; $$->tail = $$; } + | PFLOW { + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_PFLOW; + $$->next = NULL; + $$->tail = $$; + } | STRING NUMBER { int i; @@ -6318,6 +6335,7 @@ { "out", OUT}, { "overload", OVERLOAD}, { "pass", PASS}, + { "pflow", PFLOW}, { "port", PORT}, { "prio", PRIO}, { "priority", PRIORITY}, diff --git a/sbin/pfctl/pf_print_state.c b/sbin/pfctl/pf_print_state.c --- a/sbin/pfctl/pf_print_state.c +++ b/sbin/pfctl/pf_print_state.c @@ -376,6 +376,8 @@ printf(", sloppy"); if (s->state_flags & PFSTATE_NOSYNC) printf(", no-sync"); + if (s->state_flags & PFSTATE_PFLOW) + printf(", pflow"); if (s->state_flags & PFSTATE_ACK) printf(", psync-ack"); if (s->state_flags & PFSTATE_NODF) diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -1051,6 +1051,8 @@ opts = 1; if (r->rule_flag & PFRULE_STATESLOPPY) opts = 1; + if (r->rule_flag & PFRULE_PFLOW) + opts = 1; for (i = 0; !opts && i < PFTM_MAX; ++i) if (r->timeout[i]) opts = 1; @@ -1123,6 +1125,12 @@ printf("sloppy"); opts = 0; } + if (r->rule_flag & PFRULE_PFLOW) { + if (!opts) + printf(", "); + printf("pflow"); + opts = 0; + } for (i = 0; i < PFTM_MAX; ++i) if (r->timeout[i]) { int j; diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5 --- a/share/man/man5/pf.conf.5 +++ b/share/man/man5/pf.conf.5 @@ -27,7 +27,7 @@ .\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd November 17, 2023 +.Dd December 6, 2023 .Dt PF.CONF 5 .Os .Sh NAME @@ -2429,6 +2429,10 @@ This is intended to be used in situations where one does not see all packets of a connection, e.g. in asymmetric routing situations. Cannot be used with modulate or synproxy state. +.It Ar pflow +States created by this rule are exported on the +.Xr pflow 4 +interface. .El .Pp Multiple options can be specified, separated by commas: @@ -3345,7 +3349,7 @@ "max-src-conn" number | "max-src-conn-rate" number "/" number | "overload" "\*(Lt" string "\*(Gt" [ "flush" ] | - "if-bound" | "floating" ) + "if-bound" | "floating" | "pflow" ) fragmentation = [ "fragment reassemble" ] @@ -3406,6 +3410,7 @@ .Xr ip 4 , .Xr ip6 4 , .Xr pf 4 , +.Xr pflow 4 , .Xr pfsync 4 , .Xr tcp 4 , .Xr sctp 4 , diff --git a/sys/net/pflow.h b/sys/net/pflow.h --- a/sys/net/pflow.h +++ b/sys/net/pflow.h @@ -326,7 +326,6 @@ }; #ifdef _KERNEL -int export_pflow(struct pf_kstate *); int pflow_sysctl(int *, u_int, void *, size_t *, void *, size_t); #endif /* _KERNEL */ diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1186,6 +1186,7 @@ typedef void pfsync_clear_states_t(u_int32_t, const char *); typedef int pfsync_defer_t(struct pf_kstate *, struct mbuf *); typedef void pfsync_detach_ifnet_t(struct ifnet *); +typedef void pflow_export_state_t(const struct pf_kstate *); VNET_DECLARE(pfsync_state_import_t *, pfsync_state_import_ptr); #define V_pfsync_state_import_ptr VNET(pfsync_state_import_ptr) @@ -1199,6 +1200,8 @@ #define V_pfsync_clear_states_ptr VNET(pfsync_clear_states_ptr) VNET_DECLARE(pfsync_defer_t *, pfsync_defer_ptr); #define V_pfsync_defer_ptr VNET(pfsync_defer_ptr) +VNET_DECLARE(pflow_export_state_t *, pflow_export_state_ptr); +#define V_pflow_export_state_ptr VNET(pflow_export_state_ptr) extern pfsync_detach_ifnet_t *pfsync_detach_ifnet_ptr; void pfsync_state_export(union pfsync_state_union *, diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h --- a/sys/netpfil/pf/pf.h +++ b/sys/netpfil/pf/pf.h @@ -614,6 +614,7 @@ #define PFRULE_SET_TOS 0x00002000 #define PFRULE_IFBOUND 0x00010000 /* if-bound */ #define PFRULE_STATESLOPPY 0x00020000 /* sloppy state tracking */ +#define PFRULE_PFLOW 0x00040000 #ifdef _KERNEL #define PFRULE_REFS 0x0080 /* rule has references */ @@ -626,7 +627,7 @@ /* pf_state->state_flags, pf_rule_actions->flags, pf_krule->scrub_flags */ #define PFSTATE_ALLOWOPTS 0x0001 #define PFSTATE_SLOPPY 0x0002 -/* was PFSTATE_PFLOW 0x0004 */ +#define PFSTATE_PFLOW 0x0004 #define PFSTATE_NOSYNC 0x0008 #define PFSTATE_ACK 0x0010 #define PFSTATE_NODF 0x0020 diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -1397,6 +1397,9 @@ pf_sctp_multihome_detach_addr(s); + if ((s->state_flags & PFSTATE_PFLOW) && V_pflow_export_state_ptr) + V_pflow_export_state_ptr(s); + if (sks != NULL) { kh = &V_pf_keyhash[pf_hashkey(sks)]; PF_HASHROW_LOCK(kh); @@ -4872,6 +4875,8 @@ s->state_flags |= PFSTATE_SLOPPY; if (pd->flags & PFDESC_TCP_NORM) /* Set by old-style scrub rules */ s->state_flags |= PFSTATE_SCRUB_TCP; + if (r->rule_flag & PFRULE_PFLOW) + s->state_flags |= PFSTATE_PFLOW; s->act.log = pd->act.log & PF_LOG_ALL; s->sync_state = PFSYNC_S_NONE; 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 @@ -304,6 +304,7 @@ VNET_DEFINE(pfsync_delete_state_t *, pfsync_delete_state_ptr); VNET_DEFINE(pfsync_clear_states_t *, pfsync_clear_states_ptr); VNET_DEFINE(pfsync_defer_t *, pfsync_defer_ptr); +VNET_DEFINE(pflow_export_state_t *, pflow_export_state_ptr); pfsync_detach_ifnet_t *pfsync_detach_ifnet_ptr; /* pflog */ diff --git a/sys/netpfil/pf/pflow.c b/sys/netpfil/pf/pflow.c --- a/sys/netpfil/pf/pflow.c +++ b/sys/netpfil/pf/pflow.c @@ -87,18 +87,19 @@ static void pflow_timeout6(void *); static void pflow_timeout_tmpl(void *); static void copy_flow_data(struct pflow_flow *, struct pflow_flow *, - struct pf_kstate *, struct pf_state_key *, int, int); + const struct pf_kstate *, struct pf_state_key *, int, int); static void copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *, - struct pflow_ipfix_flow4 *, struct pf_kstate *, struct pf_state_key *, + struct pflow_ipfix_flow4 *, const struct pf_kstate *, struct pf_state_key *, struct pflow_softc *, int, int); static void copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *, - struct pflow_ipfix_flow6 *, struct pf_kstate *, struct pf_state_key *, + struct pflow_ipfix_flow6 *, const struct pf_kstate *, struct pf_state_key *, struct pflow_softc *, int, int); -static int pflow_pack_flow(struct pf_kstate *, struct pf_state_key *, +static int pflow_pack_flow(const struct pf_kstate *, struct pf_state_key *, struct pflow_softc *); -static int pflow_pack_flow_ipfix(struct pf_kstate *, struct pf_state_key *, +static int pflow_pack_flow_ipfix(const struct pf_kstate *, struct pf_state_key *, struct pflow_softc *); -static int export_pflow_if(struct pf_kstate*, struct pf_state_key *, +static void export_pflow(const struct pf_kstate *); +static int export_pflow_if(const struct pf_kstate*, struct pf_state_key *, struct pflow_softc *); static int copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc); static int copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow, @@ -323,6 +324,8 @@ CK_LIST_INSERT_HEAD(&V_pflowif_list, pflowif, sc_next); mtx_unlock(&V_pflowif_list_mtx); + V_pflow_export_state_ptr = export_pflow; + return (0); } @@ -352,6 +355,8 @@ return (ENOENT); } CK_LIST_REMOVE(sc, sc_next); + if (CK_LIST_EMPTY(&V_pflowif_list)) + V_pflow_export_state_ptr = NULL; mtx_unlock(&V_pflowif_list_mtx); sc->sc_dying = 1; @@ -511,7 +516,7 @@ static void copy_flow_data(struct pflow_flow *flow1, struct pflow_flow *flow2, - struct pf_kstate *st, struct pf_state_key *sk, int src, int dst) + const struct pf_kstate *st, struct pf_state_key *sk, int src, int dst) { flow1->src_ip = flow2->dest_ip = sk->addr[src].v4.s_addr; flow1->src_port = flow2->dest_port = sk->port[src]; @@ -548,7 +553,7 @@ static void copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *flow1, - struct pflow_ipfix_flow4 *flow2, struct pf_kstate *st, + struct pflow_ipfix_flow4 *flow2, const struct pf_kstate *st, struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst) { flow1->src_ip = flow2->dest_ip = sk->addr[src].v4.s_addr; @@ -585,7 +590,7 @@ static void copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *flow1, - struct pflow_ipfix_flow6 *flow2, struct pf_kstate *st, + struct pflow_ipfix_flow6 *flow2, const struct pf_kstate *st, struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst) { bcopy(&sk->addr[src].v6, &flow1->src_ip, sizeof(flow1->src_ip)); @@ -622,8 +627,8 @@ flow1->tos = flow2->tos = st->rule.ptr->tos; } -int -export_pflow(struct pf_kstate *st) +static void +export_pflow(const struct pf_kstate *st) { struct pflow_softc *sc = NULL; struct pf_state_key *sk; @@ -648,12 +653,10 @@ } PFLOW_UNLOCK(sc); } - - return (0); } static int -export_pflow_if(struct pf_kstate *st, struct pf_state_key *sk, +export_pflow_if(const struct pf_kstate *st, struct pf_state_key *sk, struct pflow_softc *sc) { struct pf_kstate pfs_copy; @@ -787,7 +790,7 @@ } static int -pflow_pack_flow(struct pf_kstate *st, struct pf_state_key *sk, +pflow_pack_flow(const struct pf_kstate *st, struct pf_state_key *sk, struct pflow_softc *sc) { struct pflow_flow flow1; @@ -812,7 +815,7 @@ } static int -pflow_pack_flow_ipfix(struct pf_kstate *st, struct pf_state_key *sk, +pflow_pack_flow_ipfix(const struct pf_kstate *st, struct pf_state_key *sk, struct pflow_softc *sc) { struct pflow_ipfix_flow4 flow4_1, flow4_2;