New IPSET MATCH extensions

Signed-off-by: Tom Eastep <teastep@shorewall.net>
This commit is contained in:
Tom Eastep 2014-01-02 09:36:35 -08:00
parent 48ceed9ecb
commit b4847d6a01
2 changed files with 88 additions and 20 deletions

View File

@ -448,7 +448,22 @@ use constant { NO_RESTRICT => 0, # FORWARD chain rule - Both -i an
ALL_RESTRICT => 12, # fw->fw rule - neither -i nor -o allowed
DESTIFACE_DISALLOW => 32, # Don't allow dest interface. Similar to INPUT_RESTRICT but generates a more relevant error message
};
#
# Possible IPSET options
#
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 = ',
);
#
# See initialize() below for additional comments on these variables
#
@ -4403,6 +4418,11 @@ sub do_proto( $$$;$ )
if ( $ports ne '' ) {
$invert = $ports =~ s/^!// ? '! ' : '';
if ( $ports =~ /^\+/ ) {
$output .= $invert;
$output .= get_set_flags( $ports, 'dst' );
} else {
$sports = '', require_capability( 'MULTIPORT', "'=' in the SOURCE PORT(S) column", 's' ) if ( $srcndst = $sports eq '=' );
if ( $multiport || $ports =~ tr/,/,/ > 0 || $sports =~ tr/,/,/ > 0 ) {
@ -4424,6 +4444,7 @@ sub do_proto( $$$;$ )
$ports = validate_portpair $pname , $ports;
$output .= ( $srcndst ? "-m multiport ${invert}--ports ${ports} " : "${invert}--dport ${ports} " );
}
}
} else {
$multiport ||= ( $sports =~ tr/,/,/ ) > 0 ;;
}
@ -4434,9 +4455,13 @@ sub do_proto( $$$;$ )
if ( $sports ne '' ) {
fatal_error "'=' in the SOURCE PORT(S) column requires one or more ports in the DEST PORT(S) column" if $sports eq '=';
$invert = $sports =~ s/^!// ? '! ' : '';
if ( $multiport ) {
$invert = $sports =~ s/^!// ? '! ' : '';
if ( $ports =~ /^\+/ ) {
$output .= $invert;
$output .= get_set_flags( $ports, 'dst' );
} elsif ( $multiport ) {
if ( port_count( $sports ) > 15 ) {
if ( $restricted ) {
fatal_error "A port list in this file may only have up to 15 ports";
@ -5424,6 +5449,7 @@ sub iprange_match() {
sub get_set_flags( $$ ) {
my ( $setname, $option ) = @_;
my $options = $option;
my $extensions = '';
require_capability( 'IPSET_MATCH' , 'ipset names in Shorewall configuration files' , '' );
@ -5431,6 +5457,28 @@ 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');
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])\]$/ ) {
$setname = $1;
my $count = $2;
@ -5463,7 +5511,7 @@ sub get_set_flags( $$ ) {
fatal_error "Invalid ipset name ($setname)" unless $setname =~ /^(6_)?[a-zA-Z][-\w]*/;
have_capability( 'OLD_IPSET_MATCH' ) ? "--set $setname $options " : "--match-set $setname $options ";
have_capability( 'OLD_IPSET_MATCH' ) ? "--set $setname $options " : "--match-set $setname $options $extensions";
}

View File

@ -327,6 +327,10 @@ our %capdesc = ( NAT_ENABLED => 'NAT',
=> 'Owner Name Match',
IPSET_MATCH => 'Ipset Match',
OLD_IPSET_MATCH => 'Old Ipset Match',
IPSET_MATCH_NOMATCH
=> 'Ipset Match nomatch',
IPSET_MATCH_COUNTERS
=> 'Ipset Match counters',
IPSET_V5 => 'Version 5 ipsets',
CONNMARK => 'CONNMARK Target',
XCONNMARK => 'Extended CONNMARK Target',
@ -904,6 +908,8 @@ sub initialize( $;$$) {
OWNER_NAME_MATCH => undef,
IPSET_MATCH => undef,
OLD_IPSET_MATCH => undef,
IPSET_MATCH_NOMATCH => undef,
IPSET_MATCH_COUNTERS => undef,
IPSET_V5 => undef,
CONNMARK => undef,
XCONNMARK => undef,
@ -4077,11 +4083,15 @@ sub IPSet_Match() {
$ipset = which $ipset unless $ipset =~ '/';
$capabilities{IPSET_MATCH_NOMATCH} = $capabilities{IPSET_MATCH_COUNTERS} = 0;
if ( $ipset && -x $ipset ) {
qt( "$ipset -X $sillyname" );
if ( qt( "$ipset -N $sillyname iphash" ) || qt( "$ipset -N $sillyname hash:ip family $fam") ) {
if ( qt1( "$iptables $iptablesw -A $sillyname -m set --match-set $sillyname src -j ACCEPT" ) ) {
$capabilities{IPSET_MATCH_NOMATCH} = qt1( "$iptables $iptablesw -A $sillyname -m set --match-set $sillyname src --return-nomatch -j ACCEPT" );
$capabilities{IPSET_MATCH_COUNTERS} = qt1( "$iptables $iptablesw -A $sillyname -m set --match-set $sillyname src --packets-lt 100 -j ACCEPT" );
qt1( "$iptables $iptablesw -F $sillyname" );
$result = ! ( $capabilities{OLD_IPSET_MATCH} = 0 );
} else {
@ -4095,6 +4105,14 @@ sub IPSet_Match() {
$result;
}
sub IPSet_Match_Nomatch() {
have_capability 'IPSET_MATCH' && $capabilities{IPSET_MATCH_NOMATCH};
}
sub IPSet_Match_Counters() {
have_capability 'IPSET_MATCH' && $capabilities{IPSET_MATCH_COUNTGERS};
}
sub IPSET_V5() {
my $ipset = $config{IPSET} || 'ipset';
my $result = 0;
@ -4383,6 +4401,8 @@ our %detect_capability =
IPP2P_MATCH => \&Ipp2p_Match,
IPRANGE_MATCH => \&IPRange_Match,
IPSET_MATCH => \&IPSet_Match,
IPSET_MATCH_NOMATCH => \&IPSet_Match_Nomatch,
IPSET_MATCH_COUNTERS => \&IPSet_Match_Counters,
IRC_HELPER => \&IRC_Helper,
IRC0_HELPER => \&IRC0_Helper,
OLD_IPSET_MATCH => \&Old_IPSet_Match,