Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 4 Aug 2008 18:41:19 GMT
From:      Gleb Kurtsou <gk@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 146643 for review
Message-ID:  <200808041841.m74IfJML028615@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=146643

Change 146643 by gk@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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200808041841.m74IfJML028615>