PERFORCE change 143463 for review

Gleb Kurtsou gk at FreeBSD.org
Sat Jun 14 19:15:06 UTC 2008


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

Change 143463 by gk at gk_h1 on 2008/06/14 19:14:27

	add ipfw_ether_addr - wrapper struct for mac address. 
	
	remove support for ethernet address mask. support any and multicast addresses
	instead. mac address mask is not supported by any another firewall i've
	seen. and it looks like it was added as a small optimization trick (to simplify
	comparasion of 2 mac addresses)
	
	remove O_ETHERADDR2. replace it with 2 commands: O_ETHER_SRC and O_ETHER_DST.
	ipfw mac (ether) is supported for backward campatibility.

Affected files ...

.. //depot/projects/soc2008/gk_l2filter/sbin-ipfw/ipfw2.c#5 edit
.. //depot/projects/soc2008/gk_l2filter/sys-netinet/ip_fw.h#7 edit
.. //depot/projects/soc2008/gk_l2filter/sys-netinet/ip_fw2.c#8 edit

Differences ...

==== //depot/projects/soc2008/gk_l2filter/sbin-ipfw/ipfw2.c#5 (text+ko) ====

@@ -1139,21 +1139,16 @@
  * prints a ethernet (MAC) address/mask pair
  */
 static void
-print_ether(uint8_t *addr, uint8_t *mask)
+print_ether(ipfw_ether_addr *addr)
 {
-	int l = contigmask(mask, 48);
-
-	if (l == 0)
+	if ((addr->flags & IP_FW_EA_CHECK) == 0) {
 		printf(" any");
-	else {
+	} else if (addr->flags & IP_FW_EA_MULTICAST) {
+		printf(" multicast");
+	} else {
+		u_char *ea = addr->octet;
 		printf(" %02x:%02x:%02x:%02x:%02x:%02x",
-		    addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
-		if (l == -1)
-			printf("&%02x:%02x:%02x:%02x:%02x:%02x",
-			    mask[0], mask[1], mask[2],
-			    mask[3], mask[4], mask[5]);
-		else if (l < 48)
-			printf("/%d", l);
+		    ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]);
 	}
 }
 
@@ -1813,20 +1808,11 @@
 			if (cmd->len & F_NOT && cmd->opcode != O_IN)
 				printf(" not");
 			switch(cmd->opcode) {
-			case O_ETHERADDR2: {
-				ipfw_insn_ether *m = (ipfw_insn_ether *)cmd;
-
-				printf(" ether");
-				print_ether(m->addr, m->mask);
-				print_ether(m->addr + 6, m->mask + 6);
-				}
-				break;
-
 			case O_ETHER_SRC: {
 				ipfw_insn_ether *m = (ipfw_insn_ether *)cmd;
 
 				printf(" src-ether");
-				print_ether(m->addr + 6, m->mask + 6);
+				print_ether(&m->ether);
 				}
 				break;
 
@@ -1834,7 +1820,7 @@
 				ipfw_insn_ether *m = (ipfw_insn_ether *)cmd;
 
 				printf(" dst-ether");
-				print_ether(m->addr, m->mask);
+				print_ether(&m->ether);
 				}
 				break;
 
@@ -4468,50 +4454,27 @@
 }
 
 static void
-get_ether_addr_mask(const char *p, uint8_t *addr, uint8_t *mask)
+get_ether_addr(const char *p, ipfw_ether_addr *addr)
 {
 	int i, l;
-	char *ap, *ptr, *optr;
 	struct ether_addr *ether;
 	const char *etherset = "0123456789abcdefABCDEF:";
 
+	bzero(addr, sizeof(*addr));
 	if (strcmp(p, "any") == 0) {
-		for (i = 0; i < ETHER_ADDR_LEN; i++)
-			addr[i] = mask[i] = 0;
+		return;
+	}
+	if (strcmp(p, "multicast") == 0) {
+		addr->flags = IP_FW_EA_CHECK | IP_FW_EA_MULTICAST;
 		return;
 	}
 
-	optr = ptr = strdup(p);
-	if ((ap = strsep(&ptr, "&/")) != NULL && *ap != 0) {
-		l = strlen(ap);
-		if (strspn(ap, etherset) != l || (ether = ether_aton(ap)) == NULL)
-			errx(EX_DATAERR, "Incorrect ethernet (MAC) address");
-		bcopy(ether, addr, ETHER_ADDR_LEN);
-	} else
+	if (strspn(p, etherset) != strlen(p) ||
+			(ether = ether_aton(p)) == NULL)
 		errx(EX_DATAERR, "Incorrect ethernet (MAC) address");
 
-	if (ptr != NULL) { /* we have mask? */
-		if (p[ptr - optr - 1] == '/') { /* mask len */
-			l = strtol(ptr, &ap, 10);
-			if (*ap != 0 || l > ETHER_ADDR_LEN * 8 || l < 0)
-				errx(EX_DATAERR, "Incorrect mask length");
-			for (i = 0; l > 0 && i < ETHER_ADDR_LEN; l -= 8, i++)
-				mask[i] = (l >= 8) ? 0xff: (~0) << (8 - l);
-		} else { /* mask */
-			l = strlen(ptr);
-			if (strspn(ptr, etherset) != l ||
-			    (ether = ether_aton(ptr)) == NULL)
-				errx(EX_DATAERR, "Incorrect mask");
-			bcopy(ether, mask, ETHER_ADDR_LEN);
-		}
-	} else { /* default mask: ff:ff:ff:ff:ff:ff */
-		for (i = 0; i < ETHER_ADDR_LEN; i++)
-			mask[i] = 0xff;
-	}
-	for (i = 0; i < ETHER_ADDR_LEN; i++)
-		addr[i] &= mask[i];
-
-	free(optr);
+	memcpy(addr->octet, ether, ETHER_ADDR_LEN);
+	addr->flags = IP_FW_EA_CHECK;
 }
 
 /*
@@ -4574,58 +4537,34 @@
  * two microinstructions, and returns the pointer to the last one.
  */
 static ipfw_insn *
-add_ether(ipfw_insn *cmd, int ac, char *av[])
+add_ether(ipfw_insn *cmd, int opcode, char *arg)
 {
 	ipfw_insn_ether *ether;
 
-	if (ac < 2)
-		errx(EX_DATAERR, "ether dst src");
-
-	cmd->opcode = O_ETHERADDR2;
+	cmd->opcode = opcode;
 	cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_ether);
 
 	ether = (ipfw_insn_ether *)cmd;
-	get_ether_addr_mask(av[0], ether->addr, ether->mask);	/* dst */
-	get_ether_addr_mask(av[1], &(ether->addr[ETHER_ADDR_LEN]),
-	    &(ether->mask[ETHER_ADDR_LEN])); /* src */
+	get_ether_addr(arg, &ether->ether);
 	return cmd;
 }
 
 static ipfw_insn *
 add_ether_src(ipfw_insn *cmd, int ac, char *av[])
 {
-	ipfw_insn_ether *ether;
-
 	if (ac < 1)
 		errx(EX_DATAERR, "src-ether src");
 
-	cmd->opcode = O_ETHER_SRC;
-	cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_ether);
-
-	ether = (ipfw_insn_ether *)cmd;
-	bzero(ether->addr, ETHER_ADDR_LEN);
-	bzero(ether->mask, ETHER_ADDR_LEN);
-	get_ether_addr_mask(av[0], &(ether->addr[ETHER_ADDR_LEN]),
-	    &(ether->mask[ETHER_ADDR_LEN])); /* src */
-	return cmd;
+	return add_ether(cmd, O_ETHER_SRC, av[0]);
 }
 
 static ipfw_insn *
 add_ether_dst(ipfw_insn *cmd, int ac, char *av[])
 {
-	ipfw_insn_ether *ether;
-
 	if (ac < 1)
 		errx(EX_DATAERR, "dst-ether dst");
 
-	cmd->opcode = O_ETHER_DST;
-	cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_ether);
-
-	ether = (ipfw_insn_ether *)cmd;
-	bzero(ether->addr + ETHER_ADDR_LEN, ETHER_ADDR_LEN);
-	bzero(ether->mask + ETHER_ADDR_LEN, ETHER_ADDR_LEN);
-	get_ether_addr_mask(av[0], ether->addr, ether->mask);	/* dst */
-	return cmd;
+	return add_ether(cmd, O_ETHER_DST, av[0]);
 }
 
 static ipfw_insn *
@@ -5644,8 +5583,11 @@
 			break;
 
 		case TOK_ETHER:
-			if (add_ether(cmd, ac, av)) {
-				ac -= 2; av += 2;
+			if (ac >= 2 && add_ether_dst(cmd, ac, av)) {
+				/*
+				 * XXX will not allocate next command here
+				 */
+				av[0] = strdup("src-ether");
 			}
 			break;
 
@@ -5968,10 +5910,9 @@
 		if (lookup_host(*av, (struct in_addr *)&ent.addr) != 0)
 			errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
 		ac--; av++;
-		ent.ether_addr = 0;
+		bzero(&ent.ether_addr, sizeof(ent.ether_addr));
 		if (do_add && ac >= 2 && strcmp(*av, "ether") == 0) {
-			uint8_t mask[8];
-			get_ether_addr_mask(av[1], (uint8_t*)&ent.ether_addr, mask);
+			get_ether_addr(av[1], &ent.ether_addr);
 			ac-=2; av+=2;
 		}
 		if (do_add && ac) {
@@ -6033,7 +5974,7 @@
 			} else {
 			    snprintf(tval_buf, sizeof(tval_buf), "%u", tval);
 			}
-			if (tbl->ent[a].ether_addr) {
+			if (tbl->ent[a].ether_addr.flags & IP_FW_EA_CHECK) {
 			    uint8_t *x = (uint8_t *)&tbl->ent[a].ether_addr;
 		            snprintf(tether_buf, sizeof(tether_buf), "ether %02x:%02x:%02x:%02x:%02x:%02x ",
 		                 x[0], x[1], x[2], x[3], x[4], x[5]);

==== //depot/projects/soc2008/gk_l2filter/sys-netinet/ip_fw.h#7 (text+ko) ====

@@ -67,7 +67,6 @@
 	O_IP_DSTPORT,		/* (n)port list:mask 4 byte ea	*/
 	O_PROTO,		/* arg1=protocol		*/
 
-	O_ETHERADDR2,		/* 2 ethernet (mac) addr:mask	*/
 	O_ETHER_SRC,		/* 2 ethernet (mac) addr:mask	*/
 	O_ETHER_DST,		/* 2 ethernet (mac) addr:mask	*/
 	O_ETHER_TYPE,		/* same as srcport		*/
@@ -264,10 +263,19 @@
 /*
  * This is used for ethernet (MAC) addr-mask pairs.
  */
+
+#define IP_FW_EA_INIT		0x01
+#define IP_FW_EA_CHECK		0x02
+#define IP_FW_EA_MULTICAST	0x04
+
+typedef struct _ip_fw_ether_addr {
+	u_char octet[6];
+	u_int16_t flags;
+} ipfw_ether_addr;
+
 typedef struct	_ipfw_insn_ether {
 	ipfw_insn o;
-	u_char addr[12];	/* dst[6] + src[6] */
-	u_char mask[12];	/* dst[6] + src[6] */
+	ipfw_ether_addr ether;
 } ipfw_insn_ether;
 
 /*
@@ -532,7 +540,7 @@
  */
 typedef struct	_ipfw_table_entry {
 	in_addr_t	addr;		/* network address		*/
-	u_int64_t	ether_addr;	/* ethernet address		*/
+	ipfw_ether_addr ether_addr;	/* ethernet address		*/
 	u_int32_t	value;		/* value			*/
 	u_int16_t	tbl;		/* table number			*/
 	u_int8_t	masklen;	/* mask length			*/

==== //depot/projects/soc2008/gk_l2filter/sys-netinet/ip_fw2.c#8 (text+ko) ====

@@ -150,10 +150,29 @@
 ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr;
 ipfw_nat_cfg_t *ipfw_nat_get_log_ptr;
 
+static __inline int ether_addr_allow(ipfw_ether_addr *want, 
+	struct ether_addr *ea)
+{
+	static ipfw_ether_addr mask = {
+		.octet = { 0xff, 0xff, 0xff, 0xff, 0xff,0xff },
+		.flags = 0
+	};
+	if ((want->flags & IP_FW_EA_CHECK) == 0)
+		return (1);
+	if (want->flags & IP_FW_EA_MULTICAST) {
+		return (ETHER_IS_MULTICAST(ea->octet));
+	}
+	
+#define EA_CMP(a) (*((u_int64_t*)(a)) & *((u_int64_t*)&mask))
+	return (EA_CMP(want) == EA_CMP(ea));
+#undef EA_CMP
+
+}
+
 struct table_entry {
 	struct radix_node	rn[2];
 	struct sockaddr_in	addr, mask;
-	u_int64_t		ether_addr;
+	ipfw_ether_addr 	ether_addr;
 	u_int32_t		value;
 };
 
@@ -1753,7 +1772,7 @@
 
 static int
 add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
-    uint8_t mlen, u_int64_t ether_addr, uint32_t value)
+    uint8_t mlen, ipfw_ether_addr *ether_addr, uint32_t value)
 {
 	struct radix_node_head *rnh;
 	struct table_entry *ent;
@@ -1768,7 +1787,7 @@
 	ent->addr.sin_len = ent->mask.sin_len = 8;
 	ent->mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
 	ent->addr.sin_addr.s_addr = addr & ent->mask.sin_addr.s_addr;
-	ent->ether_addr = ether_addr;
+	ent->ether_addr = *ether_addr;
 	IPFW_WLOCK(&layer3_chain);
 	if (rnh->rnh_addaddr(&ent->addr, &ent->mask, rnh, (void *)ent) ==
 	    NULL) {
@@ -1876,10 +1895,8 @@
 	sa.sin_addr.s_addr = addr;
 	ent = (struct table_entry *)(rnh->rnh_lookup(&sa, NULL, rnh));
 	if (ent != NULL) {
-		if (ea && ent->ether_addr) {
-			if (ent->ether_addr != ((*(u_int64_t*)ea)))
+		if (ea && !ether_addr_allow(&ent->ether_addr, ea))
 				return (0);
-		}
 		*val = ent->value;
 		return (1);
 	}
@@ -2585,20 +2602,15 @@
 				    m->m_pkthdr.rcvif, (ipfw_insn_if *)cmd);
 				break;
 
-			case O_ETHERADDR2:
 			case O_ETHER_SRC:
 			case O_ETHER_DST:
 				if (args->eh != NULL) {	/* have ethernet header */
-					u_int32_t *want = (u_int32_t *)
-						((ipfw_insn_ether *)cmd)->addr;
-					u_int32_t *mask = (u_int32_t *)
-						((ipfw_insn_ether *)cmd)->mask;
-					u_int32_t *hdr = (u_int32_t *)args->eh;
-
-					match =
-					    ( want[0] == (hdr[0] & mask[0]) &&
-					      want[1] == (hdr[1] & mask[1]) &&
-					      want[2] == (hdr[2] & mask[2]) );
+					ipfw_ether_addr *want = 
+						&(((ipfw_insn_ether *)cmd)->ether);
+					match = ether_addr_allow(want, (struct ether_addr *)
+							(cmd->opcode == O_ETHER_SRC ?
+							args->eh->ether_shost :
+							args->eh->ether_dhost));
 				}
 				break;
 
@@ -3890,7 +3902,6 @@
 				goto bad_size;
 			break;
 
-		case O_ETHERADDR2:
 		case O_ETHER_SRC:
 		case O_ETHER_DST:
 			if (cmdlen != F_INSN_SIZE(ipfw_insn_ether))
@@ -4274,7 +4285,7 @@
 			if (error)
 				break;
 			error = add_table_entry(&layer3_chain, ent.tbl,
-			    ent.addr, ent.masklen, ent.ether_addr, ent.value);
+			    ent.addr, ent.masklen, &ent.ether_addr, ent.value);
 		}
 		break;
 


More information about the p4-projects mailing list