The branch main has been updated by kp:

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

commit 87a89d6e14ac5730572d454ec12a3a30d492816e
Author:     Kristof Provost <[email protected]>
AuthorDate: 2021-09-30 15:09:57 +0000
Commit:     Kristof Provost <[email protected]>
CommitDate: 2022-03-02 16:00:07 +0000

    pfctl: support lists of mac addresses
    
    Teach the 'ether' rules to accept { mac1, mac2, ... } lists, similar to
    the lists of interfaces or IP addresses we already supported for layer 3
    filtering.
    
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D32481
---
 sbin/pfctl/parse.y            | 98 ++++++++++++++++++++++++++++---------------
 sbin/pfctl/pfctl_parser.h     |  7 ++++
 tests/sys/netpfil/pf/ether.sh | 15 +++++++
 3 files changed, 87 insertions(+), 33 deletions(-)

diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index a2d8cfef8232..b856621ecf41 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -349,7 +349,8 @@ void                 expand_label_proto(const char *, char 
*, size_t, u_int8_t);
 void            expand_label_nr(const char *, char *, size_t,
                    struct pfctl_rule *);
 void            expand_eth_rule(struct pfctl_eth_rule *,
-                   struct node_if *, struct node_etherproto *);
+                   struct node_if *, struct node_etherproto *,
+                   struct node_mac *, struct node_mac *);
 void            expand_rule(struct pfctl_rule *, struct node_if *,
                    struct node_host *, struct node_proto *, struct node_os *,
                    struct node_host *, struct node_port *, struct node_host *,
@@ -419,15 +420,12 @@ typedef struct {
                        struct node_os  *src_os;
                }                        fromto;
                struct {
-                       u_int8_t         src[ETHER_ADDR_LEN];
-                       u_int8_t         srcneg;
-                       u_int8_t         dst[ETHER_ADDR_LEN];
-                       u_int8_t         dstneg;
+                       struct node_mac *src;
+                       struct node_mac *dst;
                }                        etherfromto;
-               u_int8_t                 mac[ETHER_ADDR_LEN];
+               struct node_mac         *mac;
                struct {
-                       uint8_t          mac[ETHER_ADDR_LEN];
-                       u_int8_t         neg;
+                       struct node_mac *mac;
                } etheraddr;
                struct {
                        struct node_host        *host;
@@ -560,7 +558,7 @@ int parseport(char *, struct range *r, int);
 %type  <v.etherproto>          etherproto etherproto_list etherproto_item
 %type  <v.etherfromto>         etherfromto
 %type  <v.etheraddr>           etherfrom etherto
-%type  <v.mac>                 mac
+%type  <v.mac>                 xmac mac mac_list macspec
 %%
 
 ruleset                : /* empty */
@@ -1191,11 +1189,6 @@ etherrule        : ETHER action dir quick interface 
etherproto etherfromto etherfilter_
                        r.action = $2.b1;
                        r.direction = $3;
                        r.quick = $4.quick;
-                       /* XXX TODO: ! support */
-                       memcpy(&r.src.addr, $7.src, sizeof(r.src.addr));
-                       r.src.neg = $7.srcneg;
-                       memcpy(&r.dst.addr, $7.dst, sizeof(r.dst.addr));
-                       r.dst.neg = $7.dstneg;
                        if ($8.tag != NULL)
                                memcpy(&r.tagname, $8.tag, sizeof(r.tagname));
                        if ($8.queues.qname != NULL)
@@ -1203,7 +1196,7 @@ etherrule : ETHER action dir quick interface etherproto 
etherfromto etherfilter_
                        r.dnpipe = $8.dnpipe;
                        r.dnflags = $8.free_flags;
 
-                       expand_eth_rule(&r, $5, $6);
+                       expand_eth_rule(&r, $5, $6, $7.src, $7.dst);
                }
                ;
 
@@ -3169,48 +3162,78 @@ protoval        : STRING                        {
                ;
 
 etherfromto    : ALL                           {
-                       bzero($$.src, sizeof($$.src));
-                       $$.srcneg = 0;
-                       bzero($$.dst, sizeof($$.dst));
-                       $$.dstneg = 0;
+                       $$.src = NULL;
+                       $$.dst = NULL;
                }
                | etherfrom etherto             {
-                       memcpy(&$$.src, $1.mac, sizeof($$.src));
-                       $$.srcneg = $1.neg;
-                       memcpy(&$$.dst, $2.mac, sizeof($$.dst));
-                       $$.dstneg = $2.neg;
+                       $$.src = $1.mac;
+                       $$.dst = $2.mac;
                }
                ;
 
 etherfrom      : /* emtpy */                   {
                        bzero(&$$, sizeof($$));
                }
-               | FROM not mac                  {
-                       memcpy(&$$.mac, $3, sizeof($$));
-                       $$.neg = $2;
+               | FROM macspec                  {
+                       $$.mac = $2;
                }
                ;
 
 etherto                : /* empty */                   {
                        bzero(&$$, sizeof($$));
                }
-               | TO not mac                    {
-                       memcpy(&$$.mac, $3, sizeof($$));
-                       $$.neg = $2;
+               | TO macspec                    {
+                       $$.mac = $2;
                }
                ;
 
 mac            : string                        {
+                       $$ = calloc(1, sizeof(struct node_mac));
+                       if ($$ == NULL)
+                               err(1, "mac: calloc");
+
                        if (sscanf($1, 
"%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
-                           &$$[0], &$$[1], &$$[2], &$$[3], &$$[4],
-                           &$$[5]) != 6) {
+                           &$$->mac[0], &$$->mac[1], &$$->mac[2], &$$->mac[3], 
&$$->mac[4],
+                           &$$->mac[5]) != 6) {
                                free($$);
                                free($1);
                                yyerror("invalid MAC address");
                                YYERROR;
                        }
+                       free($1);
+                       $$->next = NULL;
+                       $$->tail = $$;
+               }
+xmac           : not mac {
+                       struct node_mac *n;
+
+                       for (n = $2; n != NULL; n = n->next)
+                               n->neg = $1;
+                       $$ = $2;
                }
                ;
+macspec                : xmac {
+                       $$ = $1;
+               }
+               | '{' optnl mac_list '}'
+               {
+                       $$ = $3;
+               }
+               ;
+mac_list       : xmac optnl {
+                       $$ = $1;
+               }
+               | mac_list comma xmac {
+                       if ($3 == NULL)
+                               $$ = $1;
+                       else if ($1 == NULL)
+                               $$ = $3;
+                       else {
+                               $1->tail->next = $3;
+                               $1->tail = $3->tail;
+                               $$ = $1;
+                       }
+               }
 
 fromto         : ALL                           {
                        $$.src.host = NULL;
@@ -5616,27 +5639,36 @@ expand_queue(struct pf_altq *a, struct node_if 
*interfaces,
 
 void
 expand_eth_rule(struct pfctl_eth_rule *r,
-    struct node_if *interfaces, struct node_etherproto *protos)
+    struct node_if *interfaces, struct node_etherproto *protos,
+    struct node_mac *srcs, struct node_mac *dsts)
 {
        struct pfctl_eth_rule *rule;
 
        LOOP_THROUGH(struct node_if, interface, interfaces,
        LOOP_THROUGH(struct node_etherproto, proto, protos,
+       LOOP_THROUGH(struct node_mac, src, srcs,
+       LOOP_THROUGH(struct node_mac, dst, dsts,
                r->nr = pf->eth_nr++;
                strlcpy(r->ifname, interface->ifname,
                    sizeof(r->ifname));
                r->ifnot = interface->not;
                r->proto = proto->proto;
+               bcopy(src->mac, r->src.addr, ETHER_ADDR_LEN);
+               r->src.neg = src->neg;
+               bcopy(dst->mac, r->dst.addr, ETHER_ADDR_LEN);
+               r->dst.neg = dst->neg;
 
                if ((rule = calloc(1, sizeof(*rule))) == NULL)
                        err(1, "calloc");
                bcopy(r, rule, sizeof(*rule));
 
                TAILQ_INSERT_TAIL(&pf->eth_rules, rule, entries);
-       ));
+       ))));
 
        FREE_LIST(struct node_if, interfaces);
        FREE_LIST(struct node_etherproto, protos);
+       FREE_LIST(struct node_mac, srcs);
+       FREE_LIST(struct node_mac, dsts);
 }
 
 void
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index 1d69682b1b6c..990f860fe8e3 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -135,6 +135,13 @@ struct node_host {
        struct node_host        *tail;
 };
 
+struct node_mac {
+       u_int8_t         mac[ETHER_ADDR_LEN];
+       bool             neg;
+       struct node_mac *next;
+       struct node_mac *tail;
+};
+
 struct node_os {
        char                    *os;
        pf_osfp_t                fingerprint;
diff --git a/tests/sys/netpfil/pf/ether.sh b/tests/sys/netpfil/pf/ether.sh
index a7e23779396f..8ca8d3fbf0c8 100644
--- a/tests/sys/netpfil/pf/ether.sh
+++ b/tests/sys/netpfil/pf/ether.sh
@@ -66,6 +66,11 @@ mac_body()
                "ether block to 00:01:02:03:04:05"
        atf_check -s exit:0 -o ignore ping -c 1 -t 1 192.0.2.2
 
+       # Should still fail for 'to', even if it's in a list
+       pft_set_rules alcatraz \
+               "ether block to { ${epair_a_mac}, 00:01:02:0:04:05 }"
+       atf_check -s exit:2 -o ignore ping -c 1 -t 1 192.0.2.2
+
        # Now try this with an interface specified
        pft_set_rules alcatraz \
                "ether block on ${epair}b from ${epair_a_mac}"
@@ -84,6 +89,16 @@ mac_body()
        pft_set_rules alcatraz \
                "ether block out on ${epair}b to ! ${epair_a_mac}"
        atf_check -s exit:0 -o ignore ping -c 1 -t 1 192.0.2.2
+
+       # Block everything not us
+       pft_set_rules alcatraz \
+               "ether block out on ${epair}b to { ! ${epair_a_mac} }"
+       atf_check -s exit:0 -o ignore ping -c 1 -t 1 192.0.2.2
+
+       # Block us now
+       pft_set_rules alcatraz \
+               "ether block out on ${epair}b to { ! 00:01:02:03:04:05 }"
+       atf_check -s exit:2 -o ignore ping -c 1 -t 1 192.0.2.2
 }
 
 mac_cleanup()

Reply via email to