diff --git a/Shorewall-perl/Shorewall/Chains.pm b/Shorewall-perl/Shorewall/Chains.pm index e3a59d7b5..7118f8aef 100644 --- a/Shorewall-perl/Shorewall/Chains.pm +++ b/Shorewall-perl/Shorewall/Chains.pm @@ -125,6 +125,7 @@ our %EXPORT_TAGS = ( get_interface_address get_interface_addresses get_interface_bcasts + get_interface_gateway get_interface_mac set_global_variables create_netfilter_load @@ -219,7 +220,9 @@ our $chainseq; our %interfaceaddr; our %interfaceaddrs; our %interfacenets; +our %interfacemacs; our %interfacebcasts; +our %interfacegateways; our @builtins = qw(PREROUTING INPUT FORWARD OUTPUT POSTROUTING); @@ -315,10 +318,12 @@ sub initialize() { # # Keep track of which interfaces have active 'address', 'addresses' and 'networks' variables # - %interfaceaddr = (); - %interfaceaddrs = (); - %interfacenets = (); - %interfacebcasts = (); + %interfaceaddr = (); + %interfaceaddrs = (); + %interfacenets = (); + %interfacemacs = (); + %interfacebcasts = (); + %interfacegateways = (); } INIT { @@ -1467,7 +1472,7 @@ sub mysplit( $ ) { # sub interface_address( $ ) { my $variable = chain_base( $_[0] ) . '_address'; - "\U$variable"; + uc $variable; } # @@ -1479,7 +1484,7 @@ sub get_interface_address ( $ ) { my $variable = interface_address( $interface ); my $function = interface_is_optional( $interface ) ? 'find_first_interface_address_if_any' : 'find_first_interface_address'; - $interfaceaddr{$interface} = "$variable=\$($function $interface)"; + $interfaceaddr{$interface} = "$variable=\$($function $interface)\n"; "\$$variable"; } @@ -1489,7 +1494,7 @@ sub get_interface_address ( $ ) { # sub interface_bcasts( $ ) { my $variable = chain_base( $_[0] ) . '_bcasts'; - "\U$variable"; + uc $variable; } # @@ -1505,12 +1510,39 @@ sub get_interface_bcasts ( $ ) { "\$$variable"; } +# +# Returns the name of the shell variable holding the gateway through the passed interface +# +sub interface_gateway( $ ) { + my $variable = chain_base( $_[0] ) . '_gateway'; + uc $variable; +} + +# +# Record that the ruleset requires the gateway address on the passed interface +# +sub get_interface_gateway ( $ ) { + my ( $interface ) = $_[0]; + + my $variable = interface_gateway( $interface ); + + if ( interface_is_optional $interface ) { + $interfacegateways{$interface} = qq($variable=\$(detect_gateway $interface)\n); + } else { + $interfacegateways{$interface} = qq($variable=\$(detect_gateway $interface) +[ -n "\$$variable" ] || fatal_error "Unable to detect the gateway through interface $interface" +); + } + + "\$$variable"; +} + # # Returns the name of the shell variable holding the addresses of the passed interface # sub interface_addresses( $ ) { my $variable = chain_base( $_[0] ) . '_addresses'; - "\U$variable"; + uc $variable; } # @@ -1537,7 +1569,7 @@ sub get_interface_addresses ( $ ) { # sub interface_nets( $ ) { my $variable = chain_base( $_[0] ) . '_networks'; - "\U$variable"; + uc $variable; } # @@ -1564,19 +1596,25 @@ sub get_interface_nets ( $ ) { # Returns the name of the shell variable holding the MAC address of the gateway for the passed provider out of the passed interface # sub interface_mac( $$ ) { - my $variable = join( '_' , chain_base( $_[0] ) , $_[1] , 'mac' ); + my $variable = join( '_' , chain_base( $_[0] ) , chain_base( $_[1] ) , 'mac' ); uc $variable; } # -# Emit code to determine the MAC address of the passed gateway IP routed out of the passed interface for the passed provider number +# Record the fact that the ruleset requires MAC address of the passed gateway IP routed out of the passed interface for the passed provider number # sub get_interface_mac( $$$ ) { my ( $ipaddr, $interface , $table ) = @_; my $variable = interface_mac( $interface , $table ); - emit qq($variable=\$(find_mac $ipaddr $interface)); + if ( interface_is_optional $interface ) { + $interfacemacs{$table} = qq($variable=\$(find_mac $ipaddr $interface)\n); + } else { + $interfacemacs{$table} = qq($variable=\$(find_mac $ipaddr $interface) +[ -n "\$$variable" ] || fatal_error "Unable to determine the MAC address of $ipaddr through interface \\"$interface\\"" +); + } "\$$variable"; } @@ -1980,6 +2018,16 @@ sub set_global_variables() { emit $_; } + for ( values %interfacegateways ) { + emit_comment unless $emitted_comment; + emit $_; + } + + for ( values %interfacemacs ) { + emit_comment unless $emitted_comment; + emit $_; + } + for ( values %interfaceaddrs ) { emit_comment unless $emitted_comment; emit_test unless $emitted_test; diff --git a/Shorewall-perl/Shorewall/Providers.pm b/Shorewall-perl/Shorewall/Providers.pm index 6ebdd436a..3672b0691 100644 --- a/Shorewall-perl/Shorewall/Providers.pm +++ b/Shorewall-perl/Shorewall/Providers.pm @@ -198,6 +198,8 @@ sub add_a_provider( $$$$$$$$ ) { fatal_error "Duplicate provider number ($number)" if $providerref->{number} == $number; } + fatal_error "Unknown Interface ($interface)" unless known_interface $interface; + my $provider = chain_base $table; emit "#\n# Add Provider $table ($number)\n#"; @@ -213,11 +215,7 @@ sub add_a_provider( $$$$$$$$ ) { if ( $gateway eq 'detect' ) { $variable = get_interface_address $interface; - emit ( "gateway=\$(detect_gateway $interface)\n", - 'if [ -z "$gateway" ]; then', - " fatal_error \"Unable to detect the gateway through interface $interface\"", - "fi\n" ); - $gateway = '$gateway'; + $gateway = get_interface_gateway $interface; } elsif ( $gateway && $gateway ne '-' ) { validate_address $gateway, 0; $variable = get_interface_address $interface; @@ -253,7 +251,7 @@ sub add_a_provider( $$$$$$$$ ) { ); } - my ( $loose, $optional, $track, $shared, $balance ) = (0,0,0,0,0); + my ( $loose, $track, $shared, $balance , $optional ) = (0,0,0,0,interface_is_optional( $interface )); unless ( $options eq '-' ) { for my $option ( split /,/, $options ) { @@ -266,6 +264,7 @@ sub add_a_provider( $$$$$$$$ ) { } elsif ( $option eq 'loose' ) { $loose = 1; } elsif ( $option eq 'optional' ) { + set_interface_option $interface, 'optional', 1; $optional = 1; } elsif ( $option eq 'shared' ) { require_capability 'REALM_MATCH', "The 'shared' option", "s"; @@ -276,7 +275,13 @@ sub add_a_provider( $$$$$$$$ ) { } } - $providers{$table} = { provider => $table, number => $number , mark => $val , optional => $optional , interface => $interface , gateway => $gateway, shared => $shared }; + $providers{$table} = { provider => $table, + number => $number , + mark => $val , + interface => $interface , + optional => $optional , + gateway => $gateway , + shared => $shared }; if ( $track ) { fatal_error "The 'track' option requires a numeric value in the MARK column" if $mark eq '-'; @@ -415,7 +420,7 @@ sub add_an_rtrule( $$$$ ) { emit ( "qt ip rule del $source $dest $priority" ) if $config{DELETE_THEN_ADD}; - my ( $base, $optional, $number ) = ( chain_base( $provider ), $providers{$provider}{optional} , $providers{$provider}{number} ); + my ( $base, $optional, $number ) = ( chain_base( $provider ) , $providers{$provider}{optional} , $providers{$provider}{number} ); emit ( '', "if [ -n \$${base}_is_up ]; then" ), push_indent if $optional; diff --git a/Shorewall-perl/Shorewall/Zones.pm b/Shorewall-perl/Shorewall/Zones.pm index c62d7cc68..1e41b7f25 100644 --- a/Shorewall-perl/Shorewall/Zones.pm +++ b/Shorewall-perl/Shorewall/Zones.pm @@ -59,6 +59,7 @@ our @EXPORT = qw( NOTHING interface_is_optional find_interfaces_by_option get_interface_option + set_interface_option validate_hosts_file find_hosts_by_option ); @@ -863,6 +864,15 @@ sub get_interface_option( $$ ) { $interfaces{$interface}{options}{$option}; } +# +# Set an option for an interface +# +sub set_interface_option( $$$ ) { + my ( $interface, $option, $value ) = @_; + + $interfaces{$interface}{options}{$option} = $value; +} + # # Validates the hosts file. Generates entries in %zone{..}{hosts} # diff --git a/Shorewall-perl/prog.header b/Shorewall-perl/prog.header index 569e1ec45..945392731 100644 --- a/Shorewall-perl/prog.header +++ b/Shorewall-perl/prog.header @@ -918,11 +918,9 @@ find_mac() # $1 = IP address, $2 = interface \<*\>) ;; *) - [ -n "$result" ] && echo $result && return + [ -n "$result" ] && echo $result ;; esac - - fatal_error "Cannot determine the MAC address of $1 through $2" } ################################################################################