Add IPv6 support to IPFW and Dummynet.
Submitted by: Mariano Tortoriello and Raffaele De Lorenzo (via luigi)
This commit is contained in:
parent
6dfe72cfb9
commit
f3ecaa630b
152
sbin/ipfw/ipfw.8
152
sbin/ipfw/ipfw.8
@ -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.
|
||||
|
@ -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 @@ read_options:
|
||||
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 @@ read_options:
|
||||
|
||||
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 @@ read_options:
|
||||
}
|
||||
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 @@ read_options:
|
||||
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;
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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 @@ check_body:
|
||||
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 @@ check_body:
|
||||
break;
|
||||
|
||||
case O_FRAG:
|
||||
match = (hlen > 0 && offset != 0);
|
||||
match = (offset != 0);
|
||||
break;
|
||||
|
||||
case O_IN: /* "out" is "not in" */
|
||||
@ -2195,7 +2401,7 @@ check_body:
|
||||
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 @@ check_body:
|
||||
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 @@ check_body:
|
||||
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 @@ check_body:
|
||||
|
||||
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 @@ check_body:
|
||||
|
||||
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 @@ check_body:
|
||||
/* 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_action:
|
||||
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, "
|
||||
|
@ -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 @@ again:
|
||||
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 @@ again:
|
||||
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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user