Add conditional logic for optional run-time address variables

Signed-off-by: Tom Eastep <teastep@shorewall.net>
This commit is contained in:
Tom Eastep 2011-01-29 12:15:34 -08:00
parent 47cdbd04db
commit 7555a0953d
4 changed files with 133 additions and 15 deletions

View File

@ -146,6 +146,8 @@ our %EXPORT_TAGS = (
do_headers do_headers
have_ipset_rules have_ipset_rules
record_runtime_address record_runtime_address
conditional_rule
conditional_rule_end
match_source_dev match_source_dev
match_dest_dev match_dest_dev
iprange_match iprange_match
@ -2689,6 +2691,38 @@ sub record_runtime_address( $ ) {
get_interface_address( $interface ) . ' '; get_interface_address( $interface ) . ' ';
} }
#
# If the passed address is a run-time address variable for an optional interface, then
# begin a conditional rule block that tests the address for nil.
#
sub conditional_rule( $$ ) {
my ( $chainref, $address ) = @_;
if ( $address =~ /^!?&(.+)$/ ) {
my $interface = $1;
if ( my $ref = known_interface $interface ) {
if ( $ref->{options}{optional} ) {
my $variable = get_interface_address( $interface );
add_commands( $chainref , "if [ $variable != " . NILIP . ' ]; then' );
incr_cmd_level $chainref;
return 1;
}
};
}
0;
}
#
# If end a conditional in a chain
#
sub conditional_rule_end( $ ) {
my $chainref = shift;
decr_cmd_level $chainref;
add_commands( $chainref , "fi\n" );
}
sub mysplit( $ ); sub mysplit( $ );
# #
@ -3453,6 +3487,8 @@ sub handle_network_list( $$ ) {
} }
################################################################################################################ ################################################################################################################
# #
# This function provides a uniform way to generate Netfilter[6] rules (something the original Shorewall # This function provides a uniform way to generate Netfilter[6] rules (something the original Shorewall
@ -3800,9 +3836,23 @@ sub expand_rule( $$$$$$$$$$;$ )
# #
my $exclude = '-j MARK --or-mark ' . in_hex( $globals{EXCLUSION_MASK} ); my $exclude = '-j MARK --or-mark ' . in_hex( $globals{EXCLUSION_MASK} );
add_rule $chainref, ( match_source_net $_ , $restriction ) . $exclude for ( mysplit $iexcl ); for ( mysplit $iexcl ) {
add_rule $chainref, ( match_dest_net $_ ) . $exclude for ( mysplit $dexcl ); my $cond = conditional_rule( $chainref, $_ );
add_rule $chainref, ( match_orig_dest $_ ) . $exclude for ( mysplit $oexcl ); add_rule $chainref, ( match_source_net $_ , $restriction ) . $exclude;
conditional_rule_end( $chainref ) if $cond;
}
for ( mysplit $dexcl ) {
my $cond = conditional_rule( $chainref, $_ );
add_rule $chainref, ( match_dest_net $_ ) . $exclude;
conditional_rule_end( $chainref ) if $cond;
}
for ( mysplit $oexcl ) {
my $cond = conditional_rule( $chainref, $_ );
add_rule $chainref, ( match_orig_dest $_ ) . $exclude;
conditional_rule_end( $chainref ) if $cond;
}
# #
# Augment the rule to include 'not excluded' # Augment the rule to include 'not excluded'
# #
@ -3819,24 +3869,46 @@ sub expand_rule( $$$$$$$$$$;$ )
# #
for my $onet ( mysplit $onets ) { for my $onet ( mysplit $onets ) {
my $cond = conditional_rule( $chainref, $onet );
$onet = match_orig_dest $onet; $onet = match_orig_dest $onet;
for my $inet ( mysplit $inets ) { for my $inet ( mysplit $inets ) {
my $cond = conditional_rule( $chainref, $inet );
my $source_match = match_source_net( $inet, $restriction ) if have_capability( 'KLUDGEFREE' ); my $source_match = match_source_net( $inet, $restriction ) if have_capability( 'KLUDGEFREE' );
for my $dnet ( mysplit $dnets ) { for my $dnet ( mysplit $dnets ) {
$source_match = match_source_net( $inet, $restriction ) unless have_capability( 'KLUDGEFREE' ); $source_match = match_source_net( $inet, $restriction ) unless have_capability( 'KLUDGEFREE' );
add_jump( $chainref, $echainref, 0, join( '', $rule, $source_match, match_dest_net( $dnet ), $onet ), 1 ); add_jump( $chainref, $echainref, 0, join( '', $rule, $source_match, match_dest_net( $dnet ), $onet ), 1 );
} }
conditional_rule_end( $chainref ) if $cond;
} }
conditional_rule_end( $chainref ) if $cond;
} }
# #
# Generate RETURNs for each exclusion # Generate RETURNs for each exclusion
# #
add_rule $echainref, ( match_source_net $_ , $restriction ) . '-j RETURN' for ( mysplit $iexcl ); for ( mysplit $iexcl ) {
add_rule $echainref, ( match_dest_net $_ ) . '-j RETURN' for ( mysplit $dexcl ); my $cond = conditional_rule( $echainref, $_ );
add_rule $echainref, ( match_orig_dest $_ ) . '-j RETURN' for ( mysplit $oexcl ); add_rule $echainref, ( match_source_net $_ , $restriction ) . '-j RETURN';
conditional_rule_end( $echainref ) if $cond;
}
for ( mysplit $dexcl ) {
my $cond = conditional_rule( $echainref, $_ );
add_rule $echainref, ( match_dest_net $_ ) . '-j RETURN';
conditional_rule_end( $echainref ) if $cond;
}
for ( mysplit $oexcl ) {
my $cond = conditional_rule( $echainref, $_ );
add_rule $echainref, ( match_orig_dest $_ ) . '-j RETURN';
conditional_rule_end( $echainref ) if $cond;
}
# #
# Log rule # Log rule
# #
@ -3863,10 +3935,15 @@ sub expand_rule( $$$$$$$$$$;$ )
# No non-trivial exclusions or we're using marks to handle them # No non-trivial exclusions or we're using marks to handle them
# #
for my $onet ( mysplit $onets ) { for my $onet ( mysplit $onets ) {
my $cond = conditional_rule( $chainref, $onet );
$onet = match_orig_dest $onet; $onet = match_orig_dest $onet;
for my $inet ( mysplit $inets ) { for my $inet ( mysplit $inets ) {
my $source_match; my $source_match;
my $cond = conditional_rule( $chainref, $inet );
$source_match = match_source_net( $inet, $restriction ) if have_capability( 'KLUDGEFREE' ); $source_match = match_source_net( $inet, $restriction ) if have_capability( 'KLUDGEFREE' );
for my $dnet ( mysplit $dnets ) { for my $dnet ( mysplit $dnets ) {
@ -3874,6 +3951,8 @@ sub expand_rule( $$$$$$$$$$;$ )
my $dest_match = match_dest_net( $dnet ); my $dest_match = match_dest_net( $dnet );
my $matches = join( '', $rule, $source_match, $dest_match, $onet ); my $matches = join( '', $rule, $source_match, $dest_match, $onet );
my $cond = conditional_rule( $chainref, $dnet );
if ( $loglevel eq '' ) { if ( $loglevel eq '' ) {
# #
# No logging -- add the target rule with matches to the rule chain # No logging -- add the target rule with matches to the rule chain
@ -3916,8 +3995,14 @@ sub expand_rule( $$$$$$$$$$;$ )
$matches, $matches,
1 ); 1 );
} }
conditional_rule_end( $chainref ) if $cond;
} }
conditional_rule_end( $chainref ) if $cond;
} }
conditional_rule_end( $chainref ) if $cond;
} }
} }
# #

View File

@ -34,6 +34,8 @@ use strict;
our @ISA = qw(Exporter); our @ISA = qw(Exporter);
our @EXPORT = qw( ALLIPv4 our @EXPORT = qw( ALLIPv4
ALLIPv6 ALLIPv6
NILIPv4
NILIPv6
IPv4_MULTICAST IPv4_MULTICAST
IPv6_MULTICAST IPv6_MULTICAST
IPv6_LINKLOCAL IPv6_LINKLOCAL
@ -44,6 +46,7 @@ our @EXPORT = qw( ALLIPv4
IPv6_SITE_ALLNODES IPv6_SITE_ALLNODES
IPv6_SITE_ALLRTRS IPv6_SITE_ALLRTRS
ALLIP ALLIP
NILIP
ALL ALL
TCP TCP
UDP UDP
@ -63,6 +66,9 @@ our @EXPORT = qw( ALLIPv4
allipv4 allipv4
allipv6 allipv6
allip allip
nilipv4
nilipv6
nilip
rfc1918_networks rfc1918_networks
resolve_proto resolve_proto
proto_name proto_name
@ -73,7 +79,7 @@ our @EXPORT = qw( ALLIPv4
validate_icmp6 validate_icmp6
); );
our @EXPORT_OK = qw( ); our @EXPORT_OK = qw( );
our $VERSION = '4.4_14'; our $VERSION = '4.4_17';
# #
# Some IPv4/6 useful stuff # Some IPv4/6 useful stuff
@ -82,6 +88,10 @@ our @allipv4 = ( '0.0.0.0/0' );
our @allipv6 = ( '::/0' ); our @allipv6 = ( '::/0' );
our $allip; our $allip;
our @allip; our @allip;
our @nilipv4 = ( '0.0.0.0' );
our @nilipv6 = ( '::' );
our $nilip;
our @nilip;
our $valid_address; our $valid_address;
our $validate_address; our $validate_address;
our $validate_net; our $validate_net;
@ -91,6 +101,8 @@ our $family;
use constant { ALLIPv4 => '0.0.0.0/0' , use constant { ALLIPv4 => '0.0.0.0/0' ,
ALLIPv6 => '::/0' , ALLIPv6 => '::/0' ,
NILIPv4 => '0.0.0.0' ,
NILIPv6 => '::' ,
IPv4_MULTICAST => '224.0.0.0/4' , IPv4_MULTICAST => '224.0.0.0/4' ,
IPv6_MULTICAST => 'ff00::/8' , IPv6_MULTICAST => 'ff00::/8' ,
IPv6_LINKLOCAL => 'fe80::/10' , IPv6_LINKLOCAL => 'fe80::/10' ,
@ -280,6 +292,14 @@ sub allipv6() {
@allipv6; @allipv6;
} }
sub nilipv4() {
@nilipv4;
}
sub nilipv6() {
@nilipv6;
}
sub rfc1918_networks() { sub rfc1918_networks() {
@rfc1918_networks @rfc1918_networks
} }
@ -674,6 +694,14 @@ sub allip() {
@allip; @allip;
} }
sub NILIP() {
$nilip;
}
sub nilip() {
@nilip;
}
sub valid_address ( $ ) { sub valid_address ( $ ) {
$valid_address->(@_); $valid_address->(@_);
} }
@ -710,6 +738,8 @@ sub initialize( $ ) {
if ( $family == F_IPV4 ) { if ( $family == F_IPV4 ) {
$allip = ALLIPv4; $allip = ALLIPv4;
@allip = @allipv4; @allip = @allipv4;
$nilip = NILIPv4;
@nilip = @nilipv4;
$valid_address = \&valid_4address; $valid_address = \&valid_4address;
$validate_address = \&validate_4address; $validate_address = \&validate_4address;
$validate_net = \&validate_4net; $validate_net = \&validate_4net;
@ -718,6 +748,8 @@ sub initialize( $ ) {
} else { } else {
$allip = ALLIPv6; $allip = ALLIPv6;
@allip = @allipv6; @allip = @allipv6;
$nilip = NILIPv6;
@nilip = @nilipv6;
$valid_address = \&valid_6address; $valid_address = \&valid_6address;
$validate_address = \&validate_6address; $validate_address = \&validate_6address;
$validate_net = \&validate_6net; $validate_net = \&validate_6net;

View File

@ -155,6 +155,7 @@ sub process_one_masq( )
my $exceptionrule = ''; my $exceptionrule = '';
my $randomize = ''; my $randomize = '';
my $persistent = ''; my $persistent = '';
my $conditional = 0;
# #
# Parse the ADDRESSES column # Parse the ADDRESSES column
# #
@ -188,7 +189,11 @@ sub process_one_masq( )
for my $addr ( split_list $addresses , 'address' ) { for my $addr ( split_list $addresses , 'address' ) {
if ( $addr =~ /^&(.+)$/ ) { if ( $addr =~ /^&(.+)$/ ) {
$target = 'SNAT '; $target = 'SNAT ';
if ( $conditional = conditional_rule( $chainref, $addr ) ) {
$addrlist .= '--to-source ' . get_interface_address $1;
} else {
$addrlist .= '--to-source ' . record_runtime_address $1; $addrlist .= '--to-source ' . record_runtime_address $1;
}
} elsif ( $addr =~ /^.*\..*\..*\./ ) { } elsif ( $addr =~ /^.*\..*\..*\./ ) {
$target = 'SNAT '; $target = 'SNAT ';
my ($ipaddr, $rest) = split ':', $addr; my ($ipaddr, $rest) = split ':', $addr;
@ -232,10 +237,7 @@ sub process_one_masq( )
'' , '' ,
$exceptionrule ); $exceptionrule );
if ( $detectaddress ) { conditional_rule_end( $chainref ) if $detectaddress || $conditional;
decr_cmd_level( $chainref );
add_commands( $chainref , 'fi' );
}
if ( $add_snat_aliases ) { if ( $add_snat_aliases ) {
my ( $interface, $alias , $remainder ) = split( /:/, $fullinterface, 3 ); my ( $interface, $alias , $remainder ) = split( /:/, $fullinterface, 3 );

View File

@ -109,9 +109,8 @@ Beta 2
file. file.
For optional interfaces, if the interface is not usable at the time For optional interfaces, if the interface is not usable at the time
that the firewall starts the all-zero address (0.0.0.0 in IPv4 and that the firewall starts, the resulting Netfilter rule(s)
:: in IPv6) will be substituted, resulting in no packets matching containing the interface address are not added.
the rule.
Beta 1 Beta 1