pf: introduce ridentifier and labels to ether rules

Make Ethernet rules more similar to the usual layer 3 rules by also
allowing ridentifier and labels to be set on them.

Reviewed by:	kp
Sponsored by:	Rubicon Communications, LLC ("Netgate")
This commit is contained in:
Christian McDonald 2023-04-24 14:55:34 -04:00 committed by Kristof Provost
parent 0912408a28
commit ef661d4a5b
18 changed files with 112 additions and 3 deletions

View File

@ -625,6 +625,9 @@ pfctl_eth_addr_to_nveth_addr(const struct pfctl_eth_addr *addr)
static void
pfctl_nveth_rule_to_eth_rule(const nvlist_t *nvl, struct pfctl_eth_rule *rule)
{
const char *const *labels;
size_t labelcount, i;
rule->nr = nvlist_get_number(nvl, "nr");
rule->quick = nvlist_get_bool(nvl, "quick");
strlcpy(rule->ifname, nvlist_get_string(nvl, "ifname"), IFNAMSIZ);
@ -636,6 +639,12 @@ pfctl_nveth_rule_to_eth_rule(const nvlist_t *nvl, struct pfctl_eth_rule *rule)
rule->match_tag = nvlist_get_number(nvl, "match_tag");
rule->match_tag_not = nvlist_get_bool(nvl, "match_tag_not");
labels = nvlist_get_string_array(nvl, "labels", &labelcount);
assert(labelcount <= PF_RULE_MAX_LABEL_COUNT);
for (i = 0; i < labelcount; i++)
strlcpy(rule->label[i], labels[i], PF_RULE_LABEL_SIZE);
rule->ridentifier = nvlist_get_number(nvl, "ridentifier");
pfctl_nveth_addr_to_eth_addr(nvlist_get_nvlist(nvl, "src"),
&rule->src);
pfctl_nveth_addr_to_eth_addr(nvlist_get_nvlist(nvl, "dst"),
@ -775,7 +784,7 @@ pfctl_add_eth_rule(int dev, const struct pfctl_eth_rule *r, const char *anchor,
nvlist_t *nvl, *addr;
void *packed;
int error = 0;
size_t size;
size_t labelcount, size;
nvl = nvlist_create(0);
@ -811,6 +820,15 @@ pfctl_add_eth_rule(int dev, const struct pfctl_eth_rule *r, const char *anchor,
pfctl_nv_add_rule_addr(nvl, "ipsrc", &r->ipsrc);
pfctl_nv_add_rule_addr(nvl, "ipdst", &r->ipdst);
labelcount = 0;
while (r->label[labelcount][0] != 0 &&
labelcount < PF_RULE_MAX_LABEL_COUNT) {
nvlist_append_string_array(nvl, "labels",
r->label[labelcount]);
labelcount++;
}
nvlist_add_number(nvl, "ridentifier", r->ridentifier);
nvlist_add_string(nvl, "qname", r->qname);
nvlist_add_string(nvl, "tagname", r->tagname);
nvlist_add_number(nvl, "dnpipe", r->dnpipe);

View File

@ -87,6 +87,9 @@ struct pfctl_eth_addr {
struct pfctl_eth_rule {
uint32_t nr;
char label[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
uint32_t ridentifier;
bool quick;
/* Filter */

View File

@ -379,6 +379,7 @@ int expand_skip_interface(struct node_if *);
int check_rulestate(int);
int getservice(char *);
int rule_label(struct pfctl_rule *, char *s[PF_RULE_MAX_LABEL_COUNT]);
int eth_rule_label(struct pfctl_eth_rule *, char *s[PF_RULE_MAX_LABEL_COUNT]);
int rt_tableid_max(void);
void mv_rules(struct pfctl_ruleset *, struct pfctl_ruleset *);
@ -1243,6 +1244,11 @@ etherrule : ETHER action dir quick interface bridge etherproto etherfromto l3fro
memcpy(&r.qname, $10.queues.qname, sizeof(r.qname));
r.dnpipe = $10.dnpipe;
r.dnflags = $10.free_flags;
if (eth_rule_label(&r, $10.label))
YYERROR;
for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++)
free($10.label[i]);
r.ridentifier = $10.ridentifier;
expand_eth_rule(&r, $5, $7, $8.src, $8.dst,
$9.src.host, $9.dst.host, $6, "");
@ -1366,6 +1372,16 @@ etherfilter_opt : etherqname {
}
filter_opts.queues = $1;
}
| RIDENTIFIER number {
filter_opts.ridentifier = $2;
}
| label {
if (filter_opts.labelcount >= PF_RULE_MAX_LABEL_COUNT) {
yyerror("label can only be used %d times", PF_RULE_MAX_LABEL_COUNT);
YYERROR;
}
filter_opts.label[filter_opts.labelcount++] = $1;
}
| TAG string {
filter_opts.tag = $2;
}
@ -6945,6 +6961,23 @@ rule_label(struct pfctl_rule *r, char *s[PF_RULE_MAX_LABEL_COUNT])
return (0);
}
int
eth_rule_label(struct pfctl_eth_rule *r, char *s[PF_RULE_MAX_LABEL_COUNT])
{
for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) {
if (s[i] == NULL)
return (0);
if (strlcpy(r->label[i], s[i], sizeof(r->label[0])) >=
sizeof(r->label[0])) {
yyerror("rule label too long (max %d chars)",
sizeof(r->label[0])-1);
return (-1);
}
}
return (0);
}
u_int16_t
parseicmpspec(char *w, sa_family_t af)
{

View File

@ -755,6 +755,8 @@ print_eth_rule(struct pfctl_eth_rule *r, const char *anchor_call,
static const char *actiontypes[] = { "pass", "block", "", "", "", "",
"", "", "", "", "", "", "match" };
int i;
if (rule_numbers)
printf("@%u ", r->nr);
@ -797,6 +799,13 @@ print_eth_rule(struct pfctl_eth_rule *r, const char *anchor_call,
print_fromto(&r->ipsrc, PF_OSFP_ANY, &r->ipdst,
r->proto == ETHERTYPE_IP ? AF_INET : AF_INET6, 0,
0, 0);
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])
printf(" queue %s", r->qname);
if (r->tagname[0])

View File

@ -0,0 +1 @@
ether block out on igb0 ridentifier 12345678

View File

@ -0,0 +1 @@
ether block out on igb0 l3 all ridentifier 12345678

View File

@ -0,0 +1 @@
ether block out on igb0 label "test"

View File

@ -0,0 +1 @@
ether block out on igb0 l3 all label "test"

View File

@ -0,0 +1 @@
ether block out on igb0 label "test" label "another label"

View File

@ -0,0 +1 @@
ether block out on igb0 l3 all label "test" label "another label"

View File

@ -0,0 +1 @@
ether block out on igb0 label "test" ridentifier 12345678

View File

@ -0,0 +1 @@
ether block out on igb0 l3 all label "test" ridentifier 12345678

View File

@ -0,0 +1 @@
ether block out on igb0 label "test" label "another test" ridentifier 12345678

View File

@ -0,0 +1 @@
ether block out on igb0 l3 all label "test" label "another test" ridentifier 12345678

View File

@ -123,3 +123,8 @@ PFCTL_TEST(1009, "Ethernet rule with mask")
PFCTL_TEST(1010, "POM_STICKYADDRESS test")
PFCTL_TEST(1011, "Test disabling scrub fragment reassemble")
PFCTL_TEST(1012, "Test scrub fragment reassemble is default")
PFCTL_TEST(1013, "Ethernet rule with ridentifier")
PFCTL_TEST(1014, "Ethernet rule with one label")
PFCTL_TEST(1015, "Ethernet rule with several labels")
PFCTL_TEST(1016, "Ethernet rule with ridentifier and one label")
PFCTL_TEST(1017, "Ethernet rule with ridentifier and several labels")

View File

@ -28,7 +28,7 @@
.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd April 21, 2023
.Dd April 26, 2023
.Dt PF.CONF 5
.Os
.Sh NAME
@ -3108,7 +3108,8 @@ logopts = logopt [ "," logopts ]
logopt = "all" | "user" | "to" interface-name
etherfilteropt-list = etherfilteropt-list etherfilteropt | etherfilteropt
etherfilteropt = "tag" string | "tagged" string | "queue" ( string )
etherfilteropt = "tag" string | "tagged" string | "queue" ( string ) |
"ridentifier" number | "label" string
filteropt-list = filteropt-list filteropt | filteropt
filteropt = user | group | flags | icmp-type | icmp6-type | "tos" tos |

View File

@ -703,6 +703,9 @@ struct pf_keth_rule {
uint8_t action;
uint16_t dnpipe;
uint32_t dnflags;
char label[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
uint32_t ridentifier;
};
union pf_krule_ptr {

View File

@ -1051,6 +1051,11 @@ pf_keth_rule_to_nveth_rule(const struct pf_keth_rule *krule)
if (nvl == NULL)
return (NULL);
for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) {
nvlist_append_string_array(nvl, "labels", krule->label[i]);
}
nvlist_add_number(nvl, "ridentifier", krule->ridentifier);
nvlist_add_number(nvl, "nr", krule->nr);
nvlist_add_bool(nvl, "quick", krule->quick);
nvlist_add_string(nvl, "ifname", krule->ifname);
@ -1126,8 +1131,29 @@ pf_nveth_rule_to_keth_rule(const nvlist_t *nvl,
{
int error = 0;
#define ERROUT(x) ERROUT_FUNCTION(errout, x)
bzero(krule, sizeof(*krule));
if (nvlist_exists_string_array(nvl, "labels")) {
const char *const *strs;
size_t items;
int ret;
strs = nvlist_get_string_array(nvl, "labels", &items);
if (items > PF_RULE_MAX_LABEL_COUNT)
ERROUT(E2BIG);
for (size_t i = 0; i < items; i++) {
ret = strlcpy(krule->label[i], strs[i],
sizeof(krule->label[0]));
if (ret >= sizeof(krule->label[0]))
ERROUT(E2BIG);
}
}
PFNV_CHK(pf_nvuint32_opt(nvl, "ridentifier", &krule->ridentifier, 0));
PFNV_CHK(pf_nvuint32(nvl, "nr", &krule->nr));
PFNV_CHK(pf_nvbool(nvl, "quick", &krule->quick));
PFNV_CHK(pf_nvstring(nvl, "ifname", krule->ifname,
@ -1192,6 +1218,7 @@ pf_nveth_rule_to_keth_rule(const nvlist_t *nvl,
krule->action != PF_MATCH)
return (EBADMSG);
#undef ERROUT
errout:
return (error);
}