Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 7 Aug 2008 20:44:06 GMT
From:      Gleb Kurtsou <gk@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 146860 for review
Message-ID:  <200808072044.m77Ki6QC010881@repoman.freebsd.org>

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

Change 146860 by gk@gk_h1 on 2008/08/07 20:43:57

	simplify ethernet stateful filtering
	add 'state-options ether' option to create ethernet state
	remove now unneeded IPFW_EA_FLOW
	since now ethernet addresses from packet are used to create a state

Affected files ...

.. //depot/projects/soc2008/gk_l2filter/sbin-ipfw/ipfw2.c#10 edit
.. //depot/projects/soc2008/gk_l2filter/sys-netinet/ip_fw.h#11 edit
.. //depot/projects/soc2008/gk_l2filter/sys-netinet/ip_fw2.c#15 edit

Differences ...

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

@@ -189,6 +189,11 @@
 	{ NULL,	0 }
 };
 
+static struct _s_x f_stateopts[] = {
+	{ "ether",	IP_FW_STATEOPT_ETHER},
+	{ NULL,	0 }
+};
+
 static struct _s_x limit_masks[] = {
 	{"all",		DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT},
 	{"src-addr",	DYN_SRC_ADDR},
@@ -358,6 +363,8 @@
 	TOK_FIB,
 	TOK_SETFIB,
 
+	TOK_STATEOPTS,
+
 	TOK_ARP_OP,
 	TOK_ARP_SRC,
 	TOK_ARP_DST,
@@ -515,6 +522,8 @@
 	{ "dst-ip6",		TOK_DSTIP6},
 	{ "src-ipv6",		TOK_SRCIP6},
 	{ "src-ip6",		TOK_SRCIP6},
+	{ "state-options",	TOK_STATEOPTS },
+	{ "state-opts",		TOK_STATEOPTS },
 	{ "arp-op",		TOK_ARP_OP},
 	{ "src-arp",		TOK_ARP_SRC},
 	{ "dst-arp",		TOK_ARP_DST},
@@ -2054,6 +2063,10 @@
 				comment = (char *)(cmd + 1);
 				break;
 
+			case O_STATEOPTS:
+				print_flags("state-options", cmd, f_stateopts);
+				break;
+
 			case O_KEEP_STATE:
 				printf(" keep-state");
 				break;
@@ -5737,6 +5750,14 @@
 			ac--; av++;
 			break;
 
+		case TOK_STATEOPTS:
+			NEED1("missing argument for state-options");
+			fill_flags(cmd, O_STATEOPTS, f_stateopts, *av);
+			if ((cmd->arg1 >> 8) & 0xff) /* clear flags specified */
+				errx(EX_DATAERR, "invalid state-options %s", *av);
+			ac--; av++;
+			break;
+
 		case TOK_ARP_SRC:
 		case TOK_ARP_DST:
 			NEED1("missing lookup table argument");

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

@@ -164,6 +164,8 @@
 	O_SETFIB,		/* arg1=FIB number */
 	O_FIB,			/* arg1=FIB desired fib number */
 
+	O_STATEOPTS,
+
 	/*
 	 * ARP opcodes
 	 */
@@ -273,7 +275,6 @@
 
 #define IPFW_EA_CHECK		0x01
 #define IPFW_EA_MULTICAST	0x02
-#define IPFW_EA_FLOW		0x04
 
 typedef struct _ipfw_ether_addr {
 	u_char octet[6];
@@ -545,6 +546,11 @@
 #define	ICMP6_UNREACH_RST	0x100	/* fake ICMPv6 code (send a TCP RST) */
 
 /*
+ * Definitions for state (dynamic rule) option names.
+ */
+#define	IP_FW_STATEOPT_ETHER	0x01
+
+/*
  * These are used for lookup tables.
  */
 typedef struct	_ipfw_table_entry {

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

@@ -152,7 +152,7 @@
 ipfw_nat_cfg_t *ipfw_nat_get_log_ptr;
 
 static __inline int ether_addr_allow(ipfw_ether_addr *want, 
-	struct ether_addr *ea)
+	ipfw_ether_addr *a)
 {
 	static ipfw_ether_addr mask = {
 		.octet = { 0xff, 0xff, 0xff, 0xff, 0xff,0xff },
@@ -160,27 +160,27 @@
 	};
 	if ((want->flags & IPFW_EA_CHECK) == 0)
 		return (1);
+
+	if ((a->flags & IPFW_EA_CHECK) == 0)
+		return (0);
+
 	if (want->flags & IPFW_EA_MULTICAST) {
-		return (ETHER_IS_MULTICAST(ea->octet));
+		return (ETHER_IS_MULTICAST(a->octet));
 	}
 	
 #define EA_CMP(a) (*((u_int64_t*)(a)) & *((u_int64_t*)&mask))
-	return (EA_CMP(want) == EA_CMP(ea));
+	return (EA_CMP(want) == EA_CMP(a));
 #undef EA_CMP
 }
 
 static __inline int ether_addr_allow_dyn(ipfw_ether_addr *want, ipfw_ether_addr *a)
 {
-	if (a->flags & IPFW_EA_CHECK) {
-		/* dynamic rule is being added. check is performed already */
-		return (1);
-	}
-	if ((a->flags & IPFW_EA_FLOW) == 0) {
+	if ((a->flags & IPFW_EA_CHECK) == 0) {
 		if (want->flags & IPFW_EA_CHECK)
 			printf("ipfw: no tag: %6D (want %6D)\n", a->octet, ":", want->octet, ":");
 		return (1);
 	}
-	return (ether_addr_allow(want, (struct ether_addr *)a->octet));
+	return (ether_addr_allow(want, a));
 }
 
 struct table_entry {
@@ -1369,7 +1369,7 @@
  * - "parent" rules for the above (O_LIMIT_PARENT).
  */
 static ipfw_dyn_rule *
-add_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule)
+add_dyn_rule(struct ipfw_flow_id *id, u_int8_t dyn_type, struct ip_fw *rule, uint32_t stateopts)
 {
 	ipfw_dyn_rule *r;
 	int i;
@@ -1401,6 +1401,10 @@
 	}
 
 	r->id = *id;
+	if ((stateopts & IP_FW_STATEOPT_ETHER) == 0) {
+		r->id.src_ether.flags = 0;
+		r->id.dst_ether.flags = 0;
+	}
 	r->expire = time_uptime + dyn_syn_lifetime;
 	r->rule = rule;
 	r->dyn_type = dyn_type;
@@ -1424,7 +1428,7 @@
  * If the lookup fails, then install one.
  */
 static ipfw_dyn_rule *
-lookup_dyn_parent(struct ipfw_flow_id *pkt, struct ip_fw *rule)
+lookup_dyn_parent(struct ipfw_flow_id *pkt, struct ip_fw *rule, uint32_t stateopts)
 {
 	ipfw_dyn_rule *q;
 	int i;
@@ -1456,7 +1460,7 @@
 				return q;
 			}
 	}
-	return add_dyn_rule(pkt, O_LIMIT_PARENT, rule);
+	return add_dyn_rule(pkt, O_LIMIT_PARENT, rule, stateopts);
 }
 
 /**
@@ -1466,7 +1470,7 @@
  * session limitations are enforced.
  */
 static int
-install_state(struct ip_fw *rule, ipfw_insn_limit *cmd,
+install_state(struct ip_fw *rule, uint32_t stateopts, ipfw_insn_limit *cmd,
     struct ip_fw_args *args, uint32_t tablearg)
 {
 	static int last_log;
@@ -1513,7 +1517,7 @@
 
 	switch (cmd->o.opcode) {
 	case O_KEEP_STATE:	/* bidir rule */
-		add_dyn_rule(&args->f_id, O_KEEP_STATE, rule);
+		add_dyn_rule(&args->f_id, O_KEEP_STATE, rule, stateopts);
 		break;
 
 	case O_LIMIT: {		/* limit number of sessions */
@@ -1554,7 +1558,7 @@
 			id.src_port = args->f_id.src_port;
 		if (limit_mask & DYN_DST_PORT)
 			id.dst_port = args->f_id.dst_port;
-		if ((parent = lookup_dyn_parent(&id, rule)) == NULL) {
+		if ((parent = lookup_dyn_parent(&id, rule, stateopts)) == NULL) {
 			printf("ipfw: %s: add parent failed\n", __func__);
 			IPFW_DYN_UNLOCK();
 			return (1);
@@ -1601,7 +1605,7 @@
 				return (1);
 			}
 		}
-		add_dyn_rule(&args->f_id, O_LIMIT, (struct ip_fw *)parent);
+		add_dyn_rule(&args->f_id, O_LIMIT, (struct ip_fw *)parent, stateopts);
 		break;
 	}
 	default:
@@ -1899,7 +1903,7 @@
 
 static int
 lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
-    struct ether_addr *ea, ipfw_ether_addr *val_ea, uint32_t *val)
+    ipfw_ether_addr *ea, uint32_t *val)
 {
 	struct radix_node_head *rnh;
 	struct table_entry *ent;
@@ -1916,8 +1920,6 @@
 			return (0);
 		/* use address to create dynamic rule */
 		*val = ent->value;
-		if (val_ea != NULL)
-			*val_ea = ent->ether_addr;
 		return (1);
 	}
 	return (0);
@@ -2263,14 +2265,14 @@
 	/*
 	 * if we have an ether header,
 	 */
-	if (args->eh) {
+	if (args->eh != NULL) {
 		etype = ntohs(args->eh->ether_type);
 		memcpy(args->f_id.src_ether.octet, args->eh->ether_shost, 
 				ETHER_ADDR_LEN);
-		args->f_id.src_ether.flags = IPFW_EA_FLOW;
+		args->f_id.src_ether.flags = IPFW_EA_CHECK;
 		memcpy(args->f_id.dst_ether.octet, args->eh->ether_dhost, 
 				ETHER_ADDR_LEN);
-		args->f_id.dst_ether.flags = IPFW_EA_FLOW;
+		args->f_id.dst_ether.flags = IPFW_EA_CHECK;
 	} else {
 		args->f_id.src_ether.flags = 0;
 		args->f_id.dst_ether.flags = 0;
@@ -2554,6 +2556,7 @@
 	for (; f; f = f->next) {
 		ipfw_insn *cmd;
 		uint32_t tablearg = 0;
+		uint32_t stateopts = 0;
 		int l, cmdlen, skip_or; /* skip rest of OR block */
 
 again:
@@ -2640,17 +2643,10 @@
 				if (args->eh != NULL) {	/* have ethernet header */
 					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));
-					if (match) {
-						/* use address to create dynamic rule */
-						ipfw_ether_addr *a = (cmd->opcode == O_ETHER_SRC ?
-								&args->f_id.src_ether :
-								&args->f_id.dst_ether);
-						*a = *want;
-					}
+					ipfw_ether_addr *a = (cmd->opcode == O_ETHER_SRC ?
+						&args->f_id.src_ether :
+						&args->f_id.dst_ether);
+					match = ether_addr_allow(want, a);
 				}
 				break;
 
@@ -2703,22 +2699,17 @@
 			case O_IP_SRC_LOOKUP:
 			case O_IP_DST_LOOKUP:
 				if (is_ipv4) {
-				    struct ether_addr *ea = NULL;
+				    ipfw_ether_addr *ea =
+					(cmd->opcode == O_IP_DST_LOOKUP ?
+					    &args->f_id.dst_ether :
+					    &args->f_id.src_ether);
 				    uint32_t a =
 					(cmd->opcode == O_IP_DST_LOOKUP) ?
 					    dst_ip.s_addr : src_ip.s_addr;
 				    uint32_t v;
 
-				    if (args->eh) {
-					ea = (struct ether_addr*)((cmd->opcode == O_IP_DST_LOOKUP) ?
-					    args->eh->ether_dhost :
-					    args->eh->ether_shost);
-				    }
 				    match = lookup_table(chain, cmd->arg1, a,
-					ea, (cmd->opcode == O_IP_DST_LOOKUP ?
-						&args->f_id.dst_ether :
-						&args->f_id.src_ether),
-					&v);
+					ea, &v);
 				    if (!match)
 					break;
 				    if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
@@ -3110,6 +3101,15 @@
 					match = 1;
 				break;
 
+			case O_STATEOPTS:
+				if ((cmd->arg1 & IP_FW_STATEOPT_ETHER)) {
+					match = (args->eh != NULL);
+					if (!match)
+						break;
+				}
+				stateopts = cmd->arg1 & 0xff;
+				break;
+
 			case O_ARP_OP:
 			case O_ARP_SRC_LOOKUP:
 			case O_ARP_DST_LOOKUP:
@@ -3139,7 +3139,7 @@
 					    match = (op >= p[0] &&
 						    op <= p[1]);
 				    } else {
-					struct ether_addr *ha;
+					ipfw_ether_addr ha;
 					uint32_t pa, v;
 
 					/*
@@ -3163,23 +3163,25 @@
 					    /*
 					     * Ignore hardware address for requests 
 					     */
-					    ha = (op == ARPOP_REQUEST ? NULL :
-						    (struct ether_addr *) ar_tha(ah));
+					    if (op != ARPOP_REQUEST) {
+						memcpy(ha.octet, ar_tha(ah), ETHER_ADDR_LEN);
+						ha.flags = IPFW_EA_CHECK;
+					    } else {
+						ha.flags = 0;
+					    }
 					} else {
 					    pa = *(uint32_t *) ar_spa(ah);
-					    ha = (struct ether_addr *) ar_sha(ah);
+					    memcpy(ha.octet, ar_sha(ah), ETHER_ADDR_LEN);
+					    ha.flags = IPFW_EA_CHECK;
 					}
 
-					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);
+					match = lookup_table(chain, cmd->arg1, pa, 
+						(ha.flags ? &ha : NULL), &v);
+					printf("ipfw: %s arp: %s: op = %d: %6D(%d) %s\n",
+						(match ? "pass" : "drop"),
+						cmd->opcode == O_ARP_DST_LOOKUP ? "dst" : "src",
+						op, ha.octet, ":", ha.flags, 
+						inet_ntoa(*(struct in_addr *)&pa));
 					if (!match)
 					    break;
 					if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
@@ -3263,7 +3265,7 @@
 			 */
 			case O_LIMIT:
 			case O_KEEP_STATE:
-				if (install_state(f,
+				if (install_state(f, stateopts,
 				    (ipfw_insn_limit *)cmd, args, tablearg)) {
 					retval = IP_FW_DENY;
 					goto done; /* error/limit violation */
@@ -3947,6 +3949,7 @@
 #endif
 		case O_IP4:
 		case O_TAG:
+		case O_STATEOPTS:
 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
 				goto bad_size;
 			break;



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