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.