PERFORCE change 145387 for review

Gleb Kurtsou gk at FreeBSD.org
Thu Jul 17 19:58:21 UTC 2008


http://perforce.freebsd.org/chv.cgi?CH=145387

Change 145387 by gk at 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	<v.icmp>		icmp6_list icmp6_item
 %type	<v.fromto>		fromto
 %type	<v.peer>		ipportspec from to
-%type	<v.host>		ipspec xhost host dynaddr host_list
+%type	<v.host>		ipspec ether xhost host dynaddr host_list
 %type	<v.host>		redir_host_list redirspec
 %type	<v.host>		route_host route_host_list routespec
 %type	<v.os>			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 <netinet/ip_icmp.h>
 #include <netinet/icmp6.h>
 #include <net/pfvar.h>
+#include <net/ethernet.h>
 #include <arpa/inet.h>
 
 #include <stdio.h>
@@ -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 {


More information about the p4-projects mailing list