PERFORCE change 146860 for review
Gleb Kurtsou
gk at FreeBSD.org
Thu Aug 7 20:44:07 UTC 2008
http://perforce.freebsd.org/chv.cgi?CH=146860
Change 146860 by gk at 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;
More information about the p4-projects
mailing list