git: cfe9b890d574 - stable/13 - pf: Introduce ridentifier

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Fri, 26 Nov 2021 19:40:10 UTC
The branch stable/13 has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=cfe9b890d574a92e8b04eb662e9ac2010d243193

commit cfe9b890d574a92e8b04eb662e9ac2010d243193
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2021-10-29 15:40:53 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2021-11-26 03:39:05 +0000

    pf: Introduce ridentifier
    
    Allow users to set a number on rules which will be exposed as part of
    the pflog header.
    The intent behind this is to allow users to correlate rules across
    updates (remember that pf rules continue to exist and match existing
    states, even if they're removed from the active ruleset) and pflog.
    
    Obtained from:  pfSense
    MFC after:      3 weeks
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D32750
    
    (cherry picked from commit 76c5eecc3490d89a9a3492ed2354802b69d69602)
---
 contrib/tcpdump/print-pflog.c      |  7 ++++++-
 lib/libpfctl/libpfctl.c            |  2 ++
 lib/libpfctl/libpfctl.h            |  1 +
 sbin/pfctl/parse.y                 | 14 ++++++++++++++
 sbin/pfctl/pfctl_parser.c          |  2 ++
 share/man/man4/pflog.4             |  3 ++-
 share/man/man5/pf.conf.5           |  7 ++++++-
 sys/net/if_pflog.h                 |  1 +
 sys/net/pfvar.h                    |  1 +
 sys/netpfil/ipfw/nat64/nat64clat.c |  2 +-
 sys/netpfil/ipfw/nat64/nat64lsn.c  |  2 +-
 sys/netpfil/ipfw/nat64/nat64stl.c  |  2 +-
 sys/netpfil/pf/if_pflog.c          |  3 ++-
 sys/netpfil/pf/pf_nv.c             |  2 ++
 14 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/contrib/tcpdump/print-pflog.c b/contrib/tcpdump/print-pflog.c
index 38201c55ee3f..49994507e728 100644
--- a/contrib/tcpdump/print-pflog.c
+++ b/contrib/tcpdump/print-pflog.c
@@ -88,10 +88,12 @@ static const struct tok pf_directions[] = {
 static void
 pflog_print(netdissect_options *ndo, const struct pfloghdr *hdr)
 {
-	uint32_t rulenr, subrulenr;
+	uint32_t rulenr, subrulenr, ridentifier;
 
 	rulenr = EXTRACT_32BITS(&hdr->rulenr);
 	subrulenr = EXTRACT_32BITS(&hdr->subrulenr);
+	ridentifier = EXTRACT_32BITS(&hdr->ridentifier);
+
 	if (subrulenr == (uint32_t)-1)
 		ND_PRINT((ndo, "rule %u/", rulenr));
 	else
@@ -102,6 +104,9 @@ pflog_print(netdissect_options *ndo, const struct pfloghdr *hdr)
 	if (hdr->uid != UID_MAX)
 		ND_PRINT((ndo, " [uid %u]", (unsigned)hdr->uid));
 
+	if (ridentifier != 0)
+		ND_PRINT((ndo, " [ridentifier %u]", ridentifier));
+
 	ND_PRINT((ndo, ": %s %s on %s: ",
 	    tok2str(pf_actions, "unkn(%u)", hdr->action),
 	    tok2str(pf_directions, "unkn(%u)", hdr->dir),
diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index c2d57d8136ca..e41f970e7696 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -455,6 +455,7 @@ pf_nvrule_to_rule(const nvlist_t *nvl, struct pfctl_rule *rule)
 	assert(labelcount <= PF_RULE_MAX_LABEL_COUNT);
 	for (size_t i = 0; i < labelcount; i++)
 		strlcpy(rule->label[i], labels[i], PF_RULE_LABEL_SIZE);
+	rule->ridentifier = nvlist_get_number(nvl, "ridentifier");
 	strlcpy(rule->ifname, nvlist_get_string(nvl, "ifname"), IFNAMSIZ);
 	strlcpy(rule->qname, nvlist_get_string(nvl, "qname"), PF_QNAME_SIZE);
 	strlcpy(rule->pqname, nvlist_get_string(nvl, "pqname"), PF_QNAME_SIZE);
@@ -566,6 +567,7 @@ pfctl_add_rule(int dev, const struct pfctl_rule *r, const char *anchor,
 		    r->label[labelcount]);
 		labelcount++;
 	}
+	nvlist_add_number(nvlr, "ridentifier", r->ridentifier);
 
 	nvlist_add_string(nvlr, "ifname", r->ifname);
 	nvlist_add_string(nvlr, "qname", r->qname);
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
index 70c144772c02..ac239d7cdcb1 100644
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -81,6 +81,7 @@ struct pfctl_rule {
 	struct pf_rule_addr	 dst;
 	union pf_rule_ptr	 skip[PF_SKIP_COUNT];
 	char			 label[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
+	u_int32_t		 ridentifier;
 	char			 ifname[IFNAMSIZ];
 	char			 qname[PF_QNAME_SIZE];
 	char			 pqname[PF_QNAME_SIZE];
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index c8a310688ca7..c075a0d4607c 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -236,6 +236,7 @@ static struct filter_opts {
 	struct node_icmp	*icmpspec;
 	u_int32_t		 tos;
 	u_int32_t		 prob;
+	u_int32_t		 ridentifier;
 	struct {
 		int			 action;
 		struct node_state_opt	*options;
@@ -260,6 +261,7 @@ static struct filter_opts {
 static struct antispoof_opts {
 	char			*label[PF_RULE_MAX_LABEL_COUNT];
 	int			 labelcount;
+	u_int32_t		 ridentifier;
 	u_int			 rtableid;
 } antispoof_opts;
 
@@ -468,6 +470,7 @@ int	parseport(char *, struct range *r, int);
 %token	BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY MAPEPORTSET
 %token	ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME
 %token	UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL
+%token	RIDENTIFIER
 %token	LOAD RULESET_OPTIMIZATION PRIO
 %token	STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
 %token	MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY
@@ -923,6 +926,7 @@ anchorrule	: ANCHOR anchorname dir quick interface af proto fromto
 			r.af = $6;
 			r.prob = $9.prob;
 			r.rtableid = $9.rtableid;
+			r.ridentifier = $9.ridentifier;
 
 			if ($9.tag)
 				if (strlcpy(r.tagname, $9.tag,
@@ -1322,6 +1326,7 @@ antispoof	: ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
 				r.logif = $2.logif;
 				r.quick = $2.quick;
 				r.af = $4;
+				r.ridentifier = $5.ridentifier;
 				if (rule_label(&r, $5.label))
 					YYERROR;
 				r.rtableid = $5.rtableid;
@@ -1374,6 +1379,7 @@ antispoof	: ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
 					r.logif = $2.logif;
 					r.quick = $2.quick;
 					r.af = $4;
+					r.ridentifier = $5.ridentifier;
 					if (rule_label(&r, $5.label))
 						YYERROR;
 					r.rtableid = $5.rtableid;
@@ -1436,6 +1442,9 @@ antispoof_opt	: label	{
 			}
 			antispoof_opts.label[antispoof_opts.labelcount++] = $1;
 		}
+		| RIDENTIFIER number {
+			antispoof_opts.ridentifier = $2;
+		}
 		| RTABLE NUMBER				{
 			if ($2 < 0 || $2 > rt_tableid_max()) {
 				yyerror("invalid rtable id");
@@ -2151,6 +2160,7 @@ pfrule		: action dir logquick interface route af proto fromto
 				YYERROR;
 			for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++)
 				free($9.label[i]);
+			r.ridentifier = $9.ridentifier;
 			r.flags = $9.flags.b1;
 			r.flagset = $9.flags.b2;
 			if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
@@ -2581,6 +2591,9 @@ filter_opt	: USER uids {
 			filter_opts.keep.action = $1.action;
 			filter_opts.keep.options = $1.options;
 		}
+		| RIDENTIFIER number {
+			filter_opts.ridentifier = $2;
+		}
 		| FRAGMENT {
 			filter_opts.fragment = 1;
 		}
@@ -5695,6 +5708,7 @@ lookup(char *s)
 		{ "return-icmp",	RETURNICMP},
 		{ "return-icmp6",	RETURNICMP6},
 		{ "return-rst",		RETURNRST},
+		{ "ridentifier",	RIDENTIFIER},
 		{ "round-robin",	ROUNDROBIN},
 		{ "route",		ROUTE},
 		{ "route-to",		ROUTETO},
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 8d39b45eb9a5..8dde3c916009 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -1019,6 +1019,8 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer
 	i = 0;
 	while (r->label[i][0])
 		printf(" label \"%s\"", r->label[i++]);
+	if (r->ridentifier)
+		printf(" ridentifier %u", r->ridentifier);
 	if (r->qname[0] && r->pqname[0])
 		printf(" queue(%s, %s)", r->qname, r->pqname);
 	else if (r->qname[0])
diff --git a/share/man/man4/pflog.4 b/share/man/man4/pflog.4
index 300092a9532b..19eb7012bca3 100644
--- a/share/man/man4/pflog.4
+++ b/share/man/man4/pflog.4
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd April 18, 2019
+.Dd October 29, 2021
 .Dt PFLOG 4
 .Os
 .Sh NAME
@@ -84,6 +84,7 @@ struct pfloghdr {
 	pid_t		rule_pid;
 	u_int8_t	dir;
 	u_int8_t	pad[3];
+	u_int32_t	ridentifier;
 };
 .Ed
 .Sh EXAMPLES
diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5
index 32f51bc00e47..cc1b902e0006 100644
--- a/share/man/man5/pf.conf.5
+++ b/share/man/man5/pf.conf.5
@@ -1867,6 +1867,9 @@ pass in inet proto tcp from any to 1.2.3.5 \e
 The macro expansion for the
 .Ar label
 directive occurs only at configuration file parse time, not during runtime.
+.It Ar ridentifier Aq Ar number
+Add an identifier (number) to the rule, which can be used to correlate the rule
+to pflog entries, even after ruleset updates.
 .It Xo Ar queue Aq Ar queue
 .No \*(Ba ( Aq Ar queue ,
 .Aq Ar queue )
@@ -2969,7 +2972,8 @@ filteropt      = user | group | flags | icmp-type | icmp6-type | "tos" tos |
                  "label" string | "tag" string | [ ! ] "tagged" string |
                  "set prio" ( number | "(" number [ [ "," ] number ] ")" ) |
                  "queue" ( string | "(" string [ [ "," ] string ] ")" ) |
-                 "rtable" number | "probability" number"%" | "prio" number
+                 "rtable" number | "probability" number"%" | "prio" number |
+                 "ridentifier" number
 
 nat-rule       = [ "no" ] "nat" [ "pass" [ "log" [ "(" logopts ")" ] ] ]
                  [ "on" ifspec ] [ af ]
@@ -2993,6 +2997,7 @@ rdr-rule       = [ "no" ] "rdr" [ "pass" [ "log" [ "(" logopts ")" ] ] ]
 
 antispoof-rule = "antispoof" [ "log" ] [ "quick" ]
                  "for" ifspec [ af ] [ "label" string ]
+                 [ "ridentifier" number ]
 
 table-rule     = "table" "\*(Lt" string "\*(Gt" [ tableopts-list ]
 tableopts-list = tableopts-list tableopts | tableopts
diff --git a/sys/net/if_pflog.h b/sys/net/if_pflog.h
index 5ed341a85d86..c77d8da1440a 100644
--- a/sys/net/if_pflog.h
+++ b/sys/net/if_pflog.h
@@ -50,6 +50,7 @@ struct pfloghdr {
 	pid_t		rule_pid;
 	u_int8_t	dir;
 	u_int8_t	pad[3];
+	u_int32_t	ridentifier;
 };
 
 #define	PFLOG_HDRLEN		sizeof(struct pfloghdr)
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 9fb231e95a2c..f9071546cbce 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -572,6 +572,7 @@ struct pf_krule {
 	struct pf_rule_addr	 dst;
 	union pf_krule_ptr	 skip[PF_SKIP_COUNT];
 	char			 label[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
+	uint32_t		 ridentifier;
 	char			 ifname[IFNAMSIZ];
 	char			 qname[PF_QNAME_SIZE];
 	char			 pqname[PF_QNAME_SIZE];
diff --git a/sys/netpfil/ipfw/nat64/nat64clat.c b/sys/netpfil/ipfw/nat64/nat64clat.c
index fcc922726d02..c48c68183e08 100644
--- a/sys/netpfil/ipfw/nat64/nat64clat.c
+++ b/sys/netpfil/ipfw/nat64/nat64clat.c
@@ -71,7 +71,7 @@ nat64clat_log(struct pfloghdr *plog, struct mbuf *m, sa_family_t family,
 	static uint32_t pktid = 0;
 
 	memset(plog, 0, sizeof(*plog));
-	plog->length = PFLOG_REAL_HDRLEN;
+	plog->length = PFLOG_HDRLEN;
 	plog->af = family;
 	plog->action = PF_NAT;
 	plog->dir = PF_IN;
diff --git a/sys/netpfil/ipfw/nat64/nat64lsn.c b/sys/netpfil/ipfw/nat64/nat64lsn.c
index bde42eeb18d6..90c27cabdf29 100644
--- a/sys/netpfil/ipfw/nat64/nat64lsn.c
+++ b/sys/netpfil/ipfw/nat64/nat64lsn.c
@@ -181,7 +181,7 @@ nat64lsn_log(struct pfloghdr *plog, struct mbuf *m, sa_family_t family,
 {
 
 	memset(plog, 0, sizeof(*plog));
-	plog->length = PFLOG_REAL_HDRLEN;
+	plog->length = PFLOG_HDRLEN;
 	plog->af = family;
 	plog->action = PF_NAT;
 	plog->dir = PF_IN;
diff --git a/sys/netpfil/ipfw/nat64/nat64stl.c b/sys/netpfil/ipfw/nat64/nat64stl.c
index 286876e553e3..a3451a107579 100644
--- a/sys/netpfil/ipfw/nat64/nat64stl.c
+++ b/sys/netpfil/ipfw/nat64/nat64stl.c
@@ -70,7 +70,7 @@ nat64stl_log(struct pfloghdr *plog, struct mbuf *m, sa_family_t family,
 	static uint32_t pktid = 0;
 
 	memset(plog, 0, sizeof(*plog));
-	plog->length = PFLOG_REAL_HDRLEN;
+	plog->length = PFLOG_HDRLEN;
 	plog->af = family;
 	plog->action = PF_NAT;
 	plog->dir = PF_IN;
diff --git a/sys/netpfil/pf/if_pflog.c b/sys/netpfil/pf/if_pflog.c
index 9eb168b9a74f..4853c1301d6f 100644
--- a/sys/netpfil/pf/if_pflog.c
+++ b/sys/netpfil/pf/if_pflog.c
@@ -215,7 +215,7 @@ pflog_packet(struct pfi_kkif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
 		return (0);
 
 	bzero(&hdr, sizeof(hdr));
-	hdr.length = PFLOG_REAL_HDRLEN;
+	hdr.length = PFLOG_HDRLEN;
 	hdr.af = af;
 	hdr.action = rm->action;
 	hdr.reason = reason;
@@ -231,6 +231,7 @@ pflog_packet(struct pfi_kkif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
 			strlcpy(hdr.ruleset, ruleset->anchor->name,
 			    sizeof(hdr.ruleset));
 	}
+	hdr.ridentifier = htonl(rm->ridentifier);
 	/*
 	 * XXXGL: we avoid pf_socket_lookup() when we are holding
 	 * state lock, since this leads to unsafe LOR.
diff --git a/sys/netpfil/pf/pf_nv.c b/sys/netpfil/pf/pf_nv.c
index d53c6fe4b84e..b6676be645d7 100644
--- a/sys/netpfil/pf/pf_nv.c
+++ b/sys/netpfil/pf/pf_nv.c
@@ -531,6 +531,7 @@ pf_nvrule_to_krule(const nvlist_t *nvl, struct pf_krule *rule)
 		}
 	}
 
+	PFNV_CHK(pf_nvuint32_opt(nvl, "ridentifier", &rule->ridentifier, 0));
 	PFNV_CHK(pf_nvstring(nvl, "ifname", rule->ifname,
 	    sizeof(rule->ifname)));
 	PFNV_CHK(pf_nvstring(nvl, "qname", rule->qname, sizeof(rule->qname)));
@@ -693,6 +694,7 @@ pf_krule_to_nvrule(struct pf_krule *rule)
 		nvlist_append_string_array(nvl, "labels", rule->label[i]);
 	}
 	nvlist_add_string(nvl, "label", rule->label[0]);
+	nvlist_add_number(nvl, "ridentifier", rule->ridentifier);
 	nvlist_add_string(nvl, "ifname", rule->ifname);
 	nvlist_add_string(nvl, "qname", rule->qname);
 	nvlist_add_string(nvl, "pqname", rule->pqname);