From owner-freebsd-ipfw@FreeBSD.ORG Sun Sep 5 23:10:00 2004 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id ED9F016A4CF for ; Sun, 5 Sep 2004 23:09:59 +0000 (GMT) Received: from c00l3r.networx.ch (c00l3r.networx.ch [62.48.2.2]) by mx1.FreeBSD.org (Postfix) with ESMTP id 72EAB43D2F for ; Sun, 5 Sep 2004 23:09:58 +0000 (GMT) (envelope-from andre@freebsd.org) Received: (qmail 26869 invoked from network); 5 Sep 2004 23:06:56 -0000 Received: from unknown (HELO freebsd.org) ([62.48.0.54]) (envelope-sender ) by c00l3r.networx.ch (qmail-ldap-1.03) with SMTP for ; 5 Sep 2004 23:06:55 -0000 Message-ID: <413B9CC5.21E7B776@freebsd.org> Date: Mon, 06 Sep 2004 01:09:57 +0200 From: Andre Oppermann X-Mailer: Mozilla 4.8 [en] (Windows NT 5.0; U) X-Accept-Language: en MIME-Version: 1.0 To: Brooks Davis References: <20040903215137.GA26762@odin.ac.hmc.edu> Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit cc: freebsd-ipfw@freebsd.org Subject: Re: ipfw2 for IPV6 X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 05 Sep 2004 23:10:00 -0000 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 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 > > #include > +#include /* def. of struct route */ > #include > #include > #include > #include > +#include > #include > #include > #include > @@ -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 /* for struct arpcom */ > #include > > +#include /* for ip6_input, ip6_output prototypes */ > +#include > + > /* > * 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 > #endif > > +#include > +#include > + > #include /* XXX for ETHERTYPE_IP */ > > #include /* 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< } > @@ -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< } > #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