Request for review: ipfw2 for IPV6
Luigi Rizzo
rizzo at icir.org
Sat Apr 24 03:45:04 PDT 2004
On Sat, Apr 24, 2004 at 07:13:38PM +0900, Jun Kuriyama wrote:
> At Wed, 14 Jan 2004 21:02:17 +0000 (UTC),
> Luigi Rizzo wrote:
> > I am attaching some very experimental (and only partly functional)
> > code to use ipfw2/dummynet with IPV6.
>
> Hi Luigi,
>
> I'd like to test this feature. Is there the latest version of your
> patch?
attached -- it was agains a -current of a week ago, so there might
be some minor conflicts in the patch due to a recent ipfw change
i actually plan to commit this to -current shortly.
cheers
luigi
diff -ubBri /myshare/cvsup/usr/src/sbin/ipfw/ipfw2.c ./sbin/ipfw/ipfw2.c
--- /myshare/cvsup/usr/src/sbin/ipfw/ipfw2.c Fri Apr 9 19:26:01 2004
+++ ./sbin/ipfw/ipfw2.c Wed Apr 21 12:48:06 2004
@@ -45,6 +45,8 @@
#include <sysexits.h>
#include <net/if.h>
+#include <net/route.h> /* def. of struct route */
+#include <netinet/icmp6.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
@@ -245,6 +247,13 @@
TOK_DROPTAIL,
TOK_PROTO,
TOK_WEIGHT,
+
+ TOK_IPV6,
+ TOK_FLOWID,
+ TOK_ICMP6TYPES,
+ TOK_EXT6HDR,
+ TOK_DSTIP6,
+ TOK_SRCIP6,
};
struct _s_x dummynet_params[] = {
@@ -267,6 +276,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 */
};
@@ -341,6 +357,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 */
@@ -828,6 +854,197 @@
}
}
+/* 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
@@ -846,6 +1063,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)
@@ -868,6 +1086,8 @@
return;
}
if ( !(*flags & HAVE_OPTIONS)) {
+ 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))
@@ -1108,6 +1328,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:
@@ -1119,13 +1370,14 @@
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;
+ if (proto != 41) /* XXX ipv6 is special */
pe = getprotobynumber(cmd->arg1);
if (flags & HAVE_OPTIONS)
printf(" proto");
@@ -1298,6 +1550,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);
@@ -1394,30 +1658,41 @@
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);
- for (l = 0; l < fs->rq_elements; l++) {
+
+ /*
+ * Do IPv4 stuff
+ */
+
+ for (l = 0; l < fs->rq_elements; l++)
+ 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);
+ 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);
@@ -1430,6 +1705,54 @@
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
@@ -1812,7 +2135,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)
@@ -1864,17 +2187,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} | 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\n"
+" verrevpath | icmp6types LIST | ext6hdr LIST |\n"
+" {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\n"
+" flow-id N[,N]\n"
);
exit(0);
}
@@ -2068,6 +2396,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
@@ -2185,7 +2734,6 @@
struct dn_pipe p;
int i;
char *end;
- uint32_t a;
void *par = NULL;
memset(&p, 0, sizeof p);
@@ -2247,16 +2795,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++;
@@ -2270,6 +2817,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;
@@ -2281,6 +2831,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;
@@ -2298,22 +2860,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);
+ /* convert to a mask for non IPv6 */
+ if (pa6 == NULL)
a = (a == 32) ? ~0 : (1 << a) - 1;
- } else
+ } 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");
+ "proto mask must be 8 bit");
p.fs.flow_mask.proto = (uint8_t)a;
}
if (a != 0)
@@ -2417,7 +2992,7 @@
break;
default:
- errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]);
+ errx(EX_DATAERR, "unrecognised option ``%s''", *av);
}
}
if (do_pipe == 1) {
@@ -2633,21 +3208,27 @@
}
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;
+ return cmd; /* special case for 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;
}
@@ -2694,6 +3275,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
@@ -2717,7 +3330,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;
@@ -2989,11 +3602,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);
@@ -3017,13 +3629,17 @@
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);
/*
@@ -3052,13 +3668,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);
/*
@@ -3164,6 +3784,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, "-,")) {
@@ -3340,8 +3966,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''",
@@ -3362,6 +3989,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)) ||
@@ -3408,6 +4049,23 @@
fill_comment(cmd, ac, av);
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:
diff -ubBri /myshare/cvsup/usr/src/sys/netinet/ip_dummynet.c ./sys/netinet/ip_dummynet.c
--- /myshare/cvsup/usr/src/sys/netinet/ip_dummynet.c Wed Mar 3 02:33:22 2004
+++ ./sys/netinet/ip_dummynet.c Wed Apr 21 13:01:30 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)
@@ -468,6 +471,15 @@
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
@@ -905,36 +917,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 */
+ 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 ;
@@ -1072,7 +1127,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);
@@ -1141,7 +1196,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,
@@ -1227,6 +1282,18 @@
fwa->dst = (struct sockaddr_in *)&(pkt->ro.ro_dst) ;
pkt->dn_dst = fwa->dst;
pkt->flags = fwa->flags;
+ } else if (dir == DN_TO_IP6_OUT) {
+ pkt->ip6opt.ro_or = fwa->dummypar.ro_or;
+ pkt->ip6opt.flags_or = fwa->dummypar.flags_or;
+ pkt->ip6opt.origifp_or = fwa->dummypar.origifp_or;
+ pkt->ip6opt.ifp_or = fwa->dummypar.ifp_or;
+ pkt->ip6opt.dst_or = fwa->dummypar.dst_or;
+ if (pkt->ip6opt.ro_or.ro_rt) { /* XXX is it correct? */
+ RT_LOCK(pkt->ip6opt.ro_or.ro_rt);
+ RT_ADDREF(pkt->ip6opt.ro_or.ro_rt);
+ RT_UNLOCK(pkt->ip6opt.ro_or.ro_rt);
+ }
+ pkt->flags = fwa->flags;
}
if (q->head == NULL)
q->head = m;
@@ -1325,6 +1392,7 @@
*/
#define DN_FREE_PKT(_m) do { \
rt_unref(dn_tag_get(_m)->ro.ro_rt, __func__); \
+ rt_unref(dn_tag_get(_m)->ip6opt.ro_or.ro_rt, __func__); \
m_freem(_m); \
} while (0)
@@ -2018,7 +2086,7 @@
ip_dn_init(void)
{
if (bootverbose)
- printf("DUMMYNET initialized (011031)\n");
+ printf("DUMMYNET with IPv6 initialized (040114)\n");
DUMMYNET_LOCK_INIT();
diff -ubBri /myshare/cvsup/usr/src/sys/netinet/ip_dummynet.h ./sys/netinet/ip_dummynet.h
--- /myshare/cvsup/usr/src/sys/netinet/ip_dummynet.h Wed Feb 25 20:55:28 2004
+++ ./sys/netinet/ip_dummynet.h Tue Apr 20 17:13:20 2004
@@ -124,12 +124,15 @@
#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 */
struct sockaddr_in *dn_dst ;
struct route ro; /* route, for ip_output. MUST COPY */
int flags ; /* flags, for ip_output (IPv6 ?) */
+ struct _ip6dn_args ip6opt; /* XXX ipv6 options */
};
#endif /* _KERNEL */
diff -ubBri /myshare/cvsup/usr/src/sys/netinet/ip_fw.h ./sys/netinet/ip_fw.h
--- /myshare/cvsup/usr/src/sys/netinet/ip_fw.h Wed Feb 25 20:55:28 2004
+++ ./sys/netinet/ip_fw.h Tue Apr 20 17:12:48 2004
@@ -126,10 +126,32 @@
*/
O_IPSEC, /* has ipsec history */
+ 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,
@@ -265,6 +287,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.
*
@@ -327,8 +373,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.
*/
@@ -384,6 +436,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.
@@ -401,6 +468,8 @@
struct ipfw_flow_id f_id; /* grabbed from IP header */
u_int32_t retval;
+
+ struct _ip6dn_args dummypar; /* dummynet->ip6_output */
};
/*
diff -ubBri /myshare/cvsup/usr/src/sys/netinet/ip_fw2.c ./sys/netinet/ip_fw2.c
--- /myshare/cvsup/usr/src/sys/netinet/ip_fw2.c Wed Feb 25 20:55:28 2004
+++ ./sys/netinet/ip_fw2.c Wed Apr 21 14:16:20 2004
@@ -79,6 +79,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 */
@@ -261,15 +264,19 @@
ip_dn_ruledel_t *ip_dn_ruledel_ptr = NULL; /* hook into dummynet */
/*
- * 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 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)) );
}
@@ -277,9 +284,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
@@ -355,10 +363,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);
@@ -476,6 +483,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...) */
@@ -679,7 +763,9 @@
{
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;
}
@@ -818,6 +904,27 @@
}
if (pkt->proto == q->id.proto &&
q->dyn_type != O_LIMIT_PARENT) {
+ 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 (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 &&
@@ -833,6 +940,7 @@
break;
}
}
+ }
next:
prev = q;
q = q->next;
@@ -1028,15 +1136,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;
@@ -1110,10 +1228,17 @@
id.dst_port = id.src_port = 0;
id.proto = args->f_id.proto;
+ 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)
@@ -1455,34 +1580,151 @@
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;
+ proto = args->f_id.proto = 0; /* mark f_id invalid */
+
+ /* 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;
+
+ /*
+ * 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;
+
+ 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 *);
- 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;
+ args->f_id.addr_type = 4;
/*
* 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;
- }
- proto = args->f_id.proto = ip->ip_p;
+ 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 */
@@ -1494,60 +1736,42 @@
}
pktlen = ip_len < pktlen ? ip_len : pktlen;
-#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)
-
if (offset == 0) {
switch (proto) {
case IPPROTO_TCP:
- {
- struct tcphdr *tcp;
-
- 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;
- }
+ 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:
- {
- struct udphdr *udp;
-
- PULLUP_TO(hlen + sizeof(struct udphdr));
- udp = L3HDR(struct udphdr, ip);
- dst_port = udp->uh_dport;
- src_port = udp->uh_sport;
- }
+ 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;
+ /* 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;
}
-#undef PULLUP_TO
}
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);
-
-after_ip_checks:
+ }
IPFW_LOCK(chain); /* XXX expensive? can we run lock free? */
mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL);
if (args->rule) {
/*
* Packet has already been tagged. Look for the next rule
@@ -1650,11 +1875,13 @@
case O_UID:
/*
* 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(
@@ -1708,7 +1935,7 @@
break;
case O_FRAG:
- match = (hlen > 0 && offset != 0);
+ match = (offset != 0);
break;
case O_IN: /* "out" is "not in" */
@@ -1793,7 +2020,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)
@@ -1813,15 +2040,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:
@@ -1835,9 +2072,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;
@@ -1852,48 +2089,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;
@@ -1909,8 +2144,11 @@
case O_VERREVPATH:
/* Outgoing packets automatically pass/match */
- match = ((oif != NULL) ||
+ match = (oif != NULL) ||
(m->m_pkthdr.rcvif == NULL) ||
+ (is_ipv6 ?
+ verify_rev_path6(&(args->f_id.src_ip6),
+ m->m_pkthdr.rcvif) :
verify_rev_path(src_ip, m->m_pkthdr.rcvif));
break;
@@ -1925,6 +2163,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
@@ -1987,7 +2279,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
@@ -2068,7 +2360,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,
@@ -2547,6 +2839,10 @@
case O_ESTAB:
case O_VERREVPATH:
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;
@@ -2660,6 +2956,29 @@
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);
@@ -2969,7 +3288,7 @@
}
ip_fw_default_rule = layer3_chain.rules;
- printf("ipfw2 initialized, divert %s, "
+ printf("ipfw2 (+ipv6) initialized, divert %s, "
"rule-based forwarding enabled, default to %s, logging ",
#ifdef IPDIVERT
"enabled",
diff -ubBri /myshare/cvsup/usr/src/sys/netinet6/ip6_input.c ./sys/netinet6/ip6_input.c
--- /myshare/cvsup/usr/src/sys/netinet6/ip6_input.c Wed Apr 7 22:46:15 2004
+++ ./sys/netinet6/ip6_input.c Tue Apr 20 17:16:03 2004
@@ -61,7 +61,7 @@
* @(#)ip_input.c 8.2 (Berkeley) 1/4/94
*/
-#include "opt_ip6fw.h"
+#include "opt_ipfw.h"
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
@@ -126,6 +126,14 @@
#include <net/net_osdep.h>
+#include <netinet/ip_fw.h>
+#ifdef IPFW2
+#include <netinet/ip_dummynet.h>
+#include <netinet/ip_var.h>
+#endif
+
+extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **));
+
extern struct domain inet6domain;
u_char ip6_protox[IPPROTO_MAX];
@@ -248,6 +257,25 @@
int srcrt = 0;
GIANT_REQUIRED; /* XXX for now */
+
+#ifdef IPFW2
+ int i, hlen;
+ struct ip_fw_args args;
+ args.eh = NULL;
+ args.oif = NULL;
+
+ M_ASSERTPKTHDR(m);
+
+ args.next_hop = ip_claim_next_hop(m);
+ args.rule = ip_dn_claim_rule(m);
+
+ if (args.rule) { /* dummynet already filtered us */
+ ip6 = mtod(m, struct ip6_hdr *);
+ hlen = sizeof (struct ip6_hdr);
+ goto iphack6 ;
+ }
+#endif /* IPFW2 */
+
#ifdef IPSEC
/*
* should the inner packet be considered authentic?
@@ -365,7 +393,9 @@
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr);
goto bad;
}
-
+#ifdef IPFW2
+iphack6:
+#endif
/*
* The following check is not documented in specs. A malicious
* party may be able to use IPv4 mapped addr to confuse tcp/udp stack
@@ -451,6 +481,52 @@
if (!m)
return;
}
+#ifdef IPFW2
+ /* now check with the firewall ipfw2 */
+
+ if (fw_enable && IPFW_LOADED) {
+ /*
+ * If we've been forwarded from the output side, then
+ * skip the firewall a second time
+ */
+
+ if (args.next_hop)
+ ours=1; /* Non sappiamo che vuol dire qui */
+
+ args.m = m;
+ i = ip_fw_chk_ptr(&args);
+ m = args.m;
+
+ if ( (i & IP_FW_PORT_DENY_FLAG) || m == NULL) { /* drop */
+ if (m)
+ m_freem(m);
+ return;
+ }
+ ip6 = mtod(m, struct ip6_hdr *); /* just in case m changed */
+ if (i == 0 && args.next_hop == NULL) /* common case */
+ goto pass6;
+ if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG) != 0) {
+ /* Send packet to the appropriate pipe */
+ ip_dn_io_ptr(m, i & 0xffff, DN_TO_IP6_IN, &args);
+ return;
+ }
+#ifdef IPDIVERT
+ if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) {
+ /* Divert or tee packet */
+ divert_info = i;
+ ours=1;
+ }
+#endif
+ if (i == 0 && args.next_hop != NULL)
+ goto pass6;
+ /*
+ * if we get here, the packet must be dropped
+ */
+ m_freem(m);
+ return;
+ }
+pass6:
+#endif /* IPFW2 */
/*
* construct source and destination address structures with
diff -ubBri /myshare/cvsup/usr/src/sys/netinet6/ip6_output.c ./sys/netinet6/ip6_output.c
--- /myshare/cvsup/usr/src/sys/netinet6/ip6_output.c Wed Apr 7 22:46:15 2004
+++ ./sys/netinet6/ip6_output.c Tue Apr 20 17:16:14 2004
@@ -61,7 +61,7 @@
* @(#)ip_output.c 8.3 (Berkeley) 1/21/94
*/
-#include "opt_ip6fw.h"
+#include "opt_ipfw.h"
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
@@ -109,8 +109,13 @@
#include <netipsec/key.h>
#endif /* FAST_IPSEC */
-#include <netinet6/ip6_fw.h>
+#include <netinet/ip_fw.h>
+#ifdef IPFW2
+#include <netinet/ip_var.h>
+#include <netinet/ip_dummynet.h>
+#endif
+#include <netinet6/ip6_fw.h>
#include <net/net_osdep.h>
#include <netinet6/ip6protosw.h>
@@ -166,11 +171,11 @@
struct inpcb *inp;
{
struct ip6_hdr *ip6, *mhip6;
- struct ifnet *ifp, *origifp;
+ struct ifnet *ifp = NULL, *origifp;
struct mbuf *m = m0;
int hlen, tlen, len, off;
struct route_in6 ip6route;
- struct sockaddr_in6 *dst;
+ struct sockaddr_in6 *dst = NULL;
int error = 0;
struct in6_ifaddr *ia = NULL;
u_long mtu;
@@ -181,6 +186,11 @@
struct route_in6 *ro_pmtu = NULL;
int hdrsplit = 0;
int needipsec = 0;
+#ifdef IPFW2
+ struct ip_fw_args args;
+ struct m_tag *dummytag;
+#endif
+
#if defined(IPSEC) || defined(FAST_IPSEC)
int needipsectun = 0;
struct secpolicy *sp = NULL;
@@ -188,6 +198,46 @@
ip6 = mtod(m, struct ip6_hdr *);
finaldst = ip6->ip6_dst;
+#ifdef IPFW2
+ args.eh = NULL;
+ args.rule = NULL; /* divert cookie */
+
+ M_ASSERTPKTHDR(m);
+
+ args.rule = ip_dn_claim_rule(m);
+
+ dummytag = m_tag_find(m, PACKET_TAG_DUMMYNET, NULL);
+ if (dummytag != NULL) {
+ struct dn_pkt_tag *dt = (struct dn_pkt_tag *)(dummytag+1);
+ /*
+ * Prevent lower layers from finding the tag
+ * Cleanup and free is done below
+ */
+ m_tag_unlink(m, dummytag);
+ /*
+ * the packet was already tagged, so part of the
+ * processing was already done, and we need to go down.
+ * Get parameters from the header.
+ */
+ args.rule = dt->rule;
+ opt = NULL;
+ ro = &dt->ip6opt.ro_or;
+ flags = dt->ip6opt.flags_or;
+ im6o = NULL;
+ origifp = dt->ip6opt.origifp_or;
+ ifp = dt->ip6opt.ifp_or;
+ dst = &dt->ip6opt.dst_or;
+ }
+ if (args.rule ) { /* dummynet already saw us */
+ ip6 = mtod(m, struct ip6_hdr *);
+ hlen = sizeof (struct ip6_hdr) ;
+ if (ro->ro_rt)
+ ia = ifatoia6(ro->ro_rt->rt_ifa);
+ bzero(&exthdrs, sizeof(exthdrs));
+ ro_pmtu = ro;
+ goto send_after_dummynet;
+ }
+#endif /* IPFW2 */
#define MAKE_EXTHDR(hp, mp) \
do { \
@@ -812,7 +862,9 @@
*/
if (ifpp)
*ifpp = ifp;
-
+#ifdef IPFW2
+send_after_dummynet:
+#endif
/* Determine path MTU. */
if ((error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu,
&alwaysfrag)) != 0)
@@ -890,6 +942,70 @@
/*
* Check with the firewall...
*/
+#ifdef IPFW2
+ if (fw_enable && IPFW_LOADED && !args.next_hop) {
+ /*
+ * Check with the firewall IPFW2...
+ * but not if we are already being fwd'd from a firewall.
+ */
+
+ struct sockaddr_in6 *old = dst;
+ args.m = m;
+ args.next_hop = (struct sockaddr_in *) dst;
+ args.oif = ifp;
+ off = ip_fw_chk_ptr(&args);
+ m = args.m;
+ dst = (struct sockaddr_in6 *) args.next_hop;
+
+ /*
+ * On return we must do the following:
+ * m == NULL -> drop the pkt (old interface, deprecated)
+ * (off & IP_FW_PORT_DENY_FLAG) -> drop the pkt (new interface)
+ * 1<=off<= 0xffff -> DIVERT
+ * (off & IP_FW_PORT_DYNT_FLAG) -> send to a DUMMYNET pipe
+ * (off & IP_FW_PORT_TEE_FLAG) -> TEE the packet
+ * dst != old -> IPFIREWALL_FORWARD
+ * off==0, dst==old -> accept
+ * If some of the above modules are not compiled in, then
+ * we should't have to check the corresponding condition
+ * (because the ipfw control socket should not accept
+ * unsupported rules), but better play safe and drop
+ * packets in case of doubt.
+ */
+ if ( (off & IP_FW_PORT_DENY_FLAG) || m == NULL) {
+ if (m)
+ m_freem(m);
+ error = EACCES;
+ goto done;
+ }
+ ip6 = mtod(m, struct ip6_hdr *); /* XXX check if necessary */
+ if (off == 0 && dst == old) /* common case */
+ goto pass6;
+ if (DUMMYNET_LOADED && (off & IP_FW_PORT_DYNT_FLAG) != 0) {
+ /*
+ * pass the pkt to dummynet. Need to include
+ * pipe number, m, ifp, ro, dst because these are
+ * not recomputed in the next pass.
+ * All other parameters have been already used and
+ * so they are not needed anymore.
+ * XXX note: if the ifp or ro entry are deleted
+ * while a pkt is in dummynet, we are in trouble!
+ */
+ args.dummypar.ro_or = *ro;
+ args.dummypar.flags_or = flags;
+ args.dummypar.ifp_or = ifp;
+ args.dummypar.origifp_or = origifp;
+ args.dummypar.dst_or = *dst;
+ args.flags = flags;
+if (args.rule != NULL)
+ error = ip_dn_io_ptr(m, off & 0xffff, DN_TO_IP6_OUT,
+ &args);
+ goto done;
+ }
+ }
+pass6:
+#endif /*IPFW2 */
+
if (ip6_fw_enable && ip6_fw_chk_ptr) {
u_short port = 0;
m->m_pkthdr.rcvif = NULL; /* XXX */
More information about the freebsd-ipfw
mailing list