Finish ipset match option implementation.

Signed-off-by: Tom Eastep <teastep@shorewall.net>
This commit is contained in:
Tom Eastep 2014-01-02 14:43:55 -08:00
parent b4847d6a01
commit 1771bb75cf
6 changed files with 333 additions and 46 deletions

View File

@ -25,7 +25,7 @@
# loaded after this one and replaces some of the functions declared here.
#
SHOREWALL_CAPVERSION=40515
SHOREWALL_CAPVERSION=40600
[ -n "${g_program:=shorewall}" ]
@ -2265,6 +2265,8 @@ determine_capabilities() {
OWNER_NAME_MATCH=
IPSET_MATCH=
OLD_IPSET_MATCH=
IPSET_MATCH_NOMATCH=
IPSET_MATCH_COUNTERS=
IPSET_V5=
CONNMARK=
XCONNMARK=
@ -2552,6 +2554,8 @@ determine_capabilities() {
if [ -n "$have_ipset" ]; then
if qt $g_tool -A $chain -m set --match-set $chain src -j ACCEPT; then
qt $g_tool -A $chain -m set --match-set $chain src --return-nomatch -j ACCEPT && IPSET_MATCH_NOMATCH=Yes
qt $g_tool -A $chain -m set --match-set $chain src --packets-lt 100 -j ACCEPT && IPSET_MATCH_COUNTERS=Yes
qt $g_tool -F $chain
IPSET_MATCH=Yes
elif qt $g_tool -A $chain -m set --set $chain src -j ACCEPT; then
@ -2686,7 +2690,9 @@ report_capabilities_unsorted() {
report_capability "Owner Name Match (OWNER_NAME_MATCH)" $OWNER_NAME_MATCH
if [ -n "$IPSET_MATCH" ]; then
report_capability "Ipset Match (IPSET_MATCH)" $IPSET_MATCH
[ -n "$OLD_IPSET_MATCH" ] && report_capability "OLD_Ipset Match (OLD_IPSET_MATCH)" $OLD_IPSET_MATCH
[ -n "$OLD_IPSET_MATCH" ] && report_capability "OLD_Ipset Match (OLD_IPSET_MATCH)" $OLD_IPSET_MATCH
[ -n "$IPSET_MATCH_NOMATCH" ] && report_capability "Ipset Match Nomatch (IPSET_MATCH_NOMATCH)" $IPSET_MATCH_NOMATCH
[ -n "$IPSET_MATCH_NOMATCH" ] && report_capability "Ipset Match Counters (IPSET_MATCH_COUNTERS)" $IPSET_MATCH_COUNTERS
fi
report_capability "CONNMARK Target (CONNMARK)" $CONNMARK
[ -n "$CONNMARK" ] && report_capability "Extended CONNMARK Target (XCONNMARK)" $XCONNMARK
@ -2808,6 +2814,8 @@ report_capabilities_unsorted1() {
report_capability1 OWNER_NAME_MATCH
report_capability1 IPSET_MATCH
report_capability1 OLD_IPSET_MATCH
report_capability1 IPSET_MATCH_NOMATCH
report_capability1 IPSET_MATCH_COUNTERS
report_capability1 CONNMARK
report_capability1 XCONNMARK
report_capability1 CONNMARK_MATCH

View File

@ -455,14 +455,8 @@ our %ipset_extensions = (
'nomatch' => '--return-nomatch ',
'no-update-counters' => '! --update-counters ',
'no-update-subcounters' => '! --update-subcounters ',
'pkts-eq' => '--packets-eq = ',
'pkts-neq' => '! --packets-eq = ',
'pkts-lt' => '--packets-lt = ',
'pkts-gt' => '--packets-gt = ',
'bytes-eq' => '--bytes-eq = ',
'bytes-neq' => '! --bytes-eq = ',
'bytes-lt' => '--bytes-lt = ',
'bytes-gt' => '--bytes-gt = ',
'packets' => '',
'bytes' => '',
);
#
# See initialize() below for additional comments on these variables
@ -5457,35 +5451,24 @@ sub get_set_flags( $$ ) {
$setname =~ s/^!//; # Caller has already taken care of leading !
if ( $setname =~ s/\((.+)\)$// ) {
fatal_error "Your iptables and/or kernel are too old to support an IPSET option list" if have_capability 'OLD_IPSET_MATCH';
my @extensions = split_list($1, 'ipset option');
my $rest = '';
for ( @extensions ) {
my ($extension, $value) = split ' ', $_;
my $match = $ipset_extensions{$extension};
fatal_error "Unknown ipset option ($extension)" unless $match;
if ( $match =~ /= $/ ) {
my $val;
fatal_error "The $extension option requires a value" unless supplied $value;
fatal_error "Invalid number ($value)" unless defined ( $val = numeric_value($value) );
$match =~ s/= $/$value /;
} else {
fatal_error "The $extension option does not require a value" if supplied $value;
}
$extensions = join( '', $extensions, $match );
}
}
if ( $setname =~ /^(.*)\[([1-6])\]$/ ) {
if ( $setname =~ /^(.*)\[([1-6])(?:,(.*))\]$/ ) {
$setname = $1;
my $count = $2;
$rest = $3;
$options .= ",$option" while --$count > 0;
} elsif ( $setname =~ /^(.*)\[((src|dst)(,(src|dst))*)\]$/ ) {
} elsif ( $setname =~ /^(.*)\[((?:src|dst)(?:,(?:src|dst))*)*(,?.+)?\]$/ ) {
$setname = $1;
$options = $2;
$rest = $3;
if ( supplied $2 ) {
$options = $2;
if ( supplied $rest ) {
fatal_error "Invalid Option List (${options}${rest})" unless $rest =~ s/^,//;
}
}
my @options = split /,/, $options;
my %typemap = ( src => 'Source', dst => 'Destination' );
@ -5495,6 +5478,50 @@ sub get_set_flags( $$ ) {
warning_message( "The '$_' ipset flag is used in a $typemap{$option} column" ), last unless $_ eq $option;
}
}
}
if ( $rest ) {
my @extensions = split_list($rest, 'ipset option');
for ( @extensions ) {
my ($extension, $relop, $value) = split /(!=|=|<|>)/, $_;
my $match = $ipset_extensions{$extension};
fatal_error "Unknown ipset option ($extension)" unless defined $match;
require_capability ( ( $extension eq 'nomatch' ?
'IPSET_MATCH_NOMATCH' :
'IPSET_MATCH_COUNTERS' ),
"The '$extension' option",
's' );
if ( $match ) {
fatal_error "The $extension option does not require a value" if supplied $relop || supplied $value;
$extensions .= "$match ";
} else {
my $val;
fatal_error "The $extension option requires a value" unless supplied $value;
fatal_error "Invalid number ($value)" unless defined ( $val = numeric_value($value) );
$extension = "--$extension";
if ( $relop =~ s/!// ) {
$extension = join( ' ', '!', $extension );
}
if ( $relop eq '<' ) {
$extension .= '-lt';
} elsif ( $relop eq '>' ) {
$extension .= '-gt';
} else {
$extension .= '-eq';
}
$extension = join( ' ', $extension, $value );
$extensions .= "$extension ";
}
}
}
$setname =~ s/^\+//;
@ -5651,7 +5678,7 @@ sub match_source_net( $;$\$ ) {
fatal_error "Multiple ipset matches require the Repeat Match capability in your kernel and iptables" unless $globals{KLUDGEFREE};
for $net ( @sets ) {
fatal_error "Expected ipset name ($net)" unless $net =~ /^(!?)(?:\+?)((?:6_)?[a-zA-Z][-\w]*(?:\[.*\])?)(?:\((.+)\))?$/;
fatal_error "Expected ipset name ($net)" unless $net =~ /^(!?)(?:\+?)((?:6_)?[a-zA-Z][-\w]*(?:\[.*\]))?(?:\((.+)\))?$/;
$result .= join( '', '-m set ', $1 ? '! ' : '', get_set_flags( $2, 'src' ) );
if ( $3 ) {
require_capability 'NFACCT_MATCH', "An nfacct object list ($3)", 's';
@ -5720,7 +5747,7 @@ sub imatch_source_net( $;$\$ ) {
return do_imac $net;
}
if ( $net =~ /^(!?)(?:\+?)((?:6_)?[a-zA-Z][-\w]*(?:\[.*\])?)(?:\((.+)\))?$/ ) {
if ( $net =~ /^(!?)(?:\+?)((?:6_)?[a-zA-Z][-\w]*(?:\[.*\]))?(?:\((.+)\))?$/ ) {
my @result = ( set => join( '', $1 ? '! ' : '', get_set_flags( $2, 'src' ) ) );
if ( $3 ) {
require_capability 'NFACCT_MATCH', "An nfacct object list ($3)", 's';
@ -5740,7 +5767,7 @@ sub imatch_source_net( $;$\$ ) {
fatal_error "Multiple ipset matches requires the Repeat Match capability in your kernel and iptables" unless $globals{KLUDGEFREE};
for $net ( @sets ) {
fatal_error "Expected ipset name ($net)" unless $net =~ /^(!?)(?:\+?)((?:6_)?[a-zA-Z][-\w]*(?:\[.*\])?)(?:\((.+)\))?$/;
fatal_error "Expected ipset name ($net)" unless $net =~ /^(!?)(?:\+?)((?:6_)?[a-zA-Z][-\w]*(?:\[.*\]))?(?:\((.+)\))?$/;
push @result , ( set => join( '', $1 ? '! ' : '', get_set_flags( $2, 'src' ) ) );
if ( $3 ) {
require_capability 'NFACCT_MATCH', "An nfacct object list ($3)", 's';
@ -5805,7 +5832,7 @@ sub match_dest_net( $;$ ) {
return iprange_match . "${invert}--dst-range $net ";
}
if ( $net =~ /^(!?)(?:\+?)((?:6_)?[a-zA-Z][-\w]*(?:\[.*\])?)(?:\((.+)\))?$/ ) {
if ( $net =~ /^(!?)(?:\+?)((?:6_)?[a-zA-Z][-\w]*(?:\[.*\]))?(?:\((.+)\))?$/ ) {
my $result = join( '', '-m set ', $1 ? '! ' : '', get_set_flags( $2, 'dst' ) );
if ( $3 ) {
require_capability 'NFACCT_MATCH', "An nfacct object list ($3)", 's';
@ -5825,7 +5852,7 @@ sub match_dest_net( $;$ ) {
fatal_error "Multiple ipset matches requires the Repeat Match capability in your kernel and iptables" unless $globals{KLUDGEFREE};
for $net ( @sets ) {
fatal_error "Expected ipset name ($net)" unless $net =~ /^(!?)(?:\+?)((?:6_)?[a-zA-Z][-\w]*(?:\[.*\])?)(?:\((.+)\))?$/;
fatal_error "Expected ipset name ($net)" unless $net =~ /^(!?)(?:\+?)((?:6_)?[a-zA-Z][-\w]*(?:\[.*\]))?(?:\((.+)\))?$/;
$result .= join( '', '-m set ', $1 ? '! ' : '', get_set_flags( $2, 'dst' ) );
}
@ -5889,7 +5916,7 @@ sub imatch_dest_net( $;$ ) {
return ( iprange => "${invert}--dst-range $net" );
}
if ( $net =~ /^(!?)(?:\+?)((?:6_)?[a-zA-Z][-\w]*(?:\[.*\])?)(?:\((.+)\))?$/ ) {
if ( $net =~ /^(!?)(?:\+?)((?:6_)?[a-zA-Z][-\w]*(?:\[.*\]))?(?:\((.+)\))?$/ ) {
my @result = ( set => join( '', $1 ? '! ' : '', get_set_flags( $2, 'dst' ) ) );
if ( $3 ) {
require_capability 'NFACCT_MATCH', "An nfacct object list ($3)", 's';
@ -5909,7 +5936,7 @@ sub imatch_dest_net( $;$ ) {
fatal_error "Multiple ipset matches requires the Repeat Match capability in your kernel and iptables" unless $globals{KLUDGEFREE};
for $net ( @sets ) {
fatal_error "Expected ipset name ($net)" unless $net =~ /^(!?)(?:\+?)((?:6_)?[a-zA-Z][-\w]*(?:\[.*\])?)(?:\((.+)\))?$/;
fatal_error "Expected ipset name ($net)" unless $net =~ /^(!?)(?:\+?)((?:6_)?[a-zA-Z][-\w]*(?:\[.*\]))?(?:\((.+)\))?$/;
push @result , ( set => join( '', $1 ? '! ' : '', get_set_flags( $2, 'dst' ) ) );
if ( $3 ) {
require_capability 'NFACCT_MATCH', "An nfacct object list ($3)", 's';

View File

@ -703,7 +703,7 @@ sub initialize( $;$$) {
EXPORT => 0,
KLUDGEFREE => '',
VERSION => "4.5.19-Beta1",
CAPVERSION => 40515 ,
CAPVERSION => 40600 ,
);
#
# From shorewall.conf file

View File

@ -47,8 +47,8 @@
<simplelist>
<member>[<replaceable>number</replaceable>] - Indicates that 'src' or
'dst' should be repeated <replaceable>number</replaceable> times.
Example: myset[2].</member>
'dst' should be repeated <replaceable>number</replaceable> times.
Example: myset[2].</member>
<member>[<replaceable>flag</replaceable>,...] where
<replaceable>flag</replaceable> is <option>src</option> or
@ -92,11 +92,134 @@
<para>In that example, when the source address of a packet matches the
<emphasis role="bold">myset</emphasis> ipset, the <emphasis
role="bold">myobject</emphasis> nfacct counter will be incremented.</para>
<para>Beginning with Shorewall 4.6.0, an ipset name (and src/dst list, if
any) can be immediately be followed by a list of match options. Available
options are:</para>
<variablelist>
<varlistentry>
<term>nomatch</term>
<listitem>
<para> If the set type supports the nomatch flag, then the matching
is reversed: a match with an element flagged with nomatch returns
true, while a match with a plain element returns false. This option
requires the 'Ipset Match nomatch' capability in your kernel and
ip[6]tables.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>no-update-counters</term>
<listitem>
<para>The packet and byte counters of the matching element in the
set won't be updated. By default, the packet and byte counters are
updated. This option and those that follow require the 'Ipset Match
counters' capability in your kernel and ip[6]tables.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>no-update-subcounters</term>
<listitem>
<para>The packet and byte counters of the matching element in the
member set of a list type of set won't be updated. Default the
packet and byte counters are updated.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>packets=<replaceable>value</replaceable></term>
<listitem>
<para>If the packet is matched an element in the set, match only if
the packet counter of the element matches the given
<replaceable>value</replaceable> too.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>packets&lt;<replaceable>value</replaceable></term>
<listitem>
<para>If the packet is matched an element in the set, match only if
the packet counter of the element is less than the given
<replaceable>value</replaceable> as well.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>packets&gt;<replaceable>value</replaceable></term>
<listitem>
<para>If the packet is matched an element in the set, match only if
the packet counter of the element is greater than the given
<replaceable>value</replaceable> as well.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>packets!=<replaceable>value</replaceable></term>
<listitem>
<para>If the packet is matched an element in the set, match only if
the packet counter of the element does not match the given
<replaceable>value</replaceable> too.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>bytes=<replaceable>value</replaceable></term>
<listitem>
<para>If the packet is matched an element in the set, match only if
the byte counter of the element matches the given
<replaceable>value</replaceable> too.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>bytes&lt;<replaceable>value</replaceable></term>
<listitem>
<para>If the packet is matched an element in the set, match only if
the byte counter of the element is less than the given
<replaceable>value</replaceable> as well.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>bytes&gt;<replaceable>value</replaceable></term>
<listitem>
<para>If the packet is matched an element in the set, match only if
the byte counter of the element is greater than the given
<replaceable>value</replaceable> as well.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>bytes!=<replaceable>value</replaceable></term>
<listitem>
<para>If the packet is matched an element in the set, match only if
the byte counter of the element does not match the given
<replaceable>value</replaceable> too.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Examples</title>
<para>In the examples that follow, <firstterm>myset</firstterm>,
<firstterm>myset1</firstterm> and <firstterm>myset2</firstterm> are ipsets
and <firstterm>myObject</firstterm> is an NFacct object name.</para>
<para>+myset</para>
<para>+myset[src]</para>
@ -104,6 +227,12 @@
<para>+myset[2]</para>
<para>+[myset1,myset2[dst]]</para>
<para>+myset[src](myObject)</para>
<para>+myset[src,nomatch,packets&gt;100]</para>
<para>+myset[nomatch,no-update-counters](myObject)</para>
</refsect1>
<refsect1>
@ -125,7 +254,7 @@
<para>/etc/shorewall/secmarks</para>
<para>/etc/shorewall/tcrules</para>
<para>/etc/shorewall/mangle</para>
</refsect1>
<refsect1>

View File

@ -91,6 +91,125 @@
<para>In that example, when the source address of a packet matches the
<emphasis role="bold">myset</emphasis> ipset, the <emphasis
role="bold">myobject</emphasis> nfacct counter will be incremented.</para>
<para>Beginning with Shorewall 4.6.0, an ipset name (and src/dst list, if
any) can be immediately be followed by a list of match options. Available
options are:</para>
<variablelist>
<varlistentry>
<term>nomatch</term>
<listitem>
<para>If the set type supports the nomatch flag, then the matching
is reversed: a match with an element flagged with nomatch returns
true, while a match with a plain element returns false. This option
requires the 'Ipset Match nomatch' capability in your kernel and
ip[6]tables.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>no-update-counters</term>
<listitem>
<para>The packet and byte counters of the matching element in the
set won't be updated. By default, the packet and byte counters are
updated. This option and those that follow require the 'Ipset Match
counters' capability in your kernel and ip[6]tables.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>no-update-subcounters</term>
<listitem>
<para>The packet and byte counters of the matching element in the
member set of a list type of set won't be updated. Default the
packet and byte counters are updated.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>packets=<replaceable>value</replaceable></term>
<listitem>
<para>If the packet is matched an element in the set, match only if
the packet counter of the element matches the given
<replaceable>value</replaceable> too.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>packets&lt;<replaceable>value</replaceable></term>
<listitem>
<para>If the packet is matched an element in the set, match only if
the packet counter of the element is less than the given
<replaceable>value</replaceable> as well.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>packets&gt;<replaceable>value</replaceable></term>
<listitem>
<para>If the packet is matched an element in the set, match only if
the packet counter of the element is greater than the given
<replaceable>value</replaceable> as well.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>packets!=<replaceable>value</replaceable></term>
<listitem>
<para>If the packet is matched an element in the set, match only if
the packet counter of the element does not match the given
<replaceable>value</replaceable> too.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>bytes=<replaceable>value</replaceable></term>
<listitem>
<para>If the packet is matched an element in the set, match only if
the byte counter of the element matches the given
<replaceable>value</replaceable> too.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>bytes&lt;<replaceable>value</replaceable></term>
<listitem>
<para>If the packet is matched an element in the set, match only if
the byte counter of the element is less than the given
<replaceable>value</replaceable> as well.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>bytes&gt;<replaceable>value</replaceable></term>
<listitem>
<para>If the packet is matched an element in the set, match only if
the byte counter of the element is greater than the given
<replaceable>value</replaceable> as well.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>bytes!=<replaceable>value</replaceable></term>
<listitem>
<para>If the packet is matched an element in the set, match only if
the byte counter of the element does not match the given
<replaceable>value</replaceable> too.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
@ -103,6 +222,10 @@
<para>+myset[2]</para>
<para>+[myset1,myset2[dst]]</para>
<para>+myset[src,nomatch,packets&gt;100]</para>
<para>+myset[nomatch,no-update-counters](myObject)</para>
</refsect1>
<refsect1>