From owner-p4-projects@FreeBSD.ORG Thu Jul 17 19:58:21 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 7AE5C1065679; Thu, 17 Jul 2008 19:58:21 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 3E7501065675 for ; Thu, 17 Jul 2008 19:58:21 +0000 (UTC) (envelope-from gk@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 24AD18FC15 for ; Thu, 17 Jul 2008 19:58:21 +0000 (UTC) (envelope-from gk@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id m6HJwLL4017927 for ; Thu, 17 Jul 2008 19:58:21 GMT (envelope-from gk@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.2/8.14.1/Submit) id m6HJwLqg017925 for perforce@freebsd.org; Thu, 17 Jul 2008 19:58:21 GMT (envelope-from gk@FreeBSD.org) Date: Thu, 17 Jul 2008 19:58:21 GMT Message-Id: <200807171958.m6HJwLqg017925@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to gk@FreeBSD.org using -f From: Gleb Kurtsou To: Perforce Change Reviews Cc: Subject: PERFORCE change 145387 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 17 Jul 2008 19:58:21 -0000 http://perforce.freebsd.org/chv.cgi?CH=145387 Change 145387 by gk@gk_h1 on 2008/07/17 19:58:11 commit some *work in progress* support for layer2 filtering with pf Affected files ... .. //depot/projects/soc2008/gk_l2filter/sbin-pfctl/parse.y#2 edit .. //depot/projects/soc2008/gk_l2filter/sbin-pfctl/pf_print_state.c#2 edit .. //depot/projects/soc2008/gk_l2filter/sbin-pfctl/pfctl.h#2 edit .. //depot/projects/soc2008/gk_l2filter/sbin-pfctl/pfctl_parser.c#2 edit .. //depot/projects/soc2008/gk_l2filter/sbin-pfctl/pfctl_parser.h#2 edit .. //depot/projects/soc2008/gk_l2filter/sys-pf/net/pf.c#2 edit .. //depot/projects/soc2008/gk_l2filter/sys-pf/net/pfvar.h#2 edit Differences ... ==== //depot/projects/soc2008/gk_l2filter/sbin-pfctl/parse.y#2 (text+ko) ==== @@ -409,7 +409,7 @@ %} -%token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS +%token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON ETHER FROM TO FLAGS %token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE %token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF %token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL @@ -442,7 +442,7 @@ %type icmp6_list icmp6_item %type fromto %type ipportspec from to -%type ipspec xhost host dynaddr host_list +%type ipspec ether xhost host dynaddr host_list %type redir_host_list redirspec %type route_host route_host_list routespec %type os xos os_list @@ -2471,12 +2471,21 @@ } ; -xhost : not host { +ether : /* empty */ { $$ = NULL; } + | ETHER ANY { $$ = NULL; } + | ETHER STRING { $$ = host_ether($2); free($2); } + ; + +xhost : not host ether { struct node_host *n; for (n = $2; n != NULL; n = n->next) n->not = $1; $$ = $2; + if ($3) { + $$->addr_ether = $3->addr_ether; + free($3); + } } | not NOROUTE { $$ = calloc(1, sizeof(struct node_host)); @@ -4723,11 +4732,13 @@ r->ifnot = interface->not; r->proto = proto->proto; r->src.addr = src_host->addr; + r->src.addr_ether = src_host->addr_ether; r->src.neg = src_host->not; r->src.port[0] = src_port->port[0]; r->src.port[1] = src_port->port[1]; r->src.port_op = src_port->op; r->dst.addr = dst_host->addr; + r->dst.addr_ether = dst_host->addr_ether; r->dst.neg = dst_host->not; r->dst.port[0] = dst_port->port[0]; r->dst.port[1] = dst_port->port[1]; @@ -4894,6 +4905,7 @@ { "drop", DROP}, { "drop-ovl", FRAGDROP}, { "dup-to", DUPTO}, + { "ether", ETHER}, { "fastroute", FASTROUTE}, { "file", FILENAME}, { "fingerprints", FINGERPRINTS}, ==== //depot/projects/soc2008/gk_l2filter/sbin-pfctl/pf_print_state.c#2 (text+ko) ==== @@ -122,6 +122,20 @@ } void +print_addr_ether(struct pf_addr_ether *addr, int verbose) +{ + if ((addr->flags & PFAE_CHECK) == 0) + return; + if (addr->flags & PFAE_MULTICAST) { + printf(" ether multicast"); + } else { + u_int8_t *ea = addr->octet; + printf(" ether %02x:%02x:%02x:%02x:%02x:%02x", + ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]); + } +} + +void print_name(struct pf_addr *addr, sa_family_t af) { char host[NI_MAXHOST]; ==== //depot/projects/soc2008/gk_l2filter/sbin-pfctl/pfctl.h#2 (text+ko) ==== @@ -117,6 +117,7 @@ char *rate2str(double); void print_addr(struct pf_addr_wrap *, sa_family_t, int); +void print_addr_ether(struct pf_addr_ether *, int); void print_host(struct pf_state_host *, sa_family_t, int); void print_seq(struct pf_state_peer *); void print_state(struct pf_state *, int); ==== //depot/projects/soc2008/gk_l2filter/sbin-pfctl/pfctl_parser.c#2 (text+ko) ==== @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -381,6 +382,7 @@ if (src->neg) printf("! "); print_addr(&src->addr, af, verbose); + print_addr_ether(&src->addr_ether, verbose); if (src->port_op) print_port(src->port_op, src->port[0], src->port[1], @@ -393,6 +395,7 @@ if (dst->neg) printf("! "); print_addr(&dst->addr, af, verbose); + print_addr_ether(&dst->addr_ether, verbose); if (dst->port_op) print_port(dst->port_op, dst->port[0], dst->port[1], @@ -1419,6 +1422,31 @@ } struct node_host * +host_ether(const char *s) +{ + struct ether_addr addr; + struct node_host *h = NULL; + + h = calloc(1, sizeof(*h)); + if (h == NULL) + err(1, "host_ether: malloc"); + + if (strcmp(s, "multicast") == 0) { + h->addr_ether.flags = PFAE_CHECK | PFAE_MULTICAST; + return (h); + } + if (!ether_aton_r(s, &addr)) { + fprintf(stderr, "can't parse ethernet address: %s\n", s); + free(h); + return (NULL); + } + memcpy(h->addr_ether.octet, addr.octet, ETHER_ADDR_LEN); + h->addr_ether.flags = PFAE_CHECK; + + return (h); +} + +struct node_host * host_if(const char *s, int mask) { struct node_host *n, *h = NULL; ==== //depot/projects/soc2008/gk_l2filter/sbin-pfctl/pfctl_parser.h#2 (text+ko) ==== @@ -112,6 +112,7 @@ struct node_host { struct pf_addr_wrap addr; + struct pf_addr_ether addr_ether; struct pf_addr bcast; struct pf_addr peer; sa_family_t af; @@ -296,6 +297,7 @@ struct node_host *ifa_exists(const char *); struct node_host *ifa_lookup(const char *, int); struct node_host *host(const char *); +struct node_host *host_ether(const char *); int append_addr(struct pfr_buffer *, char *, int); int append_addr_host(struct pfr_buffer *, ==== //depot/projects/soc2008/gk_l2filter/sys-pf/net/pf.c#2 (text+ko) ==== @@ -335,6 +335,8 @@ kif, &key, PF_LAN_EXT); \ if (*state == NULL || (*state)->timeout == PFTM_PURGE) \ return (PF_DROP); \ + if (!pf_state_check_ether(*state, pd, direction)) \ + return (PF_DROP); \ if (direction == PF_OUT && \ (((*state)->rule.ptr->rt == PF_ROUTETO && \ (*state)->rule.ptr->direction == PF_OUT) || \ @@ -699,6 +701,67 @@ } } +static __inline int +pf_addr_ether_pass(struct pf_addr_ether *want, u_int8_t *ea) +{ + static struct pf_addr_ether mask = { + .octet = { 0xff, 0xff, 0xff, 0xff, 0xff,0xff }, + .flags = 0 + }; + if ((want->flags & PFAE_CHECK) == 0) + return (1); + if (want->flags & PFAE_MULTICAST) { + return (ETHER_IS_MULTICAST(ea)); + } + +#define EA_CMP(a) (*((u_int64_t*)(a)) & *((u_int64_t*)&mask)) + return (EA_CMP(want) == EA_CMP(ea)); +#undef EA_CMP +} + +static __inline int +pf_rule_check_ether(struct pf_rule *r, struct pf_pdesc *pd) +{ + if (!pd->eh) { + if ((r->src.addr_ether.flags & PFAE_CHECK) || + (r->dst.addr_ether.flags & PFAE_CHECK)) + return (0); + return (1); + } + + if (pf_addr_ether_pass(&r->src.addr_ether, pd->eh->ether_shost) && + pf_addr_ether_pass(&r->dst.addr_ether, pd->eh->ether_dhost)) + return (1); + + return (0); +} + +static __inline int +pf_state_check_ether(struct pf_state *state, struct pf_pdesc *pd, int direction) +{ + struct pf_rule *r; + struct pf_addr_ether *src, *dst; + + if (!pd->eh) + return (1); + + r = state->rule.ptr; + + if (direction == state->direction) { + src = &r->src.addr_ether; + dst = &r->dst.addr_ether; + } else { + src = &r->dst.addr_ether; + dst = &r->src.addr_ether; + } + + if (pf_addr_ether_pass(src, pd->eh->ether_shost) && + pf_addr_ether_pass(dst, pd->eh->ether_dhost)) + return (1); + + return (0); +} + void pf_init_threshold(struct pf_threshold *threshold, u_int32_t limit, u_int32_t seconds) @@ -3356,6 +3419,8 @@ else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match( pf_osfp_fingerprint(pd, m, off, th), r->os_fingerprint)) r = TAILQ_NEXT(r, entries); + else if (!pf_rule_check_ether(r, pd)) + r = TAILQ_NEXT(r, entries); else { if (r->tag) tag = r->tag; @@ -3775,6 +3840,8 @@ r = TAILQ_NEXT(r, entries); else if (r->os_fingerprint != PF_OSFP_ANY) r = TAILQ_NEXT(r, entries); + else if (!pf_rule_check_ether(r, pd)) + r = TAILQ_NEXT(r, entries); else { if (r->tag) tag = r->tag; @@ -4112,6 +4179,8 @@ r = TAILQ_NEXT(r, entries); else if (r->os_fingerprint != PF_OSFP_ANY) r = TAILQ_NEXT(r, entries); + else if (!pf_rule_check_ether(r, pd)) + r = TAILQ_NEXT(r, entries); else { if (r->tag) tag = r->tag; @@ -4371,6 +4440,8 @@ r = TAILQ_NEXT(r, entries); else if (r->os_fingerprint != PF_OSFP_ANY) r = TAILQ_NEXT(r, entries); + else if (!pf_rule_check_ether(r, pd)) + r = TAILQ_NEXT(r, entries); else { if (r->tag) tag = r->tag; @@ -4596,6 +4667,8 @@ r = TAILQ_NEXT(r, entries); else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) r = TAILQ_NEXT(r, entries); + else if (!pf_rule_check_ether(r, pd)) + r = TAILQ_NEXT(r, entries); else { if (r->anchor == NULL) { match = 1; ==== //depot/projects/soc2008/gk_l2filter/sys-pf/net/pfvar.h#2 (text+ko) ==== @@ -165,6 +165,14 @@ #define PFI_AFLAG_MODEMASK 0x07 #define PFI_AFLAG_NOALIAS 0x08 +#define PFAE_CHECK 0x01 +#define PFAE_MULTICAST 0x02 + +struct pf_addr_ether { + u_int8_t octet[6]; + u_int16_t flags; +}; + struct pf_addr_wrap { union { struct { @@ -436,6 +444,7 @@ u_int16_t port[2]; u_int8_t neg; u_int8_t port_op; + struct pf_addr_ether addr_ether; }; struct pf_pooladdr {