Add IPv6 support to IPFW and Dummynet.
Submitted by: Mariano Tortoriello and Raffaele De Lorenzo (via luigi)
This commit is contained in:
parent
a87b3988c9
commit
8195404bed
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=145246
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
|
These places and variables are shown below, and it is important to
|
||||||
have this picture in mind in order to design a correct ruleset.
|
have this picture in mind in order to design a correct ruleset.
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
^ to upper layers V
|
^ to upper layers V
|
||||||
| |
|
| |
|
||||||
+----------->-----------+
|
+----------->-----------+
|
||||||
^ V
|
^ V
|
||||||
[ip_input] [ip_output] net.inet.ip.fw.enable=1
|
[ip(6)_input] [ip(6)_output] net.inet.ip.fw.enable=1
|
||||||
| |
|
| |
|
||||||
^ V
|
^ V
|
||||||
[ether_demux] [ether_output_frame] net.link.ether.ipfw=1
|
[ether_demux] [ether_output_frame] net.link.ether.ipfw=1
|
||||||
| |
|
| |
|
||||||
+-->--[bdg_forward]-->--+ net.link.ether.bridge_ipfw=1
|
+-->--[bdg_forward]-->--+ net.link.ether.bridge_ipfw=1
|
||||||
^ V
|
^ V
|
||||||
| to devices |
|
| to devices |
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
As can be noted from the above picture, the number of
|
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
|
but the same packets will have the MAC header stripped off when
|
||||||
.Nm
|
.Nm
|
||||||
is invoked from
|
is invoked from
|
||||||
.Cm ip_input() .
|
.Cm ip_input()
|
||||||
|
or
|
||||||
|
.Cm ip6_input() .
|
||||||
.Pp
|
.Pp
|
||||||
Also note that each packet is always checked against the complete ruleset,
|
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.
|
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
|
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
|
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
|
the match pattern will not match, but a
|
||||||
.Cm not
|
.Cm not
|
||||||
operator in front of such patterns
|
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
|
.Bl -tag -width "Source and dest. addresses and ports" -offset XXX -compact
|
||||||
.It Layer-2 header fields
|
.It Layer-2 header fields
|
||||||
When available
|
When available
|
||||||
.It IPv4 Protocol
|
.It IPv4 and IPv6 Protocol
|
||||||
TCP, UDP, ICMP, etc.
|
TCP, UDP, ICMP, etc.
|
||||||
.It Source and dest. addresses and ports
|
.It Source and dest. addresses and ports
|
||||||
.It Direction
|
.It Direction
|
||||||
@ -461,6 +465,10 @@ Version, type of service, datagram length, identification,
|
|||||||
fragment flag (non-zero IP offset),
|
fragment flag (non-zero IP offset),
|
||||||
Time To Live
|
Time To Live
|
||||||
.It IP options
|
.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
|
.It Misc. TCP header fields
|
||||||
TCP flags (SYN, FIN, ACK, RST, etc.),
|
TCP flags (SYN, FIN, ACK, RST, etc.),
|
||||||
sequence number, acknowledgment number,
|
sequence number, acknowledgment number,
|
||||||
@ -468,6 +476,8 @@ window
|
|||||||
.It TCP options
|
.It TCP options
|
||||||
.It ICMP types
|
.It ICMP types
|
||||||
for ICMP packets
|
for ICMP packets
|
||||||
|
.It ICMP6 types
|
||||||
|
for ICMP6 packets
|
||||||
.It User/group ID
|
.It User/group ID
|
||||||
When the packet can be associated with a local socket.
|
When the packet can be associated with a local socket.
|
||||||
.It Divert status
|
.It Divert status
|
||||||
@ -806,7 +816,7 @@ compatibility with
|
|||||||
.Nm ipfw1 .
|
.Nm ipfw1 .
|
||||||
In
|
In
|
||||||
.Nm ipfw2
|
.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
|
addresses and ports) can be specified in the
|
||||||
.Ar options
|
.Ar options
|
||||||
section.
|
section.
|
||||||
@ -815,11 +825,13 @@ Rule fields have the following meaning:
|
|||||||
.Bl -tag -width indent
|
.Bl -tag -width indent
|
||||||
.It Ar proto : protocol | Cm { Ar protocol Cm or ... }
|
.It Ar proto : protocol | Cm { Ar protocol Cm or ... }
|
||||||
.It Ar protocol : Oo Cm not Oc Ar protocol-name | protocol-number
|
.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
|
(for a complete list see
|
||||||
.Pa /etc/protocols ) .
|
.Pa /etc/protocols ) .
|
||||||
The
|
The
|
||||||
.Cm ip
|
.Cm ip ,
|
||||||
|
.Cm ip6 ,
|
||||||
|
.Cm ipv6 ,
|
||||||
or
|
or
|
||||||
.Cm all
|
.Cm all
|
||||||
keywords mean any protocol will match.
|
keywords mean any protocol will match.
|
||||||
@ -840,7 +852,7 @@ The second format
|
|||||||
with multiple addresses) is provided for convenience only and
|
with multiple addresses) is provided for convenience only and
|
||||||
its use is discouraged.
|
its use is discouraged.
|
||||||
.It Ar addr : Oo Cm not Oc Bro
|
.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
|
.Cm table Ns Pq Ar number Ns Op , Ns Ar value
|
||||||
.Ar | addr-list | addr-set
|
.Ar | addr-list | addr-set
|
||||||
.Brc
|
.Brc
|
||||||
@ -848,10 +860,12 @@ its use is discouraged.
|
|||||||
matches any IP address.
|
matches any IP address.
|
||||||
.It Cm me
|
.It Cm me
|
||||||
matches any IP address configured on an interface in the system.
|
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
|
The address list is evaluated at the time the packet is
|
||||||
analysed.
|
analysed.
|
||||||
.It Cm table Ns Pq Ar number Ns Op , Ns Ar value
|
.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 .
|
.Ar number .
|
||||||
If an optional 32-bit unsigned
|
If an optional 32-bit unsigned
|
||||||
.Ar value
|
.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:
|
will match the following IP addresses:
|
||||||
.br
|
.br
|
||||||
1.2.3.128, 1.2.3.35 to 1.2.3.55, 1.2.3.89 .
|
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
|
.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
|
For protocols which support port numbers (such as TCP and UDP), optional
|
||||||
.Cm ports
|
.Cm ports
|
||||||
@ -986,13 +1024,36 @@ input for delivery.
|
|||||||
Matches only packets going from a divert socket back outward to the IP
|
Matches only packets going from a divert socket back outward to the IP
|
||||||
stack output for delivery.
|
stack output for delivery.
|
||||||
.It Cm dst-ip Ar ip-address
|
.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.
|
specified as argument.
|
||||||
.It Cm dst-port Ar ports
|
.It Cm dst-port Ar ports
|
||||||
Matches IP packets whose destination port is one of the port(s)
|
Matches IP packets whose destination port is one of the port(s)
|
||||||
specified as argument.
|
specified as argument.
|
||||||
.It Cm established
|
.It Cm established
|
||||||
Matches TCP packets that have the RST or ACK bits set.
|
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
|
.It Cm frag
|
||||||
Matches packets that are fragments and not the first
|
Matches packets that are fragments and not the first
|
||||||
fragment of an IP datagram.
|
fragment of an IP datagram.
|
||||||
@ -1047,6 +1108,12 @@ address mask request
|
|||||||
.Pq Cm 17
|
.Pq Cm 17
|
||||||
and address mask reply
|
and address mask reply
|
||||||
.Pq Cm 18 .
|
.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
|
.It Cm in | out
|
||||||
Matches incoming or outgoing packets, respectively.
|
Matches incoming or outgoing packets, respectively.
|
||||||
.Cm in
|
.Cm in
|
||||||
@ -1057,7 +1124,7 @@ are mutually exclusive (in fact,
|
|||||||
is implemented as
|
is implemented as
|
||||||
.Cm not in Ns No ).
|
.Cm not in Ns No ).
|
||||||
.It Cm ipid Ar id-list
|
.It Cm ipid Ar id-list
|
||||||
Matches IP packets whose
|
Matches IPv4 packets whose
|
||||||
.Cm ip_id
|
.Cm ip_id
|
||||||
field has value included in
|
field has value included in
|
||||||
.Ar id-list ,
|
.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
|
specified in the same way as
|
||||||
.Ar ports .
|
.Ar ports .
|
||||||
.It Cm ipoptions Ar spec
|
.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
|
options specified in
|
||||||
.Ar spec .
|
.Ar spec .
|
||||||
The supported IP options are:
|
The supported IP options are:
|
||||||
@ -1089,7 +1156,7 @@ The absence of a particular option may be denoted
|
|||||||
with a
|
with a
|
||||||
.Ql \&! .
|
.Ql \&! .
|
||||||
.It Cm ipprecedence Ar precedence
|
.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 .
|
.Ar precedence .
|
||||||
.It Cm ipsec
|
.It Cm ipsec
|
||||||
Matches packets that have IPSEC history associated with them
|
Matches packets that have IPSEC history associated with them
|
||||||
@ -1111,7 +1178,7 @@ rules are handled as if with no
|
|||||||
.Cm ipsec
|
.Cm ipsec
|
||||||
flag.
|
flag.
|
||||||
.It Cm iptos Ar spec
|
.It Cm iptos Ar spec
|
||||||
Matches IP packets whose
|
Matches IPv4 packets whose
|
||||||
.Cm tos
|
.Cm tos
|
||||||
field contains the comma separated list of
|
field contains the comma separated list of
|
||||||
service types specified in
|
service types specified in
|
||||||
@ -1132,7 +1199,7 @@ The absence of a particular type may be denoted
|
|||||||
with a
|
with a
|
||||||
.Ql \&! .
|
.Ql \&! .
|
||||||
.It Cm ipttl Ar ttl-list
|
.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 ,
|
.Ar ttl-list ,
|
||||||
which is either a single value or a list of values or ranges
|
which is either a single value or a list of values or ranges
|
||||||
specified in the same way as
|
specified in the same way as
|
||||||
@ -1160,6 +1227,8 @@ set of parameters as specified in the rule.
|
|||||||
One or more
|
One or more
|
||||||
of source and destination addresses and ports can be
|
of source and destination addresses and ports can be
|
||||||
specified.
|
specified.
|
||||||
|
Currently,
|
||||||
|
only IPv4 flows are supported.
|
||||||
.It Cm { MAC | mac } Ar dst-mac src-mac
|
.It Cm { MAC | mac } Ar dst-mac src-mac
|
||||||
Match packets with a given
|
Match packets with a given
|
||||||
.Ar dst-mac
|
.Ar dst-mac
|
||||||
@ -1212,7 +1281,7 @@ and they are always printed as hexadecimal (unless the
|
|||||||
.Cm -N
|
.Cm -N
|
||||||
option is used, in which case symbolic resolution will be attempted).
|
option is used, in which case symbolic resolution will be attempted).
|
||||||
.It Cm proto Ar protocol
|
.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
|
.It Cm recv | xmit | via Brq Ar ifX | Ar if Ns Cm * | Ar ipno | Ar any
|
||||||
Matches packets received, transmitted or going through,
|
Matches packets received, transmitted or going through,
|
||||||
respectively, the interface specified by exact name
|
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
|
This is the short form of
|
||||||
.Dq Li tcpflags\ syn,!ack .
|
.Dq Li tcpflags\ syn,!ack .
|
||||||
.It Cm src-ip Ar ip-address
|
.It Cm src-ip Ar ip-address
|
||||||
Matches IP packets whose source IP is one of the address(es)
|
Matches IPv4 packets whose source IP is one of the address(es)
|
||||||
specified as argument.
|
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
|
.It Cm src-port Ar ports
|
||||||
Matches IP packets whose source port is one of the port(s)
|
Matches IP packets whose source port is one of the port(s)
|
||||||
specified as argument.
|
specified as argument.
|
||||||
@ -1388,7 +1460,7 @@ connected networks instead of all source addresses.
|
|||||||
.Sh LOOKUP TABLES
|
.Sh LOOKUP TABLES
|
||||||
Lookup tables are useful to handle large sparse address sets,
|
Lookup tables are useful to handle large sparse address sets,
|
||||||
typically from a hundred to several thousands of entries.
|
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
|
.Pp
|
||||||
Each entry is represented by an
|
Each entry is represented by an
|
||||||
.Ar addr Ns Op / Ns Ar masklen
|
.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
|
Internally, each table is stored in a Radix tree, the same way as
|
||||||
the routing table (see
|
the routing table (see
|
||||||
.Xr route 4 ) .
|
.Xr route 4 ) .
|
||||||
|
.Pp
|
||||||
|
Lookup tables currently support IPv4 addresses only.
|
||||||
.Sh SETS OF RULES
|
.Sh SETS OF RULES
|
||||||
Each rule belongs to one of 32 different
|
Each rule belongs to one of 32 different
|
||||||
.Em sets
|
.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:
|
Available mask specifiers are a combination of one or more of the following:
|
||||||
.Pp
|
.Pp
|
||||||
.Cm dst-ip Ar mask ,
|
.Cm dst-ip Ar mask ,
|
||||||
|
.Cm dst-ip6 Ar mask ,
|
||||||
.Cm src-ip Ar mask ,
|
.Cm src-ip Ar mask ,
|
||||||
|
.Cm src-ip6 Ar mask ,
|
||||||
.Cm dst-port Ar mask ,
|
.Cm dst-port Ar mask ,
|
||||||
.Cm src-port Ar mask ,
|
.Cm src-port Ar mask ,
|
||||||
|
.Cm flow-id Ar mask ,
|
||||||
.Cm proto Ar mask
|
.Cm proto Ar mask
|
||||||
or
|
or
|
||||||
.Cm all ,
|
.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).
|
thresholds are in bytes (defaults to 1500, must be greater than zero).
|
||||||
.El
|
.El
|
||||||
.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
|
.Sh CHECKLIST
|
||||||
Here are some important points to consider when designing your
|
Here are some important points to consider when designing your
|
||||||
rules:
|
rules:
|
||||||
@ -2092,6 +2177,9 @@ The following option for
|
|||||||
.Nm dummynet
|
.Nm dummynet
|
||||||
pipes/queues is not supported:
|
pipes/queues is not supported:
|
||||||
.Cm noerror .
|
.Cm noerror .
|
||||||
|
.It IPv6 Support
|
||||||
|
There was no IPv6 support in
|
||||||
|
.Nm ipfw1 .
|
||||||
.El
|
.El
|
||||||
.Sh EXAMPLES
|
.Sh EXAMPLES
|
||||||
There are far too many possible uses of
|
There are far too many possible uses of
|
||||||
@ -2396,6 +2484,8 @@ Work on
|
|||||||
.Xr dummynet 4
|
.Xr dummynet 4
|
||||||
traffic shaper supported by Akamba Corp.
|
traffic shaper supported by Akamba Corp.
|
||||||
.Sh BUGS
|
.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.
|
The syntax has grown over the years and sometimes it might be confusing.
|
||||||
Unfortunately, backward compatibility prevents cleaning up mistakes
|
Unfortunately, backward compatibility prevents cleaning up mistakes
|
||||||
made in the definition of the syntax.
|
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
|
applied, making the order of
|
||||||
.Cm divert
|
.Cm divert
|
||||||
rules in the rule sequence very important.
|
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/if.h>
|
||||||
#include <net/pfvar.h>
|
#include <net/pfvar.h>
|
||||||
|
#include <net/route.h> /* def. of struct route */
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netinet/in_systm.h>
|
#include <netinet/in_systm.h>
|
||||||
#include <netinet/ip.h>
|
#include <netinet/ip.h>
|
||||||
#include <netinet/ip_icmp.h>
|
#include <netinet/ip_icmp.h>
|
||||||
|
#include <netinet/icmp6.h>
|
||||||
#include <netinet/ip_fw.h>
|
#include <netinet/ip_fw.h>
|
||||||
#include <netinet/ip_dummynet.h>
|
#include <netinet/ip_dummynet.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
@ -266,6 +268,13 @@ enum tokens {
|
|||||||
TOK_DROPTAIL,
|
TOK_DROPTAIL,
|
||||||
TOK_PROTO,
|
TOK_PROTO,
|
||||||
TOK_WEIGHT,
|
TOK_WEIGHT,
|
||||||
|
|
||||||
|
TOK_IPV6,
|
||||||
|
TOK_FLOWID,
|
||||||
|
TOK_ICMP6TYPES,
|
||||||
|
TOK_EXT6HDR,
|
||||||
|
TOK_DSTIP6,
|
||||||
|
TOK_SRCIP6,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _s_x dummynet_params[] = {
|
struct _s_x dummynet_params[] = {
|
||||||
@ -288,6 +297,11 @@ struct _s_x dummynet_params[] = {
|
|||||||
{ "delay", TOK_DELAY },
|
{ "delay", TOK_DELAY },
|
||||||
{ "pipe", TOK_PIPE },
|
{ "pipe", TOK_PIPE },
|
||||||
{ "queue", TOK_QUEUE },
|
{ "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 },
|
{ "dummynet-params", TOK_NULL },
|
||||||
{ NULL, 0 } /* terminator */
|
{ NULL, 0 } /* terminator */
|
||||||
};
|
};
|
||||||
@ -375,6 +389,16 @@ struct _s_x rule_options[] = {
|
|||||||
{ "versrcreach", TOK_VERSRCREACH },
|
{ "versrcreach", TOK_VERSRCREACH },
|
||||||
{ "antispoof", TOK_ANTISPOOF },
|
{ "antispoof", TOK_ANTISPOOF },
|
||||||
{ "ipsec", TOK_IPSEC },
|
{ "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 },
|
{ "//", TOK_COMMENT },
|
||||||
|
|
||||||
{ "not", TOK_NOT }, /* pseudo option */
|
{ "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.
|
* show_ipfw() prints the body of an ipfw rule.
|
||||||
* Because the standard rule has at least proto src_ip dst_ip, we use
|
* 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_DSTIP 0x0004
|
||||||
#define HAVE_MAC 0x0008
|
#define HAVE_MAC 0x0008
|
||||||
#define HAVE_MACTYPE 0x0010
|
#define HAVE_MACTYPE 0x0010
|
||||||
|
#define HAVE_PROTO6 0x0080
|
||||||
#define HAVE_OPTIONS 0x8000
|
#define HAVE_OPTIONS 0x8000
|
||||||
|
|
||||||
#define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
|
#define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
|
||||||
@ -1065,6 +1283,9 @@ show_prerequisites(int *flags, int want, int cmd)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ( !(*flags & HAVE_OPTIONS)) {
|
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))
|
if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO))
|
||||||
printf(" ip");
|
printf(" ip");
|
||||||
if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP))
|
if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP))
|
||||||
@ -1329,6 +1550,37 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
|
|||||||
flags |= HAVE_DSTIP;
|
flags |= HAVE_DSTIP;
|
||||||
break;
|
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:
|
case O_IP_DSTPORT:
|
||||||
show_prerequisites(&flags, HAVE_IP, 0);
|
show_prerequisites(&flags, HAVE_IP, 0);
|
||||||
case O_IP_SRCPORT:
|
case O_IP_SRCPORT:
|
||||||
@ -1340,14 +1592,15 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case O_PROTO: {
|
case O_PROTO: {
|
||||||
struct protoent *pe;
|
struct protoent *pe = NULL;
|
||||||
|
|
||||||
if ((cmd->len & F_OR) && !or_block)
|
if ((cmd->len & F_OR) && !or_block)
|
||||||
printf(" {");
|
printf(" {");
|
||||||
if (cmd->len & F_NOT)
|
if (cmd->len & F_NOT)
|
||||||
printf(" not");
|
printf(" not");
|
||||||
proto = cmd->arg1;
|
proto = cmd->arg1;
|
||||||
pe = getprotobynumber(cmd->arg1);
|
if (proto != 41) /* XXX: IPv6 is special */
|
||||||
|
pe = getprotobynumber(cmd->arg1);
|
||||||
if (flags & HAVE_OPTIONS)
|
if (flags & HAVE_OPTIONS)
|
||||||
printf(" proto");
|
printf(" proto");
|
||||||
if (pe)
|
if (pe)
|
||||||
@ -1558,6 +1811,18 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
printf(" [opcode %d len %d]",
|
printf(" [opcode %d len %d]",
|
||||||
cmd->opcode, cmd->len);
|
cmd->opcode, cmd->len);
|
||||||
@ -1655,29 +1920,48 @@ static void
|
|||||||
list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
|
list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
|
||||||
{
|
{
|
||||||
int l;
|
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)
|
if (fs->rq_elements == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
printf("BKT Prot ___Source IP/port____ "
|
|
||||||
"____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
|
|
||||||
if (do_sort != 0)
|
if (do_sort != 0)
|
||||||
heapsort(q, fs->rq_elements, sizeof *q, sort_q);
|
heapsort(q, fs->rq_elements, sizeof *q, sort_q);
|
||||||
|
|
||||||
|
/* Print IPv4 flows */
|
||||||
|
index_printed = 0;
|
||||||
for (l = 0; l < fs->rq_elements; l++) {
|
for (l = 0; l < fs->rq_elements; l++) {
|
||||||
struct in_addr ina;
|
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);
|
printf("%3d ", q[l].hash_slot);
|
||||||
pe = getprotobynumber(q[l].id.proto);
|
pe = getprotobynumber(q[l].id.proto);
|
||||||
if (pe)
|
if (pe)
|
||||||
printf("%-4s ", pe->p_name);
|
printf("%-4s ", pe->p_name);
|
||||||
else
|
else
|
||||||
printf("%4u ", q[l].id.proto);
|
printf("%4u ", q[l].id.proto);
|
||||||
|
ina.s_addr = htonl(q[l].id.src_ip);
|
||||||
printf("%15s/%-5d ",
|
printf("%15s/%-5d ",
|
||||||
inet_ntoa(ina), q[l].id.src_port);
|
inet_ntoa(ina), q[l].id.src_port);
|
||||||
ina.s_addr = htonl(q[l].id.dst_ip);
|
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",
|
printf(" S %20qd F %20qd\n",
|
||||||
q[l].S, q[l].F);
|
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
|
static void
|
||||||
@ -2082,7 +2410,7 @@ list(int ac, char *av[], int show_counters)
|
|||||||
if (do_dynamic && ndyn) {
|
if (do_dynamic && ndyn) {
|
||||||
printf("## Dynamic rules:\n");
|
printf("## Dynamic rules:\n");
|
||||||
for (lac = ac, lav = av; lac != 0; lac--) {
|
for (lac = ac, lav = av; lac != 0; lac--) {
|
||||||
rnum = strtoul(*lav++, &endptr, 10);
|
last = rnum = strtoul(*lav++, &endptr, 10);
|
||||||
if (*endptr == '-')
|
if (*endptr == '-')
|
||||||
last = strtoul(endptr+1, &endptr, 10);
|
last = strtoul(endptr+1, &endptr, 10);
|
||||||
if (*endptr)
|
if (*endptr)
|
||||||
@ -2132,19 +2460,24 @@ help(void)
|
|||||||
"table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n"
|
"table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"RULE-BODY: check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\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"
|
" {divert|tee} PORT | forward ADDR | pipe N | queue N\n"
|
||||||
"PARAMS: [log [logamount LOGLIMIT]] [altq QUEUE_NAME]\n"
|
"PARAMS: [log [logamount LOGLIMIT]] [altq QUEUE_NAME]\n"
|
||||||
"ADDR: [ MAC dst src ether_type ] \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"
|
"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"
|
"IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n"
|
||||||
"OPTION_LIST: OPTION [OPTION_LIST]\n"
|
"OPTION_LIST: OPTION [OPTION_LIST]\n"
|
||||||
"OPTION: bridged | diverted | diverted-loopback | diverted-output |\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"
|
" estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n"
|
||||||
" iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n"
|
" iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n"
|
||||||
" ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\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"
|
" mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n"
|
||||||
" setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
|
" setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
|
||||||
" tcpdatalen LIST | verrevpath | versrcreach | antispoof\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.
|
* fills the addr and mask fields in the instruction as appropriate from av.
|
||||||
* Update length as appropriate.
|
* Update length as appropriate.
|
||||||
* The following formats are allowed:
|
* The following formats are allowed:
|
||||||
* any matches any IP. Actually returns an empty instruction.
|
|
||||||
* me returns O_IP_*_ME
|
* me returns O_IP_*_ME
|
||||||
* 1.2.3.4 single IP address
|
* 1.2.3.4 single IP address
|
||||||
* 1.2.3.4:5.6.7.8 address:mask
|
* 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
|
* helper function to process a set of flags and set bits in the
|
||||||
* appropriate masks.
|
* appropriate masks.
|
||||||
@ -2468,7 +3025,6 @@ config_pipe(int ac, char **av)
|
|||||||
struct dn_pipe p;
|
struct dn_pipe p;
|
||||||
int i;
|
int i;
|
||||||
char *end;
|
char *end;
|
||||||
uint32_t a;
|
|
||||||
void *par = NULL;
|
void *par = NULL;
|
||||||
|
|
||||||
memset(&p, 0, sizeof p);
|
memset(&p, 0, sizeof p);
|
||||||
@ -2531,16 +3087,15 @@ config_pipe(int ac, char **av)
|
|||||||
*/
|
*/
|
||||||
par = NULL;
|
par = NULL;
|
||||||
|
|
||||||
p.fs.flow_mask.dst_ip = 0;
|
bzero(&p.fs.flow_mask, sizeof(p.fs.flow_mask));
|
||||||
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;
|
|
||||||
end = NULL;
|
end = NULL;
|
||||||
|
|
||||||
while (ac >= 1) {
|
while (ac >= 1) {
|
||||||
uint32_t *p32 = NULL;
|
uint32_t *p32 = NULL;
|
||||||
uint16_t *p16 = NULL;
|
uint16_t *p16 = NULL;
|
||||||
|
uint32_t *p20 = NULL;
|
||||||
|
struct in6_addr *pa6 = NULL;
|
||||||
|
uint32_t a;
|
||||||
|
|
||||||
tok = match_token(dummynet_params, *av);
|
tok = match_token(dummynet_params, *av);
|
||||||
ac--; av++;
|
ac--; av++;
|
||||||
@ -2554,6 +3109,9 @@ config_pipe(int ac, char **av)
|
|||||||
p.fs.flow_mask.dst_port = ~0;
|
p.fs.flow_mask.dst_port = ~0;
|
||||||
p.fs.flow_mask.src_port = ~0;
|
p.fs.flow_mask.src_port = ~0;
|
||||||
p.fs.flow_mask.proto = ~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;
|
p.fs.flags_fs |= DN_HAVE_FLOW_MASK;
|
||||||
goto end_mask;
|
goto end_mask;
|
||||||
|
|
||||||
@ -2565,6 +3123,18 @@ config_pipe(int ac, char **av)
|
|||||||
p32 = &p.fs.flow_mask.src_ip;
|
p32 = &p.fs.flow_mask.src_ip;
|
||||||
break;
|
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:
|
case TOK_DSTPORT:
|
||||||
p16 = &p.fs.flow_mask.dst_port;
|
p16 = &p.fs.flow_mask.dst_port;
|
||||||
break;
|
break;
|
||||||
@ -2584,7 +3154,8 @@ config_pipe(int ac, char **av)
|
|||||||
errx(EX_USAGE, "mask: value missing");
|
errx(EX_USAGE, "mask: value missing");
|
||||||
if (*av[0] == '/') {
|
if (*av[0] == '/') {
|
||||||
a = strtoul(av[0]+1, &end, 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
|
} else
|
||||||
a = strtoul(av[0], &end, 0);
|
a = strtoul(av[0], &end, 0);
|
||||||
if (p32 != NULL)
|
if (p32 != NULL)
|
||||||
@ -2594,6 +3165,17 @@ config_pipe(int ac, char **av)
|
|||||||
errx(EX_DATAERR,
|
errx(EX_DATAERR,
|
||||||
"port mask must be 16 bit");
|
"port mask must be 16 bit");
|
||||||
*p16 = (uint16_t)a;
|
*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 {
|
} else {
|
||||||
if (a > 0xFF)
|
if (a > 0xFF)
|
||||||
errx(EX_DATAERR,
|
errx(EX_DATAERR,
|
||||||
@ -2918,21 +3500,25 @@ add_mactype(ipfw_insn *cmd, int ac, char *av)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ipfw_insn *
|
static ipfw_insn *
|
||||||
add_proto(ipfw_insn *cmd, char *av)
|
add_proto(ipfw_insn *cmd, char *av, u_char *proto)
|
||||||
{
|
{
|
||||||
struct protoent *pe;
|
struct protoent *pe;
|
||||||
u_char proto = 0;
|
|
||||||
|
*proto = IPPROTO_IP;
|
||||||
|
|
||||||
if (_substrcmp(av, "all") == 0)
|
if (_substrcmp(av, "all") == 0)
|
||||||
; /* same as "ip" */
|
; /* same as "ip" */
|
||||||
else if ((proto = atoi(av)) > 0)
|
else if ((*proto = atoi(av)) > 0)
|
||||||
; /* all done! */
|
; /* all done! */
|
||||||
else if ((pe = getprotobyname(av)) != NULL)
|
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
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
if (proto != IPPROTO_IP)
|
if (*proto != IPPROTO_IP && *proto != IPPROTO_IPV6)
|
||||||
fill_cmd(cmd, O_PROTO, 0, proto);
|
fill_cmd(cmd, O_PROTO, 0, *proto);
|
||||||
|
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2983,6 +3569,42 @@ add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode)
|
|||||||
return NULL;
|
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.
|
* Parse arguments and assemble the microinstructions which make up a rule.
|
||||||
* Rules are added into the 'rulebuf' and then copied in the correct order
|
* 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);
|
OR_START(get_proto);
|
||||||
NOT_BLOCK;
|
NOT_BLOCK;
|
||||||
NEED1("missing protocol");
|
NEED1("missing protocol");
|
||||||
if (add_proto(cmd, *av)) {
|
if (add_proto(cmd, *av, &proto)) {
|
||||||
av++; ac--;
|
av++; ac--;
|
||||||
if (F_LEN(cmd) == 0) /* plain IP */
|
if (F_LEN(cmd) == 0) /* plain IP */
|
||||||
proto = 0;
|
proto = 0;
|
||||||
@ -3355,13 +3977,14 @@ add(int ac, char *av[])
|
|||||||
OR_START(source_ip);
|
OR_START(source_ip);
|
||||||
NOT_BLOCK; /* optional "not" */
|
NOT_BLOCK; /* optional "not" */
|
||||||
NEED1("missing source address");
|
NEED1("missing source address");
|
||||||
if (add_srcip(cmd, *av)) {
|
if (add_src(cmd, *av, proto)) {
|
||||||
ac--; av++;
|
ac--; av++;
|
||||||
if (F_LEN(cmd) != 0) { /* ! any */
|
if (F_LEN(cmd) != 0) { /* ! any */
|
||||||
prev = cmd;
|
prev = cmd;
|
||||||
cmd = next_cmd(cmd);
|
cmd = next_cmd(cmd);
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
|
errx(EX_USAGE, "bad source address %s", *av);
|
||||||
OR_BLOCK(source_ip);
|
OR_BLOCK(source_ip);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3390,13 +4013,14 @@ add(int ac, char *av[])
|
|||||||
OR_START(dest_ip);
|
OR_START(dest_ip);
|
||||||
NOT_BLOCK; /* optional "not" */
|
NOT_BLOCK; /* optional "not" */
|
||||||
NEED1("missing dst address");
|
NEED1("missing dst address");
|
||||||
if (add_dstip(cmd, *av)) {
|
if (add_dst(cmd, *av, proto)) {
|
||||||
ac--; av++;
|
ac--; av++;
|
||||||
if (F_LEN(cmd) != 0) { /* ! any */
|
if (F_LEN(cmd) != 0) { /* ! any */
|
||||||
prev = cmd;
|
prev = cmd;
|
||||||
cmd = next_cmd(cmd);
|
cmd = next_cmd(cmd);
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
|
errx( EX_USAGE, "bad destination address %s", *av);
|
||||||
OR_BLOCK(dest_ip);
|
OR_BLOCK(dest_ip);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3513,6 +4137,12 @@ add(int ac, char *av[])
|
|||||||
fill_icmptypes((ipfw_insn_u32 *)cmd, *av);
|
fill_icmptypes((ipfw_insn_u32 *)cmd, *av);
|
||||||
av++; ac--;
|
av++; ac--;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOK_ICMP6TYPES:
|
||||||
|
NEED1("icmptypes requires list of types");
|
||||||
|
fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av);
|
||||||
|
av++; ac--;
|
||||||
|
break;
|
||||||
|
|
||||||
case TOK_IPTTL:
|
case TOK_IPTTL:
|
||||||
NEED1("ipttl requires TTL");
|
NEED1("ipttl requires TTL");
|
||||||
@ -3717,8 +4347,9 @@ add(int ac, char *av[])
|
|||||||
|
|
||||||
case TOK_PROTO:
|
case TOK_PROTO:
|
||||||
NEED1("missing protocol");
|
NEED1("missing protocol");
|
||||||
if (add_proto(cmd, *av)) {
|
if (add_proto(cmd, *av, &proto)) {
|
||||||
proto = cmd->arg1;
|
if (proto == IPPROTO_IPV6)
|
||||||
|
fill_cmd(cmd, O_IP6, 0, 0);
|
||||||
ac--; av++;
|
ac--; av++;
|
||||||
} else
|
} else
|
||||||
errx(EX_DATAERR, "invalid protocol ``%s''",
|
errx(EX_DATAERR, "invalid protocol ``%s''",
|
||||||
@ -3739,6 +4370,20 @@ add(int ac, char *av[])
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case TOK_SRCPORT:
|
||||||
NEED1("missing source port");
|
NEED1("missing source port");
|
||||||
if (_substrcmp(*av, "any") == 0 ||
|
if (_substrcmp(*av, "any") == 0 ||
|
||||||
@ -3787,6 +4432,24 @@ add(int ac, char *av[])
|
|||||||
fill_cmd(cmd, O_IPSEC, 0, 0);
|
fill_cmd(cmd, O_IPSEC, 0, 0);
|
||||||
break;
|
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:
|
case TOK_COMMENT:
|
||||||
fill_comment(cmd, ac, av);
|
fill_comment(cmd, ac, av);
|
||||||
av += ac;
|
av += ac;
|
||||||
|
@ -77,6 +77,9 @@
|
|||||||
#include <netinet/if_ether.h> /* for struct arpcom */
|
#include <netinet/if_ether.h> /* for struct arpcom */
|
||||||
#include <net/bridge.h>
|
#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
|
* We keep a private variable for the simulation time, but we could
|
||||||
* probably use an existing one ("softticks" in sys/kern/kern_timeout.c)
|
* 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) ;
|
ip_input(m) ;
|
||||||
break ;
|
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 :
|
case DN_TO_BDG_FWD :
|
||||||
/*
|
/*
|
||||||
* The bridge requires/assumes the Ethernet header is
|
* 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 */
|
int i = 0 ; /* we need i and q for new allocations */
|
||||||
struct dn_flow_queue *q, *prev;
|
struct dn_flow_queue *q, *prev;
|
||||||
|
int is_v6 = IS_IP6_FLOW_ID(id);
|
||||||
|
|
||||||
if ( !(fs->flags_fs & DN_HAVE_FLOW_MASK) )
|
if ( !(fs->flags_fs & DN_HAVE_FLOW_MASK) )
|
||||||
q = fs->rq[0] ;
|
q = fs->rq[0] ;
|
||||||
else {
|
else {
|
||||||
/* first, do the masking */
|
/* first, do the masking, then hash */
|
||||||
id->dst_ip &= fs->flow_mask.dst_ip ;
|
|
||||||
id->src_ip &= fs->flow_mask.src_ip ;
|
|
||||||
id->dst_port &= fs->flow_mask.dst_port ;
|
id->dst_port &= fs->flow_mask.dst_port ;
|
||||||
id->src_port &= fs->flow_mask.src_port ;
|
id->src_port &= fs->flow_mask.src_port ;
|
||||||
id->proto &= fs->flow_mask.proto ;
|
id->proto &= fs->flow_mask.proto ;
|
||||||
id->flags = 0 ; /* we don't care about this one */
|
id->flags = 0 ; /* we don't care about this one */
|
||||||
/* then, hash function */
|
if (is_v6) {
|
||||||
i = ( (id->dst_ip) & 0xffff ) ^
|
APPLY_MASK(&id->dst_ip6, &fs->flow_mask.dst_ip6);
|
||||||
( (id->dst_ip >> 15) & 0xffff ) ^
|
APPLY_MASK(&id->src_ip6, &fs->flow_mask.src_ip6);
|
||||||
( (id->src_ip << 1) & 0xffff ) ^
|
id->flow_id6 &= fs->flow_mask.flow_id6;
|
||||||
( (id->src_ip >> 16 ) & 0xffff ) ^
|
|
||||||
(id->dst_port << 1) ^ (id->src_port) ^
|
i = ((id->dst_ip6.__u6_addr.__u6_addr32[0]) & 0xffff)^
|
||||||
(id->proto );
|
((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 ;
|
i = i % fs->rq_size ;
|
||||||
/* finally, scan the current list for a match */
|
/* finally, scan the current list for a match */
|
||||||
searches++ ;
|
searches++ ;
|
||||||
for (prev=NULL, q = fs->rq[i] ; q ; ) {
|
for (prev=NULL, q = fs->rq[i] ; q ; ) {
|
||||||
search_steps++;
|
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->src_ip == q->id.src_ip &&
|
||||||
id->dst_port == q->id.dst_port &&
|
id->dst_port == q->id.dst_port &&
|
||||||
id->src_port == q->id.src_port &&
|
id->src_port == q->id.src_port &&
|
||||||
id->proto == q->id.proto &&
|
id->proto == q->id.proto &&
|
||||||
id->flags == q->id.flags)
|
id->flags == q->id.flags)
|
||||||
break ; /* found */
|
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 */
|
/* entry is idle and not in any heap, expire it */
|
||||||
struct dn_flow_queue *old_q = q ;
|
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->dn_dir = dir ;
|
||||||
|
|
||||||
pkt->ifp = fwa->oif;
|
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;
|
pkt->flags = fwa->flags;
|
||||||
|
|
||||||
if (q->head == NULL)
|
if (q->head == NULL)
|
||||||
q->head = m;
|
q->head = m;
|
||||||
else
|
else
|
||||||
@ -2015,7 +2070,7 @@ static void
|
|||||||
ip_dn_init(void)
|
ip_dn_init(void)
|
||||||
{
|
{
|
||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
printf("DUMMYNET initialized (011031)\n");
|
printf("DUMMYNET with IPv6 initialized (040826)\n");
|
||||||
|
|
||||||
DUMMYNET_LOCK_INIT();
|
DUMMYNET_LOCK_INIT();
|
||||||
|
|
||||||
|
@ -124,10 +124,13 @@ struct dn_pkt_tag {
|
|||||||
#define DN_TO_BDG_FWD 3
|
#define DN_TO_BDG_FWD 3
|
||||||
#define DN_TO_ETH_DEMUX 4
|
#define DN_TO_ETH_DEMUX 4
|
||||||
#define DN_TO_ETH_OUT 5
|
#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 */
|
dn_key output_time; /* when the pkt is due for delivery */
|
||||||
struct ifnet *ifp; /* interface, for ip_output */
|
struct ifnet *ifp; /* interface, for ip_output */
|
||||||
int flags ; /* flags, for ip_output (IPv6 ?) */
|
int flags ; /* flags, for ip_output (IPv6 ?) */
|
||||||
|
struct _ip6dn_args ip6opt; /* XXX ipv6 options */
|
||||||
};
|
};
|
||||||
#endif /* _KERNEL */
|
#endif /* _KERNEL */
|
||||||
|
|
||||||
|
@ -137,6 +137,16 @@ enum ipfw_opcodes { /* arguments (4 byte each) */
|
|||||||
O_ALTQ, /* u32 = altq classif. qid */
|
O_ALTQ, /* u32 = altq classif. qid */
|
||||||
O_DIVERTED, /* arg1=bitmap (1:loop, 2:out) */
|
O_DIVERTED, /* arg1=bitmap (1:loop, 2:out) */
|
||||||
O_TCPDATALEN, /* arg1 = tcp data len */
|
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
|
* actions for ng_ipfw
|
||||||
@ -147,6 +157,16 @@ enum ipfw_opcodes { /* arguments (4 byte each) */
|
|||||||
O_LAST_OPCODE /* not an opcode! */
|
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.
|
* Template for instructions.
|
||||||
*
|
*
|
||||||
@ -291,6 +311,30 @@ typedef struct _ipfw_insn_log {
|
|||||||
u_int32_t log_left; /* how many left to log */
|
u_int32_t log_left; /* how many left to log */
|
||||||
} ipfw_insn_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.
|
* Here we have the structure representing an ipfw rule.
|
||||||
*
|
*
|
||||||
@ -354,8 +398,14 @@ struct ipfw_flow_id {
|
|||||||
u_int16_t src_port;
|
u_int16_t src_port;
|
||||||
u_int8_t proto;
|
u_int8_t proto;
|
||||||
u_int8_t flags; /* protocol-specific flags */
|
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.
|
* Dynamic ipfw rule.
|
||||||
*/
|
*/
|
||||||
@ -438,6 +488,21 @@ enum {
|
|||||||
#define IP_FW_DIVERT_LOOPBACK_FLAG 0x00080000
|
#define IP_FW_DIVERT_LOOPBACK_FLAG 0x00080000
|
||||||
#define IP_FW_DIVERT_OUTPUT_FLAG 0x00100000
|
#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
|
* Arguments for calling ipfw_chk() and dummynet_io(). We put them
|
||||||
* all into a structure because this way it is easier and more
|
* 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 */
|
struct ipfw_flow_id f_id; /* grabbed from IP header */
|
||||||
u_int32_t cookie; /* a cookie depending on rule action */
|
u_int32_t cookie; /* a cookie depending on rule action */
|
||||||
struct inpcb *inp;
|
struct inpcb *inp;
|
||||||
|
|
||||||
|
struct _ip6dn_args dummypar; /* dummynet->ip6_output */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -86,6 +86,9 @@
|
|||||||
#include <netinet6/ipsec.h>
|
#include <netinet6/ipsec.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <netinet/ip6.h>
|
||||||
|
#include <netinet/icmp6.h>
|
||||||
|
|
||||||
#include <netinet/if_ether.h> /* XXX for ETHERTYPE_IP */
|
#include <netinet/if_ether.h> /* XXX for ETHERTYPE_IP */
|
||||||
|
|
||||||
#include <machine/in_cksum.h> /* XXX for in_cksum */
|
#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 TCP(p) ((struct tcphdr *)(p))
|
||||||
#define UDP(p) ((struct udphdr *)(p))
|
#define UDP(p) ((struct udphdr *)(p))
|
||||||
#define ICMP(p) ((struct icmp *)(p))
|
#define ICMP(p) ((struct icmp *)(p))
|
||||||
|
#define ICMP6(p) ((struct icmp6_hdr *)(p))
|
||||||
|
|
||||||
static __inline int
|
static __inline int
|
||||||
icmptype_match(struct icmp *icmp, ipfw_insn_u32 *cmd)
|
icmptype_match(struct icmp *icmp, ipfw_insn_u32 *cmd)
|
||||||
@ -555,6 +559,83 @@ verify_path(struct in_addr src, struct ifnet *ifp)
|
|||||||
return 1;
|
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...) */
|
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;
|
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);
|
i &= (curr_dyn_buckets - 1);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@ -912,19 +994,40 @@ lookup_dyn_rule_locked(struct ipfw_flow_id *pkt, int *match_direction,
|
|||||||
}
|
}
|
||||||
if (pkt->proto == q->id.proto &&
|
if (pkt->proto == q->id.proto &&
|
||||||
q->dyn_type != O_LIMIT_PARENT) {
|
q->dyn_type != O_LIMIT_PARENT) {
|
||||||
if (pkt->src_ip == q->id.src_ip &&
|
if (IS_IP6_FLOW_ID(pkt)) {
|
||||||
pkt->dst_ip == q->id.dst_ip &&
|
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->src_port == q->id.src_port &&
|
||||||
pkt->dst_port == q->id.dst_port ) {
|
pkt->dst_port == q->id.dst_port ) {
|
||||||
dir = MATCH_FORWARD;
|
dir = MATCH_FORWARD;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (pkt->src_ip == q->id.dst_ip &&
|
if (IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6),
|
||||||
pkt->dst_ip == q->id.src_ip &&
|
&(q->id.dst_ip6)) &&
|
||||||
pkt->src_port == q->id.dst_port &&
|
IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6),
|
||||||
pkt->dst_port == q->id.src_port ) {
|
&(q->id.src_ip6)) &&
|
||||||
dir = MATCH_REVERSE;
|
pkt->src_port == q->id.dst_port &&
|
||||||
break;
|
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:
|
next:
|
||||||
@ -1122,15 +1225,25 @@ lookup_dyn_parent(struct ipfw_flow_id *pkt, struct ip_fw *rule)
|
|||||||
IPFW_DYN_LOCK_ASSERT();
|
IPFW_DYN_LOCK_ASSERT();
|
||||||
|
|
||||||
if (ipfw_dyn_v) {
|
if (ipfw_dyn_v) {
|
||||||
|
int is_v6 = IS_IP6_FLOW_ID(pkt);
|
||||||
i = hash_packet( pkt );
|
i = hash_packet( pkt );
|
||||||
for (q = ipfw_dyn_v[i] ; q != NULL ; q=q->next)
|
for (q = ipfw_dyn_v[i] ; q != NULL ; q=q->next)
|
||||||
if (q->dyn_type == O_LIMIT_PARENT &&
|
if (q->dyn_type == O_LIMIT_PARENT &&
|
||||||
rule== q->rule &&
|
rule== q->rule &&
|
||||||
pkt->proto == q->id.proto &&
|
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->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;
|
q->expire = time_second + dyn_short_lifetime;
|
||||||
DEB(printf("ipfw: lookup_dyn_parent found 0x%p\n",q);)
|
DEB(printf("ipfw: lookup_dyn_parent found 0x%p\n",q);)
|
||||||
return 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.dst_port = id.src_port = 0;
|
||||||
id.proto = args->f_id.proto;
|
id.proto = args->f_id.proto;
|
||||||
|
|
||||||
if (limit_mask & DYN_SRC_ADDR)
|
if (IS_IP6_FLOW_ID (&(args->f_id))) {
|
||||||
id.src_ip = args->f_id.src_ip;
|
if (limit_mask & DYN_SRC_ADDR)
|
||||||
if (limit_mask & DYN_DST_ADDR)
|
id.src_ip6 = args->f_id.src_ip6;
|
||||||
id.dst_ip = args->f_id.dst_ip;
|
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)
|
if (limit_mask & DYN_SRC_PORT)
|
||||||
id.src_port = args->f_id.src_port;
|
id.src_port = args->f_id.src_port;
|
||||||
if (limit_mask & DYN_DST_PORT)
|
if (limit_mask & DYN_DST_PORT)
|
||||||
@ -1831,6 +1951,10 @@ ipfw_chk(struct ip_fw_args *args)
|
|||||||
* ulp is NULL if not found.
|
* ulp is NULL if not found.
|
||||||
*/
|
*/
|
||||||
void *ulp = NULL; /* upper layer protocol pointer. */
|
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)
|
if (m->m_flags & M_SKIP_FIREWALL)
|
||||||
return (IP_FW_PASS); /* accept */
|
return (IP_FW_PASS); /* accept */
|
||||||
@ -1855,15 +1979,95 @@ do { \
|
|||||||
p = (mtod(m, char *) + (len)); \
|
p = (mtod(m, char *) + (len)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* Identify IP packets and fill up veriables. */
|
/* Identify IP packets and fill up variables. */
|
||||||
if (pktlen >= sizeof(struct ip) &&
|
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) &&
|
(args->eh == NULL || ntohs(args->eh->ether_type) == ETHERTYPE_IP) &&
|
||||||
mtod(m, struct ip *)->ip_v == 4) {
|
mtod(m, struct ip *)->ip_v == 4) {
|
||||||
ip = mtod(m, struct ip *);
|
ip = mtod(m, struct ip *);
|
||||||
hlen = ip->ip_hl << 2;
|
hlen = ip->ip_hl << 2;
|
||||||
#ifdef NOTYET
|
|
||||||
args->f_id.addr_type = 4;
|
args->f_id.addr_type = 4;
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Collect parameters into local variables for faster matching.
|
* Collect parameters into local variables for faster matching.
|
||||||
@ -2027,11 +2231,13 @@ do { \
|
|||||||
case O_JAIL:
|
case O_JAIL:
|
||||||
/*
|
/*
|
||||||
* We only check offset == 0 && proto != 0,
|
* 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.
|
* packet with the ports info.
|
||||||
*/
|
*/
|
||||||
if (offset!=0)
|
if (offset!=0)
|
||||||
break;
|
break;
|
||||||
|
if (is_ipv6) /* XXX to be fixed later */
|
||||||
|
break;
|
||||||
if (proto == IPPROTO_TCP ||
|
if (proto == IPPROTO_TCP ||
|
||||||
proto == IPPROTO_UDP)
|
proto == IPPROTO_UDP)
|
||||||
match = check_uidgid(
|
match = check_uidgid(
|
||||||
@ -2086,7 +2292,7 @@ do { \
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case O_FRAG:
|
case O_FRAG:
|
||||||
match = (hlen > 0 && offset != 0);
|
match = (offset != 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case O_IN: /* "out" is "not in" */
|
case O_IN: /* "out" is "not in" */
|
||||||
@ -2195,7 +2401,7 @@ do { \
|
|||||||
case O_IP_DSTPORT:
|
case O_IP_DSTPORT:
|
||||||
/*
|
/*
|
||||||
* offset == 0 && proto != 0 is enough
|
* offset == 0 && proto != 0 is enough
|
||||||
* to guarantee that we have an IPv4
|
* to guarantee that we have a
|
||||||
* packet with port info.
|
* packet with port info.
|
||||||
*/
|
*/
|
||||||
if ((proto==IPPROTO_UDP || proto==IPPROTO_TCP)
|
if ((proto==IPPROTO_UDP || proto==IPPROTO_TCP)
|
||||||
@ -2218,12 +2424,22 @@ do { \
|
|||||||
icmptype_match(ICMP(ulp), (ipfw_insn_u32 *)cmd) );
|
icmptype_match(ICMP(ulp), (ipfw_insn_u32 *)cmd) );
|
||||||
break;
|
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:
|
case O_IPOPT:
|
||||||
match = (hlen > 0 && ipopts_match(ip, cmd) );
|
match = (hlen > 0 &&
|
||||||
|
ipopts_match(mtod(m, struct ip *), cmd) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case O_IPVER:
|
case O_IPVER:
|
||||||
match = (hlen > 0 && cmd->arg1 == ip->ip_v);
|
match = (hlen > 0 &&
|
||||||
|
cmd->arg1 == mtod(m, struct ip *)->ip_v);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case O_IPID:
|
case O_IPID:
|
||||||
@ -2237,9 +2453,9 @@ do { \
|
|||||||
if (cmd->opcode == O_IPLEN)
|
if (cmd->opcode == O_IPLEN)
|
||||||
x = ip_len;
|
x = ip_len;
|
||||||
else if (cmd->opcode == O_IPTTL)
|
else if (cmd->opcode == O_IPTTL)
|
||||||
x = ip->ip_ttl;
|
x = mtod(m, struct ip *)->ip_ttl;
|
||||||
else /* must be IPID */
|
else /* must be IPID */
|
||||||
x = ntohs(ip->ip_id);
|
x = ntohs(mtod(m, struct ip *)->ip_id);
|
||||||
if (cmdlen == 1) {
|
if (cmdlen == 1) {
|
||||||
match = (cmd->arg1 == x);
|
match = (cmd->arg1 == x);
|
||||||
break;
|
break;
|
||||||
@ -2254,12 +2470,12 @@ do { \
|
|||||||
|
|
||||||
case O_IPPRECEDENCE:
|
case O_IPPRECEDENCE:
|
||||||
match = (hlen > 0 &&
|
match = (hlen > 0 &&
|
||||||
(cmd->arg1 == (ip->ip_tos & 0xe0)) );
|
(cmd->arg1 == (mtod(m, struct ip *)->ip_tos & 0xe0)) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case O_IPTOS:
|
case O_IPTOS:
|
||||||
match = (hlen > 0 &&
|
match = (hlen > 0 &&
|
||||||
flags_match(cmd, ip->ip_tos));
|
flags_match(cmd, mtod(m, struct ip *)->ip_tos));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case O_TCPDATALEN:
|
case O_TCPDATALEN:
|
||||||
@ -2357,8 +2573,12 @@ do { \
|
|||||||
|
|
||||||
case O_VERREVPATH:
|
case O_VERREVPATH:
|
||||||
/* Outgoing packets automatically pass/match */
|
/* 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) ||
|
(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)));
|
verify_path(src_ip, m->m_pkthdr.rcvif)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2389,6 +2609,60 @@ do { \
|
|||||||
/* otherwise no match */
|
/* otherwise no match */
|
||||||
break;
|
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',
|
* The second set of opcodes represents 'actions',
|
||||||
* i.e. the terminal part of a rule once the packet
|
* 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_VERSRCREACH:
|
||||||
case O_ANTISPOOF:
|
case O_ANTISPOOF:
|
||||||
case O_IPSEC:
|
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))
|
if (cmdlen != F_INSN_SIZE(ipfw_insn))
|
||||||
goto bad_size;
|
goto bad_size;
|
||||||
break;
|
break;
|
||||||
@ -3177,6 +3455,29 @@ check_ipfw_struct(struct ip_fw *rule, int size)
|
|||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
printf("ipfw: opcode %d, unknown opcode\n",
|
printf("ipfw: opcode %d, unknown opcode\n",
|
||||||
cmd->opcode);
|
cmd->opcode);
|
||||||
@ -3577,7 +3878,7 @@ ipfw_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ip_fw_default_rule = layer3_chain.rules;
|
ip_fw_default_rule = layer3_chain.rules;
|
||||||
printf("ipfw2 initialized, divert %s, "
|
printf("ipfw2 (+ipv6) initialized, divert %s, "
|
||||||
"rule-based forwarding "
|
"rule-based forwarding "
|
||||||
#ifdef IPFIREWALL_FORWARD
|
#ifdef IPFIREWALL_FORWARD
|
||||||
"enabled, "
|
"enabled, "
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "opt_ipfw.h"
|
#include "opt_ipfw.h"
|
||||||
#include "opt_ipdn.h"
|
#include "opt_ipdn.h"
|
||||||
#include "opt_inet.h"
|
#include "opt_inet.h"
|
||||||
|
#include "opt_inet6.h"
|
||||||
#ifndef INET
|
#ifndef INET
|
||||||
#error IPFIREWALL requires INET.
|
#error IPFIREWALL requires INET.
|
||||||
#endif /* INET */
|
#endif /* INET */
|
||||||
@ -155,7 +156,10 @@ ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
|
|||||||
case IP_FW_DUMMYNET:
|
case IP_FW_DUMMYNET:
|
||||||
if (!DUMMYNET_LOADED)
|
if (!DUMMYNET_LOADED)
|
||||||
goto drop;
|
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;
|
*m0 = NULL;
|
||||||
return 0; /* packet consumed */
|
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:
|
case IP_FW_DUMMYNET:
|
||||||
if (!DUMMYNET_LOADED)
|
if (!DUMMYNET_LOADED)
|
||||||
break;
|
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;
|
*m0 = NULL;
|
||||||
return 0; /* packet consumed */
|
return 0; /* packet consumed */
|
||||||
|
|
||||||
@ -410,6 +417,9 @@ static int
|
|||||||
ipfw_hook(void)
|
ipfw_hook(void)
|
||||||
{
|
{
|
||||||
struct pfil_head *pfh_inet;
|
struct pfil_head *pfh_inet;
|
||||||
|
#ifdef INET6
|
||||||
|
struct pfil_head *pfh_inet6;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (ipfw_pfil_hooked)
|
if (ipfw_pfil_hooked)
|
||||||
return EEXIST;
|
return EEXIST;
|
||||||
@ -417,9 +427,18 @@ ipfw_hook(void)
|
|||||||
pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
|
pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
|
||||||
if (pfh_inet == NULL)
|
if (pfh_inet == NULL)
|
||||||
return ENOENT;
|
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_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
|
||||||
pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | 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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -428,6 +447,9 @@ static int
|
|||||||
ipfw_unhook(void)
|
ipfw_unhook(void)
|
||||||
{
|
{
|
||||||
struct pfil_head *pfh_inet;
|
struct pfil_head *pfh_inet;
|
||||||
|
#ifdef INET6
|
||||||
|
struct pfil_head *pfh_inet6;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!ipfw_pfil_hooked)
|
if (!ipfw_pfil_hooked)
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
@ -435,9 +457,18 @@ ipfw_unhook(void)
|
|||||||
pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
|
pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
|
||||||
if (pfh_inet == NULL)
|
if (pfh_inet == NULL)
|
||||||
return ENOENT;
|
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_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
|
||||||
pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
#include <net/netisr.h>
|
||||||
#include <net/route.h>
|
#include <net/route.h>
|
||||||
#include <net/pfil.h>
|
#include <net/pfil.h>
|
||||||
|
|
||||||
@ -167,6 +168,7 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp, inp)
|
|||||||
int hlen, tlen, len, off;
|
int hlen, tlen, len, off;
|
||||||
struct route_in6 ip6route;
|
struct route_in6 ip6route;
|
||||||
struct sockaddr_in6 *dst;
|
struct sockaddr_in6 *dst;
|
||||||
|
struct in6_addr odst;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
struct in6_ifaddr *ia = NULL;
|
struct in6_ifaddr *ia = NULL;
|
||||||
u_long mtu;
|
u_long mtu;
|
||||||
@ -524,6 +526,7 @@ skip_ipsec2:;
|
|||||||
ro = &opt->ip6po_route;
|
ro = &opt->ip6po_route;
|
||||||
dst = (struct sockaddr_in6 *)&ro->ro_dst;
|
dst = (struct sockaddr_in6 *)&ro->ro_dst;
|
||||||
|
|
||||||
|
again:
|
||||||
/*
|
/*
|
||||||
* If there is a cached route,
|
* If there is a cached route,
|
||||||
* check that it is to the same destination
|
* check that it is to the same destination
|
||||||
@ -937,12 +940,35 @@ skip_ipsec2:;
|
|||||||
if (inet6_pfil_hook.ph_busy_count == -1)
|
if (inet6_pfil_hook.ph_busy_count == -1)
|
||||||
goto passout;
|
goto passout;
|
||||||
|
|
||||||
|
odst = ip6->ip6_dst;
|
||||||
/* Run through list of hooks for output packets. */
|
/* Run through list of hooks for output packets. */
|
||||||
error = pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_OUT, inp);
|
error = pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_OUT, inp);
|
||||||
if (error != 0 || m == NULL)
|
if (error != 0 || m == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
ip6 = mtod(m, struct ip6_hdr *);
|
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:
|
passout:
|
||||||
/*
|
/*
|
||||||
* Send the packet to the outgoing interface.
|
* Send the packet to the outgoing interface.
|
||||||
|
Loading…
Reference in New Issue
Block a user