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>