aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/pfctl/parse.y98
-rw-r--r--sbin/pfctl/pfctl_parser.h7
-rw-r--r--tests/sys/netpfil/pf/ether.sh15
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()