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, ðer->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