From owner-p4-projects@FreeBSD.ORG Thu Aug 7 20:44:07 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 663F21065675; Thu, 7 Aug 2008 20:44:07 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 2A579106566B for ; Thu, 7 Aug 2008 20:44:07 +0000 (UTC) (envelope-from gk@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 178078FC18 for ; Thu, 7 Aug 2008 20:44:07 +0000 (UTC) (envelope-from gk@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.2/8.14.2) with ESMTP id m77Ki6de010883 for ; Thu, 7 Aug 2008 20:44:06 GMT (envelope-from gk@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.2/8.14.1/Submit) id m77Ki6QC010881 for perforce@freebsd.org; Thu, 7 Aug 2008 20:44:06 GMT (envelope-from gk@FreeBSD.org) Date: Thu, 7 Aug 2008 20:44:06 GMT Message-Id: <200808072044.m77Ki6QC010881@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to gk@FreeBSD.org using -f From: Gleb Kurtsou To: Perforce Change Reviews Cc: Subject: PERFORCE change 146860 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 07 Aug 2008 20:44:07 -0000 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;