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
This commit is contained in:
Kristof Provost 2021-10-29 17:40:53 +02:00
parent 80e5955b08
commit 76c5eecc34
14 changed files with 42 additions and 8 deletions

View File

@ -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),

View File

@ -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);

View File

@ -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];

View File

@ -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},

View File

@ -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)",

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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];

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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.

View File

@ -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);