summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
authorbrooks <brooks@FreeBSD.org>2005-04-18 18:35:05 +0000
committerbrooks <brooks@FreeBSD.org>2005-04-18 18:35:05 +0000
commitf3ecaa630b5d676d2b43b5da90f46c294bd63836 (patch)
treeeb64e48417a6452c61a02673f46e16a8590fd13a /sbin
parent6dfe72cfb93de2ed0bca56214d34e7154c93b420 (diff)
downloadFreeBSD-src-f3ecaa630b5d676d2b43b5da90f46c294bd63836.zip
FreeBSD-src-f3ecaa630b5d676d2b43b5da90f46c294bd63836.tar.gz
Add IPv6 support to IPFW and Dummynet.
Submitted by: Mariano Tortoriello and Raffaele De Lorenzo (via luigi)
Diffstat (limited to 'sbin')
-rw-r--r--sbin/ipfw/ipfw.8152
-rw-r--r--sbin/ipfw/ipfw2.c733
2 files changed, 820 insertions, 65 deletions
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
index 3f4bc9a..a5a8bc2 100644
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -346,18 +346,18 @@ in the protocol stack, under control of several sysctl variables.
These places and variables are shown below, and it is important to
have this picture in mind in order to design a correct ruleset.
.Bd -literal -offset indent
- ^ to upper layers V
- | |
- +----------->-----------+
- ^ V
- [ip_input] [ip_output] net.inet.ip.fw.enable=1
- | |
- ^ V
-[ether_demux] [ether_output_frame] net.link.ether.ipfw=1
- | |
- +-->--[bdg_forward]-->--+ net.link.ether.bridge_ipfw=1
- ^ V
- | to devices |
+ ^ to upper layers V
+ | |
+ +----------->-----------+
+ ^ V
+ [ip(6)_input] [ip(6)_output] net.inet.ip.fw.enable=1
+ | |
+ ^ V
+ [ether_demux] [ether_output_frame] net.link.ether.ipfw=1
+ | |
+ +-->--[bdg_forward]-->--+ net.link.ether.bridge_ipfw=1
+ ^ V
+ | to devices |
.Ed
.Pp
As can be noted from the above picture, the number of
@@ -375,13 +375,17 @@ is invoked from
but the same packets will have the MAC header stripped off when
.Nm
is invoked from
-.Cm ip_input() .
+.Cm ip_input()
+or
+.Cm ip6_input() .
.Pp
Also note that each packet is always checked against the complete ruleset,
irrespective of the place where the check occurs, or the source of the packet.
If a rule contains some match patterns or actions which are not valid
for the place of invocation (e.g.\& trying to match a MAC header within
-.Fn ip_input ) ,
+.Cm ip_input
+or
+.Cm ip6_input ),
the match pattern will not match, but a
.Cm not
operator in front of such patterns
@@ -448,7 +452,7 @@ for filtering packets, among the following:
.Bl -tag -width "Source and dest. addresses and ports" -offset XXX -compact
.It Layer-2 header fields
When available
-.It IPv4 Protocol
+.It IPv4 and IPv6 Protocol
TCP, UDP, ICMP, etc.
.It Source and dest. addresses and ports
.It Direction
@@ -461,6 +465,10 @@ Version, type of service, datagram length, identification,
fragment flag (non-zero IP offset),
Time To Live
.It IP options
+.It IPv6 Extension headers
+Fragmentation, Hop-by-Hop options,
+source routing, IPSec options.
+.It IPv6 Flow-ID
.It Misc. TCP header fields
TCP flags (SYN, FIN, ACK, RST, etc.),
sequence number, acknowledgment number,
@@ -468,6 +476,8 @@ window
.It TCP options
.It ICMP types
for ICMP packets
+.It ICMP6 types
+for ICMP6 packets
.It User/group ID
When the packet can be associated with a local socket.
.It Divert status
@@ -806,7 +816,7 @@ compatibility with
.Nm ipfw1 .
In
.Nm ipfw2
-any match pattern (including MAC headers, IPv4 protocols,
+any match pattern (including MAC headers, IP protocols,
addresses and ports) can be specified in the
.Ar options
section.
@@ -815,11 +825,13 @@ Rule fields have the following meaning:
.Bl -tag -width indent
.It Ar proto : protocol | Cm { Ar protocol Cm or ... }
.It Ar protocol : Oo Cm not Oc Ar protocol-name | protocol-number
-An IPv4 protocol specified by number or name
+An IP protocol specified by number or name
(for a complete list see
.Pa /etc/protocols ) .
The
-.Cm ip
+.Cm ip ,
+.Cm ip6 ,
+.Cm ipv6 ,
or
.Cm all
keywords mean any protocol will match.
@@ -840,7 +852,7 @@ The second format
with multiple addresses) is provided for convenience only and
its use is discouraged.
.It Ar addr : Oo Cm not Oc Bro
-.Cm any | me |
+.Cm any | me | me6
.Cm table Ns Pq Ar number Ns Op , Ns Ar value
.Ar | addr-list | addr-set
.Brc
@@ -848,10 +860,12 @@ its use is discouraged.
matches any IP address.
.It Cm me
matches any IP address configured on an interface in the system.
+.It Cm me6
+matches any IPv6 address configured on an interface in the system.
The address list is evaluated at the time the packet is
analysed.
.It Cm table Ns Pq Ar number Ns Op , Ns Ar value
-Matches any IP address for which an entry exists in the lookup table
+Matches any IPv4 address for which an entry exists in the lookup table
.Ar number .
If an optional 32-bit unsigned
.Ar value
@@ -918,6 +932,30 @@ As an example, an address specified as 1.2.3.4/24{128,35-55,89}
will match the following IP addresses:
.br
1.2.3.128, 1.2.3.35 to 1.2.3.55, 1.2.3.89 .
+.It Ar addr6-list : ip6-addr Ns Op Ns , Ns Ar addr6-list
+.It Ar ip6-addr :
+A host or subnet specified one of the following ways:
+.Pp
+.Bl -tag -width indent
+.It Ar numeric-ip | hostname
+Matches a single IPv6 address as allowed by
+.Xr inet_pton 3
+or a hostname.
+Hostnames are resolved at the time the rule is added to the firewall
+list.
+.It Ar addr Ns / Ns Ar masklen
+Matches all IPv6 addresses with base
+.Ar addr
+(specified as allowed by
+.Xr inet_pton
+or a hostname)
+and mask width of
+.Cm masklen
+bits.
+.El
+.Pp
+No support for sets of IPv6 addresses is provided because IPv6 addresses
+are typically random past the initial prefix.
.It Ar ports : Bro Ar port | port Ns \&- Ns Ar port Ns Brc Ns Op , Ns Ar ports
For protocols which support port numbers (such as TCP and UDP), optional
.Cm ports
@@ -986,13 +1024,36 @@ input for delivery.
Matches only packets going from a divert socket back outward to the IP
stack output for delivery.
.It Cm dst-ip Ar ip-address
-Matches IP packets whose destination IP is one of the address(es)
+Matches IPv4 packets whose destination IP is one of the address(es)
+specified as argument.
+.It Bro Cm dst-ip6 | dst-ipv6 Brc Ar ip6-address
+Matches IPv6 packets whose destination IP is one of the address(es)
specified as argument.
.It Cm dst-port Ar ports
Matches IP packets whose destination port is one of the port(s)
specified as argument.
.It Cm established
Matches TCP packets that have the RST or ACK bits set.
+.It Cm ext6hdr Ar header
+Matches IPv6 packets containing the extended header given by
+.Ar header .
+Supported headers are:
+.Pp
+Fragment,
+.Pq Cm frag ,
+Hop-to-hop options
+.Pq Cm hopopt ,
+Source routing
+.Pq Cm route ,
+IPSec authentication headers
+.Pq Cm ah ,
+and IPSec encapsulated security payload headers
+.Pq Cm esp .
+.It Cm flow-id Ar labels
+Matches IPv6 packets containing any of the flow labels given in
+.Ar labels .
+.Ar labels
+is a comma seperate list of numeric flow labels.
.It Cm frag
Matches packets that are fragments and not the first
fragment of an IP datagram.
@@ -1047,6 +1108,12 @@ address mask request
.Pq Cm 17
and address mask reply
.Pq Cm 18 .
+.It Cm icmp6types Ar types
+Matches ICMP6 packets whose ICMP6 type is in the list of
+.Ar types .
+The list may be specified as any combination of
+individual types (numeric) separated by commas.
+.Em Ranges are not allowed.
.It Cm in | out
Matches incoming or outgoing packets, respectively.
.Cm in
@@ -1057,7 +1124,7 @@ are mutually exclusive (in fact,
is implemented as
.Cm not in Ns No ).
.It Cm ipid Ar id-list
-Matches IP packets whose
+Matches IPv4 packets whose
.Cm ip_id
field has value included in
.Ar id-list ,
@@ -1072,7 +1139,7 @@ which is either a single value or a list of values or ranges
specified in the same way as
.Ar ports .
.It Cm ipoptions Ar spec
-Matches packets whose IP header contains the comma separated list of
+Matches packets whose IPv4 header contains the comma separated list of
options specified in
.Ar spec .
The supported IP options are:
@@ -1089,7 +1156,7 @@ The absence of a particular option may be denoted
with a
.Ql \&! .
.It Cm ipprecedence Ar precedence
-Matches IP packets whose precedence field is equal to
+Matches IPv4 packets whose precedence field is equal to
.Ar precedence .
.It Cm ipsec
Matches packets that have IPSEC history associated with them
@@ -1111,7 +1178,7 @@ rules are handled as if with no
.Cm ipsec
flag.
.It Cm iptos Ar spec
-Matches IP packets whose
+Matches IPv4 packets whose
.Cm tos
field contains the comma separated list of
service types specified in
@@ -1132,7 +1199,7 @@ The absence of a particular type may be denoted
with a
.Ql \&! .
.It Cm ipttl Ar ttl-list
-Matches IP packets whose time to live is included in
+Matches IPv4 packets whose time to live is included in
.Ar ttl-list ,
which is either a single value or a list of values or ranges
specified in the same way as
@@ -1160,6 +1227,8 @@ set of parameters as specified in the rule.
One or more
of source and destination addresses and ports can be
specified.
+Currently,
+only IPv4 flows are supported.
.It Cm { MAC | mac } Ar dst-mac src-mac
Match packets with a given
.Ar dst-mac
@@ -1212,7 +1281,7 @@ and they are always printed as hexadecimal (unless the
.Cm -N
option is used, in which case symbolic resolution will be attempted).
.It Cm proto Ar protocol
-Matches packets with the corresponding IPv4 protocol.
+Matches packets with the corresponding IP protocol.
.It Cm recv | xmit | via Brq Ar ifX | Ar if Ns Cm * | Ar ipno | Ar any
Matches packets received, transmitted or going through,
respectively, the interface specified by exact name
@@ -1260,8 +1329,11 @@ Matches TCP packets that have the SYN bit set but no ACK bit.
This is the short form of
.Dq Li tcpflags\ syn,!ack .
.It Cm src-ip Ar ip-address
-Matches IP packets whose source IP is one of the address(es)
-specified as argument.
+Matches IPv4 packets whose source IP is one of the address(es)
+specified as an argument.
+.It Cm src-ip6 Ar ip6-address
+Matches IPv6 packets whose source IP is one of the address(es)
+specified as an argument.
.It Cm src-port Ar ports
Matches IP packets whose source port is one of the port(s)
specified as argument.
@@ -1388,7 +1460,7 @@ connected networks instead of all source addresses.
.Sh LOOKUP TABLES
Lookup tables are useful to handle large sparse address sets,
typically from a hundred to several thousands of entries.
-There could be 128 different lookup tables, numbered 0 to 127.
+There may be up to 128 different lookup tables, numbered 0 to 127.
.Pp
Each entry is represented by an
.Ar addr Ns Op / Ns Ar masklen
@@ -1422,6 +1494,8 @@ or flushed
Internally, each table is stored in a Radix tree, the same way as
the routing table (see
.Xr route 4 ) .
+.Pp
+Lookup tables currently support IPv4 addresses only.
.Sh SETS OF RULES
Each rule belongs to one of 32 different
.Em sets
@@ -1694,9 +1768,12 @@ with different weights might be connected to the same pipe).
Available mask specifiers are a combination of one or more of the following:
.Pp
.Cm dst-ip Ar mask ,
+.Cm dst-ip6 Ar mask ,
.Cm src-ip Ar mask ,
+.Cm src-ip6 Ar mask ,
.Cm dst-port Ar mask ,
.Cm src-port Ar mask ,
+.Cm flow-id Ar mask ,
.Cm proto Ar mask
or
.Cm all ,
@@ -1767,6 +1844,14 @@ specifies the expected maximum packet size, only used when queue
thresholds are in bytes (defaults to 1500, must be greater than zero).
.El
.El
+.Pp
+When used with IPv6 data, dummynet currently has several limitations.
+First, debug.mpsafenet=0 must be set.
+Second, the information necessicary to route link-local packets to an
+interface is not avalable after processing by dummynet so those packets
+are dropped in the output path.
+Care should be taken to insure that link-local packets are not passed to
+dummynet.
.Sh CHECKLIST
Here are some important points to consider when designing your
rules:
@@ -2092,6 +2177,9 @@ The following option for
.Nm dummynet
pipes/queues is not supported:
.Cm noerror .
+.It IPv6 Support
+There was no IPv6 support in
+.Nm ipfw1 .
.El
.Sh EXAMPLES
There are far too many possible uses of
@@ -2396,6 +2484,8 @@ Work on
.Xr dummynet 4
traffic shaper supported by Akamba Corp.
.Sh BUGS
+Use of dummynet with IPv6 requires that debug.mpsafenet be set to 0.
+.Pp
The syntax has grown over the years and sometimes it might be confusing.
Unfortunately, backward compatibility prevents cleaning up mistakes
made in the definition of the syntax.
@@ -2424,3 +2514,5 @@ If a packet is reinserted in this manner, later rules may be incorrectly
applied, making the order of
.Cm divert
rules in the rule sequence very important.
+.Pp
+Dummynet drops all packets with IPv6 link-local addresses.
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index 4e60e5b..fb2f67d 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -49,10 +49,12 @@
#include <net/if.h>
#include <net/pfvar.h>
+#include <net/route.h> /* def. of struct route */
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
#include <netinet/ip_fw.h>
#include <netinet/ip_dummynet.h>
#include <netinet/tcp.h>
@@ -266,6 +268,13 @@ enum tokens {
TOK_DROPTAIL,
TOK_PROTO,
TOK_WEIGHT,
+
+ TOK_IPV6,
+ TOK_FLOWID,
+ TOK_ICMP6TYPES,
+ TOK_EXT6HDR,
+ TOK_DSTIP6,
+ TOK_SRCIP6,
};
struct _s_x dummynet_params[] = {
@@ -288,6 +297,11 @@ struct _s_x dummynet_params[] = {
{ "delay", TOK_DELAY },
{ "pipe", TOK_PIPE },
{ "queue", TOK_QUEUE },
+ { "flow-id", TOK_FLOWID},
+ { "dst-ipv6", TOK_DSTIP6},
+ { "dst-ip6", TOK_DSTIP6},
+ { "src-ipv6", TOK_SRCIP6},
+ { "src-ip6", TOK_SRCIP6},
{ "dummynet-params", TOK_NULL },
{ NULL, 0 } /* terminator */
};
@@ -375,6 +389,16 @@ struct _s_x rule_options[] = {
{ "versrcreach", TOK_VERSRCREACH },
{ "antispoof", TOK_ANTISPOOF },
{ "ipsec", TOK_IPSEC },
+ { "icmp6type", TOK_ICMP6TYPES },
+ { "icmp6types", TOK_ICMP6TYPES },
+ { "ext6hdr", TOK_EXT6HDR},
+ { "flow-id", TOK_FLOWID},
+ { "ipv6", TOK_IPV6},
+ { "ip6", TOK_IPV6},
+ { "dst-ipv6", TOK_DSTIP6},
+ { "dst-ip6", TOK_DSTIP6},
+ { "src-ipv6", TOK_SRCIP6},
+ { "src-ip6", TOK_SRCIP6},
{ "//", TOK_COMMENT },
{ "not", TOK_NOT }, /* pseudo option */
@@ -1025,6 +1049,199 @@ print_icmptypes(ipfw_insn_u32 *cmd)
}
}
+/*
+ * Print the ip address contained in a command.
+ */
+static void
+print_ip6(ipfw_insn_ip6 *cmd, char const *s)
+{
+ struct hostent *he = NULL;
+ int len = F_LEN((ipfw_insn *) cmd) - 1;
+ struct in6_addr *a = &(cmd->addr6);
+ char trad[255];
+
+ printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s);
+
+ if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) {
+ printf("me6");
+ return;
+ }
+ if (cmd->o.opcode == O_IP6) {
+ printf(" ipv6");
+ return;
+ }
+
+ /*
+ * len == 4 indicates a single IP, whereas lists of 1 or more
+ * addr/mask pairs have len = (2n+1). We convert len to n so we
+ * use that to count the number of entries.
+ */
+
+ for (len = len / 4; len > 0; len -= 2, a += 2) {
+ int mb = /* mask length */
+ (cmd->o.opcode == O_IP6_SRC || cmd->o.opcode == O_IP6_DST) ?
+ 128 : contigmask((uint8_t *)&(a[1]), 128);
+
+ if (mb == 128 && do_resolv)
+ he = gethostbyaddr((char *)a, sizeof(*a), AF_INET6);
+ if (he != NULL) /* resolved to name */
+ printf("%s", he->h_name);
+ else if (mb == 0) /* any */
+ printf("any");
+ else { /* numeric IP followed by some kind of mask */
+ if (inet_ntop(AF_INET6, a, trad, sizeof( trad ) ) == NULL)
+ printf("Error ntop in print_ip6\n");
+ printf("%s", trad );
+ if (mb < 0) /* XXX not really legal... */
+ printf(":%s",
+ inet_ntop(AF_INET6, &a[1], trad, sizeof(trad)));
+ else if (mb < 128)
+ printf("/%d", mb);
+ }
+ if (len > 2)
+ printf(",");
+ }
+}
+
+static void
+fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av)
+{
+ uint8_t type;
+
+ cmd->d[0] = 0;
+ while (*av) {
+ if (*av == ',')
+ av++;
+ type = strtoul(av, &av, 0);
+ if (*av != ',' && *av != '\0')
+ errx(EX_DATAERR, "invalid ICMP6 type");
+ /*
+ * XXX: shouldn't this be 0xFF? I can't see any reason why
+ * we shouldn't be able to filter all possiable values
+ * regardless of the ability of the rest of the kernel to do
+ * anything useful with them.
+ */
+ if (type > ICMP6_MAXTYPE)
+ errx(EX_DATAERR, "ICMP6 type out of range");
+ cmd->d[type / 32] |= ( 1 << (type % 32));
+ }
+ cmd->o.opcode = O_ICMP6TYPE;
+ cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6);
+}
+
+
+static void
+print_icmp6types(ipfw_insn_u32 *cmd)
+{
+ int i, j;
+ char sep= ' ';
+
+ printf(" ipv6 icmp6types");
+ for (i = 0; i < 7; i++)
+ for (j=0; j < 32; ++j) {
+ if ( (cmd->d[i] & (1 << (j))) == 0)
+ continue;
+ printf("%c%d", sep, (i*32 + j));
+ sep = ',';
+ }
+}
+
+static void
+print_flow6id( ipfw_insn_u32 *cmd)
+{
+ uint16_t i, limit = cmd->o.arg1;
+ char sep = ',';
+
+ printf(" flow-id ");
+ for( i=0; i < limit; ++i) {
+ if (i == limit - 1)
+ sep = ' ';
+ printf("%d%c", cmd->d[i], sep);
+ }
+}
+
+/* structure and define for the extension header in ipv6 */
+static struct _s_x ext6hdrcodes[] = {
+ { "frag", EXT_FRAGMENT },
+ { "hopopt", EXT_HOPOPTS },
+ { "route", EXT_ROUTING },
+ { "ah", EXT_AH },
+ { "esp", EXT_ESP },
+ { NULL, 0 }
+};
+
+/* fills command for the extension header filtering */
+int
+fill_ext6hdr( ipfw_insn *cmd, char *av)
+{
+ int tok;
+ char *s = av;
+
+ cmd->arg1 = 0;
+
+ while(s) {
+ av = strsep( &s, ",") ;
+ tok = match_token(ext6hdrcodes, av);
+ switch (tok) {
+ case EXT_FRAGMENT:
+ cmd->arg1 |= EXT_FRAGMENT;
+ break;
+
+ case EXT_HOPOPTS:
+ cmd->arg1 |= EXT_HOPOPTS;
+ break;
+
+ case EXT_ROUTING:
+ cmd->arg1 |= EXT_ROUTING;
+ break;
+
+ case EXT_AH:
+ cmd->arg1 |= EXT_AH;
+ break;
+
+ case EXT_ESP:
+ cmd->arg1 |= EXT_ESP;
+ break;
+
+ default:
+ errx( EX_DATAERR, "invalid option for ipv6 exten header" );
+ break;
+ }
+ }
+ if (cmd->arg1 == 0 )
+ return 0;
+ cmd->opcode = O_EXT_HDR;
+ cmd->len |= F_INSN_SIZE( ipfw_insn );
+ return 1;
+}
+
+void
+print_ext6hdr( ipfw_insn *cmd )
+{
+ char sep = ' ';
+
+ printf(" extension header:");
+ if (cmd->arg1 & EXT_FRAGMENT ) {
+ printf("%cfragmentation", sep);
+ sep = ',';
+ }
+ if (cmd->arg1 & EXT_HOPOPTS ) {
+ printf("%chop options", sep);
+ sep = ',';
+ }
+ if (cmd->arg1 & EXT_ROUTING ) {
+ printf("%crouting options", sep);
+ sep = ',';
+ }
+ if (cmd->arg1 & EXT_AH ) {
+ printf("%cauthentication header", sep);
+ sep = ',';
+ }
+ if (cmd->arg1 & EXT_ESP ) {
+ printf("%cencapsulated security payload", sep);
+ }
+}
+
/*
* show_ipfw() prints the body of an ipfw rule.
* Because the standard rule has at least proto src_ip dst_ip, we use
@@ -1043,6 +1260,7 @@ print_icmptypes(ipfw_insn_u32 *cmd)
#define HAVE_DSTIP 0x0004
#define HAVE_MAC 0x0008
#define HAVE_MACTYPE 0x0010
+#define HAVE_PROTO6 0x0080
#define HAVE_OPTIONS 0x8000
#define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
@@ -1065,6 +1283,9 @@ show_prerequisites(int *flags, int want, int cmd)
return;
}
if ( !(*flags & HAVE_OPTIONS)) {
+ /* XXX BED: !(*flags & HAVE_PROTO) in patch */
+ if ( !(*flags & HAVE_PROTO6) && (want & HAVE_PROTO6))
+ printf(" ipv6");
if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO))
printf(" ip");
if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP))
@@ -1329,6 +1550,37 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
flags |= HAVE_DSTIP;
break;
+ case O_IP6_SRC:
+ case O_IP6_SRC_MASK:
+ case O_IP6_SRC_ME:
+ show_prerequisites(&flags, HAVE_PROTO6, 0);
+ if (!(flags & HAVE_SRCIP))
+ printf(" from");
+ if ((cmd->len & F_OR) && !or_block)
+ printf(" {");
+ print_ip6((ipfw_insn_ip6 *)cmd,
+ (flags & HAVE_OPTIONS) ? " src-ip6" : "");
+ flags |= HAVE_SRCIP | HAVE_PROTO;
+ break;
+
+ case O_IP6_DST:
+ case O_IP6_DST_MASK:
+ case O_IP6_DST_ME:
+ show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);
+ if (!(flags & HAVE_DSTIP))
+ printf(" to");
+ if ((cmd->len & F_OR) && !or_block)
+ printf(" {");
+ print_ip6((ipfw_insn_ip6 *)cmd,
+ (flags & HAVE_OPTIONS) ? " dst-ip6" : "");
+ flags |= HAVE_DSTIP;
+ break;
+
+ case O_FLOW6ID:
+ print_flow6id( (ipfw_insn_u32 *) cmd );
+ flags |= HAVE_OPTIONS;
+ break;
+
case O_IP_DSTPORT:
show_prerequisites(&flags, HAVE_IP, 0);
case O_IP_SRCPORT:
@@ -1340,14 +1592,15 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
break;
case O_PROTO: {
- struct protoent *pe;
+ struct protoent *pe = NULL;
if ((cmd->len & F_OR) && !or_block)
printf(" {");
if (cmd->len & F_NOT)
printf(" not");
proto = cmd->arg1;
- pe = getprotobynumber(cmd->arg1);
+ if (proto != 41) /* XXX: IPv6 is special */
+ pe = getprotobynumber(cmd->arg1);
if (flags & HAVE_OPTIONS)
printf(" proto");
if (pe)
@@ -1558,6 +1811,18 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
}
break;
+ case O_IP6:
+ printf(" ipv6");
+ break;
+
+ case O_ICMP6TYPE:
+ print_icmp6types((ipfw_insn_u32 *)cmd);
+ break;
+
+ case O_EXT_HDR:
+ print_ext6hdr( (ipfw_insn *) cmd );
+ break;
+
default:
printf(" [opcode %d len %d]",
cmd->opcode, cmd->len);
@@ -1655,29 +1920,48 @@ static void
list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
{
int l;
+ int index_printed, indexes = 0;
+ char buff[255];
+ struct protoent *pe;
- printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
- fs->flow_mask.proto,
- fs->flow_mask.src_ip, fs->flow_mask.src_port,
- fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
if (fs->rq_elements == 0)
return;
- printf("BKT Prot ___Source IP/port____ "
- "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
if (do_sort != 0)
heapsort(q, fs->rq_elements, sizeof *q, sort_q);
+
+ /* Print IPv4 flows */
+ index_printed = 0;
for (l = 0; l < fs->rq_elements; l++) {
struct in_addr ina;
- struct protoent *pe;
- ina.s_addr = htonl(q[l].id.src_ip);
+ /* XXX: Should check for IPv4 flows */
+ if (IS_IP6_FLOW_ID(&(q[l].id)))
+ continue;
+
+ if (!index_printed) {
+ index_printed = 1;
+ if (indexes > 0) /* currently a no-op */
+ printf("\n");
+ indexes++;
+ printf(" "
+ "mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
+ fs->flow_mask.proto,
+ fs->flow_mask.src_ip, fs->flow_mask.src_port,
+ fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
+
+ printf("BKT Prot ___Source IP/port____ "
+ "____Dest. IP/port____ "
+ "Tot_pkt/bytes Pkt/Byte Drp\n");
+ }
+
printf("%3d ", q[l].hash_slot);
pe = getprotobynumber(q[l].id.proto);
if (pe)
printf("%-4s ", pe->p_name);
else
printf("%4u ", q[l].id.proto);
+ ina.s_addr = htonl(q[l].id.src_ip);
printf("%15s/%-5d ",
inet_ntoa(ina), q[l].id.src_port);
ina.s_addr = htonl(q[l].id.dst_ip);
@@ -1690,6 +1974,50 @@ list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
printf(" S %20qd F %20qd\n",
q[l].S, q[l].F);
}
+
+ /* Print IPv6 flows */
+ index_printed = 0;
+ for (l = 0; l < fs->rq_elements; l++) {
+ if (!IS_IP6_FLOW_ID(&(q[l].id)))
+ continue;
+
+ if (!index_printed) {
+ index_printed = 1;
+ if (indexes > 0)
+ printf("\n");
+ indexes++;
+ printf("\n mask: proto: 0x%02x, flow_id: 0x%08x, ",
+ fs->flow_mask.proto, fs->flow_mask.flow_id6);
+ inet_ntop(AF_INET6, &(fs->flow_mask.src_ip6),
+ buff, sizeof(buff));
+ printf("%s/0x%04x -> ", buff, fs->flow_mask.src_port);
+ inet_ntop( AF_INET6, &(fs->flow_mask.dst_ip6),
+ buff, sizeof(buff) );
+ printf("%s/0x%04x\n", buff, fs->flow_mask.dst_port);
+
+ printf("BKT ___Prot___ _flow-id_ "
+ "______________Source IPv6/port_______________ "
+ "_______________Dest. IPv6/port_______________ "
+ "Tot_pkt/bytes Pkt/Byte Drp\n");
+ }
+ printf("%3d ", q[l].hash_slot);
+ pe = getprotobynumber(q[l].id.proto);
+ if (pe != NULL)
+ printf("%9s ", pe->p_name);
+ else
+ printf("%9u ", q[l].id.proto);
+ printf("%7d %39s/%-5d ", q[l].id.flow_id6,
+ inet_ntop(AF_INET6, &(q[l].id.src_ip6), buff, sizeof(buff)),
+ q[l].id.src_port);
+ printf(" %39s/%-5d ",
+ inet_ntop(AF_INET6, &(q[l].id.dst_ip6), buff, sizeof(buff)),
+ q[l].id.dst_port);
+ printf(" %4qu %8qu %2u %4u %3u\n",
+ q[l].tot_pkts, q[l].tot_bytes,
+ q[l].len, q[l].len_bytes, q[l].drops);
+ if (verbose)
+ printf(" S %20qd F %20qd\n", q[l].S, q[l].F);
+ }
}
static void
@@ -2082,7 +2410,7 @@ list(int ac, char *av[], int show_counters)
if (do_dynamic && ndyn) {
printf("## Dynamic rules:\n");
for (lac = ac, lav = av; lac != 0; lac--) {
- rnum = strtoul(*lav++, &endptr, 10);
+ last = rnum = strtoul(*lav++, &endptr, 10);
if (*endptr == '-')
last = strtoul(endptr+1, &endptr, 10);
if (*endptr)
@@ -2132,19 +2460,24 @@ help(void)
"table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n"
"\n"
"RULE-BODY: check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\n"
-"ACTION: check-state | allow | count | deny | reject | skipto N |\n"
+"ACTION: check-state | allow | count | deny | unreach CODE | skipto N |\n"
" {divert|tee} PORT | forward ADDR | pipe N | queue N\n"
"PARAMS: [log [logamount LOGLIMIT]] [altq QUEUE_NAME]\n"
"ADDR: [ MAC dst src ether_type ] \n"
-" [ from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
+" [ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
+" [ ipv6|ip6 from IP6ADDR [ PORT ] to IP6ADDR [ PORTLIST ] ]\n"
"IPADDR: [not] { any | me | ip/bits{x,y,z} | table(t[,v]) | IPLIST }\n"
+"IP6ADDR: [not] { any | me | me6 | ip6/bits | IP6LIST }\n"
+"IP6LIST: { ip6 | ip6/bits }[,IP6LIST]\n"
"IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n"
"OPTION_LIST: OPTION [OPTION_LIST]\n"
"OPTION: bridged | diverted | diverted-loopback | diverted-output |\n"
-" {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n"
+" {dst-ip|src-ip} IPADDR | {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\n"
+" {dst-port|src-port} LIST |\n"
" estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n"
" iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n"
" ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n"
+" icmp6types LIST | ext6hdr LIST | flow-id N[,N] |\n"
" mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n"
" setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
" tcpdatalen LIST | verrevpath | versrcreach | antispoof\n"
@@ -2170,7 +2503,6 @@ lookup_host (char *host, struct in_addr *ipaddr)
* fills the addr and mask fields in the instruction as appropriate from av.
* Update length as appropriate.
* The following formats are allowed:
- * any matches any IP. Actually returns an empty instruction.
* me returns O_IP_*_ME
* 1.2.3.4 single IP address
* 1.2.3.4:5.6.7.8 address:mask
@@ -2357,6 +2689,231 @@ fill_ip(ipfw_insn_ip *cmd, char *av)
}
+/* Try to find ipv6 address by hostname */
+static int
+lookup_host6 (char *host, struct in6_addr *ip6addr)
+{
+ struct hostent *he;
+
+ if (!inet_pton(AF_INET6, host, ip6addr)) {
+ if ((he = gethostbyname2(host, AF_INET6)) == NULL)
+ return(-1);
+ memcpy(ip6addr, he->h_addr_list[0], sizeof( struct in6_addr));
+ }
+ return(0);
+}
+
+
+/* n2mask sets n bits of the mask */
+static void
+n2mask(struct in6_addr *mask, int n)
+{
+ static int minimask[9] =
+ { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+ u_char *p;
+
+ memset(mask, 0, sizeof(struct in6_addr));
+ p = (u_char *) mask;
+ for (; n > 0; p++, n -= 8) {
+ if (n >= 8)
+ *p = 0xff;
+ else
+ *p = minimask[n];
+ }
+ return;
+}
+
+
+/*
+ * fill the addr and mask fields in the instruction as appropriate from av.
+ * Update length as appropriate.
+ * The following formats are allowed:
+ * any matches any IP6. Actually returns an empty instruction.
+ * me returns O_IP6_*_ME
+ *
+ * 03f1::234:123:0342 single IP6 addres
+ * 03f1::234:123:0342/24 address/mask
+ * 03f1::234:123:0342/24,03f1::234:123:0343/ List of address
+ *
+ * Set of address (as in ipv6) not supported because ipv6 address
+ * are typically random past the initial prefix.
+ * Return 1 on success, 0 on failure.
+ */
+static int
+fill_ip6(ipfw_insn_ip6 *cmd, char *av)
+{
+ int len = 0;
+ struct in6_addr *d = &(cmd->addr6);
+ /*
+ * Needed for multiple address.
+ * Note d[1] points to struct in6_add r mask6 of cmd
+ */
+
+ cmd->o.len &= ~F_LEN_MASK; /* zero len */
+
+ if (strcmp(av, "any") == 0)
+ return (1);
+
+
+ if (strcmp(av, "me") == 0) { /* Set the data for "me" opt*/
+ cmd->o.len |= F_INSN_SIZE(ipfw_insn);
+ return (1);
+ }
+
+ if (strcmp(av, "me6") == 0) { /* Set the data for "me" opt*/
+ cmd->o.len |= F_INSN_SIZE(ipfw_insn);
+ return (1);
+ }
+
+ av = strdup(av);
+ while (av) {
+ /*
+ * After the address we can have '/' indicating a mask,
+ * or ',' indicating another address follows.
+ */
+
+ char *p;
+ int masklen;
+ char md = '\0';
+
+ if ((p = strpbrk(av, "/,")) ) {
+ md = *p; /* save the separator */
+ *p = '\0'; /* terminate address string */
+ p++; /* and skip past it */
+ }
+ /* now p points to NULL, mask or next entry */
+
+ /* lookup stores address in *d as a side effect */
+ if (lookup_host6(av, d) != 0) {
+ /* XXX: failed. Free memory and go */
+ errx(EX_DATAERR, "bad address \"%s\"", av);
+ }
+ /* next, look at the mask, if any */
+ masklen = (md == '/') ? atoi(p) : 128;
+ if (masklen > 128 || masklen < 0)
+ errx(EX_DATAERR, "bad width \"%s\''", p);
+ else
+ n2mask(&d[1], masklen);
+
+ APPLY_MASK(d, &d[1]) /* mask base address with mask */
+
+ /* find next separator */
+
+ if (md == '/') { /* find separator past the mask */
+ p = strpbrk(p, ",");
+ if (p != NULL)
+ p++;
+ }
+ av = p;
+
+ /* Check this entry */
+ if (masklen == 0) {
+ /*
+ * 'any' turns the entire list into a NOP.
+ * 'not any' never matches, so it is removed from the
+ * list unless it is the only item, in which case we
+ * report an error.
+ */
+ if (cmd->o.len & F_NOT && av == NULL && len == 0)
+ errx(EX_DATAERR, "not any never matches");
+ continue;
+ }
+
+ /*
+ * A single IP can be stored alone
+ */
+ if (masklen == 128 && av == NULL && len == 0) {
+ len = F_INSN_SIZE(struct in6_addr);
+ break;
+ }
+
+ /* Update length and pointer to arguments */
+ len += F_INSN_SIZE(struct in6_addr)*2;
+ d += 2;
+ } /* end while */
+
+ /*
+ * Total length of the command, remember that 1 is the size of
+ * the base command.
+ */
+ cmd->o.len |= len+1;
+ free(av);
+ return (1);
+}
+
+/*
+ * fills command for ipv6 flow-id filtering
+ * note that the 20 bit flow number is stored in a array of u_int32_t
+ * it's supported lists of flow-id, so in the o.arg1 we store how many
+ * additional flow-id we want to filter, the basic is 1
+ */
+void
+fill_flow6( ipfw_insn_u32 *cmd, char *av )
+{
+ u_int32_t type; /* Current flow number */
+ u_int16_t nflow = 0; /* Current flow index */
+ char *s = av;
+ cmd->d[0] = 0; /* Initializing the base number*/
+
+ while (s) {
+ av = strsep( &s, ",") ;
+ type = strtoul(av, &av, 0);
+ if (*av != ',' && *av != '\0')
+ errx(EX_DATAERR, "invalid ipv6 flow number %s", av);
+ if (type > 0xfffff)
+ errx(EX_DATAERR, "flow number out of range %s", av);
+ cmd->d[nflow] |= type;
+ nflow++;
+ }
+ if( nflow > 0 ) {
+ cmd->o.opcode = O_FLOW6ID;
+ cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + nflow;
+ cmd->o.arg1 = nflow;
+ }
+ else {
+ errx(EX_DATAERR, "invalid ipv6 flow number %s", av);
+ }
+}
+
+static ipfw_insn *
+add_srcip6(ipfw_insn *cmd, char *av)
+{
+
+ fill_ip6((ipfw_insn_ip6 *)cmd, av);
+ if (F_LEN(cmd) == 0) /* any */
+ ;
+ if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */
+ cmd->opcode = O_IP6_SRC_ME;
+ } else if (F_LEN(cmd) ==
+ (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) {
+ /* single IP, no mask*/
+ cmd->opcode = O_IP6_SRC;
+ } else { /* addr/mask opt */
+ cmd->opcode = O_IP6_SRC_MASK;
+ }
+ return cmd;
+}
+
+static ipfw_insn *
+add_dstip6(ipfw_insn *cmd, char *av)
+{
+
+ fill_ip6((ipfw_insn_ip6 *)cmd, av);
+ if (F_LEN(cmd) == 0) /* any */
+ ;
+ if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */
+ cmd->opcode = O_IP6_DST_ME;
+ } else if (F_LEN(cmd) ==
+ (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) {
+ /* single IP, no mask*/
+ cmd->opcode = O_IP6_DST;
+ } else { /* addr/mask opt */
+ cmd->opcode = O_IP6_DST_MASK;
+ }
+ return cmd;
+}
+
+
/*
* helper function to process a set of flags and set bits in the
* appropriate masks.
@@ -2468,7 +3025,6 @@ config_pipe(int ac, char **av)
struct dn_pipe p;
int i;
char *end;
- uint32_t a;
void *par = NULL;
memset(&p, 0, sizeof p);
@@ -2531,16 +3087,15 @@ config_pipe(int ac, char **av)
*/
par = NULL;
- p.fs.flow_mask.dst_ip = 0;
- p.fs.flow_mask.src_ip = 0;
- p.fs.flow_mask.dst_port = 0;
- p.fs.flow_mask.src_port = 0;
- p.fs.flow_mask.proto = 0;
+ bzero(&p.fs.flow_mask, sizeof(p.fs.flow_mask));
end = NULL;
while (ac >= 1) {
uint32_t *p32 = NULL;
uint16_t *p16 = NULL;
+ uint32_t *p20 = NULL;
+ struct in6_addr *pa6 = NULL;
+ uint32_t a;
tok = match_token(dummynet_params, *av);
ac--; av++;
@@ -2554,6 +3109,9 @@ config_pipe(int ac, char **av)
p.fs.flow_mask.dst_port = ~0;
p.fs.flow_mask.src_port = ~0;
p.fs.flow_mask.proto = ~0;
+ n2mask(&(p.fs.flow_mask.dst_ip6), 128);
+ n2mask(&(p.fs.flow_mask.src_ip6), 128);
+ p.fs.flow_mask.flow_id6 = ~0;
p.fs.flags_fs |= DN_HAVE_FLOW_MASK;
goto end_mask;
@@ -2565,6 +3123,18 @@ config_pipe(int ac, char **av)
p32 = &p.fs.flow_mask.src_ip;
break;
+ case TOK_DSTIP6:
+ pa6 = &(p.fs.flow_mask.dst_ip6);
+ break;
+
+ case TOK_SRCIP6:
+ pa6 = &(p.fs.flow_mask.src_ip6);
+ break;
+
+ case TOK_FLOWID:
+ p20 = &p.fs.flow_mask.flow_id6;
+ break;
+
case TOK_DSTPORT:
p16 = &p.fs.flow_mask.dst_port;
break;
@@ -2584,7 +3154,8 @@ config_pipe(int ac, char **av)
errx(EX_USAGE, "mask: value missing");
if (*av[0] == '/') {
a = strtoul(av[0]+1, &end, 0);
- a = (a == 32) ? ~0 : (1 << a) - 1;
+ if (pa6 == NULL)
+ a = (a == 32) ? ~0 : (1 << a) - 1;
} else
a = strtoul(av[0], &end, 0);
if (p32 != NULL)
@@ -2594,6 +3165,17 @@ config_pipe(int ac, char **av)
errx(EX_DATAERR,
"port mask must be 16 bit");
*p16 = (uint16_t)a;
+ } else if (p20 != NULL) {
+ if (a > 0xfffff)
+ errx(EX_DATAERR,
+ "flow_id mask must be 20 bit");
+ *p20 = (uint32_t)a;
+ } else if (pa6 != NULL) {
+ if (a < 0 || a > 128)
+ errx(EX_DATAERR,
+ "in6addr invalid mask len");
+ else
+ n2mask(pa6, a);
} else {
if (a > 0xFF)
errx(EX_DATAERR,
@@ -2918,21 +3500,25 @@ add_mactype(ipfw_insn *cmd, int ac, char *av)
}
static ipfw_insn *
-add_proto(ipfw_insn *cmd, char *av)
+add_proto(ipfw_insn *cmd, char *av, u_char *proto)
{
struct protoent *pe;
- u_char proto = 0;
+
+ *proto = IPPROTO_IP;
if (_substrcmp(av, "all") == 0)
; /* same as "ip" */
- else if ((proto = atoi(av)) > 0)
+ else if ((*proto = atoi(av)) > 0)
; /* all done! */
else if ((pe = getprotobyname(av)) != NULL)
- proto = pe->p_proto;
+ *proto = pe->p_proto;
+ else if (strcmp(av, "ipv6") == 0 || strcmp(av, "ip6"))
+ *proto = IPPROTO_IPV6;
else
return NULL;
- if (proto != IPPROTO_IP)
- fill_cmd(cmd, O_PROTO, 0, proto);
+ if (*proto != IPPROTO_IP && *proto != IPPROTO_IPV6)
+ fill_cmd(cmd, O_PROTO, 0, *proto);
+
return cmd;
}
@@ -2983,6 +3569,42 @@ add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode)
return NULL;
}
+static ipfw_insn *
+add_src(ipfw_insn *cmd, char *av, u_char proto)
+{
+ struct in6_addr a;
+
+ if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 ||
+ inet_pton(AF_INET6, av, &a))
+ return add_srcip6(cmd, av);
+ /* XXX: should check for IPv4, not !IPv6 */
+ if (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
+ !inet_pton(AF_INET6, av, &a))
+ return add_srcip(cmd, av);
+ if (strcmp(av, "any") != 0)
+ return cmd;
+
+ return NULL;
+}
+
+static ipfw_insn *
+add_dst(ipfw_insn *cmd, char *av, u_char proto)
+{
+ struct in6_addr a;
+
+ if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 ||
+ inet_pton(AF_INET6, av, &a))
+ return add_dstip6(cmd, av);
+ /* XXX: should check for IPv4, not !IPv6 */
+ if (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
+ !inet_pton(AF_INET6, av, &a))
+ return add_dstip(cmd, av);
+ if (strcmp(av, "any") != 0)
+ return cmd;
+
+ return NULL;
+}
+
/*
* Parse arguments and assemble the microinstructions which make up a rule.
* Rules are added into the 'rulebuf' and then copied in the correct order
@@ -3327,7 +3949,7 @@ add(int ac, char *av[])
OR_START(get_proto);
NOT_BLOCK;
NEED1("missing protocol");
- if (add_proto(cmd, *av)) {
+ if (add_proto(cmd, *av, &proto)) {
av++; ac--;
if (F_LEN(cmd) == 0) /* plain IP */
proto = 0;
@@ -3355,13 +3977,14 @@ add(int ac, char *av[])
OR_START(source_ip);
NOT_BLOCK; /* optional "not" */
NEED1("missing source address");
- if (add_srcip(cmd, *av)) {
+ if (add_src(cmd, *av, proto)) {
ac--; av++;
if (F_LEN(cmd) != 0) { /* ! any */
prev = cmd;
cmd = next_cmd(cmd);
}
- }
+ } else
+ errx(EX_USAGE, "bad source address %s", *av);
OR_BLOCK(source_ip);
/*
@@ -3390,13 +4013,14 @@ add(int ac, char *av[])
OR_START(dest_ip);
NOT_BLOCK; /* optional "not" */
NEED1("missing dst address");
- if (add_dstip(cmd, *av)) {
+ if (add_dst(cmd, *av, proto)) {
ac--; av++;
if (F_LEN(cmd) != 0) { /* ! any */
prev = cmd;
cmd = next_cmd(cmd);
}
- }
+ } else
+ errx( EX_USAGE, "bad destination address %s", *av);
OR_BLOCK(dest_ip);
/*
@@ -3513,6 +4137,12 @@ read_options:
fill_icmptypes((ipfw_insn_u32 *)cmd, *av);
av++; ac--;
break;
+
+ case TOK_ICMP6TYPES:
+ NEED1("icmptypes requires list of types");
+ fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av);
+ av++; ac--;
+ break;
case TOK_IPTTL:
NEED1("ipttl requires TTL");
@@ -3717,8 +4347,9 @@ read_options:
case TOK_PROTO:
NEED1("missing protocol");
- if (add_proto(cmd, *av)) {
- proto = cmd->arg1;
+ if (add_proto(cmd, *av, &proto)) {
+ if (proto == IPPROTO_IPV6)
+ fill_cmd(cmd, O_IP6, 0, 0);
ac--; av++;
} else
errx(EX_DATAERR, "invalid protocol ``%s''",
@@ -3739,6 +4370,20 @@ read_options:
}
break;
+ case TOK_SRCIP6:
+ NEED1("missing source IP6");
+ if (add_srcip6(cmd, *av)) {
+ ac--; av++;
+ }
+ break;
+
+ case TOK_DSTIP6:
+ NEED1("missing destination IP6");
+ if (add_dstip6(cmd, *av)) {
+ ac--; av++;
+ }
+ break;
+
case TOK_SRCPORT:
NEED1("missing source port");
if (_substrcmp(*av, "any") == 0 ||
@@ -3787,6 +4432,24 @@ read_options:
fill_cmd(cmd, O_IPSEC, 0, 0);
break;
+ case TOK_IPV6:
+ fill_cmd(cmd, O_IP6, 0, 0);
+ ac--; av++;
+ break;
+
+ case TOK_EXT6HDR:
+ fill_ext6hdr( cmd, *av );
+ ac--; av++;
+ break;
+
+ case TOK_FLOWID:
+ if (proto != IPPROTO_IPV6 )
+ errx( EX_USAGE, "flow-id filter is active "
+ "only for ipv6 protocol\n");
+ fill_flow6( (ipfw_insn_u32 *) cmd, *av );
+ ac--; av++;
+ break;
+
case TOK_COMMENT:
fill_comment(cmd, ac, av);
av += ac;
OpenPOWER on IntegriCloud