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