Add IPv6 support to IPFW and Dummynet.

Submitted by:	Mariano Tortoriello and Raffaele De Lorenzo (via luigi)
This commit is contained in:
Brooks Davis 2005-04-18 18:35:05 +00:00
parent a87b3988c9
commit 8195404bed
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=145246
8 changed files with 1351 additions and 113 deletions

View File

@ -346,18 +346,18 @@ in the protocol stack, under control of several sysctl variables.
These places and variables are shown below, and it is important to
have this picture in mind in order to design a correct ruleset.
.Bd -literal -offset indent
^ to upper layers V
| |
+----------->-----------+
^ V
[ip_input] [ip_output] net.inet.ip.fw.enable=1
| |
^ V
[ether_demux] [ether_output_frame] net.link.ether.ipfw=1
| |
+-->--[bdg_forward]-->--+ net.link.ether.bridge_ipfw=1
^ V
| to devices |
^ to upper layers V
| |
+----------->-----------+
^ V
[ip(6)_input] [ip(6)_output] net.inet.ip.fw.enable=1
| |
^ V
[ether_demux] [ether_output_frame] net.link.ether.ipfw=1
| |
+-->--[bdg_forward]-->--+ net.link.ether.bridge_ipfw=1
^ V
| to devices |
.Ed
.Pp
As can be noted from the above picture, the number of
@ -375,13 +375,17 @@ is invoked from
but the same packets will have the MAC header stripped off when
.Nm
is invoked from
.Cm ip_input() .
.Cm ip_input()
or
.Cm ip6_input() .
.Pp
Also note that each packet is always checked against the complete ruleset,
irrespective of the place where the check occurs, or the source of the packet.
If a rule contains some match patterns or actions which are not valid
for the place of invocation (e.g.\& trying to match a MAC header within
.Fn ip_input ) ,
.Cm ip_input
or
.Cm ip6_input ),
the match pattern will not match, but a
.Cm not
operator in front of such patterns
@ -448,7 +452,7 @@ for filtering packets, among the following:
.Bl -tag -width "Source and dest. addresses and ports" -offset XXX -compact
.It Layer-2 header fields
When available
.It IPv4 Protocol
.It IPv4 and IPv6 Protocol
TCP, UDP, ICMP, etc.
.It Source and dest. addresses and ports
.It Direction
@ -461,6 +465,10 @@ Version, type of service, datagram length, identification,
fragment flag (non-zero IP offset),
Time To Live
.It IP options
.It IPv6 Extension headers
Fragmentation, Hop-by-Hop options,
source routing, IPSec options.
.It IPv6 Flow-ID
.It Misc. TCP header fields
TCP flags (SYN, FIN, ACK, RST, etc.),
sequence number, acknowledgment number,
@ -468,6 +476,8 @@ window
.It TCP options
.It ICMP types
for ICMP packets
.It ICMP6 types
for ICMP6 packets
.It User/group ID
When the packet can be associated with a local socket.
.It Divert status
@ -806,7 +816,7 @@ compatibility with
.Nm ipfw1 .
In
.Nm ipfw2
any match pattern (including MAC headers, IPv4 protocols,
any match pattern (including MAC headers, IP protocols,
addresses and ports) can be specified in the
.Ar options
section.
@ -815,11 +825,13 @@ Rule fields have the following meaning:
.Bl -tag -width indent
.It Ar proto : protocol | Cm { Ar protocol Cm or ... }
.It Ar protocol : Oo Cm not Oc Ar protocol-name | protocol-number
An IPv4 protocol specified by number or name
An IP protocol specified by number or name
(for a complete list see
.Pa /etc/protocols ) .
The
.Cm ip
.Cm ip ,
.Cm ip6 ,
.Cm ipv6 ,
or
.Cm all
keywords mean any protocol will match.
@ -840,7 +852,7 @@ The second format
with multiple addresses) is provided for convenience only and
its use is discouraged.
.It Ar addr : Oo Cm not Oc Bro
.Cm any | me |
.Cm any | me | me6
.Cm table Ns Pq Ar number Ns Op , Ns Ar value
.Ar | addr-list | addr-set
.Brc
@ -848,10 +860,12 @@ its use is discouraged.
matches any IP address.
.It Cm me
matches any IP address configured on an interface in the system.
.It Cm me6
matches any IPv6 address configured on an interface in the system.
The address list is evaluated at the time the packet is
analysed.
.It Cm table Ns Pq Ar number Ns Op , Ns Ar value
Matches any IP address for which an entry exists in the lookup table
Matches any IPv4 address for which an entry exists in the lookup table
.Ar number .
If an optional 32-bit unsigned
.Ar value
@ -918,6 +932,30 @@ As an example, an address specified as 1.2.3.4/24{128,35-55,89}
will match the following IP addresses:
.br
1.2.3.128, 1.2.3.35 to 1.2.3.55, 1.2.3.89 .
.It Ar addr6-list : ip6-addr Ns Op Ns , Ns Ar addr6-list
.It Ar ip6-addr :
A host or subnet specified one of the following ways:
.Pp
.Bl -tag -width indent
.It Ar numeric-ip | hostname
Matches a single IPv6 address as allowed by
.Xr inet_pton 3
or a hostname.
Hostnames are resolved at the time the rule is added to the firewall
list.
.It Ar addr Ns / Ns Ar masklen
Matches all IPv6 addresses with base
.Ar addr
(specified as allowed by
.Xr inet_pton
or a hostname)
and mask width of
.Cm masklen
bits.
.El
.Pp
No support for sets of IPv6 addresses is provided because IPv6 addresses
are typically random past the initial prefix.
.It Ar ports : Bro Ar port | port Ns \&- Ns Ar port Ns Brc Ns Op , Ns Ar ports
For protocols which support port numbers (such as TCP and UDP), optional
.Cm ports
@ -986,13 +1024,36 @@ input for delivery.
Matches only packets going from a divert socket back outward to the IP
stack output for delivery.
.It Cm dst-ip Ar ip-address
Matches IP packets whose destination IP is one of the address(es)
Matches IPv4 packets whose destination IP is one of the address(es)
specified as argument.
.It Bro Cm dst-ip6 | dst-ipv6 Brc Ar ip6-address
Matches IPv6 packets whose destination IP is one of the address(es)
specified as argument.
.It Cm dst-port Ar ports
Matches IP packets whose destination port is one of the port(s)
specified as argument.
.It Cm established
Matches TCP packets that have the RST or ACK bits set.
.It Cm ext6hdr Ar header
Matches IPv6 packets containing the extended header given by
.Ar header .
Supported headers are:
.Pp
Fragment,
.Pq Cm frag ,
Hop-to-hop options
.Pq Cm hopopt ,
Source routing
.Pq Cm route ,
IPSec authentication headers
.Pq Cm ah ,
and IPSec encapsulated security payload headers
.Pq Cm esp .
.It Cm flow-id Ar labels
Matches IPv6 packets containing any of the flow labels given in
.Ar labels .
.Ar labels
is a comma seperate list of numeric flow labels.
.It Cm frag
Matches packets that are fragments and not the first
fragment of an IP datagram.
@ -1047,6 +1108,12 @@ address mask request
.Pq Cm 17
and address mask reply
.Pq Cm 18 .
.It Cm icmp6types Ar types
Matches ICMP6 packets whose ICMP6 type is in the list of
.Ar types .
The list may be specified as any combination of
individual types (numeric) separated by commas.
.Em Ranges are not allowed.
.It Cm in | out
Matches incoming or outgoing packets, respectively.
.Cm in
@ -1057,7 +1124,7 @@ are mutually exclusive (in fact,
is implemented as
.Cm not in Ns No ).
.It Cm ipid Ar id-list
Matches IP packets whose
Matches IPv4 packets whose
.Cm ip_id
field has value included in
.Ar id-list ,
@ -1072,7 +1139,7 @@ which is either a single value or a list of values or ranges
specified in the same way as
.Ar ports .
.It Cm ipoptions Ar spec
Matches packets whose IP header contains the comma separated list of
Matches packets whose IPv4 header contains the comma separated list of
options specified in
.Ar spec .
The supported IP options are:
@ -1089,7 +1156,7 @@ The absence of a particular option may be denoted
with a
.Ql \&! .
.It Cm ipprecedence Ar precedence
Matches IP packets whose precedence field is equal to
Matches IPv4 packets whose precedence field is equal to
.Ar precedence .
.It Cm ipsec
Matches packets that have IPSEC history associated with them
@ -1111,7 +1178,7 @@ rules are handled as if with no
.Cm ipsec
flag.
.It Cm iptos Ar spec
Matches IP packets whose
Matches IPv4 packets whose
.Cm tos
field contains the comma separated list of
service types specified in
@ -1132,7 +1199,7 @@ The absence of a particular type may be denoted
with a
.Ql \&! .
.It Cm ipttl Ar ttl-list
Matches IP packets whose time to live is included in
Matches IPv4 packets whose time to live is included in
.Ar ttl-list ,
which is either a single value or a list of values or ranges
specified in the same way as
@ -1160,6 +1227,8 @@ set of parameters as specified in the rule.
One or more
of source and destination addresses and ports can be
specified.
Currently,
only IPv4 flows are supported.
.It Cm { MAC | mac } Ar dst-mac src-mac
Match packets with a given
.Ar dst-mac
@ -1212,7 +1281,7 @@ and they are always printed as hexadecimal (unless the
.Cm -N
option is used, in which case symbolic resolution will be attempted).
.It Cm proto Ar protocol
Matches packets with the corresponding IPv4 protocol.
Matches packets with the corresponding IP protocol.
.It Cm recv | xmit | via Brq Ar ifX | Ar if Ns Cm * | Ar ipno | Ar any
Matches packets received, transmitted or going through,
respectively, the interface specified by exact name
@ -1260,8 +1329,11 @@ Matches TCP packets that have the SYN bit set but no ACK bit.
This is the short form of
.Dq Li tcpflags\ syn,!ack .
.It Cm src-ip Ar ip-address
Matches IP packets whose source IP is one of the address(es)
specified as argument.
Matches IPv4 packets whose source IP is one of the address(es)
specified as an argument.
.It Cm src-ip6 Ar ip6-address
Matches IPv6 packets whose source IP is one of the address(es)
specified as an argument.
.It Cm src-port Ar ports
Matches IP packets whose source port is one of the port(s)
specified as argument.
@ -1388,7 +1460,7 @@ connected networks instead of all source addresses.
.Sh LOOKUP TABLES
Lookup tables are useful to handle large sparse address sets,
typically from a hundred to several thousands of entries.
There could be 128 different lookup tables, numbered 0 to 127.
There may be up to 128 different lookup tables, numbered 0 to 127.
.Pp
Each entry is represented by an
.Ar addr Ns Op / Ns Ar masklen
@ -1422,6 +1494,8 @@ or flushed
Internally, each table is stored in a Radix tree, the same way as
the routing table (see
.Xr route 4 ) .
.Pp
Lookup tables currently support IPv4 addresses only.
.Sh SETS OF RULES
Each rule belongs to one of 32 different
.Em sets
@ -1694,9 +1768,12 @@ with different weights might be connected to the same pipe).
Available mask specifiers are a combination of one or more of the following:
.Pp
.Cm dst-ip Ar mask ,
.Cm dst-ip6 Ar mask ,
.Cm src-ip Ar mask ,
.Cm src-ip6 Ar mask ,
.Cm dst-port Ar mask ,
.Cm src-port Ar mask ,
.Cm flow-id Ar mask ,
.Cm proto Ar mask
or
.Cm all ,
@ -1767,6 +1844,14 @@ specifies the expected maximum packet size, only used when queue
thresholds are in bytes (defaults to 1500, must be greater than zero).
.El
.El
.Pp
When used with IPv6 data, dummynet currently has several limitations.
First, debug.mpsafenet=0 must be set.
Second, the information necessicary to route link-local packets to an
interface is not avalable after processing by dummynet so those packets
are dropped in the output path.
Care should be taken to insure that link-local packets are not passed to
dummynet.
.Sh CHECKLIST
Here are some important points to consider when designing your
rules:
@ -2092,6 +2177,9 @@ The following option for
.Nm dummynet
pipes/queues is not supported:
.Cm noerror .
.It IPv6 Support
There was no IPv6 support in
.Nm ipfw1 .
.El
.Sh EXAMPLES
There are far too many possible uses of
@ -2396,6 +2484,8 @@ Work on
.Xr dummynet 4
traffic shaper supported by Akamba Corp.
.Sh BUGS
Use of dummynet with IPv6 requires that debug.mpsafenet be set to 0.
.Pp
The syntax has grown over the years and sometimes it might be confusing.
Unfortunately, backward compatibility prevents cleaning up mistakes
made in the definition of the syntax.
@ -2424,3 +2514,5 @@ If a packet is reinserted in this manner, later rules may be incorrectly
applied, making the order of
.Cm divert
rules in the rule sequence very important.
.Pp
Dummynet drops all packets with IPv6 link-local addresses.

View File

@ -49,10 +49,12 @@
#include <net/if.h>
#include <net/pfvar.h>
#include <net/route.h> /* def. of struct route */
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
#include <netinet/ip_fw.h>
#include <netinet/ip_dummynet.h>
#include <netinet/tcp.h>
@ -266,6 +268,13 @@ enum tokens {
TOK_DROPTAIL,
TOK_PROTO,
TOK_WEIGHT,
TOK_IPV6,
TOK_FLOWID,
TOK_ICMP6TYPES,
TOK_EXT6HDR,
TOK_DSTIP6,
TOK_SRCIP6,
};
struct _s_x dummynet_params[] = {
@ -288,6 +297,11 @@ struct _s_x dummynet_params[] = {
{ "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 */
};
@ -375,6 +389,16 @@ struct _s_x rule_options[] = {
{ "versrcreach", TOK_VERSRCREACH },
{ "antispoof", TOK_ANTISPOOF },
{ "ipsec", TOK_IPSEC },
{ "icmp6type", TOK_ICMP6TYPES },
{ "icmp6types", TOK_ICMP6TYPES },
{ "ext6hdr", TOK_EXT6HDR},
{ "flow-id", TOK_FLOWID},
{ "ipv6", TOK_IPV6},
{ "ip6", TOK_IPV6},
{ "dst-ipv6", TOK_DSTIP6},
{ "dst-ip6", TOK_DSTIP6},
{ "src-ipv6", TOK_SRCIP6},
{ "src-ip6", TOK_SRCIP6},
{ "//", TOK_COMMENT },
{ "not", TOK_NOT }, /* pseudo option */
@ -1025,6 +1049,199 @@ print_icmptypes(ipfw_insn_u32 *cmd)
}
}
/*
* 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");
/*
* XXX: shouldn't this be 0xFF? I can't see any reason why
* we shouldn't be able to filter all possiable values
* regardless of the ability of the rest of the kernel to do
* anything useful with them.
*/
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 header" );
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);
}
}
/*
* show_ipfw() prints the body of an ipfw rule.
* Because the standard rule has at least proto src_ip dst_ip, we use
@ -1043,6 +1260,7 @@ print_icmptypes(ipfw_insn_u32 *cmd)
#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)
@ -1065,6 +1283,9 @@ show_prerequisites(int *flags, int want, int cmd)
return;
}
if ( !(*flags & HAVE_OPTIONS)) {
/* XXX BED: !(*flags & HAVE_PROTO) in patch */
if ( !(*flags & HAVE_PROTO6) && (want & HAVE_PROTO6))
printf(" ipv6");
if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO))
printf(" ip");
if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP))
@ -1329,6 +1550,37 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
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:
@ -1340,14 +1592,15 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
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)
@ -1558,6 +1811,18 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
}
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);
@ -1655,29 +1920,48 @@ static void
list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
{
int l;
int index_printed, indexes = 0;
char buff[255];
struct protoent *pe;
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);
/* Print IPv4 flows */
index_printed = 0;
for (l = 0; l < fs->rq_elements; l++) {
struct in_addr ina;
struct protoent *pe;
ina.s_addr = htonl(q[l].id.src_ip);
/* XXX: Should check for IPv4 flows */
if (IS_IP6_FLOW_ID(&(q[l].id)))
continue;
if (!index_printed) {
index_printed = 1;
if (indexes > 0) /* currently a no-op */
printf("\n");
indexes++;
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);
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);
@ -1690,6 +1974,50 @@ list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
printf(" S %20qd F %20qd\n",
q[l].S, q[l].F);
}
/* Print IPv6 flows */
index_printed = 0;
for (l = 0; l < fs->rq_elements; l++) {
if (!IS_IP6_FLOW_ID(&(q[l].id)))
continue;
if (!index_printed) {
index_printed = 1;
if (indexes > 0)
printf("\n");
indexes++;
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 != NULL)
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);
}
}
static void
@ -2082,7 +2410,7 @@ list(int ac, char *av[], int show_counters)
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)
@ -2132,19 +2460,24 @@ help(void)
"table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n"
"\n"
"RULE-BODY: check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\n"
"ACTION: check-state | allow | count | deny | reject | skipto N |\n"
"ACTION: check-state | allow | count | deny | unreach CODE | skipto N |\n"
" {divert|tee} PORT | forward ADDR | pipe N | queue N\n"
"PARAMS: [log [logamount LOGLIMIT]] [altq QUEUE_NAME]\n"
"ADDR: [ MAC dst src ether_type ] \n"
" [ from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
" [ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
" [ ipv6|ip6 from IP6ADDR [ PORT ] to IP6ADDR [ PORTLIST ] ]\n"
"IPADDR: [not] { any | me | ip/bits{x,y,z} | table(t[,v]) | IPLIST }\n"
"IP6ADDR: [not] { any | me | me6 | ip6/bits | IP6LIST }\n"
"IP6LIST: { ip6 | ip6/bits }[,IP6LIST]\n"
"IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n"
"OPTION_LIST: OPTION [OPTION_LIST]\n"
"OPTION: bridged | diverted | diverted-loopback | diverted-output |\n"
" {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n"
" {dst-ip|src-ip} IPADDR | {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\n"
" {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"
" icmp6types LIST | ext6hdr LIST | flow-id N[,N] |\n"
" mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n"
" setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
" tcpdatalen LIST | verrevpath | versrcreach | antispoof\n"
@ -2170,7 +2503,6 @@ lookup_host (char *host, struct in_addr *ipaddr)
* 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 IP. Actually returns an empty instruction.
* me returns O_IP_*_ME
* 1.2.3.4 single IP address
* 1.2.3.4:5.6.7.8 address:mask
@ -2357,6 +2689,231 @@ fill_ip(ipfw_insn_ip *cmd, char *av)
}
/* 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;
memset(mask, 0, sizeof(struct in6_addr));
p = (u_char *) mask;
for (; n > 0; p++, n -= 8) {
if (n >= 8)
*p = 0xff;
else
*p = minimask[n];
}
return;
}
/*
* fill 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 (strcmp(av, "any") == 0)
return (1);
if (strcmp(av, "me") == 0) { /* Set the data for "me" opt*/
cmd->o.len |= F_INSN_SIZE(ipfw_insn);
return (1);
}
if (strcmp(av, "me6") == 0) { /* 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) {
/* XXX: 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 != NULL)
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 && av == NULL && len == 0)
errx(EX_DATAERR, "not any never matches");
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 length 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;
}
/*
* helper function to process a set of flags and set bits in the
* appropriate masks.
@ -2468,7 +3025,6 @@ config_pipe(int ac, char **av)
struct dn_pipe p;
int i;
char *end;
uint32_t a;
void *par = NULL;
memset(&p, 0, sizeof p);
@ -2531,16 +3087,15 @@ config_pipe(int ac, char **av)
*/
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;
tok = match_token(dummynet_params, *av);
ac--; av++;
@ -2554,6 +3109,9 @@ config_pipe(int ac, char **av)
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;
@ -2565,6 +3123,18 @@ config_pipe(int ac, char **av)
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;
@ -2584,7 +3154,8 @@ config_pipe(int ac, char **av)
errx(EX_USAGE, "mask: value missing");
if (*av[0] == '/') {
a = strtoul(av[0]+1, &end, 0);
a = (a == 32) ? ~0 : (1 << a) - 1;
if (pa6 == NULL)
a = (a == 32) ? ~0 : (1 << a) - 1;
} else
a = strtoul(av[0], &end, 0);
if (p32 != NULL)
@ -2594,6 +3165,17 @@ config_pipe(int ac, char **av)
errx(EX_DATAERR,
"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 > 0xFF)
errx(EX_DATAERR,
@ -2918,21 +3500,25 @@ add_mactype(ipfw_insn *cmd, int ac, char *av)
}
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 (_substrcmp(av, "all") == 0)
; /* 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 (strcmp(av, "ipv6") == 0 || strcmp(av, "ip6"))
*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;
}
@ -2983,6 +3569,42 @@ add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode)
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);
/* XXX: should check for IPv4, not !IPv6 */
if (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
!inet_pton(AF_INET6, av, &a))
return add_srcip(cmd, av);
if (strcmp(av, "any") != 0)
return cmd;
return NULL;
}
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);
/* XXX: should check for IPv4, not !IPv6 */
if (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
!inet_pton(AF_INET6, av, &a))
return add_dstip(cmd, av);
if (strcmp(av, "any") != 0)
return cmd;
return NULL;
}
/*
* Parse arguments and assemble the microinstructions which make up a rule.
* Rules are added into the 'rulebuf' and then copied in the correct order
@ -3327,7 +3949,7 @@ add(int ac, char *av[])
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;
@ -3355,13 +3977,14 @@ add(int ac, char *av[])
OR_START(source_ip);
NOT_BLOCK; /* optional "not" */
NEED1("missing source address");
if (add_srcip(cmd, *av)) {
if (add_src(cmd, *av, proto)) {
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);
/*
@ -3390,13 +4013,14 @@ add(int ac, char *av[])
OR_START(dest_ip);
NOT_BLOCK; /* optional "not" */
NEED1("missing dst address");
if (add_dstip(cmd, *av)) {
if (add_dst(cmd, *av, proto)) {
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);
/*
@ -3513,6 +4137,12 @@ add(int ac, char *av[])
fill_icmptypes((ipfw_insn_u32 *)cmd, *av);
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");
@ -3717,8 +4347,9 @@ add(int ac, char *av[])
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''",
@ -3739,6 +4370,20 @@ add(int ac, char *av[])
}
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 (_substrcmp(*av, "any") == 0 ||
@ -3787,6 +4432,24 @@ add(int ac, char *av[])
fill_cmd(cmd, O_IPSEC, 0, 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;
case TOK_COMMENT:
fill_comment(cmd, ac, av);
av += ac;

View File

@ -77,6 +77,9 @@
#include <netinet/if_ether.h> /* for struct arpcom */
#include <net/bridge.h>
#include <netinet/ip6.h> /* for ip6_input, ip6_output prototypes */
#include <netinet6/ip6_var.h>
/*
* We keep a private variable for the simulation time, but we could
* probably use an existing one ("softticks" in sys/kern/kern_timeout.c)
@ -461,6 +464,14 @@ transmit_event(struct dn_pipe *pipe)
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,37 +909,80 @@ find_queue(struct dn_flow_set *fs, struct ipfw_flow_id *id)
{
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 */
else if (pipe_expire && q->head == NULL && q->S == q->F+1 ) {
/* No match. Check if we can expire the entry */
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 ;
@ -1200,8 +1254,9 @@ dummynet_io(struct mbuf *m, int dir, struct ip_fw_args *fwa)
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
@ -2015,7 +2070,7 @@ static void
ip_dn_init(void)
{
if (bootverbose)
printf("DUMMYNET initialized (011031)\n");
printf("DUMMYNET with IPv6 initialized (040826)\n");
DUMMYNET_LOCK_INIT();

View File

@ -124,10 +124,13 @@ struct dn_pkt_tag {
#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 */

View File

@ -137,6 +137,16 @@ enum ipfw_opcodes { /* arguments (4 byte each) */
O_ALTQ, /* u32 = altq classif. qid */
O_DIVERTED, /* arg1=bitmap (1:loop, 2:out) */
O_TCPDATALEN, /* arg1 = tcp data len */
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,
/*
* actions for ng_ipfw
@ -147,6 +157,16 @@ enum ipfw_opcodes { /* arguments (4 byte each) */
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.
*
@ -291,6 +311,30 @@ typedef struct _ipfw_insn_log {
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.
*
@ -354,8 +398,14 @@ struct ipfw_flow_id {
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.
*/
@ -438,6 +488,21 @@ enum {
#define IP_FW_DIVERT_LOOPBACK_FLAG 0x00080000
#define IP_FW_DIVERT_OUTPUT_FLAG 0x00100000
/*
* 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
@ -455,6 +520,8 @@ struct ip_fw_args {
struct ipfw_flow_id f_id; /* grabbed from IP header */
u_int32_t cookie; /* a cookie depending on rule action */
struct inpcb *inp;
struct _ip6dn_args dummypar; /* dummynet->ip6_output */
};
/*

View File

@ -86,6 +86,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 */
@ -325,6 +328,7 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_keepalive, CTLFLAG_RW,
#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 icmp *icmp, ipfw_insn_u32 *cmd)
@ -555,6 +559,83 @@ verify_path(struct in_addr src, struct ifnet *ifp)
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...) */
@ -773,7 +854,8 @@ hash_packet(struct ipfw_flow_id *id)
{
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;
}
@ -912,19 +994,40 @@ lookup_dyn_rule_locked(struct ipfw_flow_id *pkt, int *match_direction,
}
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:
@ -1122,15 +1225,25 @@ lookup_dyn_parent(struct ipfw_flow_id *pkt, struct ip_fw *rule)
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;
@ -1204,10 +1317,17 @@ install_state(struct ip_fw *rule, ipfw_insn_limit *cmd,
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)
@ -1831,6 +1951,10 @@ ipfw_chk(struct ip_fw_args *args)
* 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 (IP_FW_PASS); /* accept */
@ -1855,15 +1979,95 @@ do { \
p = (mtod(m, char *) + (len)); \
} while (0)
/* Identify IP packets and fill up veriables. */
if (pktlen >= sizeof(struct ip) &&
/* Identify IP packets and fill up variables. */
if (pktlen >= sizeof(struct ip6_hdr) &&
(args->eh == NULL || 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;
/* Search extension headers to find upper layer protocols */
while (ulp == NULL) {
switch (proto) {
case IPPROTO_ICMPV6:
PULLUP_TO(hlen, ulp, struct icmp6_hdr);
args->f_id.flags = ICMP6(ulp)->icmp6_type;
break;
case IPPROTO_TCP:
PULLUP_TO(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:
PULLUP_TO(hlen, ulp, struct udphdr);
dst_port = UDP(ulp)->uh_dport;
src_port = UDP(ulp)->uh_sport;
break;
case IPPROTO_HOPOPTS:
PULLUP_TO(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:
PULLUP_TO(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:
PULLUP_TO(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:
PULLUP_TO(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 == NULL || ntohs(args->eh->ether_type) == ETHERTYPE_IP) &&
mtod(m, struct ip *)->ip_v == 4) {
ip = mtod(m, struct ip *);
hlen = ip->ip_hl << 2;
#ifdef NOTYET
args->f_id.addr_type = 4;
#endif
/*
* Collect parameters into local variables for faster matching.
@ -2027,11 +2231,13 @@ do { \
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(
@ -2086,7 +2292,7 @@ do { \
break;
case O_FRAG:
match = (hlen > 0 && offset != 0);
match = (offset != 0);
break;
case O_IN: /* "out" is "not in" */
@ -2195,7 +2401,7 @@ do { \
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)
@ -2218,12 +2424,22 @@ do { \
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:
@ -2237,9 +2453,9 @@ do { \
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;
@ -2254,12 +2470,12 @@ do { \
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_TCPDATALEN:
@ -2357,8 +2573,12 @@ do { \
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;
@ -2389,6 +2609,60 @@ do { \
/* 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
@ -3030,6 +3304,10 @@ check_ipfw_struct(struct ip_fw *rule, int size)
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;
@ -3177,6 +3455,29 @@ check_ipfw_struct(struct ip_fw *rule, int size)
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);
@ -3577,7 +3878,7 @@ ipfw_init(void)
}
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, "

View File

@ -30,6 +30,7 @@
#include "opt_ipfw.h"
#include "opt_ipdn.h"
#include "opt_inet.h"
#include "opt_inet6.h"
#ifndef INET
#error IPFIREWALL requires INET.
#endif /* INET */
@ -155,7 +156,10 @@ ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
case IP_FW_DUMMYNET:
if (!DUMMYNET_LOADED)
goto drop;
ip_dn_io_ptr(*m0, DN_TO_IP_IN, &args);
if (mtod(*m0, struct ip *)->ip_v == 4)
ip_dn_io_ptr(*m0, DN_TO_IP_IN, &args);
else if (mtod(*m0, struct ip *)->ip_v == 6)
ip_dn_io_ptr(*m0, DN_TO_IP6_IN, &args);
*m0 = NULL;
return 0; /* packet consumed */
@ -278,7 +282,10 @@ ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
case IP_FW_DUMMYNET:
if (!DUMMYNET_LOADED)
break;
ip_dn_io_ptr(*m0, DN_TO_IP_OUT, &args);
if (mtod(*m0, struct ip *)->ip_v == 4)
ip_dn_io_ptr(*m0, DN_TO_IP_OUT, &args);
else if (mtod(*m0, struct ip *)->ip_v == 6)
ip_dn_io_ptr(*m0, DN_TO_IP6_OUT, &args);
*m0 = NULL;
return 0; /* packet consumed */
@ -410,6 +417,9 @@ static int
ipfw_hook(void)
{
struct pfil_head *pfh_inet;
#ifdef INET6
struct pfil_head *pfh_inet6;
#endif
if (ipfw_pfil_hooked)
return EEXIST;
@ -417,9 +427,18 @@ ipfw_hook(void)
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;
}
@ -428,6 +447,9 @@ static int
ipfw_unhook(void)
{
struct pfil_head *pfh_inet;
#ifdef INET6
struct pfil_head *pfh_inet6;
#endif
if (!ipfw_pfil_hooked)
return ENOENT;
@ -435,9 +457,18 @@ ipfw_unhook(void)
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;
}

View File

@ -78,6 +78,7 @@
#include <sys/kernel.h>
#include <net/if.h>
#include <net/netisr.h>
#include <net/route.h>
#include <net/pfil.h>
@ -167,6 +168,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp, inp)
int hlen, tlen, len, off;
struct route_in6 ip6route;
struct sockaddr_in6 *dst;
struct in6_addr odst;
int error = 0;
struct in6_ifaddr *ia = NULL;
u_long mtu;
@ -524,6 +526,7 @@ skip_ipsec2:;
ro = &opt->ip6po_route;
dst = (struct sockaddr_in6 *)&ro->ro_dst;
again:
/*
* If there is a cached route,
* check that it is to the same destination
@ -937,12 +940,35 @@ skip_ipsec2:;
if (inet6_pfil_hook.ph_busy_count == -1)
goto passout;
odst = ip6->ip6_dst;
/* Run through list of hooks for output packets. */
error = pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_OUT, inp);
if (error != 0 || m == NULL)
goto done;
ip6 = mtod(m, struct ip6_hdr *);
/* See if destination IP address was changed by packet filter. */
if (!IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst)) {
m->m_flags |= M_SKIP_FIREWALL;
/* If destination is now ourself drop to ip6_input(). */
if (in6_localaddr(&ip6->ip6_dst)) {
if (m->m_pkthdr.rcvif == NULL)
m->m_pkthdr.rcvif = loif;
if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
m->m_pkthdr.csum_flags |=
CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
m->m_pkthdr.csum_data = 0xffff;
}
m->m_pkthdr.csum_flags |=
CSUM_IP_CHECKED | CSUM_IP_VALID;
error = netisr_queue(NETISR_IPV6, m);
goto done;
} else
goto again; /* Redo the routing table lookup. */
}
/* XXX: IPFIREWALL_FORWARD */
passout:
/*
* Send the packet to the outgoing interface.