PERFORCE change 146643 for review
Gleb Kurtsou
gk at FreeBSD.org
Mon Aug 4 18:41:20 UTC 2008
http://perforce.freebsd.org/chv.cgi?CH=146643
Change 146643 by gk at gk_h1 on 2008/08/04 18:41:00
implement arp filtering
Affected files ...
.. //depot/projects/soc2008/gk_l2filter/sbin-ipfw/ipfw2.c#8 edit
.. //depot/projects/soc2008/gk_l2filter/sys-netinet/ip_fw.h#10 edit
.. //depot/projects/soc2008/gk_l2filter/sys-netinet/ip_fw2.c#13 edit
Differences ...
==== //depot/projects/soc2008/gk_l2filter/sbin-ipfw/ipfw2.c#8 (text+ko) ====
@@ -52,6 +52,7 @@
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_dl.h>
+#include <net/if_arp.h>
#include <net/pfvar.h>
#include <net/route.h> /* def. of struct route */
#include <netinet/in.h>
@@ -202,6 +203,7 @@
* This is only used in this code.
*/
#define IPPROTO_ETHERTYPE 0x1000
+#define IPPROTO_ARPOP 0x1001
static struct _s_x ether_types[] = {
/*
* Note, we cannot use "-:&/" in the names because they are field
@@ -229,6 +231,15 @@
{ "ns", 0x0600 },
{ NULL, 0 }
};
+static struct _s_x arp_ops[] = {
+ { "request", ARPOP_REQUEST },
+ { "reply", ARPOP_REPLY },
+ { "rev_request", ARPOP_REVREQUEST },
+ { "rev_reply", ARPOP_REVREPLY },
+ { "inv_request", ARPOP_INVREQUEST },
+ { "inv_reply", ARPOP_INVREPLY },
+ { NULL, 0 }
+};
static void show_usage(void);
@@ -346,6 +357,10 @@
TOK_FIB,
TOK_SETFIB,
+
+ TOK_ARP_OP,
+ TOK_ARP_SRC,
+ TOK_ARP_DST,
};
struct _s_x dummynet_params[] = {
@@ -500,6 +515,9 @@
{ "dst-ip6", TOK_DSTIP6},
{ "src-ipv6", TOK_SRCIP6},
{ "src-ip6", TOK_SRCIP6},
+ { "arp-op", TOK_ARP_OP},
+ { "src-arp", TOK_ARP_SRC},
+ { "dst-arp", TOK_ARP_DST},
{ "//", TOK_COMMENT },
{ "not", TOK_NOT }, /* pseudo option */
@@ -645,6 +663,13 @@
printf("%s", s);
else
printf("0x%04x", port);
+ } else if (proto == IPPROTO_ARPOP) {
+ char const *s;
+
+ if (do_resolv && (s = match_value(arp_ops, port)) )
+ printf("%s", s);
+ else
+ printf("0x%04x", port);
} else {
struct servent *se = NULL;
if (do_resolv) {
@@ -666,6 +691,7 @@
{"iplen", O_IPLEN},
{"ipttl", O_IPTTL},
{"ether-type", O_ETHER_TYPE},
+ {"arp-op", O_ARP_OP},
{"tcpdatalen", O_TCPDATALEN},
{"tagged", O_TAGGED},
{NULL, 0}
@@ -706,6 +732,7 @@
* In particular:
* proto == -1 disables the protocol check;
* proto == IPPROTO_ETHERTYPE looks up an internal table
+ * proto == IPPROTO_ARPOP looks up an internal table
* proto == <some value in /etc/protocols> matches the values there.
* Returns *end == s in case the parameter is not found.
*/
@@ -749,6 +776,13 @@
*end = s1;
return i;
}
+ } else if (proto == IPPROTO_ARPOP) {
+ i = match_token(arp_ops, buf);
+ free(buf);
+ if (i != -1) { /* found */
+ *end = s1;
+ return i;
+ }
} else {
struct protoent *pe = NULL;
struct servent *se;
@@ -1838,6 +1872,21 @@
printf(" fib %u", cmd->arg1 );
break;
+ case O_ARP_OP:
+ print_newports((ipfw_insn_u16 *)cmd,
+ IPPROTO_ARPOP, cmd->opcode);
+ break;
+
+ case O_ARP_SRC_LOOKUP:
+ case O_ARP_DST_LOOKUP:
+ printf(" %s-arp table(%u",
+ cmd->opcode == O_ARP_DST_LOOKUP ? "dst" : "src",
+ ((ipfw_insn *)cmd)->arg1);
+ if (F_LEN((ipfw_insn *)cmd) == F_INSN_SIZE(ipfw_insn_u32))
+ printf(",%u", *((ipfw_insn_u32 *)cmd)->d);
+ printf(")");
+ break;
+
case O_IN:
printf(cmd->len & F_NOT ? " out" : " in");
break;
@@ -5677,6 +5726,29 @@
ac--; av++;
break;
+ case TOK_ARP_OP:
+ NEED1("missing arp operation");
+ if (strcmp(*av, "any") != 0) {
+ if (!fill_newports((ipfw_insn_u16 *)cmd, *av, IPPROTO_ARPOP))
+ errx(EX_DATAERR, "invalid arp operation %s", *av);
+ cmd->opcode = O_ARP_OP;
+ }
+ ac--; av++;
+ break;
+
+ case TOK_ARP_SRC:
+ case TOK_ARP_DST:
+ NEED1("missing lookup table argument");
+ fill_ip((ipfw_insn_ip *)cmd, *av);
+ if (cmd->opcode != O_IP_DST_LOOKUP) /* table */
+ errx(EX_USAGE, "invalid lookup table %s\n", *av);
+ if (i == TOK_ARP_DST)
+ cmd->opcode = O_ARP_DST_LOOKUP;
+ else
+ cmd->opcode = O_ARP_SRC_LOOKUP;
+ ac--; av++;
+ break;
+
default:
errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s);
}
==== //depot/projects/soc2008/gk_l2filter/sys-netinet/ip_fw.h#10 (text+ko) ====
@@ -164,6 +164,13 @@
O_SETFIB, /* arg1=FIB number */
O_FIB, /* arg1=FIB desired fib number */
+ /*
+ * ARP opcodes
+ */
+ O_ARP_OP, /* same as srcport */
+ O_ARP_SRC_LOOKUP, /* arg1=table number, u32=value */
+ O_ARP_DST_LOOKUP, /* arg1=table number, u32=value */
+
O_LAST_OPCODE /* not an opcode! */
};
==== //depot/projects/soc2008/gk_l2filter/sys-netinet/ip_fw2.c#13 (text+ko) ====
@@ -65,6 +65,7 @@
#include <sys/syslog.h>
#include <sys/ucred.h>
#include <net/if.h>
+#include <net/if_arp.h>
#include <net/radix.h>
#include <net/route.h>
#include <net/pf_mtag.h>
@@ -1936,8 +1937,9 @@
if (ea && !ether_addr_allow(&ent->ether_addr, ea))
return (0);
/* use address to create dynamic rule */
- *val_ea = ent->ether_addr;
*val = ent->value;
+ if (val_ea != NULL)
+ *val_ea = ent->ether_addr;
return (1);
}
return (0);
@@ -2510,6 +2512,13 @@
ip = mtod(m, struct ip *);
args->f_id.src_ip = ntohl(src_ip.s_addr);
args->f_id.dst_ip = ntohl(dst_ip.s_addr);
+ } else if (pktlen >= ETHER_HDR_LEN && args->eh != NULL &&
+ (args->flags & IP_FW_ARGS_LAYER2)) {
+ void *hdr;
+ switch (ntohs(args->eh->ether_type)) {
+ case ETHERTYPE_ARP:
+ PULLUP_TO(ETHER_HDR_LEN, hdr, struct arphdr);
+ }
}
#undef PULLUP_TO
if (proto) { /* we may have port numbers, store them */
@@ -3127,6 +3136,86 @@
match = 1;
break;
+ case O_ARP_OP:
+ case O_ARP_SRC_LOOKUP:
+ case O_ARP_DST_LOOKUP:
+ if (args->flags & IP_FW_ARGS_LAYER2 &&
+ pktlen >= ETHER_HDR_LEN && args->eh != NULL) {
+ struct arphdr *ah;
+ int op;
+
+ op = ntohs(args->eh->ether_type);
+ if (op != ETHERTYPE_ARP && op != ETHERTYPE_REVARP)
+ break;
+
+ ah = (struct arphdr*)(mtod(m, char*) + ETHER_HDR_LEN);
+ op = ntohs(ah->ar_op);
+
+ if (ntohs(ah->ar_pro) != ETHERTYPE_IP ||
+ ntohs(ah->ar_hrd) != ARPHRD_ETHER)
+ break;
+
+ if (cmd->opcode == O_ARP_OP) {
+ u_int16_t *p =
+ ((ipfw_insn_u16 *)cmd)->ports;
+ int i;
+
+ for (i = cmdlen - 1; !match && i > 0;
+ i--, p += 2)
+ match = (op >= p[0] &&
+ op <= p[1]);
+ } else {
+ struct ether_addr *ha;
+ uint32_t pa, v;
+
+ /*
+ * XXX: Drop RARP requests
+ * Protocol addresses are undefined
+ * and table lookup by hardware address is not supported
+ */
+ if (op == ARPOP_REVREQUEST)
+ break;
+
+ if (cmd->opcode == O_ARP_DST_LOOKUP) {
+ /*
+ * XXX: Drop Inverse ARP requests
+ * Target protocol address is not specified
+ * and table lookup by hardware address is not supported
+ */
+ if (op == ARPOP_INVREQUEST)
+ break;
+ pa = *(uint32_t *) ar_tpa(ah);
+
+ /*
+ * Ignore hardware address for requests
+ */
+ ha = (op == ARPOP_REQUEST ? NULL :
+ (struct ether_addr *) ar_tha(ah));
+ } else {
+ pa = *(uint32_t *) ar_spa(ah);
+ ha = (struct ether_addr *) ar_sha(ah);
+ }
+
+ if (ha)
+ printf("ipfw: arp: %s: op = %d: %6D %s\n",
+ cmd->opcode == O_ARP_DST_LOOKUP ? "dst" : "src",
+ op, ha, ":", inet_ntoa(*(struct in_addr *)&pa));
+ else
+ printf("ipfw: arp: %s: op = %d: NULL %s\n",
+ cmd->opcode == O_ARP_DST_LOOKUP ? "dst" : "src",
+ op, inet_ntoa(*(struct in_addr *)&pa));
+
+ match = lookup_table(chain, cmd->arg1, pa, ha, NULL, &v);
+ if (!match)
+ break;
+ if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
+ match = ((ipfw_insn_u32 *)cmd)->d[0] == v;
+ else
+ tablearg = v;
+ }
+ }
+ break;
+
case O_TAGGED: {
uint32_t tag = (cmd->arg1 == IP_FW_TABLEARG) ?
tablearg : cmd->arg1;
@@ -3956,6 +4045,8 @@
case O_IP_SRC_LOOKUP:
case O_IP_DST_LOOKUP:
+ case O_ARP_SRC_LOOKUP:
+ case O_ARP_DST_LOOKUP:
if (cmd->arg1 >= IPFW_TABLES_MAX) {
printf("ipfw: invalid table number %d\n",
cmd->arg1);
@@ -3982,9 +4073,10 @@
goto bad_size;
break;
- case O_ETHER_TYPE:
case O_IP_SRCPORT:
case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */
+ case O_ETHER_TYPE:
+ case O_ARP_OP:
if (cmdlen < 2 || cmdlen > 31)
goto bad_size;
break;
More information about the p4-projects
mailing list