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 static void
pfctl_nveth_rule_to_eth_rule(const nvlist_t *nvl, struct pfctl_eth_rule *rule) 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->nr = nvlist_get_number(nvl, "nr");
rule->quick = nvlist_get_bool(nvl, "quick"); rule->quick = nvlist_get_bool(nvl, "quick");
strlcpy(rule->ifname, nvlist_get_string(nvl, "ifname"), IFNAMSIZ); 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 = nvlist_get_number(nvl, "match_tag");
rule->match_tag_not = nvlist_get_bool(nvl, "match_tag_not"); 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"), pfctl_nveth_addr_to_eth_addr(nvlist_get_nvlist(nvl, "src"),
&rule->src); &rule->src);
pfctl_nveth_addr_to_eth_addr(nvlist_get_nvlist(nvl, "dst"), 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; nvlist_t *nvl, *addr;
void *packed; void *packed;
int error = 0; int error = 0;
size_t size; size_t labelcount, size;
nvl = nvlist_create(0); 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, "ipsrc", &r->ipsrc);
pfctl_nv_add_rule_addr(nvl, "ipdst", &r->ipdst); 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, "qname", r->qname);
nvlist_add_string(nvl, "tagname", r->tagname); nvlist_add_string(nvl, "tagname", r->tagname);
nvlist_add_number(nvl, "dnpipe", r->dnpipe); nvlist_add_number(nvl, "dnpipe", r->dnpipe);

View File

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

View File

@ -379,6 +379,7 @@ int expand_skip_interface(struct node_if *);
int check_rulestate(int); int check_rulestate(int);
int getservice(char *); int getservice(char *);
int rule_label(struct pfctl_rule *, char *s[PF_RULE_MAX_LABEL_COUNT]); 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); int rt_tableid_max(void);
void mv_rules(struct pfctl_ruleset *, struct pfctl_ruleset *); 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)); memcpy(&r.qname, $10.queues.qname, sizeof(r.qname));
r.dnpipe = $10.dnpipe; r.dnpipe = $10.dnpipe;
r.dnflags = $10.free_flags; 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, expand_eth_rule(&r, $5, $7, $8.src, $8.dst,
$9.src.host, $9.dst.host, $6, ""); $9.src.host, $9.dst.host, $6, "");
@ -1366,6 +1372,16 @@ etherfilter_opt : etherqname {
} }
filter_opts.queues = $1; 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 { | TAG string {
filter_opts.tag = $2; filter_opts.tag = $2;
} }
@ -6945,6 +6961,23 @@ rule_label(struct pfctl_rule *r, char *s[PF_RULE_MAX_LABEL_COUNT])
return (0); 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 u_int16_t
parseicmpspec(char *w, sa_family_t af) 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", "", "", "", "", static const char *actiontypes[] = { "pass", "block", "", "", "", "",
"", "", "", "", "", "", "match" }; "", "", "", "", "", "", "match" };
int i;
if (rule_numbers) if (rule_numbers)
printf("@%u ", r->nr); 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, print_fromto(&r->ipsrc, PF_OSFP_ANY, &r->ipdst,
r->proto == ETHERTYPE_IP ? AF_INET : AF_INET6, 0, r->proto == ETHERTYPE_IP ? AF_INET : AF_INET6, 0,
0, 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]) if (r->qname[0])
printf(" queue %s", r->qname); printf(" queue %s", r->qname);
if (r->tagname[0]) 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(1010, "POM_STICKYADDRESS test")
PFCTL_TEST(1011, "Test disabling scrub fragment reassemble") PFCTL_TEST(1011, "Test disabling scrub fragment reassemble")
PFCTL_TEST(1012, "Test scrub fragment reassemble is default") 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 .\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE. .\" POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd April 21, 2023 .Dd April 26, 2023
.Dt PF.CONF 5 .Dt PF.CONF 5
.Os .Os
.Sh NAME .Sh NAME
@ -3108,7 +3108,8 @@ logopts = logopt [ "," logopts ]
logopt = "all" | "user" | "to" interface-name logopt = "all" | "user" | "to" interface-name
etherfilteropt-list = etherfilteropt-list etherfilteropt | etherfilteropt 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-list = filteropt-list filteropt | filteropt
filteropt = user | group | flags | icmp-type | icmp6-type | "tos" tos | filteropt = user | group | flags | icmp-type | icmp6-type | "tos" tos |

View File

@ -703,6 +703,9 @@ struct pf_keth_rule {
uint8_t action; uint8_t action;
uint16_t dnpipe; uint16_t dnpipe;
uint32_t dnflags; uint32_t dnflags;
char label[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
uint32_t ridentifier;
}; };
union pf_krule_ptr { 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) if (nvl == NULL)
return (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_number(nvl, "nr", krule->nr);
nvlist_add_bool(nvl, "quick", krule->quick); nvlist_add_bool(nvl, "quick", krule->quick);
nvlist_add_string(nvl, "ifname", krule->ifname); nvlist_add_string(nvl, "ifname", krule->ifname);
@ -1126,8 +1131,29 @@ pf_nveth_rule_to_keth_rule(const nvlist_t *nvl,
{ {
int error = 0; int error = 0;
#define ERROUT(x) ERROUT_FUNCTION(errout, x)
bzero(krule, sizeof(*krule)); 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_nvuint32(nvl, "nr", &krule->nr));
PFNV_CHK(pf_nvbool(nvl, "quick", &krule->quick)); PFNV_CHK(pf_nvbool(nvl, "quick", &krule->quick));
PFNV_CHK(pf_nvstring(nvl, "ifname", krule->ifname, 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) krule->action != PF_MATCH)
return (EBADMSG); return (EBADMSG);
#undef ERROUT
errout: errout:
return (error); return (error);
} }