diff --git a/Shorewall/Perl/Shorewall/Providers.pm b/Shorewall/Perl/Shorewall/Providers.pm index 7453c7e65..5865b2ca4 100644 --- a/Shorewall/Perl/Shorewall/Providers.pm +++ b/Shorewall/Perl/Shorewall/Providers.pm @@ -661,38 +661,40 @@ sub process_a_provider( $ ) { fatal_error 'A non-empty COPY column requires that a routing table be specified in the DUPLICATE column' unless $copy eq 'none'; } - $providers{$table} = { provider => $table, - number => $number , - id => $config{USE_RT_NAMES} ? $table : $number, - rawmark => $mark , - mark => $val ? in_hex($val) : $val , - interface => $interface , - physical => $physical , - optional => $optional , - gateway => $gateway , - gatewaycase => $gatewaycase , - shared => $shared , - default => $default , - copy => $copy , - balance => $balance , - pref => $pref , - mtu => $mtu , - noautosrc => $noautosrc , - track => $track , - loose => $loose , - duplicate => $duplicate , - address => $address , - mac => $mac , - local => $local , - tproxy => $tproxy , - load => $load , - pseudo => $pseudo , - what => $what , - hostroute => $hostroute , - rules => [] , - routes => [] , - routedests => {} , - persistent => $persistent, + $providers{$table} = { provider => $table, + number => $number , + id => $config{USE_RT_NAMES} ? $table : $number, + rawmark => $mark , + mark => $val ? in_hex($val) : $val , + interface => $interface , + physical => $physical , + optional => $optional , + gateway => $gateway , + gatewaycase => $gatewaycase , + shared => $shared , + default => $default , + copy => $copy , + balance => $balance , + pref => $pref , + mtu => $mtu , + noautosrc => $noautosrc , + track => $track , + loose => $loose , + duplicate => $duplicate , + address => $address , + mac => $mac , + local => $local , + tproxy => $tproxy , + load => $load , + pseudo => $pseudo , + what => $what , + hostroute => $hostroute , + rules => [] , + persistent_rules => [] , + routes => [] , + persistent_routes => [], + routedests => {} , + persistent => $persistent, }; $provider_interfaces{$interface} = $table unless $shared; @@ -772,6 +774,75 @@ sub add_a_provider( $$ ) { my $base = uc $dev; my $realm = ''; + if ( $persistent ) { + emit( '', + '#', + "# Persistent $what $table is currently disabled", + '#', + "do_persistent_${what}_${table}() {" ); + + push_indent; + + if ( $gatewaycase eq 'none' ) { + if ( $tproxy ) { + emit 'run_ip route add local ' . ALLIP . " dev $physical table $id"; + } else { + emit "run_ip route add default dev $physical table $id"; + } + } + + if ( $gateway ) { + $address = get_interface_address $interface unless $address; + + if ( $hostroute ) { + if ( $family == F_IPV4 ) { + emit qq(run_ip route replace $gateway src $address dev $physical ${mtu}); + emit qq(run_ip route replace $gateway src $address dev $physical ${mtu}table $id $realm); + } else { + emit qq(qt \$IP -6 route add $gateway src $address dev $physical ${mtu}); + emit qq(qt \$IP -6 route del $gateway src $address dev $physical ${mtu}table $id $realm); + emit qq(run_ip route add $gateway src $address dev $physical ${mtu}table $id $realm); + } + } + + emit "run_ip route add default via $gateway src $address dev $physical ${mtu}table $id $realm"; + } + + if ( ! $noautosrc ) { + if ( $shared ) { + emit "qt \$IP -$family rule del from $address" if $config{DELETE_THEN_ADD}; + emit( "run_ip rule add from $address pref 20000 table $id" , + "echo \"\$IP -$family rule del from $address pref 20000> /dev/null 2>&1\" >> \${VARDIR}/undo_${table}_routing" ); + } else { + emit ( "find_interface_addresses $physical | while read address; do" ); + emit ( " qt \$IP -$family rule del from \$address" ) if $config{DELETE_THEN_ADD}; + emit ( " run_ip rule add from \$address pref 20000 table $id", + " echo \"\$IP -$family rule del from \$address pref 20000 > /dev/null 2>&1\" >> \${VARDIR}/undo_${table}_routing", + ' rulenum=$(($rulenum + 1))', + 'done' + ); + } + + if ( @{$providerref->{persistent_routes}} ) { + emit ''; + emit $_ for @{$providers{$table}->{persistent_routes}}; + } + + if ( @{$providerref->{persistent_rules}} ) { + emit ''; + emit $_ for @{$providers{$table}->{persistent_rules}}; + } + } + + emit( qq(\n), + qq(rm -f \${VARDIR}/${physical}_enabled) ); + + + pop_indent; + + emit( "}\n" ); + } + if ( $shared ) { my $variable = $providers{$table}{mac} = get_interface_mac( $gateway, $interface , $table, $mac ); $realm = "realm $number"; @@ -971,6 +1042,7 @@ CEOF emit( "setup_${dev}_tc" ) if $tcdevices->{$interface}; } + emit( qq( echo 1 > \${VARDIR}/${physical}_enabled) ) if $persistent; emit_started_message( '', 2, $pseudo, $table, $number ); pop_indent; @@ -978,6 +1050,7 @@ CEOF unless ( $pseudo ) { emit( 'else' ); emit( qq( echo $weight > \${VARDIR}/${physical}_weight) ); + emit( qq( echo 1 > \${VARDIR}/${physical}_enabled) ) if $persistent; emit_started_message( ' ', '', $pseudo, $table, $number ); } @@ -995,6 +1068,8 @@ CEOF emit( qq(echo 1 > \${VARDIR}/${physical}.status) ); if ( $optional ) { + emit( "persistent_${what}_${table}\n" ) if $persistent; + if ( $shared ) { emit ( "error_message \"WARNING: Gateway $gateway is not reachable -- Provider $table ($number) not Started\"" ); } elsif ( $pseudo ) { @@ -1062,6 +1137,16 @@ CEOF emit ( '', "distribute_load $maxload @load_interfaces" ) if $load; + if ( $persistent ) { + emit ( '', + 'if [ $COMMAND = disable ]; then', + " do_persistent_${what}_${table}", + "else", + " rm -f \${VARDIR}/${physical}_enabled\n" + "fi\n", + ); + } + unless ( $shared ) { emit( '', "qt \$TC qdisc del dev $physical root", @@ -1168,12 +1253,20 @@ sub add_an_rtrule1( $$$$$ ) { $mark = ' fwmark ' . in_hex( $mark ) . '/' . in_hex( $mask ); } + my $persistent = ( $priority =~s/!$// ); + fatal_error "Invalid priority ($priority)" unless $priority && $priority =~ /^\d{1,5}$/; $priority = "pref $priority"; push @{$providerref->{rules}}, "qt \$IP -$family rule del $source ${dest}${mark} $priority" if $config{DELETE_THEN_ADD}; push @{$providerref->{rules}}, "run_ip rule add $source ${dest}${mark} $priority table $id"; + + if ( $persistent ) { + push @{$providerref->{persistent_rules}}, "qt \$IP -$family rule del $source ${dest}${mark} $priority" if $config{DELETE_THEN_ADD}; + push @{$providerref->{persistent_rules}}, "run_ip rule add $source ${dest}${mark} $priority table $id"; + } + push @{$providerref->{rules}}, "echo \"\$IP -$family rule del $source ${dest}${mark} $priority > /dev/null 2>&1\" >> \${VARDIR}/undo_${provider}_routing"; progress_message " Routing rule \"$currentline\" $done"; @@ -1191,9 +1284,9 @@ sub add_an_rtrule( ) { } sub add_a_route( ) { - my ( $provider, $dest, $gateway, $device ) = + my ( $provider, $dest, $gateway, $device, $options ) = split_line( 'routes file', - { provider => 0, dest => 1, gateway => 2, device => 3 } ); + { provider => 0, dest => 1, gateway => 2, device => 3, options=> 4 } ); our $current_if; @@ -1229,12 +1322,13 @@ sub add_a_route( ) { validate_address ( $gateway, 1 ) if $gateway ne '-'; } - my $providerref = $providers{$provider}; - my $number = $providerref->{number}; - my $id = $providerref->{id}; - my $physical = $device eq '-' ? $providers{$provider}{physical} : physical_name( $device ); - my $routes = $providerref->{routes}; - my $routedests = $providerref->{routedests}; + my $providerref = $providers{$provider}; + my $number = $providerref->{number}; + my $id = $providerref->{id}; + my $physical = $device eq '-' ? $providers{$provider}{physical} : physical_name( $device ); + my $routes = $providerref->{routes}; + my $persistent_routes = $providerref->{persistent_routes}; + my $routedests = $providerref->{routedests}; fatal_error "You may not add routes to the $provider table" if $number == LOCAL_TABLE || $number == UNSPEC_TABLE; @@ -1246,21 +1340,40 @@ sub add_a_route( ) { $routedests->{$dest} = 1; } + my $persistent; + + if ( $options != '-' ) { + for ( split_list1( 'option', $options ) ) { + my ( $option, $value ) = split /=/, $options; + + if ( $option eq 'persistent' ) { + fatal_error "The 'persistent' option does not accept a value" if supplied $value; + $persistent = 1; + } else { + fatal_error "Invalid route option($option)"; + } + } + } + if ( $gateway ne '-' ) { if ( $device ne '-' ) { - push @$routes, qq(run_ip route add $dest via $gateway dev $physical table $id); - push @$routes, q(echo "$IP ) . qq(-$family route del $dest via $gateway dev $physical table $id > /dev/null 2>&1" >> \${VARDIR}/undo_${provider}_routing) if $number >= DEFAULT_TABLE; + push @$routes, qq(run_ip route add $dest via $gateway dev $physical table $id); + push @$persistent_routes, qq(run_ip route add $dest via $gateway dev $physical table $id) if $persistent; + push @$routes, q(echo "$IP ) . qq(-$family route del $dest via $gateway dev $physical table $id > /dev/null 2>&1" >> \${VARDIR}/undo_${provider}_routing) if $number >= DEFAULT_TABLE; } elsif ( $null ) { - push @$routes, qq(run_ip route add $null $dest table $id); - push @$routes, q(echo "$IP ) . qq(-$family route del $null $dest table $id > /dev/null 2>&1" >> \${VARDIR}/undo_${provider}_routing) if $number >= DEFAULT_TABLE; + push @$routes, qq(run_ip route add $null $dest table $id); + push @$persistent_routes, qq(run_ip route add $null $dest table $id) if $persistent; + push @$routes, q(echo "$IP ) . qq(-$family route del $null $dest table $id > /dev/null 2>&1" >> \${VARDIR}/undo_${provider}_routing) if $number >= DEFAULT_TABLE; } else { - push @$routes, qq(run_ip route add $dest via $gateway table $id); - push @$routes, q(echo "$IP ) . qq(-$family route del $dest via $gateway table $id > /dev/null 2>&1" >> \${VARDIR}/undo_${provider}_routing) if $number >= DEFAULT_TABLE; + push @$routes, qq(run_ip route add $dest via $gateway table $id); + push @$persistent_routes, qq(run_ip route add $dest via $gateway table $id) if $persistent; + push @$routes, q(echo "$IP ) . qq(-$family route del $dest via $gateway table $id > /dev/null 2>&1" >> \${VARDIR}/undo_${provider}_routing) if $number >= DEFAULT_TABLE; } } else { fatal_error "You must specify a device for this route" unless $physical; - push @$routes, qq(run_ip route add $dest dev $physical table $id); - push @$routes, q(echo "$IP ) . qq(-$family route del $dest dev $physical table $id > /dev/null 2>&1" >> \${VARDIR}/undo_${provider}_routing) if $number >= DEFAULT_TABLE; + push @$routes, qq(run_ip route add $dest dev $physical table $id); + push @$persistent_routes, qq(run_ip route add $dest dev $physical table $id) if $persistent; + push @$routes, q(echo "$IP ) . qq(-$family route del $dest dev $physical table $id > /dev/null 2>&1" >> \${VARDIR}/undo_${provider}_routing) if $number >= DEFAULT_TABLE; } progress_message " Route \"$currentline\" $done"; @@ -1531,8 +1644,11 @@ EOF } if ( $providerref->{pseudo} ) { - emit ( " if [ ! -f \${VARDIR}/$product/undo_${provider}_routing ]; then", + emit ( " if [ ! -f \${VARDIR}/undo_${provider}_routing ]; then", " start_interface_$provider" ); + } elsif ( $providerref->{persistent} ) { + emit ( " if [ ! -f \${VARDIR}/$providerref->{physical}_enabled ]; then", + " start_provider_$provider" ); } else { emit ( " if [ -z \"`\$IP -$family route ls table $providerref->{number}`\" ]; then", " start_provider_$provider" ); @@ -1580,7 +1696,9 @@ EOF } if ( $providerref->{pseudo} ) { - emit( " if [ -f \${VARDIR}/$product/undo_${provider}_routing ]; then" ); + emit( " if [ -f \${VARDIR}/undo_${provider}_routing ]; then" ); + } elsif ( $providerref->{persistent} ) { + emit( " if [ -f \${VARDIR}/$providerref->{physical}_enabled ]; then" ); } else { emit( " if [ -n \"`\$IP -$family route ls table $providerref->{number}`\" ]; then" ); } diff --git a/Shorewall/configfiles/routes b/Shorewall/configfiles/routes index 6c2e0a2ce..fb6ead6e7 100644 --- a/Shorewall/configfiles/routes +++ b/Shorewall/configfiles/routes @@ -4,6 +4,6 @@ # For information about entries in this file, type "man shorewall-routes" # # For additional information, see http://www.shorewall.net/MultiISP.html -############################################################################## -#PROVIDER DEST GATEWAY DEVICE +############################################################################### +#PROVIDER DEST GATEWAY DEVICE OPTIONS diff --git a/Shorewall/manpages/shorewall-providers.xml b/Shorewall/manpages/shorewall-providers.xml index 17a23755c..bafc3e37f 100644 --- a/Shorewall/manpages/shorewall-providers.xml +++ b/Shorewall/manpages/shorewall-providers.xml @@ -375,6 +375,35 @@ such as Debian 7. + + + persistent + + + Added in Shorewall 5.0.2 and alters the behavior of the + disable command: + + + + The provider's routing table still contains the + apprioriate default route. + + + + Unless the option is + specified, routing rules are generated to route traffic + from the interfaces address(es) out of the provider's + routing table. + + + + Persistent routing rules in shorewall-rtrules(5) + are present. + + + + diff --git a/Shorewall/manpages/shorewall-routes.xml b/Shorewall/manpages/shorewall-routes.xml index b99236df4..b65222862 100644 --- a/Shorewall/manpages/shorewall-routes.xml +++ b/Shorewall/manpages/shorewall-routes.xml @@ -81,6 +81,27 @@ specified in the GATEWAY column. + + + OPTIONS (Optional) + + + Added in Shorewall 5.0.2. + + Allowed options are: + + + + persistent + + + If specified, the route remains in the provider's + routing table even when the provider is disabled. + + + + + diff --git a/Shorewall/manpages/shorewall-rtrules.xml b/Shorewall/manpages/shorewall-rtrules.xml index 2c2ff073a..bdd5d23d2 100644 --- a/Shorewall/manpages/shorewall-rtrules.xml +++ b/Shorewall/manpages/shorewall-rtrules.xml @@ -89,7 +89,8 @@ PRIORITY - - priority + priority[!] The rule's numeric priority which @@ -124,6 +125,10 @@ + + Beginning with Shorewall 5.0.2, the priority may be followed + optionally by an exclaimation mark ("!"). This causes the rule to + remain in place if the interface is disabled. diff --git a/Shorewall6/configfiles/routes b/Shorewall6/configfiles/routes index 1a6ab5d16..743418e35 100644 --- a/Shorewall6/configfiles/routes +++ b/Shorewall6/configfiles/routes @@ -4,6 +4,6 @@ # For information about entries in this file, type "man shorewall6-routes" # # For additional information, see http://www.shorewall.net/MultiISP.html -############################################################################## -#PROVIDER DEST GATEWAY DEVICE +############################################################################### +#PROVIDER DEST GATEWAY DEVICE OPTIONS diff --git a/Shorewall6/manpages/shorewall6-providers.xml b/Shorewall6/manpages/shorewall6-providers.xml index bf0c22131..d6f5885a9 100644 --- a/Shorewall6/manpages/shorewall6-providers.xml +++ b/Shorewall6/manpages/shorewall6-providers.xml @@ -346,6 +346,35 @@ such as Debian 7. + + + persistent + + + Added in Shorewall 5.0.2 and alters the behavior of the + disable command: + + + + The provider's routing table still contains the + apprioriate default route. + + + + Unless the option is + specified, routing rules are generated to route traffic + from the interfaces address(es) out of the provider's + routing table. + + + + Persistent routing rules in shorewall6-rtrules(5) + are present. + + + + diff --git a/Shorewall6/manpages/shorewall6-routes.xml b/Shorewall6/manpages/shorewall6-routes.xml index 534eb8bbd..a1df782e9 100644 --- a/Shorewall6/manpages/shorewall6-routes.xml +++ b/Shorewall6/manpages/shorewall6-routes.xml @@ -81,6 +81,27 @@ specified in the GATEWAY column. + + + OPTIONS (Optional) + + + Added in Shorewall 5.0.2. + + Allowed options are: + + + + persistent + + + If specified, the route remains in the provider's + routing table even when the provider is disabled. + + + + + diff --git a/Shorewall6/manpages/shorewall6-rtrules.xml b/Shorewall6/manpages/shorewall6-rtrules.xml index 66520e359..28a1dc01e 100644 --- a/Shorewall6/manpages/shorewall6-rtrules.xml +++ b/Shorewall6/manpages/shorewall6-rtrules.xml @@ -89,7 +89,8 @@ PRIORITY - - priority + priority[!] The rule's numeric priority which @@ -102,7 +103,7 @@ 1000-1999 - Before Shorewall6-generated 'MARK' rules + Before Shorewall-generated 'MARK' rules @@ -110,7 +111,7 @@ 11000-11999 - After 'MARK' rules but before Shorewall6-generated rules + After 'MARK' rules but before Shorewall-generated rules for ISP interfaces. @@ -124,6 +125,10 @@ + + Beginning with Shorewall 5.0.2, the priority may be followed + optionally by an exclaimation mark ("!"). This causes the rule to + remain in place if the interface is disabled.