diff options
| author | Kristof Provost <kp@FreeBSD.org> | 2022-01-20 17:31:45 +0000 |
|---|---|---|
| committer | Kristof Provost <kp@FreeBSD.org> | 2022-03-02 16:00:08 +0000 |
| commit | b590f17a11aacaeb0a70d075df04d40c6b7eb947 (patch) | |
| tree | 92d2004c61326d6b425d4b2905c90160da45bc6e /sbin/pfctl | |
| parent | fdadb006828680427e13436d3d219a73464953ed (diff) | |
Diffstat (limited to 'sbin/pfctl')
| -rw-r--r-- | sbin/pfctl/parse.y | 97 | ||||
| -rw-r--r-- | sbin/pfctl/pfctl_parser.c | 33 | ||||
| -rw-r--r-- | sbin/pfctl/pfctl_parser.h | 1 |
3 files changed, 118 insertions, 13 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y index 5f10c4ab2e17..346ec9d9a587 100644 --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -377,6 +377,9 @@ int invalid_redirect(struct node_host *, sa_family_t); u_int16_t parseicmpspec(char *, sa_family_t); int kw_casecmp(const void *, const void *); int map_tos(char *string, int *); +struct node_mac* node_mac_from_string(const char *); +struct node_mac* node_mac_from_string_masklen(const char *, int); +struct node_mac* node_mac_from_string_mask(const char *, const char *); static TAILQ_HEAD(loadanchorshead, loadanchors) loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead); @@ -3277,22 +3280,25 @@ etherto : /* empty */ { } ; -mac : string { - $$ = calloc(1, sizeof(struct node_mac)); +mac : string '/' NUMBER { + $$ = node_mac_from_string_masklen($1, $3); + free($1); if ($$ == NULL) - err(1, "mac: calloc"); - - if (sscanf($1, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", - &$$->mac[0], &$$->mac[1], &$$->mac[2], &$$->mac[3], &$$->mac[4], - &$$->mac[5]) != 6) { - free($$); - free($1); - yyerror("invalid MAC address"); YYERROR; + } + | string { + if (strchr($1, '&')) { + /* mac&mask */ + char *mac = strtok($1, "&"); + char *mask = strtok(NULL, "&"); + $$ = node_mac_from_string_mask(mac, mask); + } else { + $$ = node_mac_from_string($1); } free($1); - $$->next = NULL; - $$->tail = $$; + if ($$ == NULL) + YYERROR; + } xmac : not mac { struct node_mac *n; @@ -5741,8 +5747,10 @@ expand_eth_rule(struct pfctl_eth_rule *r, r->ifnot = interface->not; r->proto = proto->proto; bcopy(src->mac, r->src.addr, ETHER_ADDR_LEN); + bcopy(src->mask, r->src.mask, ETHER_ADDR_LEN); r->src.neg = src->neg; bcopy(dst->mac, r->dst.addr, ETHER_ADDR_LEN); + bcopy(dst->mask, r->dst.mask, ETHER_ADDR_LEN); r->dst.neg = dst->neg; r->nr = pf->eastack[pf->asd]->match++; @@ -6899,3 +6907,68 @@ rt_tableid_max(void) return (RT_TABLEID_MAX); #endif } + +struct node_mac* +node_mac_from_string(const char *str) +{ + struct node_mac *m; + + m = calloc(1, sizeof(struct node_mac)); + if (m == NULL) + err(1, "mac: calloc"); + + if (sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + &m->mac[0], &m->mac[1], &m->mac[2], &m->mac[3], &m->mac[4], + &m->mac[5]) != 6) { + free(m); + yyerror("invalid MAC address"); + return (NULL); + } + + memset(m->mask, 0xff, ETHER_ADDR_LEN); + m->next = NULL; + m->tail = m; + + return (m); +} + +struct node_mac* +node_mac_from_string_masklen(const char *str, int masklen) +{ + struct node_mac *m; + + if (masklen < 0 || masklen > (ETHER_ADDR_LEN * 8)) { + yyerror("invalid MAC mask length"); + return (NULL); + } + + m = node_mac_from_string(str); + if (m == NULL) + return (NULL); + + memset(m->mask, 0, ETHER_ADDR_LEN); + for (int i = 0; i < masklen; i++) + m->mask[i / 8] |= 1 << (i % 8); + + return (m); +} + +struct node_mac* +node_mac_from_string_mask(const char *str, const char *mask) +{ + struct node_mac *m; + + m = node_mac_from_string(str); + if (m == NULL) + return (NULL); + + if (sscanf(mask, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + &m->mask[0], &m->mask[1], &m->mask[2], &m->mask[3], &m->mask[4], + &m->mask[5]) != 6) { + free(m); + yyerror("invalid MAC mask"); + return (NULL); + } + + return (m); +} diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index 0db0ad355cf7..1637d7358d0d 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -694,7 +694,9 @@ print_src_node(struct pf_src_node *sn, int opts) static void print_eth_addr(const struct pfctl_eth_addr *a) { - int i; + int i, masklen = ETHER_ADDR_LEN * 8; + bool seen_unset = false; + for (i = 0; i < ETHER_ADDR_LEN; i++) { if (a->addr[i] != 0) break; @@ -707,6 +709,35 @@ print_eth_addr(const struct pfctl_eth_addr *a) printf("%s%02x:%02x:%02x:%02x:%02x:%02x", a->neg ? "! " : "", a->addr[0], a->addr[1], a->addr[2], a->addr[3], a->addr[4], a->addr[5]); + + for (i = 0; i < (ETHER_ADDR_LEN * 8); i++) { + bool isset = a->mask[i / 8] & (1 << i % 8); + + if (! seen_unset) { + if (isset) + continue; + seen_unset = true; + masklen = i; + } else { + /* Not actually a continuous mask, so print the whole + * thing. */ + if (isset) + break; + continue; + } + } + + if (masklen == (ETHER_ADDR_LEN * 8)) + return; + + if (i == (ETHER_ADDR_LEN * 8)) { + printf("/%d", masklen); + return; + } + + printf("&%02x:%02x:%02x:%02x:%02x:%02x", + a->mask[0], a->mask[1], a->mask[2], a->mask[3], a->mask[4], + a->mask[5]); } void diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h index e60132d15855..60bbae7a3fcd 100644 --- a/sbin/pfctl/pfctl_parser.h +++ b/sbin/pfctl/pfctl_parser.h @@ -138,6 +138,7 @@ struct node_host { struct node_mac { u_int8_t mac[ETHER_ADDR_LEN]; + u_int8_t mask[ETHER_ADDR_LEN]; bool neg; struct node_mac *next; struct node_mac *tail; |
