Index: sbin/ipfw/ipfw.8 =================================================================== --- sbin/ipfw/ipfw.8 +++ sbin/ipfw/ipfw.8 @@ -1555,6 +1555,8 @@ .It Bro Cm dst-ip6 | dst-ipv6 Brc Ar ip6-address Matches IPv6 packets whose destination IP is one of the address(es) specified as argument. +.It Cm dst-mac Ar mac-address +Matches packets with the destination MAC address specified as the argument. .It Cm dst-port Ar ports Matches IP packets whose destination port is one of the port(s) specified as argument. @@ -1794,7 +1796,7 @@ One or more of source and destination addresses and ports can be specified. -.It Cm lookup Bro Cm dst-ip | dst-port | src-ip | src-port | uid | jail Brc Ar name +.It Cm lookup Bro Cm dst-ip | dst-mac | dst-port | src-ip | src-mac | src-port | uid | jail Brc Ar name Search an entry in lookup table .Ar name that matches the field specified as argument. @@ -1943,6 +1945,8 @@ .It Cm src-ip6 Ar ip6-address Matches IPv6 packets whose source IP is one of the address(es) specified as an argument. +.It Cm src-mac Ar mac-address +Matches packets with the source MAC address specified as the argument. .It Cm src-port Ar ports Matches IP packets whose source port is one of the port(s) specified as argument. @@ -2107,7 +2111,7 @@ .It Ar table-type : Ar addr | iface | number | flow .It Ar table-key : Ar addr Ns Oo / Ns Ar masklen Oc | iface-name | number | flow-spec .It Ar flow-spec : Ar flow-field Ns Op , Ns Ar flow-spec -.It Ar flow-field : src-ip | proto | src-port | dst-ip | dst-port +.It Ar flow-field : src-ip | proto | src-mac | src-port | dst-ip | dst-mac | dst-port .It Cm addr Matches IPv4 or IPv6 address. Each entry is represented by an Index: sbin/ipfw/ipfw2.h =================================================================== --- sbin/ipfw/ipfw2.h +++ sbin/ipfw/ipfw2.h @@ -156,6 +156,8 @@ TOK_ICMPTYPES, TOK_MAC, TOK_MACTYPE, + TOK_DSTMAC, + TOK_SRCMAC, TOK_VERREVPATH, TOK_VERSRCREACH, TOK_ANTISPOOF, Index: sbin/ipfw/ipfw2.c =================================================================== --- sbin/ipfw/ipfw2.c +++ sbin/ipfw/ipfw2.c @@ -297,7 +297,7 @@ */ static int lookup_key[] = { TOK_DSTIP, TOK_SRCIP, TOK_DSTPORT, TOK_SRCPORT, - TOK_UID, TOK_JAIL, TOK_DSCP, -1 }; + TOK_SRCMAC, TOK_DSTMAC, TOK_UID, TOK_JAIL, TOK_DSCP, -1 }; static struct _s_x rule_options[] = { { "tagged", TOK_TAGGED }, @@ -353,6 +353,8 @@ { "proto", TOK_PROTO }, { "MAC", TOK_MAC }, { "mac", TOK_MAC }, + { "dst-mac", TOK_DSTMAC }, + { "src-mac", TOK_SRCMAC }, { "mac-type", TOK_MACTYPE }, { "verrevpath", TOK_VERREVPATH }, { "versrcreach", TOK_VERSRCREACH }, @@ -3426,8 +3428,8 @@ const char *macset = "0123456789abcdefABCDEF:"; if (strcmp(p, "any") == 0) { - for (i = 0; i < ETHER_ADDR_LEN; i++) - addr[i] = mask[i] = 0; + bzero(addr, ETHER_ADDR_LEN); + bzero(mask, ETHER_ADDR_LEN); return; } @@ -3546,7 +3548,40 @@ return cmd; } +/* + * Fetch and add a single MAC address and type, with masks, and assume + * the other to be a wildcard/zero MAC address. This generates one or + * two microinstructions, and returns the pointer to the last one. + */ static ipfw_insn * +add_singlemac(ipfw_insn *cmd, char *av[], int src, int cblen) +{ + ipfw_insn_mac *mac; + + if ( av[0] == NULL ) + errx(EX_DATAERR, "%s-mac mac", (src ? "src" : "dst")); + + cmd->opcode = O_MACADDR2; + cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac); + CHECK_CMDLEN; + + mac = (ipfw_insn_mac *) cmd; + + if (src) { /* dest mac is any */ + bzero(mac->addr, ETHER_ADDR_LEN); + bzero(mac->mask, ETHER_ADDR_LEN); + get_mac_addr_mask(av[0], &(mac->addr[ETHER_ADDR_LEN]), + &(mac->mask[ETHER_ADDR_LEN])); + } else { /* src mask is any */ + get_mac_addr_mask(av[0], mac->addr, mac->mask); + bzero(&(mac->addr[ETHER_ADDR_LEN]), ETHER_ADDR_LEN); + bzero(&(mac->mask[ETHER_ADDR_LEN]), ETHER_ADDR_LEN); + } + + return cmd; +} + +static ipfw_insn * add_mactype(ipfw_insn *cmd, char *av, int cblen) { if (!av) @@ -4890,6 +4925,16 @@ if (!add_mactype(cmd, *av, cblen)) errx(EX_DATAERR, "invalid mac type %s", *av); av++; + break; + + case TOK_SRCMAC: + if (add_singlemac(cmd, av, 1, cblen)) + av++; + break; + + case TOK_DSTMAC: + if (add_singlemac(cmd, av, 0, cblen)) + av++; break; case TOK_VERREVPATH: Index: sbin/ipfw/main.c =================================================================== --- sbin/ipfw/main.c +++ sbin/ipfw/main.c @@ -66,7 +66,7 @@ "OPTION_LIST: OPTION [OPTION_LIST]\n" "OPTION: bridged | diverted | diverted-loopback | diverted-output |\n" " {dst-ip|src-ip} IPADDR | {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\n" -" {dst-port|src-port} LIST |\n" +" {dst-mac|src-mac} MAC | {dst-port|src-port} LIST |\n" " estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n" " iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n" " ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n"