ipfw2 for IPV6
Andre Oppermann
andre at freebsd.org
Sun Sep 5 16:10:00 PDT 2004
Brooks Davis wrote:
>
> I'm working on updating the IPFW2 for IPv6 patch Luigi posted back in
> April. I've got it partially working with pfil, but I've run into some
> issues with linklocal addresses and dummynet6. Inbound rules work fine,
> but output rules do not because the route struct is not carried in to
> the pfil hook and thus the output interface is lost.
You are supposed to give the output interface as an argument to pfil_run_
hooks(). Doesn't that sufficise?
> I'm looking for comments on the best way to solve this problem. I don't
> know IPv6 all that well, so I'm not sure what to propose.
Neither me but I noticed that in IPv6 there are three places where pfils
are connected. That doesn't make sense to me.
I guess the best thing is to involve <gnn at neville-neil.org> into this.
He's cutting his teeth on the IPv6 code and this is probably something
he can give some insights.
> The work is being done in perforce at:
>
> //depot/user/brooks/dummynet6
>
> I've included a patch against current below. Be aware that you must
> run with debug.mpsafenet=0 if you want to try IPv6 output rules. The
> current code doesn't handle the case where the firewall changes the
> destination, but modulo bugs, we are probably at feature parity with
> ip6fw.
Repeat after me with the voice of Gollum "must not reference or carry
on any pointers to rtentry's through ipfw or dummynet... my preciousss...".
;-)
PS: What about ipfw6?
--
Andre
> -- Brooks
>
> Changed files:
> sbin/ipfw/ipfw2.c
> sys/netinet/ip_dummynet.c
> sys/netinet/ip_dummynet.h
> sys/netinet/ip_fw.h
> sys/netinet/ip_fw2.c
> sys/netinet/ip_fw_pfil.c
>
> --- ../cleanup/sbin/ipfw/ipfw2.c Wed Sep 1 08:01:19 2004
> +++ sbin/ipfw/ipfw2.c Thu Sep 2 16:40:48 2004
> @@ -45,10 +45,12 @@
> #include <sysexits.h>
>
> #include <net/if.h>
> +#include <net/route.h> /* def. of struct route */
> #include <netinet/in.h>
> #include <netinet/in_systm.h>
> #include <netinet/ip.h>
> #include <netinet/ip_icmp.h>
> +#include <netinet/icmp6.h>
> #include <netinet/ip_fw.h>
> #include <netinet/ip_dummynet.h>
> #include <netinet/tcp.h>
> @@ -253,6 +255,13 @@
> TOK_DROPTAIL,
> TOK_PROTO,
> TOK_WEIGHT,
> +
> + TOK_IPV6,
> + TOK_FLOWID,
> + TOK_ICMP6TYPES,
> + TOK_EXT6HDR,
> + TOK_DSTIP6,
> + TOK_SRCIP6,
> };
>
> struct _s_x dummynet_params[] = {
> @@ -275,6 +284,13 @@
> { "delay", TOK_DELAY },
> { "pipe", TOK_PIPE },
> { "queue", TOK_QUEUE },
> +
> + { "flow-id", TOK_FLOWID},
> + { "dst-ipv6", TOK_DSTIP6},
> + { "dst-ip6", TOK_DSTIP6},
> + { "src-ipv6", TOK_SRCIP6},
> + { "src-ip6", TOK_SRCIP6},
> +
> { "dummynet-params", TOK_NULL },
> { NULL, 0 } /* terminator */
> };
> @@ -299,6 +315,7 @@
> { "unreach", TOK_UNREACH },
> { "check-state", TOK_CHECKSTATE },
> { "//", TOK_COMMENT },
> +
> { NULL, 0 } /* terminator */
> };
>
> @@ -352,6 +369,16 @@
> { "ipsec", TOK_IPSEC },
> { "//", TOK_COMMENT },
>
> + { "icmp6type", TOK_ICMP6TYPES },
> + { "icmp6types", TOK_ICMP6TYPES },
> + { "ext6hdr", TOK_EXT6HDR},
> + { "flow-id", TOK_FLOWID},
> + { "ipv6", TOK_IPV6},
> + { "dst-ipv6", TOK_DSTIP6},
> + { "dst-ip6", TOK_DSTIP6},
> + { "src-ipv6", TOK_SRCIP6},
> + { "src-ip6", TOK_SRCIP6},
> +
> { "not", TOK_NOT }, /* pseudo option */
> { "!", /* escape ? */ TOK_NOT }, /* pseudo option */
> { "or", TOK_OR }, /* pseudo option */
> @@ -848,6 +875,196 @@
> }
> }
>
> +/* XXX ipv6 stuff */
> +/*
> + * Print the ip address contained in a command.
> + */
> +static void
> +print_ip6(ipfw_insn_ip6 *cmd, char const *s)
> +{
> + struct hostent *he = NULL;
> + int len = F_LEN((ipfw_insn *) cmd) - 1;
> + struct in6_addr *a = &(cmd->addr6);
> + char trad[255];
> +
> + printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s);
> +
> + if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) {
> + printf("me6");
> + return;
> + }
> + if (cmd->o.opcode == O_IP6) {
> + printf(" ipv6");
> + return;
> + }
> +
> + /*
> + * len == 4 indicates a single IP, whereas lists of 1 or more
> + * addr/mask pairs have len = (2n+1). We convert len to n so we
> + * use that to count the number of entries.
> + */
> +
> + for (len = len / 4; len > 0; len -= 2, a += 2) {
> + int mb = /* mask length */
> + (cmd->o.opcode == O_IP6_SRC || cmd->o.opcode == O_IP6_DST) ?
> + 128 : contigmask((uint8_t *)&(a[1]), 128);
> +
> + if (mb == 128 && do_resolv)
> + he = gethostbyaddr((char *)a, sizeof(*a), AF_INET6);
> + if (he != NULL) /* resolved to name */
> + printf("%s", he->h_name);
> + else if (mb == 0) /* any */
> + printf("any");
> + else { /* numeric IP followed by some kind of mask */
> + if (inet_ntop(AF_INET6, a, trad, sizeof( trad ) ) == NULL)
> + printf("Error ntop in print_ip6\n");
> + printf("%s", trad );
> + if (mb < 0) /* XXX not really legal... */
> + printf(":%s",
> + inet_ntop(AF_INET6, &a[1], trad, sizeof(trad)));
> + else if (mb < 128)
> + printf("/%d", mb);
> + }
> + if (len > 2)
> + printf(",");
> + }
> +}
> +
> +static void
> +fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av)
> +{
> + uint8_t type;
> +
> + cmd->d[0] = 0;
> + while (*av) {
> + if (*av == ',')
> + av++;
> + type = strtoul(av, &av, 0);
> + if (*av != ',' && *av != '\0')
> + errx(EX_DATAERR, "invalid ICMP6 type");
> + if (type > ICMP6_MAXTYPE)
> + errx(EX_DATAERR, "ICMP6 type out of range");
> + cmd->d[type / 32] |= ( 1 << (type % 32));
> + }
> + cmd->o.opcode = O_ICMP6TYPE;
> + cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6);
> +}
> +
> +
> +static void
> +print_icmp6types(ipfw_insn_u32 *cmd)
> +{
> + int i, j;
> + char sep= ' ';
> +
> + printf(" ipv6 icmp6types");
> + for (i = 0; i < 7; i++)
> + for (j=0; j < 32; ++j) {
> + if ( (cmd->d[i] & (1 << (j))) == 0)
> + continue;
> + printf("%c%d", sep, (i*32 + j));
> + sep = ',';
> + }
> +}
> +
> +static void
> +print_flow6id( ipfw_insn_u32 *cmd)
> +{
> + uint16_t i, limit = cmd->o.arg1;
> + char sep = ',';
> +
> + printf(" flow-id ");
> + for( i=0; i < limit; ++i) {
> + if (i == limit - 1)
> + sep = ' ';
> + printf("%d%c", cmd->d[i], sep);
> + }
> +}
> +
> +/* structure and define for the extension header in ipv6 */
> +static struct _s_x ext6hdrcodes[] = {
> + { "frag", EXT_FRAGMENT },
> + { "hopopt", EXT_HOPOPTS },
> + { "route", EXT_ROUTING },
> + { "ah", EXT_AH },
> + { "esp", EXT_ESP },
> + { NULL, 0 }
> +};
> +
> +/* fills command for the extension header filtering */
> +int
> +fill_ext6hdr( ipfw_insn *cmd, char *av)
> +{
> + int tok;
> + char *s = av;
> +
> + cmd->arg1 = 0;
> +
> + while(s) {
> + av = strsep( &s, ",") ;
> + tok = match_token(ext6hdrcodes, av);
> + switch (tok) {
> + case EXT_FRAGMENT:
> + cmd->arg1 |= EXT_FRAGMENT;
> + break;
> +
> + case EXT_HOPOPTS:
> + cmd->arg1 |= EXT_HOPOPTS;
> + break;
> +
> + case EXT_ROUTING:
> + cmd->arg1 |= EXT_ROUTING;
> + break;
> +
> + case EXT_AH:
> + cmd->arg1 |= EXT_AH;
> + break;
> +
> + case EXT_ESP:
> + cmd->arg1 |= EXT_ESP;
> + break;
> +
> + default:
> + errx( EX_DATAERR, "invalid option for ipv6 exten headear" );
> + break;
> + }
> + }
> + if (cmd->arg1 == 0 )
> + return 0;
> + cmd->opcode = O_EXT_HDR;
> + cmd->len |= F_INSN_SIZE( ipfw_insn );
> + return 1;
> +}
> +
> +void
> +print_ext6hdr( ipfw_insn *cmd )
> +{
> + char sep = ' ';
> +
> + printf(" extension header:");
> + if (cmd->arg1 & EXT_FRAGMENT ) {
> + printf("%cfragmentation", sep);
> + sep = ',';
> + }
> + if (cmd->arg1 & EXT_HOPOPTS ) {
> + printf("%chop options", sep);
> + sep = ',';
> + }
> + if (cmd->arg1 & EXT_ROUTING ) {
> + printf("%crouting options", sep);
> + sep = ',';
> + }
> + if (cmd->arg1 & EXT_AH ) {
> + printf("%cauthentication header", sep);
> + sep = ',';
> + }
> + if (cmd->arg1 & EXT_ESP ) {
> + printf("%cencapsulated security payload", sep);
> + }
> +}
> +
> +/* XXX end of ipv6 stuff */
> +
> /*
> * show_ipfw() prints the body of an ipfw rule.
> * Because the standard rule has at least proto src_ip dst_ip, we use
> @@ -866,6 +1083,7 @@
> #define HAVE_DSTIP 0x0004
> #define HAVE_MAC 0x0008
> #define HAVE_MACTYPE 0x0010
> +#define HAVE_PROTO6 0x0080
> #define HAVE_OPTIONS 0x8000
>
> #define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
> @@ -888,6 +1106,9 @@
> return;
> }
> if ( !(*flags & HAVE_OPTIONS)) {
> + /* XXX: This is what the patch has, but shouldn't that be PROTO6? */
> + if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO6))
> + printf(" ipv6");
> if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO))
> printf(" ip");
> if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP))
> @@ -1130,6 +1351,37 @@
> flags |= HAVE_DSTIP;
> break;
>
> + case O_IP6_SRC:
> + case O_IP6_SRC_MASK:
> + case O_IP6_SRC_ME:
> + show_prerequisites(&flags, HAVE_PROTO6, 0);
> + if (!(flags & HAVE_SRCIP))
> + printf(" from");
> + if ((cmd->len & F_OR) && !or_block)
> + printf(" {");
> + print_ip6((ipfw_insn_ip6 *)cmd,
> + (flags & HAVE_OPTIONS) ? " src-ip6" : "");
> + flags |= HAVE_SRCIP | HAVE_PROTO;
> + break;
> +
> + case O_IP6_DST:
> + case O_IP6_DST_MASK:
> + case O_IP6_DST_ME:
> + show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);
> + if (!(flags & HAVE_DSTIP))
> + printf(" to");
> + if ((cmd->len & F_OR) && !or_block)
> + printf(" {");
> + print_ip6((ipfw_insn_ip6 *)cmd,
> + (flags & HAVE_OPTIONS) ? " dst-ip6" : "");
> + flags |= HAVE_DSTIP;
> + break;
> +
> + case O_FLOW6ID:
> + print_flow6id( (ipfw_insn_u32 *) cmd );
> + flags |= HAVE_OPTIONS;
> + break;
> +
> case O_IP_DSTPORT:
> show_prerequisites(&flags, HAVE_IP, 0);
> case O_IP_SRCPORT:
> @@ -1141,14 +1393,15 @@
> break;
>
> case O_PROTO: {
> - struct protoent *pe;
> + struct protoent *pe = NULL;
>
> if ((cmd->len & F_OR) && !or_block)
> printf(" {");
> if (cmd->len & F_NOT)
> printf(" not");
> proto = cmd->arg1;
> - pe = getprotobynumber(cmd->arg1);
> + if (proto != 41) /* XXX: ipv6 is special */
> + pe = getprotobynumber(cmd->arg1);
> if (flags & HAVE_OPTIONS)
> printf(" proto");
> if (pe)
> @@ -1332,6 +1585,18 @@
> }
> break;
>
> + case O_IP6:
> + printf(" ipv6");
> + break;
> +
> + case O_ICMP6TYPE:
> + print_icmp6types((ipfw_insn_u32 *)cmd);
> + break;
> +
> + case O_EXT_HDR:
> + print_ext6hdr( (ipfw_insn *) cmd );
> + break;
> +
> default:
> printf(" [opcode %d len %d]",
> cmd->opcode, cmd->len);
> @@ -1428,42 +1693,104 @@
> static void
> list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
> {
> - int l;
> + int l, index_print = 0;
> + char buff[255];
>
> - printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
> - fs->flow_mask.proto,
> - fs->flow_mask.src_ip, fs->flow_mask.src_port,
> - fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
> if (fs->rq_elements == 0)
> return;
>
> - printf("BKT Prot ___Source IP/port____ "
> - "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
> if (do_sort != 0)
> heapsort(q, fs->rq_elements, sizeof *q, sort_q);
> +
> + /*
> + * Do IPv4 stuff
> + */
> for (l = 0; l < fs->rq_elements; l++) {
> - struct in_addr ina;
> - struct protoent *pe;
> + if (!IS_IP6_FLOW_ID(&(q[l].id))) {
> + struct in_addr ina;
> + struct protoent *pe;
>
> - ina.s_addr = htonl(q[l].id.src_ip);
> - printf("%3d ", q[l].hash_slot);
> - pe = getprotobynumber(q[l].id.proto);
> - if (pe)
> - printf("%-4s ", pe->p_name);
> - else
> - printf("%4u ", q[l].id.proto);
> - printf("%15s/%-5d ",
> - inet_ntoa(ina), q[l].id.src_port);
> - ina.s_addr = htonl(q[l].id.dst_ip);
> - printf("%15s/%-5d ",
> - inet_ntoa(ina), q[l].id.dst_port);
> - printf("%4qu %8qu %2u %4u %3u\n",
> - q[l].tot_pkts, q[l].tot_bytes,
> - q[l].len, q[l].len_bytes, q[l].drops);
> - if (verbose)
> - printf(" S %20qd F %20qd\n",
> - q[l].S, q[l].F);
> + if (!index_print) {
> + index_print = 1;
> + printf("\n mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
> + fs->flow_mask.proto,
> + fs->flow_mask.src_ip,
> + fs->flow_mask.src_port,
> + fs->flow_mask.dst_ip,
> + fs->flow_mask.dst_port);
> + printf(" BKT Prot ___Source IP/port____ "
> + "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
> + }
> + printf(" %3d ", q[l].hash_slot);
> +
> + pe = getprotobynumber(q[l].id.proto);
> + if (pe)
> + printf("%-4s ", pe->p_name);
> + else
> + printf("%4u ", q[l].id.proto);
> + ina.s_addr = htonl(q[l].id.src_ip);
> + printf("%15s/%-5d ",
> + inet_ntoa(ina), q[l].id.src_port);
> + ina.s_addr = htonl(q[l].id.dst_ip);
> + printf("%15s/%-5d ",
> + inet_ntoa(ina), q[l].id.dst_port);
> + printf("%4qu %8qu %2u %4u %3u\n",
> + q[l].tot_pkts, q[l].tot_bytes,
> + q[l].len, q[l].len_bytes, q[l].drops);
> + if (verbose)
> + printf(" S %20qd F %20qd\n",
> + q[l].S, q[l].F);
> + }
> + }
> +
> + /*
> + * Do IPv6 stuff
> + */
> +
> + index_print = 0;
> + for (l = 0; l < fs->rq_elements; l++) {
> + if (IS_IP6_FLOW_ID(&(q[l].id))) {
> + struct protoent *pe;
> +
> + if (!index_print) {
> + index_print = 1;
> + printf("\n mask: proto: 0x%02x, flow_id: 0x%08x, ",
> + fs->flow_mask.proto, fs->flow_mask.flow_id6 );
> + inet_ntop(AF_INET6, &(fs->flow_mask.src_ip6),
> + buff, sizeof(buff) );
> + printf("%s/0x%04x -> ", buff, fs->flow_mask.src_port);
> + inet_ntop( AF_INET6, &(fs->flow_mask.dst_ip6),
> + buff, sizeof(buff) );
> + printf("%s/0x%04x\n", buff, fs->flow_mask.dst_port);
> +
> + printf(" BKT ___Prot___ _flow-id_ "
> + "______________Source IPv6/port_______________ "
> + "_______________Dest. IPv6/port_______________ "
> + "Tot_pkt/bytes Pkt/Byte Drp\n");
> + }
> + printf(" %3d ", q[l].hash_slot);
> + pe = getprotobynumber(q[l].id.proto);
> + if (pe)
> + printf("%9s ", pe->p_name);
> + else
> + printf("%9u ", q[l].id.proto);
> + printf("%7d %39s/%-5d ", q[l].id.flow_id6,
> + inet_ntop(AF_INET6, &(q[l].id.src_ip6),
> + buff, sizeof(buff)),
> + q[l].id.src_port);
> + printf(" %39s/%-5d ",
> + inet_ntop(AF_INET6, &(q[l].id.dst_ip6),
> + buff, sizeof(buff)),
> + q[l].id.dst_port);
> + printf(" %4qu %8qu %2u %4u %3u\n",
> + q[l].tot_pkts, q[l].tot_bytes,
> + q[l].len, q[l].len_bytes, q[l].drops);
> + if (verbose)
> + printf(" S %20qd F %20qd\n",
> + q[l].S, q[l].F);
> + }
> }
> + printf("\n");
> }
>
> static void
> @@ -1852,7 +2179,7 @@
> if (do_dynamic && ndyn) {
> printf("## Dynamic rules:\n");
> for (lac = ac, lav = av; lac != 0; lac--) {
> - rnum = strtoul(*lav++, &endptr, 10);
> + last = rnum = strtoul(*lav++, &endptr, 10);
> if (*endptr == '-')
> last = strtoul(endptr+1, &endptr, 10);
> if (*endptr)
> @@ -1905,17 +2232,22 @@
> "ACTION: check-state | allow | count | deny | reject | skipto N |\n"
> " {divert|tee} PORT | forward ADDR | pipe N | queue N\n"
> "ADDR: [ MAC dst src ether_type ] \n"
> -" [ from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
> +" [ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
> +" [ ipv6 from IP6ADDR [ PORT ] to IP6ADDR [ PORTLIST ] ]\n"
> "IPADDR: [not] { any | me | ip/bits{x,y,z} | table(t[,v]) | IPLIST }\n"
> "IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n"
> +"IP6ADDR: [not] { any | me | me6 | ip6/bits | IP6LIST }\n"
> +"IP6LIST: { ip6 | ip6/bits }[,IP6LIST]\n"
> "OPTION_LIST: OPTION [OPTION_LIST]\n"
> -"OPTION: bridged | {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n"
> +"OPTION: bridged | {dst-ip|src-ip} IPADDR | {dst-port|src-port} LIST |\n"
> " estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n"
> " iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n"
> " ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n"
> " mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n"
> " setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
> -" verrevpath | versrcreach | antispoof\n"
> +" verrevpath | icmp6types LIST | ext6hdr LIST |\n"
> +" {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\n"
> +" flow-id N[,N]\n"
> );
> exit(0);
> }
> @@ -2124,6 +2456,227 @@
> cmd->o.len |= len+1;
> }
>
> +/* XXX more ipv6 stuff */
> +/* Try to find ipv6 address by hostname */
> +static int
> +lookup_host6 (char *host, struct in6_addr *ip6addr)
> +{
> + struct hostent *he;
> +
> + if (!inet_pton(AF_INET6, host, ip6addr)) {
> + if ((he = gethostbyname2(host, AF_INET6)) == NULL)
> + return(-1);
> + memcpy( ip6addr, he->h_addr_list[0], sizeof( struct in6_addr));
> + }
> + return(0);
> +}
> +
> +/* n2mask sets n bits of the mask */
> +
> +static void
> +n2mask(struct in6_addr *mask, int n)
> +{
> + static int minimask[9] = {
> + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
> + };
> + u_char *p;
> + int i;
> +
> + memset(mask, 0, sizeof(struct in6_addr));
> + p = (u_char *) mask;
> + for (i = 0; i < 16; i++, p++, n -= 8) {
> + if (n >= 8) {
> + *p = 0xff;
> + continue;
> + }
> + *p = minimask[n];
> + break;
> + }
> + return;
> +}
> +
> +/*
> + * fills the addr and mask fields in the instruction as appropriate from av.
> + * Update length as appropriate.
> + * The following formats are allowed:
> + * any matches any IP6. Actually returns an empty instruction.
> + * me returns O_IP6_*_ME
> + *
> + * 03f1::234:123:0342 single IP6 addres
> + * 03f1::234:123:0342/24 address/mask
> + * 03f1::234:123:0342/24,03f1::234:123:0343/ List of address
> + *
> + * Set of address (as in ipv6) not supported because ipv6 address
> + * are typically random past the initial prefix.
> + * Return 1 on success, 0 on failure.
> + */
> +
> +static int
> +fill_ip6(ipfw_insn_ip6 *cmd, char *av)
> +{
> + int len = 0;
> + struct in6_addr *d = &(cmd->addr6);
> + /* Needed for multiple address.
> + * Note d[1] points to struct in6_add r mask6 of cmd
> + */
> +
> + cmd->o.len &= ~F_LEN_MASK; /* zero len */
> +
> + if (!strncmp(av, "any", strlen(av)))
> + return 1;
> +
> +
> + if (!strncmp(av, "me", strlen(av))) { /* Set the data for "me" opt*/
> + cmd->o.len |= F_INSN_SIZE(ipfw_insn);
> + return 1;
> + }
> + if (!strncmp(av, "me6", strlen(av))) { /* Set the data for "me" opt*/
> + cmd->o.len |= F_INSN_SIZE(ipfw_insn);
> + return 1;
> + }
> +
> + av = strdup(av);
> + while (av) {
> + /*
> + * After the address we can have '/' indicating a mask,
> + * or ',' indicating another address follows.
> + */
> +
> + char *p;
> + int masklen;
> + char md = '\0';
> +
> + if ((p = strpbrk( av, "/,")) ) {
> + md = *p; /* save the separator */
> + *p = '\0'; /* terminate address string */
> + p++; /* and skip past it */
> + }
> + /* now p points to NULL, mask or next entry */
> +
> + /* lookup stores address in *d as a side effect */
> + if (lookup_host6(av, d) != 0) {
> + /* failed. Free memory and go */
> + errx(EX_DATAERR, "bad address \"%s\"", av);
> + }
> + /* next, look at the mask, if any */
> + masklen = (md == '/') ? atoi(p) : 128;
> + if (masklen > 128 || masklen < 0)
> + errx(EX_DATAERR, "bad width \"%s\''", p);
> + else
> + n2mask( &d[1], masklen);
> +
> + APPLY_MASK( d, &d[1]) /* mask base address with mask */
> +
> + /* find next separator */
> +
> + if (md == '/') { /* find separator past the mask */
> + p = strpbrk(p, ",");
> + if (p)
> + p++;
> + }
> + av = p;
> +
> + /* Check this entry */
> + if (masklen == 0) {
> + /*
> + * 'any' turns the entire list into a NOP.
> + * 'not any' never matches, so it is removed from the
> + * list unless it is the only item, in which case we
> + * report an error.
> + */
> + if (cmd->o.len & F_NOT) { /* "not any" never matches */
> + if (av == NULL && len == 0) /* only this entry */
> + errx(EX_DATAERR, "not any never matches");
> + }
> + /* else do nothing and skip this entry */
> + continue;
> + }
> +
> + /*
> + * A single IP can be stored alone
> + */
> + if (masklen == 128 && av == NULL && len == 0) {
> + len = F_INSN_SIZE(struct in6_addr);
> + break;
> + }
> +
> + /* Update length and pointer to arguments */
> + len += F_INSN_SIZE(struct in6_addr)*2;
> + d += 2;
> + } /* end while */
> +
> + /* Total lenght of the command, remember that 1 is the size of the base command */
> + cmd->o.len |= len+1;
> + free(av);
> + return 1;
> +}
> +
> +/*
> + * fills command for ipv6 flow-id filtering
> + * note that the 20 bit flow number is stored in a array of u_int32_t
> + * it's supported lists of flow-id, so in the o.arg1 we store how many
> + * additional flow-id we want to filter, the basic is 1
> + */
> +void
> +fill_flow6( ipfw_insn_u32 *cmd, char *av )
> +{
> + u_int32_t type; /* Current flow number */
> + u_int16_t nflow = 0; /* Current flow index */
> + char *s = av;
> + cmd->d[0] = 0; /* Initializing the base number*/
> +
> + while (s) {
> + av = strsep( &s, ",") ;
> + type = strtoul(av, &av, 0);
> + if (*av != ',' && *av != '\0')
> + errx(EX_DATAERR, "invalid ipv6 flow number %s", av);
> + if (type > 0xfffff)
> + errx(EX_DATAERR, "flow number out of range %s", av);
> + cmd->d[nflow] |= type;
> + nflow++;
> + }
> + if( nflow > 0 ) {
> + cmd->o.opcode = O_FLOW6ID;
> + cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + nflow;
> + cmd->o.arg1 = nflow;
> + }
> + else {
> + errx(EX_DATAERR, "invalid ipv6 flow number %s", av);
> + }
> +}
> +
> +static ipfw_insn *
> +add_srcip6(ipfw_insn *cmd, char *av)
> +{
> + fill_ip6( (ipfw_insn_ip6 *) cmd, av);
> + if (F_LEN(cmd) == 0) /* any */
> + ;
> + if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* "me" */
> + cmd->opcode = O_IP6_SRC_ME;
> + else if (F_LEN(cmd) == (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn)))
> + /* single IP, no mask*/
> + cmd->opcode = O_IP6_SRC;
> + else /* addr/mask opt */
> + cmd->opcode = O_IP6_SRC_MASK;
> + return cmd;
> +}
> +
> +static ipfw_insn *
> +add_dstip6(ipfw_insn *cmd, char *av)
> +{
> + fill_ip6((ipfw_insn_ip6 *)cmd, av);
> + if (F_LEN(cmd) == 0) /* any */
> + ;
> + if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* "me" */
> + cmd->opcode = O_IP6_DST_ME;
> + else if (F_LEN(cmd) == (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn)))
> + /* single IP, no mask*/
> + cmd->opcode = O_IP6_DST;
> + else /* addr/mask opt */
> + cmd->opcode = O_IP6_DST_MASK;
> + return cmd;
> +}
> +/* end ipv6 stuff */
>
> /*
> * helper function to process a set of flags and set bits in the
> @@ -2236,7 +2789,6 @@
> struct dn_pipe p;
> int i;
> char *end;
> - uint32_t a;
> void *par = NULL;
>
> memset(&p, 0, sizeof p);
> @@ -2298,16 +2850,15 @@
> */
> par = NULL;
>
> - p.fs.flow_mask.dst_ip = 0;
> - p.fs.flow_mask.src_ip = 0;
> - p.fs.flow_mask.dst_port = 0;
> - p.fs.flow_mask.src_port = 0;
> - p.fs.flow_mask.proto = 0;
> + bzero(&p.fs.flow_mask, sizeof(p.fs.flow_mask));
> end = NULL;
>
> while (ac >= 1) {
> uint32_t *p32 = NULL;
> uint16_t *p16 = NULL;
> + uint32_t *p20 = NULL;
> + struct in6_addr *pa6 = NULL;
> + uint32_t a; /* the mask */
>
> tok = match_token(dummynet_params, *av);
> ac--; av++;
> @@ -2321,6 +2872,9 @@
> p.fs.flow_mask.dst_port = ~0;
> p.fs.flow_mask.src_port = ~0;
> p.fs.flow_mask.proto = ~0;
> + n2mask( &(p.fs.flow_mask.dst_ip6), 128);
> + n2mask( &(p.fs.flow_mask.src_ip6), 128);
> + p.fs.flow_mask.flow_id6 = ~0;
> p.fs.flags_fs |= DN_HAVE_FLOW_MASK;
> goto end_mask;
>
> @@ -2332,6 +2886,18 @@
> p32 = &p.fs.flow_mask.src_ip;
> break;
>
> + case TOK_DSTIP6:
> + pa6 = &(p.fs.flow_mask.dst_ip6);
> + break;
> +
> + case TOK_SRCIP6:
> + pa6 = &(p.fs.flow_mask.src_ip6);
> + break;
> +
> + case TOK_FLOWID:
> + p20 = &p.fs.flow_mask.flow_id6;
> + break;
> +
> case TOK_DSTPORT:
> p16 = &p.fs.flow_mask.dst_port;
> break;
> @@ -2349,22 +2915,35 @@
> }
> if (ac < 1)
> errx(EX_USAGE, "mask: value missing");
> - if (*av[0] == '/') {
> + if (*av[0] == '/') { /* mask len */
> a = strtoul(av[0]+1, &end, 0);
> - a = (a == 32) ? ~0 : (1 << a) - 1;
> - } else
> + /* convert to a mask for non IPv6 */
> + if (pa6 == NULL)
> + a = (a == 32) ? ~0 : (1 << a) - 1;
> + } else /* explicit mask (non IPv6) */
> a = strtoul(av[0], &end, 0);
> if (p32 != NULL)
> *p32 = a;
> else if (p16 != NULL) {
> - if (a > 65535)
> + if (a > 0xffff)
> errx(EX_DATAERR,
> - "mask: must be 16 bit");
> + "port mask must be 16 bit");
> *p16 = (uint16_t)a;
> + } else if (p20 != NULL) {
> + if (a > 0xfffff)
> + errx(EX_DATAERR,
> + "flow_id mask must be 20 bit");
> + *p20 = (uint32_t)a;
> + } else if (pa6 != NULL) {
> + if (a < 0 || a > 128)
> + errx(EX_DATAERR,
> + "in6addr invalid mask len");
> + else
> + n2mask(pa6, a);
> } else {
> - if (a > 255)
> + if (a > 0xff)
> errx(EX_DATAERR,
> - "mask: must be 8 bit");
> + "porto mask must be 8 bit");
> p.fs.flow_mask.proto = (uint8_t)a;
> }
> if (a != 0)
> @@ -2468,7 +3047,7 @@
> break;
>
> default:
> - errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]);
> + errx(EX_DATAERR, "unrecognised option ``%s''", *av);
> }
> }
> if (do_pipe == 1) {
> @@ -2684,21 +3263,25 @@
> }
>
> static ipfw_insn *
> -add_proto(ipfw_insn *cmd, char *av)
> +add_proto(ipfw_insn *cmd, char *av, u_char *proto)
> {
> struct protoent *pe;
> - u_char proto = 0;
> +
> + *proto = IPPROTO_IP;
>
> if (!strncmp(av, "all", strlen(av)))
> ; /* same as "ip" */
> - else if ((proto = atoi(av)) > 0)
> + else if ((*proto = atoi(av)) > 0)
> ; /* all done! */
> else if ((pe = getprotobyname(av)) != NULL)
> - proto = pe->p_proto;
> + *proto = pe->p_proto;
> + else if(!strncmp(av, "ipv6", strlen(av)) ||
> + !strncmp(av, "ip6", strlen(av)) )
> + *proto = IPPROTO_IPV6;
> else
> return NULL;
> - if (proto != IPPROTO_IP)
> - fill_cmd(cmd, O_PROTO, 0, proto);
> + if (proto != IPPROTO_IP && *proto != IPPROTO_IPV6)
> + fill_cmd(cmd, O_PROTO, 0, *proto);
> return cmd;
> }
>
> @@ -2749,6 +3332,38 @@
> return NULL;
> }
>
> +static ipfw_insn *
> +add_src(ipfw_insn *cmd, char *av, u_char proto)
> +{
> + struct in6_addr a;
> + if( proto == IPPROTO_IPV6 || strcmp( av, "me6") == 0 || inet_pton(AF_INET6, av, &a ))
> + return add_srcip6(cmd, av);
> +
> + if (proto == IPPROTO_IP || strcmp( av, "me") == 0 || !inet_pton(AF_INET6, av, &a ) )
> + return add_srcip(cmd, av);
> +
> + if( !strcmp( av, "any") )
> + return cmd;
> +
> + return NULL; /* bad address */
> +}
> +
> +static ipfw_insn *
> +add_dst(ipfw_insn *cmd, char *av, u_char proto)
> +{
> + struct in6_addr a;
> + if( proto == IPPROTO_IPV6 || strcmp( av, "me6") == 0 || inet_pton(AF_INET6, av, &a ))
> + return add_dstip6(cmd, av);
> +
> + if (proto == IPPROTO_IP || strcmp( av, "me") == 0 || !inet_pton(AF_INET6, av, &a ) )
> + return add_dstip(cmd, av);
> +
> + if( !strcmp( av, "any") )
> + return cmd;
> +
> + return NULL; /* bad address */
> +}
> +
> /*
> * Parse arguments and assemble the microinstructions which make up a rule.
> * Rules are added into the 'rulebuf' and then copied in the correct order
> @@ -2772,7 +3387,7 @@
> */
> static uint32_t rulebuf[255], actbuf[255], cmdbuf[255];
>
> - ipfw_insn *src, *dst, *cmd, *action, *prev=NULL;
> + ipfw_insn *src, *dst, *cmd, *action, *prev=NULL, *retval=NULL;
> ipfw_insn *first_cmd; /* first match pattern */
>
> struct ip_fw *rule;
> @@ -3051,11 +3666,9 @@
> OR_START(get_proto);
> NOT_BLOCK;
> NEED1("missing protocol");
> - if (add_proto(cmd, *av)) {
> + if (add_proto(cmd, *av, &proto)) {
> av++; ac--;
> - if (F_LEN(cmd) == 0) /* plain IP */
> - proto = 0;
> - else {
> + if (F_LEN(cmd) != 0) { /* plain IP */
> proto = cmd->arg1;
> prev = cmd;
> cmd = next_cmd(cmd);
> @@ -3079,13 +3692,16 @@
> OR_START(source_ip);
> NOT_BLOCK; /* optional "not" */
> NEED1("missing source address");
> - if (add_srcip(cmd, *av)) {
> + retval = add_src(cmd, *av, proto);
> +
> + if (retval) {
> ac--; av++;
> if (F_LEN(cmd) != 0) { /* ! any */
> prev = cmd;
> cmd = next_cmd(cmd);
> }
> - }
> + } else
> + errx(EX_USAGE, "bad source address %s", *av);
> OR_BLOCK(source_ip);
>
> /*
> @@ -3114,13 +3730,16 @@
> OR_START(dest_ip);
> NOT_BLOCK; /* optional "not" */
> NEED1("missing dst address");
> - if (add_dstip(cmd, *av)) {
> + retval = add_dst(cmd, *av, proto);
> +
> + if (retval) {
> ac--; av++;
> if (F_LEN(cmd) != 0) { /* ! any */
> prev = cmd;
> cmd = next_cmd(cmd);
> }
> - }
> + } else
> + errx( EX_USAGE, "bad destination address %s", *av);
> OR_BLOCK(dest_ip);
>
> /*
> @@ -3226,6 +3845,12 @@
> av++; ac--;
> break;
>
> + case TOK_ICMP6TYPES:
> + NEED1("icmptypes requires list of types");
> + fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av);
> + av++; ac--;
> + break;
> +
> case TOK_IPTTL:
> NEED1("ipttl requires TTL");
> if (strpbrk(*av, "-,")) {
> @@ -3418,8 +4043,9 @@
>
> case TOK_PROTO:
> NEED1("missing protocol");
> - if (add_proto(cmd, *av)) {
> - proto = cmd->arg1;
> + if (add_proto(cmd, *av, &proto)) {
> + if ( proto == IPPROTO_IPV6 )
> + fill_cmd(cmd, O_IP6, 0, 0);
> ac--; av++;
> } else
> errx(EX_DATAERR, "invalid protocol ``%s''",
> @@ -3440,6 +4066,20 @@
> }
> break;
>
> + case TOK_SRCIP6:
> + NEED1("missing source IP6");
> + if (add_srcip6(cmd, *av)) {
> + ac--; av++;
> + }
> + break;
> +
> + case TOK_DSTIP6:
> + NEED1("missing destination IP6");
> + if (add_dstip6(cmd, *av)) {
> + ac--; av++;
> + }
> + break;
> +
> case TOK_SRCPORT:
> NEED1("missing source port");
> if (!strncmp(*av, "any", strlen(*av)) ||
> @@ -3493,6 +4133,24 @@
> av += ac;
> ac = 0;
> break;
> +
> + case TOK_IPV6:
> + fill_cmd(cmd, O_IP6, 0, 0);
> + ac--; av++;
> + break;
> +
> + case TOK_EXT6HDR:
> + fill_ext6hdr( cmd, *av );
> + ac--; av++;
> + break;
> +
> + case TOK_FLOWID:
> + if (proto != IPPROTO_IPV6 )
> + errx( EX_USAGE, "flow-id filter is active only for ipv6 protocol\n");
> + fill_flow6( (ipfw_insn_u32 *) cmd, *av );
> + ac--;av++;
> + break;
> +
>
> default:
> errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s);
> --- ../cleanup/sys/netinet/ip_dummynet.c Thu Aug 26 21:19:18 2004
> +++ sys/netinet/ip_dummynet.c Fri Sep 3 13:37:35 2004
> @@ -77,6 +77,9 @@
> #include <netinet/if_ether.h> /* for struct arpcom */
> #include <net/bridge.h>
>
> +#include <netinet/ip6.h> /* for ip6_input, ip6_output prototypes */
> +#include <netinet6/ip6_var.h>
> +
> /*
> * We keep a private variable for the simulation time, but we could
> * probably use an existing one ("softticks" in sys/kern/kern_timeout.c)
> @@ -461,6 +464,14 @@
> ip_input(m) ;
> break ;
>
> + case DN_TO_IP6_IN:
> + ip6_input(m) ;
> + break ;
> +
> + case DN_TO_IP6_OUT:
> + (void)ip6_output(m, NULL, NULL, pkt->flags, NULL, NULL, NULL);
> + break ;
> +
> case DN_TO_BDG_FWD :
> /*
> * The bridge requires/assumes the Ethernet header is
> @@ -898,36 +909,79 @@
> {
> int i = 0 ; /* we need i and q for new allocations */
> struct dn_flow_queue *q, *prev;
> + int is_v6 = IS_IP6_FLOW_ID(id);
>
> if ( !(fs->flags_fs & DN_HAVE_FLOW_MASK) )
> q = fs->rq[0] ;
> else {
> - /* first, do the masking */
> - id->dst_ip &= fs->flow_mask.dst_ip ;
> - id->src_ip &= fs->flow_mask.src_ip ;
> + /* first, do the masking, then hash */
> id->dst_port &= fs->flow_mask.dst_port ;
> id->src_port &= fs->flow_mask.src_port ;
> id->proto &= fs->flow_mask.proto ;
> id->flags = 0 ; /* we don't care about this one */
> - /* then, hash function */
> - i = ( (id->dst_ip) & 0xffff ) ^
> - ( (id->dst_ip >> 15) & 0xffff ) ^
> - ( (id->src_ip << 1) & 0xffff ) ^
> - ( (id->src_ip >> 16 ) & 0xffff ) ^
> - (id->dst_port << 1) ^ (id->src_port) ^
> - (id->proto );
> + if (is_v6) {
> + APPLY_MASK(&id->dst_ip6, &fs->flow_mask.dst_ip6);
> + APPLY_MASK(&id->src_ip6, &fs->flow_mask.src_ip6);
> + id->flow_id6 &= fs->flow_mask.flow_id6;
> +
> + i = ((id->dst_ip6.__u6_addr.__u6_addr32[0]) & 0xffff)^
> + ((id->dst_ip6.__u6_addr.__u6_addr32[1]) & 0xffff)^
> + ((id->dst_ip6.__u6_addr.__u6_addr32[2]) & 0xffff)^
> + ((id->dst_ip6.__u6_addr.__u6_addr32[3]) & 0xffff)^
> +
> + ((id->dst_ip6.__u6_addr.__u6_addr32[0] >> 15) & 0xffff)^
> + ((id->dst_ip6.__u6_addr.__u6_addr32[1] >> 15) & 0xffff)^
> + ((id->dst_ip6.__u6_addr.__u6_addr32[2] >> 15) & 0xffff)^
> + ((id->dst_ip6.__u6_addr.__u6_addr32[3] >> 15) & 0xffff)^
> +
> + ((id->src_ip6.__u6_addr.__u6_addr32[0] << 1) & 0xfffff)^
> + ((id->src_ip6.__u6_addr.__u6_addr32[1] << 1) & 0xfffff)^
> + ((id->src_ip6.__u6_addr.__u6_addr32[2] << 1) & 0xfffff)^
> + ((id->src_ip6.__u6_addr.__u6_addr32[3] << 1) & 0xfffff)^
> +
> + ((id->src_ip6.__u6_addr.__u6_addr32[0] << 16) & 0xffff)^
> + ((id->src_ip6.__u6_addr.__u6_addr32[1] << 16) & 0xffff)^
> + ((id->src_ip6.__u6_addr.__u6_addr32[2] << 16) & 0xffff)^
> + ((id->src_ip6.__u6_addr.__u6_addr32[3] << 16) & 0xffff)^
> +
> + (id->dst_port << 1) ^ (id->src_port) ^
> + (id->proto ) ^
> + (id->flow_id6);
> + } else {
> + id->dst_ip &= fs->flow_mask.dst_ip ;
> + id->src_ip &= fs->flow_mask.src_ip ;
> +
> + i = ( (id->dst_ip) & 0xffff ) ^
> + ( (id->dst_ip >> 15) & 0xffff ) ^
> + ( (id->src_ip << 1) & 0xffff ) ^
> + ( (id->src_ip >> 16 ) & 0xffff ) ^
> + (id->dst_port << 1) ^ (id->src_port) ^
> + (id->proto );
> + }
> i = i % fs->rq_size ;
> /* finally, scan the current list for a match */
> searches++ ;
> for (prev=NULL, q = fs->rq[i] ; q ; ) {
> search_steps++;
> - if (id->dst_ip == q->id.dst_ip &&
> + if (is_v6 &&
> + IN6_ARE_ADDR_EQUAL(&id->dst_ip6,&q->id.dst_ip6) &&
> + IN6_ARE_ADDR_EQUAL(&id->src_ip6,&q->id.src_ip6) &&
> + id->dst_port == q->id.dst_port &&
> + id->src_port == q->id.src_port &&
> + id->proto == q->id.proto &&
> + id->flags == q->id.flags &&
> + id->flow_id6 == q->id.flow_id6)
> + break ; /* found */
> +
> + if (!is_v6 && id->dst_ip == q->id.dst_ip &&
> id->src_ip == q->id.src_ip &&
> id->dst_port == q->id.dst_port &&
> id->src_port == q->id.src_port &&
> id->proto == q->id.proto &&
> id->flags == q->id.flags)
> break ; /* found */
> +
> + /* No match. Check if we can expire the entry */
> else if (pipe_expire && q->head == NULL && q->S == q->F+1 ) {
> /* entry is idle and not in any heap, expire it */
> struct dn_flow_queue *old_q = q ;
> @@ -1065,7 +1119,7 @@
> {
> #if IPFW2
> struct dn_flow_set *fs;
> - ipfw_insn *cmd = rule->cmd + rule->act_ofs;
> + ipfw_insn *cmd = ACTION_PTR(rule);
>
> if (cmd->opcode == O_LOG)
> cmd += F_LEN(cmd);
> @@ -1132,7 +1186,7 @@
> struct dn_flow_queue *q = NULL ;
> int is_pipe;
> #if IPFW2
> - ipfw_insn *cmd = fwa->rule->cmd + fwa->rule->act_ofs;
> + ipfw_insn *cmd = ACTION_PTR(fwa->rule);
> #endif
>
> KASSERT(m->m_nextpkt == NULL,
> @@ -1202,8 +1256,9 @@
> pkt->dn_dir = dir ;
>
> pkt->ifp = fwa->oif;
> - if (dir == DN_TO_IP_OUT)
> + if (dir == DN_TO_IP_OUT || dir == DN_TO_IP6_OUT)
> pkt->flags = fwa->flags;
> +
> if (q->head == NULL)
> q->head = m;
> else
> @@ -1372,7 +1427,7 @@
> * remove references from all ipfw rules to all pipes.
> */
> static void
> -dummynet_flush()
> +dummynet_flush(void)
> {
> struct dn_pipe *curr_p, *p ;
> struct dn_flow_set *fs, *curr_fs;
> @@ -2017,7 +2072,7 @@
> ip_dn_init(void)
> {
> if (bootverbose)
> - printf("DUMMYNET initialized (011031)\n");
> + printf("DUMMYNET with IPv6 initialized (040826)\n");
>
> DUMMYNET_LOCK_INIT();
>
> --- ../cleanup/sys/netinet/ip_dummynet.h Thu Aug 26 21:19:18 2004
> +++ sys/netinet/ip_dummynet.h Fri Aug 27 13:12:06 2004
> @@ -124,10 +124,13 @@
> #define DN_TO_BDG_FWD 3
> #define DN_TO_ETH_DEMUX 4
> #define DN_TO_ETH_OUT 5
> +#define DN_TO_IP6_IN 6
> +#define DN_TO_IP6_OUT 7
>
> dn_key output_time; /* when the pkt is due for delivery */
> struct ifnet *ifp; /* interface, for ip_output */
> int flags ; /* flags, for ip_output (IPv6 ?) */
> + struct _ip6dn_args ip6opt; /* XXX ipv6 options */
> };
> #endif /* _KERNEL */
>
> --- ../cleanup/sys/netinet/ip_fw.h Thu Aug 26 21:19:19 2004
> +++ sys/netinet/ip_fw.h Fri Aug 27 13:12:06 2004
> @@ -134,11 +134,31 @@
> O_IP_DST_LOOKUP, /* arg1=table number, u32=value */
> O_ANTISPOOF, /* none */
> O_JAIL, /* u32 = id */
> + O_IP6_SRC, /* address without mask */
> + O_IP6_SRC_ME, /* my addresses */
> + O_IP6_SRC_MASK, /* address with the mask */
> + O_IP6_DST,
> + O_IP6_DST_ME,
> + O_IP6_DST_MASK,
> + O_FLOW6ID, /* for flow id tag in the ipv6 pkt */
> + O_ICMP6TYPE, /* icmp6 packet type filtering */
> + O_EXT_HDR, /* filtering for ipv6 extension header */
> + O_IP6,
>
> O_LAST_OPCODE /* not an opcode! */
> };
>
> /*
> + * The extension header are filtered only for presence using a bit
> + * vector with a flag for each header.
> + */
> +#define EXT_FRAGMENT 0x1
> +#define EXT_HOPOPTS 0x2
> +#define EXT_ROUTING 0x4
> +#define EXT_AH 0x8
> +#define EXT_ESP 0x10
> +
> +/*
> * Template for instructions.
> *
> * ipfw_insn is used for all instructions which require no operands,
> @@ -274,6 +294,30 @@
> u_int32_t log_left; /* how many left to log */
> } ipfw_insn_log;
>
> +/* Apply ipv6 mask on ipv6 addr */
> +#define APPLY_MASK(addr,mask) \
> + (addr)->__u6_addr.__u6_addr32[0] &= (mask)->__u6_addr.__u6_addr32[0]; \
> + (addr)->__u6_addr.__u6_addr32[1] &= (mask)->__u6_addr.__u6_addr32[1]; \
> + (addr)->__u6_addr.__u6_addr32[2] &= (mask)->__u6_addr.__u6_addr32[2]; \
> + (addr)->__u6_addr.__u6_addr32[3] &= (mask)->__u6_addr.__u6_addr32[3];
> +
> +/* Structure for ipv6 */
> +typedef struct _ipfw_insn_ip6 {
> + ipfw_insn o;
> + struct in6_addr addr6;
> + struct in6_addr mask6;
> +} ipfw_insn_ip6;
> +
> +/* Used to support icmp6 types */
> +typedef struct _ipfw_insn_icmp6 {
> + ipfw_insn o;
> + uint32_t d[7]; /* XXX This number si related to the netinet/icmp6.h
> + * define ICMP6_MAXTYPE
> + * as follows: n = ICMP6_MAXTYPE/32 + 1
> + * Actually is 203
> + */
> +} ipfw_insn_icmp6;
> +
> /*
> * Here we have the structure representing an ipfw rule.
> *
> @@ -336,8 +380,14 @@
> u_int16_t src_port;
> u_int8_t proto;
> u_int8_t flags; /* protocol-specific flags */
> + uint8_t addr_type; /* 4 = ipv4, 6 = ipv6, 1=ether ? */
> + struct in6_addr dst_ip6; /* could also store MAC addr! */
> + struct in6_addr src_ip6;
> + u_int32_t flow_id6;
> };
>
> +#define IS_IP6_FLOW_ID(id) ((id)->addr_type == 6)
> +
> /*
> * Dynamic ipfw rule.
> */
> @@ -410,6 +460,21 @@
> #define IP_FW_PORT_DENY_FLAG 0x40000
>
> /*
> + * Structure for collecting parameters to dummynet for ip6_output forwarding
> + */
> +struct _ip6dn_args {
> + struct ip6_pktopts *opt_or;
> + struct route_in6 ro_or;
> + int flags_or;
> + struct ip6_moptions *im6o_or;
> + struct ifnet *origifp_or;
> + struct ifnet *ifp_or;
> + struct sockaddr_in6 dst_or;
> + u_long mtu_or;
> + struct route_in6 ro_pmtu_or;
> +};
> +
> +/*
> * Arguments for calling ipfw_chk() and dummynet_io(). We put them
> * all into a structure because this way it is easier and more
> * efficient to pass variables around and extend the interface.
> @@ -425,6 +490,8 @@
>
> struct ipfw_flow_id f_id; /* grabbed from IP header */
> u_int32_t retval;
> +
> + struct _ip6dn_args dummypar; /* dummynet->ip6_output */
> };
>
> /*
> --- ../cleanup/sys/netinet/ip_fw2.c Thu Aug 26 21:19:21 2004
> +++ sys/netinet/ip_fw2.c Thu Sep 2 20:22:12 2004
> @@ -82,6 +82,9 @@
> #include <netinet6/ipsec.h>
> #endif
>
> +#include <netinet/ip6.h>
> +#include <netinet/icmp6.h>
> +
> #include <netinet/if_ether.h> /* XXX for ETHERTYPE_IP */
>
> #include <machine/in_cksum.h> /* XXX for in_cksum */
> @@ -277,14 +280,19 @@
>
>
> /*
> - * This macro maps an ip pointer into a layer3 header pointer of type T
> + * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T
> + * Other macros just cast void * into the appropriate type
> */
> -#define L3HDR(T, ip) ((T *)((u_int32_t *)(ip) + (ip)->ip_hl))
> +#define L3HDR(T, ip) ((T *)((u_int32_t *)(ip) + (ip)->ip_hl))
> +#define TCP(p) ((struct tcphdr *)(p))
> +#define UDP(p) ((struct udphdr *)(p))
> +#define ICMP(p) ((struct icmp *)(p))
> +#define ICMP6(p) ((struct icmp6_hdr *)(p))
>
> static __inline int
> -icmptype_match(struct ip *ip, ipfw_insn_u32 *cmd)
> +icmptype_match(struct icmp *icmp, ipfw_insn_u32 *cmd)
> {
> - int type = L3HDR(struct icmp,ip)->icmp_type;
> + int type = icmp->icmp_type;
>
> return (type <= ICMP_MAXTYPE && (cmd->d[0] & (1<<type)) );
> }
> @@ -293,9 +301,10 @@
> (1 << ICMP_TSTAMP) | (1 << ICMP_IREQ) | (1 << ICMP_MASKREQ) )
>
> static int
> -is_icmp_query(struct ip *ip)
> +is_icmp_query(struct icmp *icmp)
> {
> - int type = L3HDR(struct icmp, ip)->icmp_type;
> + int type = icmp->icmp_type;
> +
> return (type <= ICMP_MAXTYPE && (TT & (1<<type)) );
> }
> #undef TT
> @@ -371,10 +380,9 @@
> }
>
> static int
> -tcpopts_match(struct ip *ip, ipfw_insn *cmd)
> +tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd)
> {
> int optlen, bits = 0;
> - struct tcphdr *tcp = L3HDR(struct tcphdr,ip);
> u_char *cp = (u_char *)(tcp + 1);
> int x = (tcp->th_off << 2) - sizeof(struct tcphdr);
>
> @@ -515,6 +523,83 @@
> return 1;
> }
>
> +/*
> + * ipv6 specific rules here...
> + */
> +static __inline int
> +icmp6type_match (int type, ipfw_insn_u32 *cmd)
> +{
> + return (type <= ICMP6_MAXTYPE && (cmd->d[type/32] & (1<<(type%32)) ) );
> +}
> +
> +static int
> +flow6id_match( int curr_flow, ipfw_insn_u32 *cmd )
> +{
> + int i;
> + for (i=0; i <= cmd->o.arg1; ++i )
> + if (curr_flow == cmd->d[i] )
> + return 1;
> + return 0;
> +}
> +
> +/* support for IP6_*_ME opcodes */
> +static int
> +search_ip6_addr_net (struct in6_addr * ip6_addr)
> +{
> + struct ifnet *mdc;
> + struct ifaddr *mdc2;
> + struct in6_ifaddr *fdm;
> + struct in6_addr copia;
> +
> + TAILQ_FOREACH(mdc, &ifnet, if_link)
> + for (mdc2 = mdc->if_addrlist.tqh_first; mdc2;
> + mdc2 = mdc2->ifa_list.tqe_next) {
> + if (!mdc2->ifa_addr)
> + continue;
> + if (mdc2->ifa_addr->sa_family == AF_INET6) {
> + fdm = (struct in6_ifaddr *)mdc2;
> + copia = fdm->ia_addr.sin6_addr;
> + /* need for leaving scope_id in the sock_addr */
> + in6_clearscope(&copia);
> + if (IN6_ARE_ADDR_EQUAL(ip6_addr, &copia))
> + return 1;
> + }
> + }
> + return 0;
> +}
> +
> +static int
> +verify_rev_path6(struct in6_addr *src, struct ifnet *ifp)
> +{
> + static struct route_in6 ro;
> + struct sockaddr_in6 *dst;
> +
> + dst = (struct sockaddr_in6 * )&(ro.ro_dst);
> +
> + if ( !(IN6_ARE_ADDR_EQUAL (src, &dst->sin6_addr) )) {
> + bzero(dst, sizeof(*dst));
> + dst->sin6_family = AF_INET6;
> + dst->sin6_len = sizeof(*dst);
> + dst->sin6_addr = *src;
> + rtalloc_ign((struct route *)&ro, RTF_CLONING);
> + }
> + if ((ro.ro_rt == NULL) || (ifp == NULL) ||
> + (ro.ro_rt->rt_ifp->if_index != ifp->if_index))
> + return 0;
> + return 1;
> +}
> +static __inline int
> +hash_packet6(struct ipfw_flow_id *id)
> +{
> + u_int32_t i;
> + i= (id->dst_ip6.__u6_addr.__u6_addr32[0]) ^
> + (id->dst_ip6.__u6_addr.__u6_addr32[1]) ^
> + (id->dst_ip6.__u6_addr.__u6_addr32[2]) ^
> + (id->dst_ip6.__u6_addr.__u6_addr32[3]) ^
> + (id->dst_port) ^ (id->src_port) ^ (id->flow_id6);
> + return i;
> +}
> +/* end of ipv6 opcodes */
>
> static u_int64_t norule_counter; /* counter for ipfw_log(NULL...) */
>
> @@ -718,7 +803,8 @@
> {
> u_int32_t i;
>
> - i = (id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port);
> + i = IS_IP6_FLOW_ID(id) ? hash_packet6(id):
> + (id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port);
> i &= (curr_dyn_buckets - 1);
> return i;
> }
> @@ -857,19 +943,40 @@
> }
> if (pkt->proto == q->id.proto &&
> q->dyn_type != O_LIMIT_PARENT) {
> - if (pkt->src_ip == q->id.src_ip &&
> - pkt->dst_ip == q->id.dst_ip &&
> + if (IS_IP6_FLOW_ID(pkt)) {
> + if (IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6),
> + &(q->id.src_ip6)) &&
> + IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6),
> + &(q->id.dst_ip6)) &&
> pkt->src_port == q->id.src_port &&
> pkt->dst_port == q->id.dst_port ) {
> dir = MATCH_FORWARD;
> break;
> - }
> - if (pkt->src_ip == q->id.dst_ip &&
> - pkt->dst_ip == q->id.src_ip &&
> - pkt->src_port == q->id.dst_port &&
> - pkt->dst_port == q->id.src_port ) {
> - dir = MATCH_REVERSE;
> - break;
> + }
> + if (IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6),
> + &(q->id.dst_ip6)) &&
> + IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6),
> + &(q->id.src_ip6)) &&
> + pkt->src_port == q->id.dst_port &&
> + pkt->dst_port == q->id.src_port ) {
> + dir = MATCH_REVERSE;
> + break;
> + }
> + } else {
> + if (pkt->src_ip == q->id.src_ip &&
> + pkt->dst_ip == q->id.dst_ip &&
> + pkt->src_port == q->id.src_port &&
> + pkt->dst_port == q->id.dst_port ) {
> + dir = MATCH_FORWARD;
> + break;
> + }
> + if (pkt->src_ip == q->id.dst_ip &&
> + pkt->dst_ip == q->id.src_ip &&
> + pkt->src_port == q->id.dst_port &&
> + pkt->dst_port == q->id.src_port ) {
> + dir = MATCH_REVERSE;
> + break;
> + }
> }
> }
> next:
> @@ -1067,15 +1174,25 @@
> IPFW_DYN_LOCK_ASSERT();
>
> if (ipfw_dyn_v) {
> + int is_v6 = IS_IP6_FLOW_ID(pkt);
> i = hash_packet( pkt );
> for (q = ipfw_dyn_v[i] ; q != NULL ; q=q->next)
> if (q->dyn_type == O_LIMIT_PARENT &&
> rule== q->rule &&
> pkt->proto == q->id.proto &&
> - pkt->src_ip == q->id.src_ip &&
> - pkt->dst_ip == q->id.dst_ip &&
> pkt->src_port == q->id.src_port &&
> - pkt->dst_port == q->id.dst_port) {
> + pkt->dst_port == q->id.dst_port &&
> + (
> + (is_v6 &&
> + IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6),
> + &(q->id.src_ip6)) &&
> + IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6),
> + &(q->id.dst_ip6))) ||
> + (!is_v6 &&
> + pkt->src_ip == q->id.src_ip &&
> + pkt->dst_ip == q->id.dst_ip)
> + )
> + ) {
> q->expire = time_second + dyn_short_lifetime;
> DEB(printf("ipfw: lookup_dyn_parent found 0x%p\n",q);)
> return q;
> @@ -1149,10 +1266,17 @@
> id.dst_port = id.src_port = 0;
> id.proto = args->f_id.proto;
>
> - if (limit_mask & DYN_SRC_ADDR)
> - id.src_ip = args->f_id.src_ip;
> - if (limit_mask & DYN_DST_ADDR)
> - id.dst_ip = args->f_id.dst_ip;
> + if (IS_IP6_FLOW_ID (&(args->f_id))) {
> + if (limit_mask & DYN_SRC_ADDR)
> + id.src_ip6 = args->f_id.src_ip6;
> + if (limit_mask & DYN_DST_ADDR)
> + id.dst_ip6 = args->f_id.dst_ip6;
> + } else {
> + if (limit_mask & DYN_SRC_ADDR)
> + id.src_ip = args->f_id.src_ip;
> + if (limit_mask & DYN_DST_ADDR)
> + id.dst_ip = args->f_id.dst_ip;
> + }
> if (limit_mask & DYN_SRC_PORT)
> id.src_port = args->f_id.src_port;
> if (limit_mask & DYN_DST_PORT)
> @@ -1730,97 +1854,192 @@
> struct in_addr src_ip, dst_ip; /* NOTE: network format */
> u_int16_t ip_len=0;
> int pktlen;
> + /*
> + * dyn_dir = MATCH_UNKNOWN when rules unchecked,
> + * MATCH_NONE when checked and not matched (q = NULL),
> + * MATCH_FORWARD or MATCH_REVERSE otherwise (q != NULL)
> + */
> int dyn_dir = MATCH_UNKNOWN;
> ipfw_dyn_rule *q = NULL;
> struct ip_fw_chain *chain = &layer3_chain;
> struct m_tag *mtag;
> + /*
> + * We store in ulp a pointer to the upper layer protocol header.
> + * In the ipv4 case this is easy to determine from the header,
> + * but for ipv6 we might have some additional headers in the
> + * middle. ulp is NULL if not found.
> + */
> + void *ulp = NULL; /* upper layer protocol pointer. */
> + /* XXX ipv6 variables */
> + int is_ipv6 = 0;
> + u_int16_t ext_hd = 0; /* bits vector for extension header filtering */
> + /* end of ipv6 variables */
>
> if (m->m_flags & M_SKIP_FIREWALL)
> return 0; /* accept */
> - /*
> - * dyn_dir = MATCH_UNKNOWN when rules unchecked,
> - * MATCH_NONE when checked and not matched (q = NULL),
> - * MATCH_FORWARD or MATCH_REVERSE otherwise (q != NULL)
> - */
> -
> pktlen = m->m_pkthdr.len;
> - if (args->eh == NULL || /* layer 3 packet */
> - ( m->m_pkthdr.len >= sizeof(struct ip) &&
> - ntohs(args->eh->ether_type) == ETHERTYPE_IP))
> - hlen = ip->ip_hl << 2;
> + proto = args->f_id.proto = 0; /* mark f_id invalid */
>
> - /*
> - * Collect parameters into local variables for faster matching.
> - */
> - if (hlen == 0) { /* do not grab addresses for non-ip pkts */
> - proto = args->f_id.proto = 0; /* mark f_id invalid */
> - goto after_ip_checks;
> - }
> + /* Identify ipv6 packets and fill up variables. */
> + if (pktlen >= sizeof(struct ip6_hdr) &&
> + (!args->eh || ntohs(args->eh->ether_type)==ETHERTYPE_IPV6) &&
> + mtod(m, struct ip *)->ip_v == 6) {
> + is_ipv6 = 1;
> + args->f_id.addr_type = 6;
> + hlen = sizeof(struct ip6_hdr);
> + proto = mtod(m, struct ip6_hdr *)->ip6_nxt;
>
> - proto = args->f_id.proto = ip->ip_p;
> - src_ip = ip->ip_src;
> - dst_ip = ip->ip_dst;
> - if (args->eh != NULL) { /* layer 2 packets are as on the wire */
> - offset = ntohs(ip->ip_off) & IP_OFFMASK;
> - ip_len = ntohs(ip->ip_len);
> - } else {
> - offset = ip->ip_off & IP_OFFMASK;
> - ip_len = ip->ip_len;
> - }
> - pktlen = ip_len < pktlen ? ip_len : pktlen;
> + /*
> + * PULLUP6(len, p, T) makes sure that len + sizeof(T) is
> + * contiguous, then it sets p to point at the offset "len" in
> + * the mbuf. WARNING: the pointer might become stale after
> + * other pullups (but we never use it this way).
> + */
> +#define PULLUP6(len, p, T) \
> + do { \
> + int x = (len) + sizeof(T); \
> + if ((m)->m_len < x) { \
> + args->m = m = m_pullup(m, x); \
> + if (m == 0) \
> + goto pullup_failed; \
> + } \
> + p = (mtod(m, char *) + (len)); \
> + } while (0)
> +
> + /* Search extension headers to find upper layer protocols */
> + while (ulp == NULL) {
> + switch (proto) {
> + case IPPROTO_ICMPV6:
> + PULLUP6(hlen, ulp, struct icmp6_hdr);
> + args->f_id.flags = ICMP6(ulp)->icmp6_type;
> + break;
> +
> + case IPPROTO_TCP:
> + PULLUP6(hlen, ulp, struct tcphdr);
> + dst_port = TCP(ulp)->th_dport;
> + src_port = TCP(ulp)->th_sport;
> + args->f_id.flags = TCP(ulp)->th_flags;
> + break;
> +
> + case IPPROTO_UDP:
> + PULLUP6(hlen, ulp, struct udphdr);
> + dst_port = UDP(ulp)->uh_dport;
> + src_port = UDP(ulp)->uh_sport;
> + break;
> +
> + case IPPROTO_HOPOPTS:
> + PULLUP6(hlen, ulp, struct ip6_hbh);
> + ext_hd |= EXT_HOPOPTS;
> + hlen += sizeof(struct ip6_hbh);
> + proto = ((struct ip6_hbh *)ulp)->ip6h_nxt;
> + ulp = NULL;
> + break;
> +
> + case IPPROTO_ROUTING:
> + PULLUP6(hlen, ulp, struct ip6_rthdr);
> + ext_hd |= EXT_ROUTING;
> + hlen += sizeof(struct ip6_rthdr);
> + proto = ((struct ip6_rthdr *)ulp)->ip6r_nxt;
> + ulp = NULL;
> + break;
> +
> + case IPPROTO_FRAGMENT:
> + PULLUP6(hlen, ulp, struct ip6_frag);
> + ext_hd |= EXT_FRAGMENT;
> + hlen += sizeof (struct ip6_frag);
> + proto = ((struct ip6_frag *)ulp)->ip6f_nxt;
> + offset = 1;
> + ulp = NULL; /* XXX is it correct ? */
> + break;
> +
> + case IPPROTO_AH:
> + case IPPROTO_NONE:
> + case IPPROTO_ESP:
> + PULLUP6(hlen, ulp, struct ip6_ext);
> + if (proto == IPPROTO_AH)
> + ext_hd |= EXT_AH;
> + else if (proto == IPPROTO_ESP)
> + ext_hd |= EXT_ESP;
> + hlen += ((struct ip6_ext *)ulp)->ip6e_len +
> + sizeof (struct ip6_ext);
> + proto = ((struct ip6_ext *)ulp)->ip6e_nxt;
> + ulp = NULL;
> + break;
>
> -#define PULLUP_TO(len) \
> - do { \
> - if ((m)->m_len < (len)) { \
> - args->m = m = m_pullup(m, (len)); \
> - if (m == 0) \
> - goto pullup_failed; \
> - ip = mtod(m, struct ip *); \
> - } \
> - } while (0)
> + default:
> + printf( "IPFW2: IPV6 - Unknown Extension Header (%d)\n",
> + proto);
> + return 0; /* deny */
> + break;
> + } /*switch */
> + }
> + args->f_id.src_ip6 = mtod(m,struct ip6_hdr *)->ip6_src;
> + args->f_id.dst_ip6 = mtod(m,struct ip6_hdr *)->ip6_dst;
> + args->f_id.src_ip = 0;
> + args->f_id.dst_ip = 0;
> + args->f_id.flow_id6 = ntohs(mtod(m, struct ip6_hdr *)->ip6_flow);
> + /* hlen != 0 is used to detect ipv4 packets, so clear it now */
> + hlen = 0;
> + } else if (pktlen >= sizeof(struct ip) &&
> + (!args->eh || ntohs(args->eh->ether_type) == ETHERTYPE_IP) &&
> + mtod(m, struct ip *)->ip_v == 4) {
> + ip = mtod(m, struct ip *);
> + hlen = ip->ip_hl << 2;
> + args->f_id.addr_type = 4;
>
> - if (offset == 0) {
> - switch (proto) {
> - case IPPROTO_TCP:
> - {
> - struct tcphdr *tcp;
> + /*
> + * Collect parameters into local variables for faster matching.
> + */
>
> - PULLUP_TO(hlen + sizeof(struct tcphdr));
> - tcp = L3HDR(struct tcphdr, ip);
> - dst_port = tcp->th_dport;
> - src_port = tcp->th_sport;
> - args->f_id.flags = tcp->th_flags;
> - }
> - break;
> + proto = ip->ip_p;
> + src_ip = ip->ip_src;
> + dst_ip = ip->ip_dst;
> + if (args->eh != NULL) { /* layer 2 packets are as on the wire */
> + offset = ntohs(ip->ip_off) & IP_OFFMASK;
> + ip_len = ntohs(ip->ip_len);
> + } else {
> + offset = ip->ip_off & IP_OFFMASK;
> + ip_len = ip->ip_len;
> + }
> + pktlen = ip_len < pktlen ? ip_len : pktlen;
>
> - case IPPROTO_UDP:
> - {
> - struct udphdr *udp;
> + if (offset == 0) {
> + switch (proto) {
> + case IPPROTO_TCP:
> + PULLUP6(hlen, ulp, struct tcphdr);
> + dst_port = TCP(ulp)->th_dport;
> + src_port = TCP(ulp)->th_sport;
> + args->f_id.flags = TCP(ulp)->th_flags;
> + break;
>
> - PULLUP_TO(hlen + sizeof(struct udphdr));
> - udp = L3HDR(struct udphdr, ip);
> - dst_port = udp->uh_dport;
> - src_port = udp->uh_sport;
> - }
> - break;
> + case IPPROTO_UDP:
> + PULLUP6(hlen, ulp, struct udphdr);
> + dst_port = UDP(ulp)->uh_dport;
> + src_port = UDP(ulp)->uh_sport;
> + break;
>
> - case IPPROTO_ICMP:
> - PULLUP_TO(hlen + 4); /* type, code and checksum. */
> - args->f_id.flags = L3HDR(struct icmp, ip)->icmp_type;
> - break;
> + case IPPROTO_ICMP:
> + /*
> + * we only care for 4 bytes: type, code,
> + * checksum
> + */
> + PULLUP6(hlen, ulp, struct icmp);
> + args->f_id.flags = ICMP(ulp)->icmp_type;
> + break;
>
> - default:
> - break;
> + default:
> + break;
> + }
> }
> -#undef PULLUP_TO
> - }
> -
> - args->f_id.src_ip = ntohl(src_ip.s_addr);
> - args->f_id.dst_ip = ntohl(dst_ip.s_addr);
> - args->f_id.src_port = src_port = ntohs(src_port);
> - args->f_id.dst_port = dst_port = ntohs(dst_port);
>
> -after_ip_checks:
> + args->f_id.src_ip = ntohl(src_ip.s_addr);
> + args->f_id.dst_ip = ntohl(dst_ip.s_addr);
> + }
> + if (proto) { /* we may have port numbers, store them */
> + args->f_id.proto = proto;
> + args->f_id.src_port = src_port = ntohs(src_port);
> + args->f_id.dst_port = dst_port = ntohs(dst_port);
> + }
> IPFW_LOCK(chain); /* XXX expensive? can we run lock free? */
> mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL);
> if (args->rule) {
> @@ -1926,11 +2145,13 @@
> case O_JAIL:
> /*
> * We only check offset == 0 && proto != 0,
> - * as this ensures that we have an IPv4
> + * as this ensures that we have a
> * packet with the ports info.
> */
> if (offset!=0)
> break;
> + if (is_ipv6) /* XXX to be fixed later */
> + break;
> if (proto == IPPROTO_TCP ||
> proto == IPPROTO_UDP)
> match = check_uidgid(
> @@ -1985,7 +2206,7 @@
> break;
>
> case O_FRAG:
> - match = (hlen > 0 && offset != 0);
> + match = (offset != 0);
> break;
>
> case O_IN: /* "out" is "not in" */
> @@ -2087,7 +2308,7 @@
> case O_IP_DSTPORT:
> /*
> * offset == 0 && proto != 0 is enough
> - * to guarantee that we have an IPv4
> + * to guarantee that we have a
> * packet with port info.
> */
> if ((proto==IPPROTO_UDP || proto==IPPROTO_TCP)
> @@ -2107,15 +2328,25 @@
>
> case O_ICMPTYPE:
> match = (offset == 0 && proto==IPPROTO_ICMP &&
> - icmptype_match(ip, (ipfw_insn_u32 *)cmd) );
> + icmptype_match(ICMP(ulp), (ipfw_insn_u32 *)cmd) );
> + break;
> +
> + case O_ICMP6TYPE:
> + match = is_ipv6 && offset == 0 &&
> + proto==IPPROTO_ICMPV6 &&
> + icmp6type_match(
> + ICMP6(ulp)->icmp6_type,
> + (ipfw_insn_u32 *)cmd);
> break;
>
> case O_IPOPT:
> - match = (hlen > 0 && ipopts_match(ip, cmd) );
> + match = (hlen > 0 &&
> + ipopts_match(mtod(m, struct ip *), cmd) );
> break;
>
> case O_IPVER:
> - match = (hlen > 0 && cmd->arg1 == ip->ip_v);
> + match = (hlen > 0 &&
> + cmd->arg1 == mtod(m, struct ip *)->ip_v);
> break;
>
> case O_IPID:
> @@ -2129,9 +2360,9 @@
> if (cmd->opcode == O_IPLEN)
> x = ip_len;
> else if (cmd->opcode == O_IPTTL)
> - x = ip->ip_ttl;
> + x = mtod(m, struct ip *)->ip_ttl;
> else /* must be IPID */
> - x = ntohs(ip->ip_id);
> + x = ntohs(mtod(m, struct ip *)->ip_id);
> if (cmdlen == 1) {
> match = (cmd->arg1 == x);
> break;
> @@ -2146,48 +2377,46 @@
>
> case O_IPPRECEDENCE:
> match = (hlen > 0 &&
> - (cmd->arg1 == (ip->ip_tos & 0xe0)) );
> + (cmd->arg1 == (mtod(m, struct ip *)->ip_tos & 0xe0)) );
> break;
>
> case O_IPTOS:
> match = (hlen > 0 &&
> - flags_match(cmd, ip->ip_tos));
> + flags_match(cmd, mtod(m, struct ip *)->ip_tos));
> break;
>
> case O_TCPFLAGS:
> match = (proto == IPPROTO_TCP && offset == 0 &&
> - flags_match(cmd,
> - L3HDR(struct tcphdr,ip)->th_flags));
> + flags_match(cmd, TCP(ulp)->th_flags));
> break;
>
> case O_TCPOPTS:
> match = (proto == IPPROTO_TCP && offset == 0 &&
> - tcpopts_match(ip, cmd));
> + tcpopts_match(TCP(ulp), cmd));
> break;
>
> case O_TCPSEQ:
> match = (proto == IPPROTO_TCP && offset == 0 &&
> ((ipfw_insn_u32 *)cmd)->d[0] ==
> - L3HDR(struct tcphdr,ip)->th_seq);
> + TCP(ulp)->th_seq);
> break;
>
> case O_TCPACK:
> match = (proto == IPPROTO_TCP && offset == 0 &&
> ((ipfw_insn_u32 *)cmd)->d[0] ==
> - L3HDR(struct tcphdr,ip)->th_ack);
> + TCP(ulp)->th_ack);
> break;
>
> case O_TCPWIN:
> match = (proto == IPPROTO_TCP && offset == 0 &&
> - cmd->arg1 ==
> - L3HDR(struct tcphdr,ip)->th_win);
> + cmd->arg1 == TCP(ulp)->th_win);
> break;
>
> case O_ESTAB:
> /* reject packets which have SYN only */
> /* XXX should i also check for TH_ACK ? */
> match = (proto == IPPROTO_TCP && offset == 0 &&
> - (L3HDR(struct tcphdr,ip)->th_flags &
> + ( TCP(ulp)->th_flags &
> (TH_RST | TH_ACK | TH_SYN)) != TH_SYN);
> break;
>
> @@ -2203,8 +2432,12 @@
>
> case O_VERREVPATH:
> /* Outgoing packets automatically pass/match */
> - match = (hlen > 0 && ((oif != NULL) ||
> + /* XXX BED: verify_path was verify_rev_path in the diff... */
> + match = ((oif != NULL) ||
> (m->m_pkthdr.rcvif == NULL) ||
> + (is_ipv6 ?
> + verify_rev_path6(&(args->f_id.src_ip6),
> + m->m_pkthdr.rcvif) :
> verify_path(src_ip, m->m_pkthdr.rcvif)));
> break;
>
> @@ -2235,6 +2468,60 @@
> /* otherwise no match */
> break;
>
> + case O_IP6_SRC:
> + match = is_ipv6 &&
> + IN6_ARE_ADDR_EQUAL(&args->f_id.src_ip6,
> + &((ipfw_insn_ip6 *)cmd)->addr6);
> + break;
> +
> + case O_IP6_DST:
> + match = is_ipv6 &&
> + IN6_ARE_ADDR_EQUAL(&args->f_id.dst_ip6,
> + &((ipfw_insn_ip6 *)cmd)->addr6);
> + break;
> + case O_IP6_SRC_MASK:
> + if (is_ipv6) {
> + ipfw_insn_ip6 *te = (ipfw_insn_ip6 *)cmd;
> + struct in6_addr p = args->f_id.src_ip6;
> +
> + APPLY_MASK(&p, &te->mask6);
> + match = IN6_ARE_ADDR_EQUAL(&te->addr6, &p);
> + }
> + break;
> +
> + case O_IP6_DST_MASK:
> + if (is_ipv6) {
> + ipfw_insn_ip6 *te = (ipfw_insn_ip6 *)cmd;
> + struct in6_addr p = args->f_id.dst_ip6;
> +
> + APPLY_MASK(&p, &te->mask6);
> + match = IN6_ARE_ADDR_EQUAL(&te->addr6, &p);
> + }
> + break;
> +
> + case O_IP6_SRC_ME:
> + match= is_ipv6 && search_ip6_addr_net(&args->f_id.src_ip6);
> + break;
> +
> + case O_IP6_DST_ME:
> + match= is_ipv6 && search_ip6_addr_net(&args->f_id.dst_ip6);
> + break;
> +
> + case O_FLOW6ID:
> + match = is_ipv6 &&
> + flow6id_match(args->f_id.flow_id6,
> + (ipfw_insn_u32 *) cmd);
> + break;
> +
> + case O_EXT_HDR:
> + match = is_ipv6 &&
> + (ext_hd & ((ipfw_insn *) cmd)->arg1);
> + break;
> +
> + case O_IP6:
> + match = is_ipv6;
> + break;
> +
> /*
> * The second set of opcodes represents 'actions',
> * i.e. the terminal part of a rule once the packet
> @@ -2297,7 +2584,7 @@
> if (dyn_dir == MATCH_UNKNOWN &&
> (q = lookup_dyn_rule(&args->f_id,
> &dyn_dir, proto == IPPROTO_TCP ?
> - L3HDR(struct tcphdr, ip) : NULL))
> + TCP(ulp) : NULL))
> != NULL) {
> /*
> * Found dynamic entry, update stats
> @@ -2378,7 +2665,7 @@
> */
> if (hlen > 0 &&
> (proto != IPPROTO_ICMP ||
> - is_icmp_query(ip)) &&
> + is_icmp_query(ICMP(ulp))) &&
> !(m->m_flags & (M_BCAST|M_MCAST)) &&
> !IN_MULTICAST(ntohl(dst_ip.s_addr))) {
> send_reject(args, cmd->arg1,
> @@ -2859,6 +3146,10 @@
> case O_VERSRCREACH:
> case O_ANTISPOOF:
> case O_IPSEC:
> + case O_IP6_SRC_ME:
> + case O_IP6_DST_ME:
> + case O_EXT_HDR:
> + case O_IP6:
> if (cmdlen != F_INSN_SIZE(ipfw_insn))
> goto bad_size;
> break;
> @@ -2985,9 +3276,32 @@
> return EINVAL;
> }
> break;
> + case O_IP6_SRC:
> + case O_IP6_DST:
> + if (cmdlen != F_INSN_SIZE(struct in6_addr) +
> + F_INSN_SIZE(ipfw_insn))
> + goto bad_size;
> + break;
> +
> + case O_FLOW6ID:
> + if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
> + ((ipfw_insn_u32 *)cmd)->o.arg1)
> + goto bad_size;
> + break;
> +
> + case O_IP6_SRC_MASK:
> + case O_IP6_DST_MASK:
> + if ( !(cmdlen & 1) || cmdlen > 127)
> + goto bad_size;
> + break;
> + case O_ICMP6TYPE:
> + if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) )
> + goto bad_size;
> + break;
> +
> default:
> printf("ipfw: opcode %d, unknown opcode\n",
> - cmd->opcode);
> + cmd->opcode);
> return EINVAL;
> }
> }
> @@ -3379,7 +3693,7 @@
> }
>
> ip_fw_default_rule = layer3_chain.rules;
> - printf("ipfw2 initialized, divert %s, "
> + printf("ipfw2 (+ipv6) initialized, divert %s, "
> "rule-based forwarding "
> #ifdef IPFIREWALL_FORWARD
> "enabled, "
> --- ../cleanup/sys/netinet/ip_fw_pfil.c Fri Aug 27 15:18:18 2004
> +++ sys/netinet/ip_fw_pfil.c Thu Sep 2 22:37:05 2004
> @@ -31,6 +31,7 @@
> #include "opt_ipdn.h"
> #include "opt_ipdivert.h"
> #include "opt_inet.h"
> +#include "opt_inet6.h"
> #ifndef INET
> #error IPFIREWALL requires INET.
> #endif /* INET */
> @@ -111,7 +112,10 @@
> goto pass;
>
> if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) != 0) {
> - ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP_IN, &args);
> + if (mtod(*m0, struct ip *)->ip_v == 4)
> + ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP_IN, &args);
> + else if (mtod(*m0, struct ip *)->ip_v == 6)
> + ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP6_IN, &args);
> *m0 = NULL;
> return 0; /* packet consumed */
> }
> @@ -194,7 +198,10 @@
> goto pass;
>
> if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) != 0) {
> - ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP_OUT, &args);
> + if (mtod(*m0, struct ip *)->ip_v == 4)
> + ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP_OUT, &args);
> + else if (mtod(*m0, struct ip *)->ip_v == 6)
> + ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP6_OUT, &args);
> *m0 = NULL;
> return 0; /* packet consumed */
> }
> @@ -326,6 +333,9 @@
> ipfw_hook(void)
> {
> struct pfil_head *pfh_inet;
> +#ifdef INET6
> + struct pfil_head *pfh_inet6;
> +#endif
>
> if (ipfw_pfil_hooked)
> return EEXIST;
> @@ -333,9 +343,18 @@
> pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
> if (pfh_inet == NULL)
> return ENOENT;
> +#ifdef INET6
> + pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
> + if (pfh_inet6 == NULL)
> + return ENOENT;
> +#endif
>
> pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
> pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
> +#ifdef INET6
> + pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
> + pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
> +#endif
>
> return 0;
> }
> @@ -344,6 +363,9 @@
> ipfw_unhook(void)
> {
> struct pfil_head *pfh_inet;
> +#ifdef INET6
> + struct pfil_head *pfh_inet6;
> +#endif
>
> if (!ipfw_pfil_hooked)
> return ENOENT;
> @@ -351,9 +373,18 @@
> pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
> if (pfh_inet == NULL)
> return ENOENT;
> +#ifdef INET6
> + pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
> + if (pfh_inet6 == NULL)
> + return ENOENT;
> +#endif
>
> pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
> pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
> +#ifdef INET6
> + pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
> + pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
> +#endif
>
> return 0;
> }
>
> --
> Any statement of the form "X is the one, true Y" is FALSE.
> PGP fingerprint 655D 519C 26A7 82E7 2529 9BF0 5D8E 8BE9 F238 1AD4
>
> --------------------------------------------------------------------------------
> Part 1.2Type: application/pgp-signature
More information about the freebsd-ipfw
mailing list