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
have_ipset_rules
record_runtime_address
conditional_rule
conditional_rule_end
match_source_dev
match_dest_dev
iprange_match
@ -2689,6 +2691,38 @@ sub record_runtime_address( $ ) {
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( $ );
#
@ -3453,6 +3487,8 @@ sub handle_network_list( $$ ) {
}
################################################################################################################
#
# 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} );
add_rule $chainref, ( match_source_net $_ , $restriction ) . $exclude for ( mysplit $iexcl );
add_rule $chainref, ( match_dest_net $_ ) . $exclude for ( mysplit $dexcl );
add_rule $chainref, ( match_orig_dest $_ ) . $exclude for ( mysplit $oexcl );
for ( mysplit $iexcl ) {
my $cond = conditional_rule( $chainref, $_ );
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'
#
@ -3819,24 +3869,46 @@ sub expand_rule( $$$$$$$$$$;$ )
#
for my $onet ( mysplit $onets ) {
my $cond = conditional_rule( $chainref, $onet );
$onet = match_orig_dest $onet;
for my $inet ( mysplit $inets ) {
my $cond = conditional_rule( $chainref, $inet );
my $source_match = match_source_net( $inet, $restriction ) if have_capability( 'KLUDGEFREE' );
for my $dnet ( mysplit $dnets ) {
$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 );
}
conditional_rule_end( $chainref ) if $cond;
}
conditional_rule_end( $chainref ) if $cond;
}
#
# Generate RETURNs for each exclusion
#
add_rule $echainref, ( match_source_net $_ , $restriction ) . '-j RETURN' for ( mysplit $iexcl );
add_rule $echainref, ( match_dest_net $_ ) . '-j RETURN' for ( mysplit $dexcl );
add_rule $echainref, ( match_orig_dest $_ ) . '-j RETURN' for ( mysplit $oexcl );
for ( mysplit $iexcl ) {
my $cond = conditional_rule( $echainref, $_ );
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
#
@ -3863,10 +3935,15 @@ sub expand_rule( $$$$$$$$$$;$ )
# No non-trivial exclusions or we're using marks to handle them
#
for my $onet ( mysplit $onets ) {
my $cond = conditional_rule( $chainref, $onet );
$onet = match_orig_dest $onet;
for my $inet ( mysplit $inets ) {
my $source_match;
my $cond = conditional_rule( $chainref, $inet );
$source_match = match_source_net( $inet, $restriction ) if have_capability( 'KLUDGEFREE' );
for my $dnet ( mysplit $dnets ) {
@ -3874,6 +3951,8 @@ sub expand_rule( $$$$$$$$$$;$ )
my $dest_match = match_dest_net( $dnet );
my $matches = join( '', $rule, $source_match, $dest_match, $onet );
my $cond = conditional_rule( $chainref, $dnet );
if ( $loglevel eq '' ) {
#
# No logging -- add the target rule with matches to the rule chain
@ -3916,8 +3995,14 @@ sub expand_rule( $$$$$$$$$$;$ )
$matches,
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 @EXPORT = qw( ALLIPv4
ALLIPv6
NILIPv4
NILIPv6
IPv4_MULTICAST
IPv6_MULTICAST
IPv6_LINKLOCAL
@ -44,6 +46,7 @@ our @EXPORT = qw( ALLIPv4
IPv6_SITE_ALLNODES
IPv6_SITE_ALLRTRS
ALLIP
NILIP
ALL
TCP
UDP
@ -63,6 +66,9 @@ our @EXPORT = qw( ALLIPv4
allipv4
allipv6
allip
nilipv4
nilipv6
nilip
rfc1918_networks
resolve_proto
proto_name
@ -73,7 +79,7 @@ our @EXPORT = qw( ALLIPv4
validate_icmp6
);
our @EXPORT_OK = qw( );
our $VERSION = '4.4_14';
our $VERSION = '4.4_17';
#
# Some IPv4/6 useful stuff
@ -82,6 +88,10 @@ our @allipv4 = ( '0.0.0.0/0' );
our @allipv6 = ( '::/0' );
our $allip;
our @allip;
our @nilipv4 = ( '0.0.0.0' );
our @nilipv6 = ( '::' );
our $nilip;
our @nilip;
our $valid_address;
our $validate_address;
our $validate_net;
@ -91,6 +101,8 @@ our $family;
use constant { ALLIPv4 => '0.0.0.0/0' ,
ALLIPv6 => '::/0' ,
NILIPv4 => '0.0.0.0' ,
NILIPv6 => '::' ,
IPv4_MULTICAST => '224.0.0.0/4' ,
IPv6_MULTICAST => 'ff00::/8' ,
IPv6_LINKLOCAL => 'fe80::/10' ,
@ -280,6 +292,14 @@ sub allipv6() {
@allipv6;
}
sub nilipv4() {
@nilipv4;
}
sub nilipv6() {
@nilipv6;
}
sub rfc1918_networks() {
@rfc1918_networks
}
@ -674,6 +694,14 @@ sub allip() {
@allip;
}
sub NILIP() {
$nilip;
}
sub nilip() {
@nilip;
}
sub valid_address ( $ ) {
$valid_address->(@_);
}
@ -710,6 +738,8 @@ sub initialize( $ ) {
if ( $family == F_IPV4 ) {
$allip = ALLIPv4;
@allip = @allipv4;
$nilip = NILIPv4;
@nilip = @nilipv4;
$valid_address = \&valid_4address;
$validate_address = \&validate_4address;
$validate_net = \&validate_4net;
@ -718,6 +748,8 @@ sub initialize( $ ) {
} else {
$allip = ALLIPv6;
@allip = @allipv6;
$nilip = NILIPv6;
@nilip = @nilipv6;
$valid_address = \&valid_6address;
$validate_address = \&validate_6address;
$validate_net = \&validate_6net;

View File

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

View File

@ -109,9 +109,8 @@ Beta 2
file.
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
:: in IPv6) will be substituted, resulting in no packets matching
the rule.
that the firewall starts, the resulting Netfilter rule(s)
containing the interface address are not added.
Beta 1