git: 76c5eecc3490 - main - pf: Introduce ridentifier

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Fri, 05 Nov 2021 09:17:04 UTC
The branch main has been updated by kp:

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

commit 76c5eecc3490d89a9a3492ed2354802b69d69602
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2021-10-29 15:40:53 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2021-11-05 08:39:56 +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
---
 contrib/tcpdump/print-pflog.c      |  7 ++++++-
 lib/libpfctl/libpfctl.c            |  2 ++
 lib/libpfctl/libpfctl.h            |  1 +
 sbin/pfctl/parse.y                 | 15 ++++++++++++++-
 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(+), 8 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 aaf5998ed0d6..9abfbdce8cf1 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);
@@ -569,6 +570,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 1f7259ee8d32..71806ed217ee 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 e22e60182c73..a21643070028 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;
@@ -263,6 +264,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;
 
@@ -471,7 +473,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	DNPIPE DNQUEUE
+%token	DNPIPE DNQUEUE RIDENTIFIER
 %token	LOAD RULESET_OPTIMIZATION PRIO
 %token	STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
 %token	MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY
@@ -927,6 +929,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,
@@ -1326,6 +1329,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;
@@ -1378,6 +1382,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;
@@ -1440,6 +1445,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");
@@ -2155,6 +2163,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) {
@@ -2594,6 +2603,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;
 		}
@@ -5736,6 +5748,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 91a3a38ef016..a9bea39a6771 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);
 	/* Only dnrpipe as we might do (0, 42) to only queue return traffic. */
 	if (r->dnrpipe)
 		printf(" %s(%d, %d)",
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 9f69db70d90b..63b8acaef358 100644
--- a/share/man/man5/pf.conf.5
+++ b/share/man/man5/pf.conf.5
@@ -1896,6 +1896,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 )
@@ -3000,7 +3003,8 @@ filteropt      = user | group | flags | icmp-type | icmp6-type | "tos" tos |
                  "queue" ( string | "(" string [ [ "," ] string ] ")" ) |
                  "rtable" number | "probability" number"%" | "prio" number |
                  "dnpipe" ( number | "(" number "," number ")" ) |
-                 "dnqueue" ( number | "(" number "," number ")" )
+                 "dnqueue" ( number | "(" number "," number ")" ) |
+                 "ridentifier" number
 
 nat-rule       = [ "no" ] "nat" [ "pass" [ "log" [ "(" logopts ")" ] ] ]
                  [ "on" ifspec ] [ af ]
@@ -3024,6 +3028,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 e9277dce4963..a6994e8b1846 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -578,6 +578,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 933603066e21..143d84416542 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)));
@@ -696,6 +697,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);