2009-02-22 18:30:14 +01:00
#
2009-06-13 16:07:55 +02:00
# Shorewall 4.4 -- /usr/share/shorewall/Shorewall/Providers.pm
2009-02-22 18:30:14 +01:00
#
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
#
2012-01-12 16:14:04 +01:00
# (c) 2007,2008,2009,2010.2011,2012 - Tom Eastep (teastep@shorewall.net)
2009-02-22 18:30:14 +01:00
#
# Complete documentation is available at http://shorewall.net
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of Version 2 of the GNU General Public License
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
2010-12-21 00:07:53 +01:00
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MAS 02110-1301 USA.
2009-02-22 18:30:14 +01:00
#
2010-11-17 05:38:54 +01:00
# This module deals with the /etc/shorewall/providers,
2012-01-09 16:19:10 +01:00
# /etc/shorewall/rtrules and /etc/shorewall/routes files.
2009-02-22 18:30:14 +01:00
#
package Shorewall::Providers ;
require Exporter ;
use Shorewall::Config qw( :DEFAULT :internal ) ;
use Shorewall::IPAddrs ;
use Shorewall::Zones ;
use Shorewall::Chains qw( :DEFAULT :internal ) ;
2011-08-27 18:21:02 +02:00
use Shorewall::Proc qw( setup_interface_proc ) ;
2009-02-22 18:30:14 +01:00
use strict ;
our @ ISA = qw( Exporter ) ;
2011-08-25 02:37:39 +02:00
our @ EXPORT = qw( process_providers
setup_providers
@ routemarked_interfaces
handle_stickiness
2012-01-16 04:23:44 +01:00
handle_optional_interfaces
2012-06-01 17:12:07 +02:00
compile_updown
2012-01-16 04:23:44 +01:00
setup_load_distribution
2012-07-07 17:02:57 +02:00
have_providers
2012-01-16 04:23:44 +01:00
) ;
2009-02-22 18:30:14 +01:00
our @ EXPORT_OK = qw( initialize lookup_provider ) ;
2011-10-09 18:00:14 +02:00
our $ VERSION = '4.4_24' ;
2009-02-22 18:30:14 +01:00
use constant { LOCAL_TABLE = > 255 ,
MAIN_TABLE = > 254 ,
DEFAULT_TABLE = > 253 ,
2011-10-09 18:00:14 +02:00
BALANCE_TABLE = > 250 ,
2009-02-22 18:30:14 +01:00
UNSPEC_TABLE = > 0
} ;
2012-12-23 22:16:54 +01:00
our @ routemarked_providers ;
our % routemarked_interfaces ;
2009-02-22 18:30:14 +01:00
our @ routemarked_interfaces ;
2012-12-23 22:16:54 +01:00
our % provider_interfaces ;
our @ load_providers ;
our @ load_interfaces ;
2009-02-22 18:30:14 +01:00
2012-12-23 22:16:54 +01:00
our $ balancing ;
our $ fallback ;
our $ metrics ;
our $ first_default_route ;
our $ first_fallback_route ;
our $ maxload ;
our $ tproxies ;
2009-02-22 18:30:14 +01:00
2012-12-23 22:16:54 +01:00
our % providers ;
2009-02-22 18:30:14 +01:00
2012-12-23 22:16:54 +01:00
our @ providers ;
2009-02-22 18:30:14 +01:00
2012-12-23 22:16:54 +01:00
our $ family ;
2009-02-22 18:30:14 +01:00
2012-12-23 22:16:54 +01:00
our $ lastmark ;
2010-01-11 23:22:01 +01:00
2009-06-17 16:30:01 +02:00
use constant { ROUTEMARKED_SHARED = > 1 , ROUTEMARKED_UNSHARED = > 2 } ;
2009-02-22 18:30:14 +01:00
#
2009-08-20 23:32:15 +02:00
# Rather than initializing globals in an INIT block or during declaration,
2009-08-16 18:24:51 +02:00
# we initialize them in a function. This is done for two reasons:
#
2009-08-17 19:45:46 +02:00
# 1. Proper initialization depends on the address family which isn't
2009-08-16 18:24:51 +02:00
# known until the compiler has started.
#
# 2. The compiler can run multiple times in the same process so it has to be
2009-08-17 19:45:46 +02:00
# able to re-initialize its dependent modules' state.
2009-02-22 18:30:14 +01:00
#
sub initialize ( $ ) {
$ family = shift ;
2012-01-06 01:49:26 +01:00
@ routemarked_providers = ( ) ;
2009-02-22 18:30:14 +01:00
% routemarked_interfaces = ( ) ;
@ routemarked_interfaces = ( ) ;
2009-06-17 16:30:01 +02:00
% provider_interfaces = ( ) ;
2012-01-14 01:37:05 +01:00
@ load_providers = ( ) ;
2012-01-16 04:23:44 +01:00
@ load_interfaces = ( ) ;
2012-01-06 01:49:26 +01:00
$ balancing = 0 ;
$ fallback = 0 ;
2012-06-11 22:53:53 +02:00
$ metrics = 0 ;
2012-01-06 01:49:26 +01:00
$ first_default_route = 1 ;
$ first_fallback_route = 1 ;
2012-01-16 04:23:44 +01:00
$ maxload = 0 ;
2012-06-24 02:09:46 +02:00
$ tproxies = 0 ;
2009-02-22 18:30:14 +01:00
2011-08-29 19:05:36 +02:00
% providers = ( local = > { number = > LOCAL_TABLE , mark = > 0 , optional = > 0 , routes = > [] , rules = > [] } ,
main = > { number = > MAIN_TABLE , mark = > 0 , optional = > 0 , routes = > [] , rules = > [] } ,
default = > { number = > DEFAULT_TABLE , mark = > 0 , optional = > 0 , routes = > [] , rules = > [] } ,
2011-10-09 18:00:14 +02:00
balance = > { number = > BALANCE_TABLE , mark = > 0 , optional = > 0 , routes = > [] , rules = > [] } ,
2011-08-29 19:05:36 +02:00
unspec = > { number = > UNSPEC_TABLE , mark = > 0 , optional = > 0 , routes = > [] , rules = > [] } ) ;
2009-02-22 18:30:14 +01:00
@ providers = ( ) ;
}
#
# Set up marking for 'tracked' interfaces.
#
sub setup_route_marking () {
2010-01-11 23:22:01 +01:00
my $ mask = in_hex ( $ globals { PROVIDER_MASK } ) ;
2012-11-21 19:27:42 +01:00
my $ exmask = have_capability ( 'EXMARK' ) ? "/$mask" : '' ;
2009-02-22 18:30:14 +01:00
2009-11-07 16:39:28 +01:00
require_capability ( $ _ , q( The provider 'track' option ) , 's' ) for qw/CONNMARK_MATCH CONNMARK/ ;
2009-02-22 18:30:14 +01:00
2012-10-11 16:34:57 +02:00
if ( $ config { RESTORE_ROUTEMARKS } ) {
add_ijump $ mangle_table - > { $ _ } , j = > 'CONNMARK' , targetopts = > "--restore-mark --mask $mask" for qw/PREROUTING OUTPUT/ ;
} else {
2012-11-21 19:19:24 +01:00
add_ijump $ mangle_table - > { $ _ } , j = > 'CONNMARK' , targetopts = > "--restore-mark --mask $mask" , connmark = > "! --mark 0/$mask" for qw/PREROUTING OUTPUT/ ;
2012-10-11 16:34:57 +02:00
}
2009-02-22 18:30:14 +01:00
2009-02-25 17:56:48 +01:00
my $ chainref = new_chain 'mangle' , 'routemark' ;
2009-02-22 18:30:14 +01:00
2012-01-14 01:37:05 +01:00
if ( @ routemarked_providers ) {
my $ chainref1 = new_chain 'mangle' , 'setsticky' ;
my $ chainref2 = new_chain 'mangle' , 'setsticko' ;
2009-02-22 18:30:14 +01:00
2012-01-14 01:37:05 +01:00
my % marked_interfaces ;
2009-02-22 18:30:14 +01:00
2012-01-14 01:37:05 +01:00
for my $ providerref ( @ routemarked_providers ) {
my $ interface = $ providerref - > { interface } ;
my $ physical = $ providerref - > { physical } ;
my $ mark = $ providerref - > { mark } ;
2009-02-22 18:30:14 +01:00
2012-01-14 01:37:05 +01:00
unless ( $ marked_interfaces { $ interface } ) {
add_ijump $ mangle_table - > { PREROUTING } , j = > $ chainref , i = > $ physical , mark = > "--mark 0/$mask" ;
add_ijump $ mangle_table - > { PREROUTING } , j = > $ chainref1 , i = > "! $physical" , mark = > "--mark $mark/$mask" ;
add_ijump $ mangle_table - > { OUTPUT } , j = > $ chainref2 , mark = > "--mark $mark/$mask" ;
$ marked_interfaces { $ interface } = 1 ;
}
if ( $ providerref - > { shared } ) {
add_commands ( $ chainref , qq( if [ -n "$providerref->{mac}" ]; then ) ) , incr_cmd_level ( $ chainref ) if $ providerref - > { optional } ;
2012-11-21 19:27:42 +01:00
add_ijump $ chainref , j = > 'MARK' , targetopts = > "--set-mark $providerref->{mark}${exmask}" , imatch_source_dev ( $ interface ) , mac = > "--mac-source $providerref->{mac}" ;
2012-01-14 01:37:05 +01:00
decr_cmd_level ( $ chainref ) , add_commands ( $ chainref , "fi\n" ) if $ providerref - > { optional } ;
} else {
2012-11-21 19:27:42 +01:00
add_ijump $ chainref , j = > 'MARK' , targetopts = > "--set-mark $providerref->{mark}${exmask}" , imatch_source_dev ( $ interface ) ;
2012-01-14 01:37:05 +01:00
}
2009-02-22 18:30:14 +01:00
}
2012-01-14 01:37:05 +01:00
add_ijump $ chainref , j = > 'CONNMARK' , targetopts = > "--save-mark --mask $mask" , mark = > "! --mark 0/$mask" ;
2009-02-22 18:30:14 +01:00
}
2012-01-16 04:23:44 +01:00
if ( @ load_interfaces ) {
2012-01-14 01:37:05 +01:00
my $ chainref1 = new_chain 'mangle' , 'balance' ;
my @ match ;
add_ijump $ chainref , g = > $ chainref1 , mark = > "--mark 0/$mask" ;
add_ijump $ mangle_table - > { OUTPUT } , j = > $ chainref1 , state_imatch ( 'NEW,RELATED' ) , mark = > "--mark 0/$mask" ;
2012-01-16 04:23:44 +01:00
for my $ physical ( @ load_interfaces ) {
2012-01-14 01:37:05 +01:00
2012-01-16 04:23:44 +01:00
my $ chainref2 = new_chain ( 'mangle' , load_chain ( $ physical ) ) ;
2012-01-14 01:37:05 +01:00
2012-02-19 23:20:09 +01:00
set_optflags ( $ chainref2 , DONT_OPTIMIZE | DONT_MOVE | DONT_DELETE ) ;
2012-04-24 23:52:57 +02:00
2012-01-14 01:37:05 +01:00
add_ijump ( $ chainref1 ,
j = > $ chainref2 ,
mark = > "--mark 0/$mask" ) ;
}
}
2009-02-22 18:30:14 +01:00
}
sub copy_table ( $$$ ) {
my ( $ duplicate , $ number , $ realm ) = @ _ ;
2012-04-24 23:52:57 +02:00
2011-10-24 22:15:36 +02:00
my $ filter = $ family == F_IPV6 ? q( fgrep -v ' cache ' | sed 's/ via :: / /' | ) : '' ;
2009-10-23 22:41:51 +02:00
2011-08-27 18:21:02 +02:00
emit '' ;
2009-02-22 18:30:14 +01:00
if ( $ realm ) {
2011-10-24 22:15:36 +02:00
emit ( "\$IP -$family -o route show table $duplicate | sed -r 's/ realm [[:alnum:]_]+//' | ${filter}while read net route; do" )
2009-02-22 18:30:14 +01:00
} else {
2011-10-24 22:15:36 +02:00
emit ( "\$IP -$family -o route show table $duplicate | ${filter}while read net route; do" )
2009-02-22 18:30:14 +01:00
}
emit ( ' case $net in' ,
2011-05-14 22:56:39 +02:00
' default)' ,
2009-02-22 18:30:14 +01:00
' ;;' ,
2011-11-18 16:07:51 +01:00
' *)' ) ;
2012-04-24 23:52:57 +02:00
2011-11-18 16:07:51 +01:00
if ( $ family == F_IPV4 ) {
emit ( ' case $net in' ,
' 255.255.255.255*)' ,
' ;;' ,
' *)' ,
" run_ip route add table $number \$net \$route $realm" ,
' ;;' ,
' esac' ,
) ;
} else {
emit ( " run_ip route add table $number \$net \$route $realm" ) ;
}
emit ( ' ;;' ,
2009-02-22 18:30:14 +01:00
' esac' ,
"done\n"
) ;
}
sub copy_and_edit_table ( $$$$ ) {
my ( $ duplicate , $ number , $ copy , $ realm ) = @ _ ;
2011-10-24 22:15:36 +02:00
my $ filter = $ family == F_IPV6 ? q( fgrep -v ' cache ' | sed 's/ via :: / /' | ) : '' ;
2009-11-08 16:00:43 +01:00
#
2009-11-13 01:45:39 +01:00
# Map physical names in $copy to logical names
2009-11-08 16:00:43 +01:00
#
$ copy = join ( '|' , map ( physical_name ( $ _ ) , split ( ',' , $ copy ) ) ) ;
2009-11-11 19:17:53 +01:00
#
# Shell and iptables use a different wildcard character
#
2011-11-04 21:48:13 +01:00
$ copy =~ s/\+/*/g ;
2012-04-24 23:52:57 +02:00
2011-08-27 18:21:02 +02:00
emit '' ;
2009-02-22 18:30:14 +01:00
if ( $ realm ) {
2011-10-24 22:15:36 +02:00
emit ( "\$IP -$family -o route show table $duplicate | sed -r 's/ realm [[:alnum:]]+//' | ${filter}while read net route; do" )
2009-02-22 18:30:14 +01:00
} else {
2011-10-24 22:15:36 +02:00
emit ( "\$IP -$family -o route show table $duplicate | ${filter}while read net route; do" )
2009-02-22 18:30:14 +01:00
}
emit ( ' case $net in' ,
2011-05-14 22:56:39 +02:00
' default)' ,
2009-02-22 18:30:14 +01:00
' ;;' ,
' *)' ,
' case $(find_device $route) in' ,
2011-11-18 16:07:51 +01:00
" $copy)" ) ;
if ( $ family == F_IPV4 ) {
emit ( ' case $net in' ,
' 255.255.255.255*)' ,
' ;;' ,
' *)' ,
" run_ip route add table $number \$net \$route $realm" ,
' ;;' ,
' esac' ,
) ;
} else {
emit ( " run_ip route add table $number \$net \$route $realm" ) ;
2012-04-24 23:52:57 +02:00
}
2011-11-18 16:07:51 +01:00
emit ( ' ;;' ,
2009-02-22 18:30:14 +01:00
' esac' ,
' ;;' ,
' esac' ,
"done\n" ) ;
}
sub balance_default_route ( $$$$ ) {
my ( $ weight , $ gateway , $ interface , $ realm ) = @ _ ;
$ balancing = 1 ;
emit '' ;
if ( $ first_default_route ) {
2011-10-21 20:55:15 +02:00
if ( $ family == F_IPV4 ) {
if ( $ gateway ) {
emit "DEFAULT_ROUTE=\"nexthop via $gateway dev $interface weight $weight $realm\"" ;
} else {
emit "DEFAULT_ROUTE=\"nexthop dev $interface weight $weight $realm\"" ;
}
2009-02-22 18:30:14 +01:00
} else {
2011-10-22 21:48:07 +02:00
#
# IPv6 doesn't support multi-hop routes
#
2011-10-21 20:55:15 +02:00
if ( $ gateway ) {
emit "DEFAULT_ROUTE=\"via $gateway dev $interface $realm\"" ;
} else {
emit "DEFAULT_ROUTE=\"dev $interface $realm\"" ;
}
2009-02-22 18:30:14 +01:00
}
$ first_default_route = 0 ;
} else {
2011-10-21 20:55:15 +02:00
fatal_error "Only one 'balance' provider is allowed with IPv6" if $ family == F_IPV6 ;
2009-02-22 18:30:14 +01:00
if ( $ gateway ) {
emit "DEFAULT_ROUTE=\"\$DEFAULT_ROUTE nexthop via $gateway dev $interface weight $weight $realm\"" ;
} else {
emit "DEFAULT_ROUTE=\"\$DEFAULT_ROUTE nexthop dev $interface weight $weight $realm\"" ;
}
}
}
sub balance_fallback_route ( $$$$ ) {
my ( $ weight , $ gateway , $ interface , $ realm ) = @ _ ;
$ fallback = 1 ;
emit '' ;
if ( $ first_fallback_route ) {
2011-10-21 20:55:15 +02:00
if ( $ family == F_IPV4 ) {
if ( $ gateway ) {
emit "FALLBACK_ROUTE=\"nexthop via $gateway dev $interface weight $weight $realm\"" ;
} else {
emit "FALLBACK_ROUTE=\"nexthop dev $interface weight $weight $realm\"" ;
}
2009-02-22 18:30:14 +01:00
} else {
2011-10-22 21:48:07 +02:00
#
# IPv6 doesn't support multi-hop routes
#
2011-10-21 20:55:15 +02:00
if ( $ gateway ) {
emit "FALLBACK_ROUTE=\"via $gateway dev $interface $realm\"" ;
} else {
emit "FALLBACK_ROUTE=\"dev $interface $realm\"" ;
}
2009-02-22 18:30:14 +01:00
}
$ first_fallback_route = 0 ;
} else {
2011-10-21 20:55:15 +02:00
fatal_error "Only one 'fallback' provider is allowed with IPv6" if $ family == F_IPV6 ;
2009-02-22 18:30:14 +01:00
if ( $ gateway ) {
emit "FALLBACK_ROUTE=\"\$FALLBACK_ROUTE nexthop via $gateway dev $interface weight $weight $realm\"" ;
} else {
emit "FALLBACK_ROUTE=\"\$FALLBACK_ROUTE nexthop dev $interface weight $weight $realm\"" ;
}
}
}
2012-11-16 18:48:21 +01:00
sub start_provider ( $$$$ ) {
my ( $ what , $ table , $ number , $ test ) = @ _ ;
2009-02-22 18:30:14 +01:00
2012-11-16 18:48:21 +01:00
emit "\n#\n# Add $what $table ($number)\n#" ;
if ( $ number ) {
emit "start_provider_$table() {" ;
} else {
emit "start_interface_$table() {" ;
}
2011-08-25 02:37:39 +02:00
push_indent ;
2009-02-22 18:30:14 +01:00
emit $ test ;
push_indent ;
2012-11-20 22:27:15 +01:00
2012-11-16 18:48:21 +01:00
if ( $ number ) {
emit "qt ip -$family route flush table $number" ;
emit "echo \"qt \$IP -$family route flush table $number\" > \${VARDIR}/undo_${table}_routing" ;
2012-11-20 22:27:15 +01:00
} else {
emit ( "> \${VARDIR}/undo_${table}_routing" ) ;
2012-11-16 18:48:21 +01:00
}
2009-02-22 18:30:14 +01:00
}
2011-08-28 17:04:06 +02:00
#
# Process a record in the providers file
#
2012-11-16 18:48:21 +01:00
sub process_a_provider ( $ ) {
my $ pseudo = $ _ [ 0 ] ; # When true, this is an optional interface that we are treating somewhat like a provider.
2009-02-22 18:30:14 +01:00
2011-09-26 02:08:53 +02:00
my ( $ table , $ number , $ mark , $ duplicate , $ interface , $ gateway , $ options , $ copy ) =
2011-10-01 20:39:12 +02:00
split_line 'providers file' , { table = > 0 , number = > 1 , mark = > 2 , duplicate = > 3 , interface = > 4 , gateway = > 5 , options = > 6 , copy = > 7 } ;
2009-02-22 18:30:14 +01:00
fatal_error "Duplicate provider ($table)" if $ providers { $ table } ;
2011-10-01 18:56:25 +02:00
fatal_error 'NAME must be specified' if $ table eq '-' ;
2011-08-25 02:37:39 +02:00
2012-11-16 18:48:21 +01:00
unless ( $ pseudo ) {
fatal_error "Invalid Provider Name ($table)" unless $ table =~ /^[\w]+$/ ;
my $ num = numeric_value $ number ;
2009-02-22 18:30:14 +01:00
2012-11-16 18:48:21 +01:00
fatal_error 'NUMBER must be specified' if $ number eq '-' ;
fatal_error "Invalid Provider number ($number)" unless defined $ num ;
2009-02-22 18:30:14 +01:00
2012-11-16 18:48:21 +01:00
$ number = $ num ;
2009-02-22 18:30:14 +01:00
2012-11-16 18:48:21 +01:00
for my $ providerref ( values % providers ) {
fatal_error "Duplicate provider number ($number)" if $ providerref - > { number } == $ number ;
}
2009-02-22 18:30:14 +01:00
}
2011-10-01 18:56:25 +02:00
fatal_error 'INTERFACE must be specified' if $ interface eq '-' ;
2009-02-22 18:30:14 +01:00
( $ interface , my $ address ) = split /:/ , $ interface ;
my $ shared = 0 ;
if ( defined $ address ) {
validate_address $ address , 0 ;
$ shared = 1 ;
require_capability 'REALM_MATCH' , "Configuring multiple providers through one interface" , "s" ;
}
2010-12-20 19:32:04 +01:00
fatal_error "Unknown Interface ($interface)" unless known_interface ( $ interface ) ;
2009-11-06 18:22:16 +01:00
fatal_error "A bridge port ($interface) may not be configured as a provider interface" if port_to_bridge $ interface ;
2009-08-20 23:32:15 +02:00
2009-11-08 16:00:43 +01:00
my $ physical = get_physical $ interface ;
2009-04-20 17:30:15 +02:00
my $ gatewaycase = '' ;
2009-02-22 18:30:14 +01:00
2012-11-20 16:06:27 +01:00
if ( $ physical =~ /\+$/ ) {
return 0 if $ pseudo ;
fatal_error "Wildcard interfaces ($physical) may not be used as provider interfaces" ;
}
2009-02-22 18:30:14 +01:00
if ( $ gateway eq 'detect' ) {
fatal_error "Configuring multiple providers through one interface requires an explicit gateway" if $ shared ;
$ gateway = get_interface_gateway $ interface ;
2009-04-20 17:30:15 +02:00
$ gatewaycase = 'detect' ;
2009-04-20 19:28:18 +02:00
} elsif ( $ gateway && $ gateway ne '-' ) {
validate_address $ gateway , 0 ;
$ gatewaycase = 'specified' ;
2009-02-22 18:30:14 +01:00
} else {
2009-04-20 19:28:18 +02:00
$ gatewaycase = 'none' ;
fatal_error "Configuring multiple providers through one interface requires a gateway" if $ shared ;
$ gateway = '' ;
2009-02-22 18:30:14 +01:00
}
2012-11-16 18:48:21 +01:00
my ( $ loose , $ track , $ balance , $ default , $ default_balance , $ optional , $ mtu , $ tproxy , $ local , $ load , $ what ) ;
if ( $ pseudo ) {
( $ loose , $ track , $ balance , $ default , $ default_balance , $ optional , $ mtu , $ tproxy , $ local , $ load , $ what ) =
( 0 , 0 , 0 , 0 , 0 , 1 , '' , 0 , 0 , 0 , 'interface' ) ;
} else {
( $ loose , $ track , $ balance , $ default , $ default_balance , $ optional , $ mtu , $ tproxy , $ local , $ load , $ what ) =
( 0 , $ config { TRACK_PROVIDERS } , 0 , 0 , $ config { USE_DEFAULT_RT } ? 1 : 0 , interface_is_optional ( $ interface ) , '' , 0 , 0 , 0 , 'provider' ) ;
}
2009-02-22 18:30:14 +01:00
unless ( $ options eq '-' ) {
for my $ option ( split_list $ options , 'option' ) {
if ( $ option eq 'track' ) {
2011-08-30 18:31:06 +02:00
require_capability ( 'MANGLE_ENABLED' , q( The 'track' option ) , 's' ) ;
2009-02-22 18:30:14 +01:00
$ track = 1 ;
2009-10-20 21:24:28 +02:00
} elsif ( $ option eq 'notrack' ) {
$ track = 0 ;
2009-02-22 18:30:14 +01:00
} elsif ( $ option =~ /^balance=(\d+)$/ ) {
2011-10-21 20:55:15 +02:00
fatal_error q( 'balance=<weight>' is not available in IPv6 ) if $ family == F_IPV6 ;
2009-02-22 18:30:14 +01:00
$ balance = $ 1 ;
} elsif ( $ option eq 'balance' ) {
$ balance = 1 ;
} elsif ( $ option eq 'loose' ) {
$ loose = 1 ;
$ default_balance = 0 ;
} elsif ( $ option eq 'optional' ) {
2011-12-01 20:23:22 +01:00
unless ( $ shared ) {
warning_message q( The 'optional' provider option is deprecated - use the 'optional' interface option instead ) ;
set_interface_option $ interface , 'optional' , 1 ;
}
2009-02-22 18:30:14 +01:00
$ optional = 1 ;
} elsif ( $ option =~ /^src=(.*)$/ ) {
fatal_error "OPTION 'src' not allowed on shared interface" if $ shared ;
2009-03-05 21:27:22 +01:00
$ address = validate_address ( $ 1 , 1 ) ;
2009-02-22 18:30:14 +01:00
} elsif ( $ option =~ /^mtu=(\d+)$/ ) {
$ mtu = "mtu $1 " ;
} elsif ( $ option =~ /^fallback=(\d+)$/ ) {
2011-10-21 20:55:15 +02:00
fatal_error q( 'fallback=<weight>' is not available in IPv6 ) if $ family == F_IPV6 ;
2011-10-09 18:00:14 +02:00
$ default = $ 1 ;
$ default_balance = 0 ;
fatal_error 'fallback must be non-zero' unless $ default ;
2009-02-22 18:30:14 +01:00
} elsif ( $ option eq 'fallback' ) {
2011-10-09 18:00:14 +02:00
$ default = - 1 ;
$ default_balance = 0 ;
2012-05-10 23:23:33 +02:00
} elsif ( $ option eq 'local' ) {
warning_message q( The 'local' provider option is deprecated in favor of 'tproxy' ) ;
$ local = $ tproxy = 1 ;
$ track = 0 if $ config { TRACK_PROVIDERS } ;
$ default_balance = 0 if $ config { USE_DEFAULT_RT } ;
2012-05-10 20:19:23 +02:00
} elsif ( $ option eq 'tproxy' ) {
$ tproxy = 1 ;
$ track = 0 if $ config { TRACK_PROVIDERS } ;
$ default_balance = 0 if $ config { USE_DEFAULT_RT } ;
2012-01-14 01:37:05 +01:00
} elsif ( $ option =~ /^load=(0?\.\d{1,8})/ ) {
$ load = $ 1 ;
require_capability 'STATISTIC_MATCH' , "load=$load" , 's' ;
2009-02-22 18:30:14 +01:00
} else {
fatal_error "Invalid option ($option)" ;
}
}
}
2011-06-30 19:00:01 +02:00
fatal_error q( The 'balance' and 'fallback' options are mutually exclusive ) if $ balance && $ default ;
2012-01-14 01:37:05 +01:00
if ( $ load ) {
fatal_error q( The 'balance=<weight>' and 'load=<load-factor>' options are mutually exclusive ) if $ balance > 1 ;
fatal_error q( The 'fallback=<weight>' and 'load=<load-factor>' options are mutually exclusive ) if $ default > 1 ;
2012-01-16 04:23:44 +01:00
$ maxload += $ load ;
2012-01-14 01:37:05 +01:00
}
2012-05-10 23:23:33 +02:00
if ( $ local ) {
2012-06-24 02:09:46 +02:00
fatal_error "GATEWAY not valid with 'local' provider" unless $ gatewaycase eq 'none' ;
fatal_error "'track' not valid with 'local'" if $ track ;
fatal_error "DUPLICATE not valid with 'local'" if $ duplicate ne '-' ;
2012-05-10 23:23:33 +02:00
} elsif ( $ tproxy ) {
2012-06-24 02:09:46 +02:00
fatal_error "Only one 'tproxy' provider is allowed" if $ tproxies + + ;
2012-05-10 20:19:23 +02:00
fatal_error "GATEWAY not valid with 'tproxy' provider" unless $ gatewaycase eq 'none' ;
fatal_error "'track' not valid with 'tproxy'" if $ track ;
fatal_error "DUPLICATE not valid with 'tproxy'" if $ duplicate ne '-' ;
fatal_error "MARK not allowed with 'tproxy'" if $ mark ne '-' ;
$ mark = $ globals { TPROXY_MARK } ;
2011-08-28 17:04:06 +02:00
}
2010-01-11 23:22:01 +01:00
my $ val = 0 ;
my $ pref ;
$ mark = ( $ lastmark += ( 1 << $ config { PROVIDER_OFFSET } ) ) if $ mark eq '-' && $ track ;
if ( $ mark ne '-' ) {
2011-08-30 18:31:06 +02:00
require_capability ( 'MANGLE_ENABLED' , 'Provider marks' , '' ) ;
2012-05-10 23:23:33 +02:00
if ( $ tproxy && ! $ local ) {
2012-05-10 20:19:23 +02:00
$ val = $ globals { TPROXY_MARK } ;
$ pref = 1 ;
} else {
$ val = numeric_value $ mark ;
2010-01-11 23:22:01 +01:00
2012-05-10 20:19:23 +02:00
fatal_error "Invalid Mark Value ($mark)" unless defined $ val && $ val ;
2010-01-11 23:22:01 +01:00
2012-05-10 20:19:23 +02:00
verify_mark $ mark ;
2010-01-11 23:22:01 +01:00
2012-05-10 20:19:23 +02:00
fatal_error "Invalid Mark Value ($mark)" unless ( $ val & $ globals { PROVIDER_MASK } ) == $ val ;
2010-01-11 23:22:01 +01:00
2012-05-10 20:19:23 +02:00
fatal_error "Provider MARK may not be specified when PROVIDER_BITS=0" unless $ config { PROVIDER_BITS } ;
2010-01-11 23:22:01 +01:00
2012-05-10 20:19:23 +02:00
for my $ providerref ( values % providers ) {
fatal_error "Duplicate mark value ($mark)" if numeric_value ( $ providerref - > { mark } ) == $ val ;
}
2010-01-11 23:22:01 +01:00
2012-05-10 20:19:23 +02:00
$ lastmark = $ val ;
$ pref = 10000 + $ number - 1 ;
}
2010-01-11 23:22:01 +01:00
}
2012-11-16 18:48:21 +01:00
unless ( $ loose || $ pseudo ) {
2009-05-21 18:39:43 +02:00
warning_message q( The 'proxyarp' option is dangerous when specified on a Provider interface ) if get_interface_option ( $ interface , 'proxyarp' ) ;
warning_message q( The 'proxyndp' option is dangerous when specified on a Provider interface ) if get_interface_option ( $ interface , 'proxyndp' ) ;
}
2009-02-22 18:30:14 +01:00
$ balance = $ default_balance unless $ balance ;
2011-08-28 17:04:06 +02:00
fatal_error "Interface $interface is already associated with non-shared provider $provider_interfaces{$interface}" if $ provider_interfaces { $ table } ;
if ( $ duplicate ne '-' ) {
fatal_error "The DUPLICATE column must be empty when USE_DEFAULT_RT=Yes" if $ config { USE_DEFAULT_RT } ;
} elsif ( $ copy ne '-' ) {
fatal_error "The COPY column must be empty when USE_DEFAULT_RT=Yes" if $ config { USE_DEFAULT_RT } ;
fatal_error 'A non-empty COPY column requires that a routing table be specified in the DUPLICATE column' ;
}
2009-06-15 20:35:46 +02:00
$ providers { $ table } = { provider = > $ table ,
number = > $ number ,
2011-08-28 17:04:06 +02:00
rawmark = > $ mark ,
2009-06-15 20:35:46 +02:00
mark = > $ val ? in_hex ( $ val ) : $ val ,
interface = > $ interface ,
2009-11-08 16:00:43 +01:00
physical = > $ physical ,
2009-06-15 20:35:46 +02:00
optional = > $ optional ,
gateway = > $ gateway ,
gatewaycase = > $ gatewaycase ,
shared = > $ shared ,
2011-08-25 02:37:39 +02:00
default = > $ default ,
2011-08-28 17:04:06 +02:00
copy = > $ copy ,
balance = > $ balance ,
pref = > $ pref ,
mtu = > $ mtu ,
track = > $ track ,
loose = > $ loose ,
duplicate = > $ duplicate ,
address = > $ address ,
2012-05-10 23:23:33 +02:00
local = > $ local ,
2012-05-10 20:19:23 +02:00
tproxy = > $ tproxy ,
2012-01-14 01:37:05 +01:00
load = > $ load ,
2012-11-16 18:48:21 +01:00
pseudo = > $ pseudo ,
what = > $ what ,
2011-08-25 02:37:39 +02:00
rules = > [] ,
routes = > [] ,
} ;
2009-02-22 18:30:14 +01:00
2012-11-16 18:48:21 +01:00
$ provider_interfaces { $ interface } = $ table unless $ shared ;
2009-02-22 18:30:14 +01:00
if ( $ track ) {
fatal_error "The 'track' option requires a numeric value in the MARK column" if $ mark eq '-' ;
if ( $ routemarked_interfaces { $ interface } ) {
2009-06-17 16:30:01 +02:00
fatal_error "Interface $interface is tracked through an earlier provider" if $ routemarked_interfaces { $ interface } == ROUTEMARKED_UNSHARED ;
2009-02-22 18:30:14 +01:00
fatal_error "Multiple providers through the same interface must their IP address specified in the INTERFACES" unless $ shared ;
} else {
2009-06-17 16:30:01 +02:00
$ routemarked_interfaces { $ interface } = $ shared ? ROUTEMARKED_SHARED : ROUTEMARKED_UNSHARED ;
2009-02-22 18:30:14 +01:00
push @ routemarked_interfaces , $ interface ;
}
push @ routemarked_providers , $ providers { $ table } ;
}
2012-01-16 04:23:44 +01:00
push @ load_interfaces , $ physical if $ load ;
2012-01-14 01:37:05 +01:00
2011-08-28 17:04:06 +02:00
push @ providers , $ table ;
2009-02-22 18:30:14 +01:00
2012-11-16 18:48:21 +01:00
progress_message " Provider \"$currentline\" $done" unless $ pseudo ;
2012-11-20 16:06:27 +01:00
return 1 ;
2012-11-16 18:48:21 +01:00
}
#
# Emit a 'started' message
#
sub emit_started_message ( $$$$$ ) {
my ( $ spaces , $ level , $ pseudo , $ name , $ number ) = @ _ ;
if ( $ pseudo ) {
emit qq( ${spaces}progress_message${level} " Optional interface $name Started" ) ;
} else {
emit qq( ${spaces}progress_message${level} " Provider $name ( $number ) Started" ) ;
}
2011-08-28 17:04:06 +02:00
}
#
# Generate the start_provider_...() function for the passed provider
#
sub add_a_provider ( $$ ) {
2012-04-24 23:52:57 +02:00
2011-08-28 17:04:06 +02:00
my ( $ providerref , $ tcdevices ) = @ _ ;
2012-04-24 23:52:57 +02:00
2011-08-28 17:04:06 +02:00
my $ table = $ providerref - > { provider } ;
my $ number = $ providerref - > { number } ;
my $ mark = $ providerref - > { rawmark } ;
my $ interface = $ providerref - > { interface } ;
my $ physical = $ providerref - > { physical } ;
my $ optional = $ providerref - > { optional } ;
my $ gateway = $ providerref - > { gateway } ;
my $ gatewaycase = $ providerref - > { gatewaycase } ;
my $ shared = $ providerref - > { shared } ;
my $ default = $ providerref - > { default } ;
my $ copy = $ providerref - > { copy } ;
my $ balance = $ providerref - > { balance } ;
my $ pref = $ providerref - > { pref } ;
my $ mtu = $ providerref - > { mtu } ;
my $ track = $ providerref - > { track } ;
my $ loose = $ providerref - > { loose } ;
my $ duplicate = $ providerref - > { duplicate } ;
my $ address = $ providerref - > { address } ;
2012-05-10 23:23:33 +02:00
my $ local = $ providerref - > { local } ;
2012-05-10 20:19:23 +02:00
my $ tproxy = $ providerref - > { tproxy } ;
2012-01-14 01:37:05 +01:00
my $ load = $ providerref - > { load } ;
2012-11-16 18:48:21 +01:00
my $ pseudo = $ providerref - > { pseudo } ;
my $ what = $ providerref - > { what } ;
my $ label = $ pseudo ? 'Optional Interface' : 'Provider' ;
2012-01-14 01:37:05 +01:00
2012-12-28 19:39:19 +01:00
my $ dev = var_base $ physical ;
2011-08-28 17:04:06 +02:00
my $ base = uc $ dev ;
my $ realm = '' ;
2009-08-20 23:32:15 +02:00
2009-02-22 18:30:14 +01:00
if ( $ shared ) {
2009-04-20 17:30:15 +02:00
my $ variable = $ providers { $ table } { mac } = get_interface_mac ( $ gateway , $ interface , $ table ) ;
2009-02-22 18:30:14 +01:00
$ realm = "realm $number" ;
2012-11-16 18:48:21 +01:00
start_provider ( $ label , $ table , $ number , qq( if interface_is_usable $physical && [ -n "$variable" ]; then ) ) ;
} elsif ( $ pseudo ) {
start_provider ( $ label , $ table , $ number , qq( if [ -n "\$SW_${base}_IS_USABLE" ]; then ) ) ;
2009-04-20 17:30:15 +02:00
} else {
2009-06-17 18:39:35 +02:00
if ( $ optional ) {
2012-11-16 18:48:21 +01:00
start_provider ( $ label , $ table , $ number , qq( if [ -n "\$SW_${base}_IS_USABLE" ]; then ) ) ;
2009-06-17 18:39:35 +02:00
} elsif ( $ gatewaycase eq 'detect' ) {
2012-11-16 18:48:21 +01:00
start_provider ( $ label , $ table , $ number , qq( if interface_is_usable $physical && [ -n "$gateway" ]; then ) ) ;
2009-06-17 18:39:35 +02:00
} else {
2012-11-16 18:48:21 +01:00
start_provider ( $ label , $ table , $ number , "if interface_is_usable $physical; then" ) ;
2009-06-17 18:39:35 +02:00
}
$ provider_interfaces { $ interface } = $ table ;
2010-01-17 17:12:44 +01:00
if ( $ gatewaycase eq 'none' ) {
2012-05-10 20:19:23 +02:00
if ( $ tproxy ) {
2011-02-13 17:13:22 +01:00
emit 'run_ip route add local ' . ALLIP . " dev $physical table $number" ;
2010-01-17 17:12:44 +01:00
} else {
emit "run_ip route add default dev $physical table $number" ;
}
}
2009-06-17 18:39:35 +02:00
}
2012-01-15 02:43:25 +01:00
2012-05-08 22:55:13 +02:00
emit ( "echo $load > \${VARDIR}/${physical}_load" ,
'echo ' . in_hex ( $ mark ) . '/' . in_hex ( $ globals { PROVIDER_MASK } ) . " > \${VARDIR}/${physical}_mark" ) if $ load ;
2012-01-15 02:43:25 +01:00
2012-04-24 23:52:57 +02:00
emit ( '' ,
2012-01-16 04:23:44 +01:00
"cat <<EOF >> \${VARDIR}/undo_${table}_routing" ) ;
2012-04-24 23:52:57 +02:00
2012-01-16 04:23:44 +01:00
emit_unindented 'case \$COMMAND in' ;
emit_unindented ' enable|disable)' ;
emit_unindented ' ;;' ;
emit_unindented ' *)' ;
emit_unindented " rm -f \${VARDIR}/${physical}_load" if $ load ;
2012-05-08 22:55:13 +02:00
emit_unindented " rm -f \${VARDIR}/${physical}_mark" if $ load ;
2012-01-16 04:23:44 +01:00
emit_unindented << "CEOF" , 1 ;
rm - f \ $ { VARDIR } / $ { physical } . status
; ;
esac
EOF
CEOF
2011-09-01 01:38:58 +02:00
#
# /proc for this interface
#
2011-08-27 18:21:02 +02:00
setup_interface_proc ( $ interface ) ;
2009-04-20 17:30:15 +02:00
if ( $ mark ne '-' ) {
2012-05-10 20:19:23 +02:00
my $ hexmark = in_hex ( $ mark ) ;
2012-05-10 23:23:33 +02:00
my $ mask = have_capability 'FWMARK_RT_MASK' ? '/' . in_hex ( $ globals { $ tproxy && ! $ local ? 'TPROXY_MARK' : 'PROVIDER_MASK' } ) : '' ;
2009-04-20 17:30:15 +02:00
2012-05-10 20:19:23 +02:00
emit ( "qt \$IP -$family rule del fwmark ${hexmark}${mask}" ) if $ config { DELETE_THEN_ADD } ;
2010-07-04 18:08:04 +02:00
2012-05-10 20:19:23 +02:00
emit ( "run_ip rule add fwmark ${hexmark}${mask} pref $pref table $number" ,
"echo \"qt \$IP -$family rule del fwmark ${hexmark}${mask}\" >> \${VARDIR}/undo_${table}_routing"
2009-04-20 17:30:15 +02:00
) ;
2009-02-22 18:30:14 +01:00
}
if ( $ duplicate ne '-' ) {
if ( $ copy eq '-' ) {
copy_table ( $ duplicate , $ number , $ realm ) ;
} else {
if ( $ copy eq 'none' ) {
$ copy = $ interface ;
} else {
2009-11-08 16:00:43 +01:00
$ copy = "$interface,$copy" ;
2009-02-22 18:30:14 +01:00
}
copy_and_edit_table ( $ duplicate , $ number , $ copy , $ realm ) ;
}
}
if ( $ gateway ) {
$ address = get_interface_address $ interface unless $ address ;
2011-04-19 19:56:59 +02:00
if ( $ family == F_IPV4 ) {
2011-05-08 14:43:53 +02:00
emit "run_ip route replace $gateway src $address dev $physical ${mtu}" ;
2011-04-19 19:56:59 +02:00
emit "run_ip route replace $gateway src $address dev $physical ${mtu}table $number $realm" ;
} else {
2011-12-26 20:58:06 +01:00
emit "qt \$IP -6 route add $gateway src $address dev $physical ${mtu}" ;
2011-04-19 19:56:59 +02:00
emit "qt \$IP -6 route del $gateway src $address dev $physical ${mtu}table $number $realm" ;
emit "run_ip route add $gateway src $address dev $physical ${mtu}table $number $realm" ;
}
2011-10-09 18:00:14 +02:00
2011-05-08 14:51:58 +02:00
emit "run_ip route add default via $gateway src $address dev $physical ${mtu}table $number $realm" ;
2011-08-27 17:29:55 +02:00
}
2009-02-22 18:30:14 +01:00
2011-10-09 18:00:14 +02:00
if ( $ balance ) {
balance_default_route ( $ balance , $ gateway , $ physical , $ realm ) ;
} elsif ( $ default > 0 ) {
2011-09-01 01:38:58 +02:00
balance_fallback_route ( $ default , $ gateway , $ physical , $ realm ) ;
2009-02-22 18:30:14 +01:00
} elsif ( $ default ) {
emit '' ;
if ( $ gateway ) {
2011-04-19 19:56:59 +02:00
if ( $ family == F_IPV4 ) {
2012-06-12 01:57:49 +02:00
emit qq( run_ip route replace $gateway/32 dev $physical table ) . DEFAULT_TABLE ;
2011-04-19 19:56:59 +02:00
emit qq( run_ip route replace default via $gateway src $address dev $physical table ) . DEFAULT_TABLE . qq( metric $number ) ;
} else {
emit qq( qt \$IP -6 route del default via $gateway src $address dev $physical table ) . DEFAULT_TABLE . qq( metric $number ) ;
emit qq( run_ip route add default via $gateway src $address dev $physical table ) . DEFAULT_TABLE . qq( metric $number ) ;
}
2011-08-25 02:37:39 +02:00
emit qq( echo "qt \$IP -$family route del default via $gateway table ) . DEFAULT_TABLE . qq( " >> \${VARDIR}/undo_${table}_routing ) ;
2012-06-12 01:57:49 +02:00
emit qq( echo "qt \$IP -4 route del $gateway/32 dev $physical table ) . DEFAULT_TABLE . qq( " >> \${VARDIR}/undo_${table}_routing ) if $ family == F_IPV4 ;
2009-02-22 18:30:14 +01:00
} else {
2009-11-08 16:00:43 +01:00
emit qq( run_ip route add default table ) . DEFAULT_TABLE . qq( dev $physical metric $number ) ;
2011-08-25 02:37:39 +02:00
emit qq( echo "qt \$IP -$family route del default dev $physical table ) . DEFAULT_TABLE . qq( " >> \${VARDIR}/undo_${table}_routing ) ;
2009-02-22 18:30:14 +01:00
}
2012-04-24 23:52:57 +02:00
2012-06-11 22:53:53 +02:00
$ metrics = 1 ;
2009-02-22 18:30:14 +01:00
}
2011-12-21 17:01:25 +01:00
emit ( qq( \ n ) ,
qq( if ! \$IP -6 rule ls | egrep -q "32767:[[:space:]]+from all lookup ( default|253 ) "; then ) ,
qq( qt \$IP -6 rule add from all table ) . DEFAULT_TABLE . qq( prio 32767\n ) ,
qq( fi ) ) if $ family == F_IPV6 ;
2011-10-25 06:15:09 +02:00
2012-05-10 20:19:23 +02:00
unless ( $ tproxy ) {
2011-10-24 17:50:15 +02:00
emit '' ;
2011-08-28 17:04:06 +02:00
if ( $ loose ) {
if ( $ config { DELETE_THEN_ADD } ) {
2011-10-24 17:50:15 +02:00
emit ( "find_interface_addresses $physical | while read address; do" ,
2011-08-28 17:04:06 +02:00
" qt \$IP -$family rule del from \$address" ,
'done'
) ;
}
} elsif ( $ shared ) {
emit "qt \$IP -$family rule del from $address" if $ config { DELETE_THEN_ADD } ;
emit ( "run_ip rule add from $address pref 20000 table $number" ,
"echo \"qt \$IP -$family rule del from $address\" >> \${VARDIR}/undo_${table}_routing" ) ;
2012-11-16 18:48:21 +01:00
} elsif ( ! $ pseudo ) {
2011-08-28 17:04:06 +02:00
emit ( "find_interface_addresses $physical | while read address; do" ) ;
2011-09-01 15:06:50 +02:00
emit ( " qt \$IP -$family rule del from \$address" ) if $ config { DELETE_THEN_ADD } ;
2011-10-24 02:11:41 +02:00
emit ( " run_ip rule add from \$address pref 20000 table $number" ,
2011-09-01 15:06:50 +02:00
" echo \"qt \$IP -$family rule del from \$address\" >> \${VARDIR}/undo_${table}_routing" ,
' rulenum=$(($rulenum + 1))' ,
'done'
2011-08-28 17:04:06 +02:00
) ;
}
2009-02-22 18:30:14 +01:00
}
2011-08-28 17:04:06 +02:00
if ( @ { $ providerref - > { rules } } ) {
emit '' ;
emit $ _ for @ { $ providers { $ table } - > { rules } } ;
}
2012-04-24 23:52:57 +02:00
2011-08-28 17:04:06 +02:00
if ( @ { $ providerref - > { routes } } ) {
emit '' ;
emit $ _ for @ { $ providers { $ table } - > { routes } } ;
}
2011-08-25 02:37:39 +02:00
2011-09-14 17:25:47 +02:00
emit ( '' ) ;
2012-04-24 23:52:57 +02:00
2011-09-14 17:25:47 +02:00
my ( $ tbl , $ weight ) ;
2011-09-01 01:38:58 +02:00
2012-01-16 04:23:44 +01:00
emit ( qq( echo 0 > \${VARDIR}/${physical}.status ) ) ;
2012-04-24 23:52:57 +02:00
if ( $ optional ) {
2012-01-16 04:23:44 +01:00
emit ( '' ,
'if [ $COMMAND = enable ]; then' ) ;
2011-08-26 01:00:27 +02:00
2011-09-14 17:25:47 +02:00
push_indent ;
2011-08-26 01:00:27 +02:00
2011-10-09 18:00:14 +02:00
if ( $ balance || $ default > 0 ) {
$ tbl = $ default ? DEFAULT_TABLE : $ config { USE_DEFAULT_RT } ? BALANCE_TABLE : MAIN_TABLE ;
2011-09-14 17:25:47 +02:00
$ weight = $ balance ? $ balance : $ default ;
2011-10-21 20:55:15 +02:00
if ( $ family == F_IPV4 ) {
if ( $ gateway ) {
emit qq( add_gateway "nexthop via $gateway dev $physical weight $weight $realm" ) . $ tbl ;
} else {
emit qq( add_gateway "nexthop dev $physical weight $weight $realm" ) . $ tbl ;
}
2011-09-14 17:25:47 +02:00
} else {
2011-10-22 21:48:07 +02:00
#
# IPv6 doesn't support multi-hop routes
#
2011-10-21 20:55:15 +02:00
if ( $ gateway ) {
emit qq( add_gateway "via $gateway dev $physical $realm" ) . $ tbl ;
} else {
2012-05-12 16:15:24 +02:00
emit qq( add_gateway "dev $physical $realm" ) . $ tbl ;
2011-10-21 20:55:15 +02:00
}
2011-09-14 17:25:47 +02:00
}
2012-01-17 16:24:12 +01:00
} else {
2011-09-14 17:25:47 +02:00
$ weight = 1 ;
}
2011-08-28 17:04:06 +02:00
2012-01-16 04:23:44 +01:00
emit ( "distribute_load $maxload @load_interfaces" ) if $ load ;
2012-01-14 01:37:05 +01:00
2011-12-01 19:41:03 +01:00
unless ( $ shared ) {
emit ( "setup_${dev}_tc" ) if $ tcdevices - > { $ interface } ;
}
2009-02-22 18:30:14 +01:00
2012-11-16 18:48:21 +01:00
emit_started_message ( '' , 2 , $ pseudo , $ table , $ number ) ;
2011-09-14 15:24:22 +02:00
2011-09-14 17:25:47 +02:00
pop_indent ;
2012-04-24 23:52:57 +02:00
2012-11-21 01:10:30 +01:00
unless ( $ pseudo ) {
emit ( 'else' ) ;
emit ( qq( echo $weight > \${VARDIR}/${physical}_weight ) ) ;
emit_started_message ( ' ' , '' , $ pseudo , $ table , $ number ) ;
}
2012-11-16 18:48:21 +01:00
emit "fi\n" ;
2011-09-14 15:24:22 +02:00
} else {
2012-01-15 02:43:25 +01:00
emit ( qq( echo 0 > \${VARDIR}/${physical}.status ) ) ;
2011-09-14 17:25:47 +02:00
emit ( qq( progress_message "Provider $table ( $number ) Started" ) ) ;
2011-09-14 15:24:22 +02:00
}
2012-04-24 23:52:57 +02:00
2011-09-01 01:38:58 +02:00
pop_indent ;
2009-02-22 18:30:14 +01:00
emit 'else' ;
2011-09-01 01:38:58 +02:00
push_indent ;
2012-04-24 23:52:57 +02:00
2012-01-16 04:23:44 +01:00
emit ( qq( echo 1 > \${VARDIR}/${physical}.status ) ) ;
2011-09-01 01:38:58 +02:00
2009-02-22 18:30:14 +01:00
if ( $ optional ) {
2009-04-20 17:30:15 +02:00
if ( $ shared ) {
2012-04-24 23:52:57 +02:00
emit ( "error_message \"WARNING: Gateway $gateway is not reachable -- Provider $table ($number) not Started\"" ) ;
2012-11-16 18:48:21 +01:00
} elsif ( $ pseudo ) {
emit ( "error_message \"WARNING: Optional Interface $physical is not usable -- $table not Started\"" ) ;
2009-10-24 17:50:15 +02:00
} else {
2011-09-01 01:38:58 +02:00
emit ( "error_message \"WARNING: Interface $physical is not usable -- Provider $table ($number) not Started\"" ) ;
2009-04-20 17:30:15 +02:00
}
2009-02-22 18:30:14 +01:00
} else {
2009-04-20 17:30:15 +02:00
if ( $ shared ) {
2011-09-01 01:38:58 +02:00
emit ( "fatal_error \"Gateway $gateway is not reachable -- Provider $table ($number) Cannot be Started\"" ) ;
2009-04-20 17:30:15 +02:00
} else {
2011-09-01 01:38:58 +02:00
emit ( "fatal_error \"Interface $physical is not usable -- Provider $table ($number) Cannot be Started\"" ) ;
2009-04-20 17:30:15 +02:00
}
2009-02-22 18:30:14 +01:00
}
2011-09-01 01:38:58 +02:00
pop_indent ;
2011-08-25 02:37:39 +02:00
emit 'fi' ;
2009-05-05 20:38:45 +02:00
2011-08-25 02:37:39 +02:00
pop_indent ;
2009-02-22 18:30:14 +01:00
2012-11-16 18:48:21 +01:00
emit "} # End of start_${what}_${table}();" ;
2011-08-26 01:00:27 +02:00
if ( $ optional ) {
emit ( '' ,
'#' ,
2012-11-16 18:48:21 +01:00
"# Stop $what $table" ,
2011-08-26 01:00:27 +02:00
'#' ,
2012-11-16 18:48:21 +01:00
"stop_${what}_${table}() {" ) ;
2011-08-26 01:00:27 +02:00
push_indent ;
my $ undo = "\${VARDIR}/undo_${table}_routing" ;
2011-10-09 18:00:14 +02:00
emit ( "if [ -f $undo ]; then" ) ;
push_indent ;
2011-08-26 01:00:27 +02:00
2011-10-09 18:00:14 +02:00
if ( $ balance || $ default > 0 ) {
$ tbl = $ default ? DEFAULT_TABLE : $ config { USE_DEFAULT_RT } ? BALANCE_TABLE : MAIN_TABLE ;
2011-08-26 01:00:27 +02:00
$ weight = $ balance ? $ balance : $ default ;
2011-10-09 18:00:14 +02:00
my $ via ;
2011-08-26 01:00:27 +02:00
2011-10-09 18:00:14 +02:00
if ( $ gateway ) {
$ via = "via $gateway dev $physical" ;
2012-04-24 23:52:57 +02:00
} else {
2011-10-09 18:00:14 +02:00
$ via = "dev $physical" ;
}
2011-10-22 21:48:07 +02:00
$ via . = " weight $weight" unless $ weight < 0 or $ family == F_IPV6 ; # IPv6 doesn't support route weights
2011-08-26 01:00:27 +02:00
$ via . = " $realm" if $ realm ;
2011-10-09 18:00:14 +02:00
emit ( qq( delete_gateway "$via" $tbl $physical ) ) ;
2011-08-26 01:00:27 +02:00
}
2011-10-09 18:00:14 +02:00
2012-11-20 22:27:15 +01:00
emit ( ". $undo" ) ;
if ( $ pseudo ) {
emit ( "rm -f $undo" ) ;
} else {
emit ( "> $undo" ) ;
}
2011-10-09 18:00:14 +02:00
2012-01-16 04:23:44 +01:00
emit ( '' ,
"distribute_load $maxload @load_interfaces" ) if $ load ;
2012-01-14 01:37:05 +01:00
2011-12-01 19:41:03 +01:00
unless ( $ shared ) {
2012-04-24 23:52:57 +02:00
emit ( '' ,
2011-12-01 19:41:03 +01:00
"qt \$TC qdisc del dev $physical root" ,
"qt \$TC qdisc del dev $physical ingress\n" ) if $ tcdevices - > { $ interface } ;
}
2011-10-09 18:00:14 +02:00
2012-11-16 18:48:21 +01:00
emit ( "echo 1 > \${VARDIR}/${physical}.status" ) ;
if ( $ pseudo ) {
emit ( "progress_message2 \" Optional Interface $table stopped\"" ) ;
} else {
emit ( "progress_message2 \" Provider $table ($number) stopped\"" ) ;
}
2011-10-09 18:00:14 +02:00
pop_indent ;
2011-08-27 21:33:24 +02:00
2011-10-09 18:00:14 +02:00
emit ( 'else' ,
2011-08-26 01:00:27 +02:00
" startup_error \"$undo does not exist\"" ,
'fi'
) ;
pop_indent ;
emit '}' ;
}
2009-11-16 21:43:44 +01:00
}
2009-05-05 20:38:45 +02:00
sub add_an_rtrule ( ) {
2012-01-09 16:19:10 +01:00
my ( $ source , $ dest , $ provider , $ priority , $ originalmark ) = split_line 'rtrules file' , { source = > 0 , dest = > 1 , provider = > 2 , priority = > 3 , mark = > 4 } ;
2009-02-22 18:30:14 +01:00
2009-11-17 20:14:02 +01:00
our $ current_if ;
2009-11-16 21:43:44 +01:00
2009-02-22 18:30:14 +01:00
unless ( $ providers { $ provider } ) {
my $ found = 0 ;
if ( "\L$provider" =~ /^(0x[a-f0-9]+|0[0-7]*|[0-9]*)$/ ) {
my $ provider_number = numeric_value $ provider ;
for ( keys % providers ) {
if ( $ providers { $ _ } { number } == $ provider_number ) {
$ provider = $ _ ;
$ found = 1 ;
last ;
}
}
}
fatal_error "Unknown provider ($provider)" unless $ found ;
}
2011-08-25 02:37:39 +02:00
my $ providerref = $ providers { $ provider } ;
my $ number = $ providerref - > { number } ;
2011-08-29 19:05:36 +02:00
fatal_error "You may not add rules for the $provider provider" if $ number == LOCAL_TABLE || $ number == UNSPEC_TABLE ;
2012-01-09 16:19:10 +01:00
fatal_error "You must specify either the source or destination in a rtrules entry" if $ source eq '-' && $ dest eq '-' ;
2009-02-22 18:30:14 +01:00
if ( $ dest eq '-' ) {
2009-08-20 23:32:15 +02:00
$ dest = 'to ' . ALLIP ;
2009-02-22 18:30:14 +01:00
} else {
2012-09-23 21:16:17 +02:00
$ dest = validate_net ( $ dest , 0 ) ;
2009-02-22 18:30:14 +01:00
$ dest = "to $dest" ;
}
if ( $ source eq '-' ) {
$ source = 'from ' . ALLIP ;
2012-01-06 20:59:22 +01:00
} elsif ( $ source =~ s/^&// ) {
2012-02-23 22:36:00 +01:00
$ source = 'from ' . record_runtime_address '&' , $ source ;
2009-02-22 18:30:14 +01:00
} elsif ( $ family == F_IPV4 ) {
if ( $ source =~ /:/ ) {
( my $ interface , $ source , my $ remainder ) = split ( /:/ , $ source , 3 ) ;
fatal_error "Invalid SOURCE" if defined $ remainder ;
2012-09-23 21:16:17 +02:00
$ source = validate_net ( $ source , 0 ) ;
2009-11-08 16:00:43 +01:00
$ interface = physical_name $ interface ;
2009-02-22 18:30:14 +01:00
$ source = "iif $interface from $source" ;
} elsif ( $ source =~ /\..*\..*/ ) {
2012-09-23 21:16:17 +02:00
$ source = validate_net ( $ source , 0 ) ;
2009-02-22 18:30:14 +01:00
$ source = "from $source" ;
} else {
2012-05-08 23:52:18 +02:00
$ source = 'iif ' . physical_name $ source ;
2009-02-22 18:30:14 +01:00
}
2012-09-23 21:16:17 +02:00
} elsif ( $ source =~ /^(.+?):<(.+)>\s*$/ || $ source =~ /^(.+?):\[(.+)\]\s*$/ || $ source =~ /^(.+?):(\[.+?\](?:\/\d+))$/ ) {
2009-02-22 18:30:14 +01:00
my ( $ interface , $ source ) = ( $ 1 , $ 2 ) ;
2012-09-23 21:16:17 +02:00
$ source = validate_net ( $ source , 0 ) ;
2009-11-08 16:00:43 +01:00
$ interface = physical_name $ interface ;
2009-02-22 18:30:14 +01:00
$ source = "iif $interface from $source" ;
} elsif ( $ source =~ /:.*:/ || $ source =~ /\..*\..*/ ) {
2012-09-23 21:16:17 +02:00
$ source = validate_net ( $ source , 0 ) ;
2009-02-22 18:30:14 +01:00
$ source = "from $source" ;
} else {
2012-05-08 23:52:18 +02:00
$ source = 'iif ' . physical_name $ source ;
2009-02-22 18:30:14 +01:00
}
2011-10-23 16:56:53 +02:00
my $ mark = '' ;
my $ mask ;
if ( $ originalmark ne '-' ) {
validate_mark ( $ originalmark ) ;
( $ mark , $ mask ) = split '/' , $ originalmark ;
$ mask = $ globals { PROVIDER_MASK } unless supplied $ mask ;
$ mark = ' fwmark ' . in_hex ( $ mark ) . '/' . in_hex ( $ mask ) ;
}
2009-02-22 18:30:14 +01:00
fatal_error "Invalid priority ($priority)" unless $ priority && $ priority =~ /^\d{1,5}$/ ;
$ priority = "priority $priority" ;
2011-10-23 16:56:53 +02:00
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 $number" ;
push @ { $ providerref - > { rules } } , "echo \"qt \$IP -$family rule del $source ${dest}${mark} $priority\" >> \${VARDIR}/undo_${provider}_routing" ;
2009-02-22 18:30:14 +01:00
progress_message " Routing rule \"$currentline\" $done" ;
}
2010-11-17 05:38:54 +01:00
sub add_a_route ( ) {
2011-10-01 20:39:12 +02:00
my ( $ provider , $ dest , $ gateway , $ device ) = split_line 'routes file' , { provider = > 0 , dest = > 1 , gateway = > 2 , device = > 3 } ;
2010-11-17 05:38:54 +01:00
our $ current_if ;
2011-10-01 18:56:25 +02:00
fatal_error 'PROVIDER must be specified' if $ provider eq '-' ;
2010-11-17 05:38:54 +01:00
unless ( $ providers { $ provider } ) {
my $ found = 0 ;
if ( "\L$provider" =~ /^(0x[a-f0-9]+|0[0-7]*|[0-9]*)$/ ) {
my $ provider_number = numeric_value $ provider ;
for ( keys % providers ) {
if ( $ providers { $ _ } { number } == $ provider_number ) {
$ provider = $ _ ;
2010-11-27 19:28:44 +01:00
$ found = 1 ;
2010-11-17 05:38:54 +01:00
last ;
}
}
}
2010-11-27 19:28:44 +01:00
fatal_error "Unknown provider ($provider)" unless $ found ;
2010-11-17 05:38:54 +01:00
}
2011-10-01 18:56:25 +02:00
fatal_error 'DEST must be specified' if $ dest eq '-' ;
2013-01-14 02:00:14 +01:00
$ dest = validate_net ( $ dest , 0 ) ;
2010-11-17 05:38:54 +01:00
validate_address ( $ gateway , 1 ) if $ gateway ne '-' ;
2011-08-25 02:37:39 +02:00
my $ providerref = $ providers { $ provider } ;
my $ number = $ providerref - > { number } ;
2010-11-17 17:35:20 +01:00
my $ physical = $ device eq '-' ? $ providers { $ provider } { physical } : physical_name ( $ device ) ;
2011-08-25 02:37:39 +02:00
my $ routes = $ providerref - > { routes } ;
2010-11-17 05:38:54 +01:00
2011-08-29 19:05:36 +02:00
fatal_error "You may not add routes to the $provider table" if $ number == LOCAL_TABLE || $ number == UNSPEC_TABLE ;
2012-04-24 23:52:57 +02:00
2010-11-17 05:38:54 +01:00
if ( $ gateway ne '-' ) {
2010-11-17 17:35:20 +01:00
if ( $ device ne '-' ) {
2011-08-25 02:37:39 +02:00
push @$ routes , qq( run_ip route add $dest via $gateway dev $physical table $number ) ;
emit qq( echo "qt \$IP -$family route del $dest via $gateway dev $physical table $number" >> \${VARDIR}/undo_${provider}_routing ) if $ number >= DEFAULT_TABLE ;
2010-11-17 17:35:20 +01:00
} else {
2011-08-25 02:37:39 +02:00
push @$ routes , qq( run_ip route add $dest via $gateway table $number ) ;
2012-04-24 23:52:57 +02:00
emit qq( echo "\$IP -$family route del $dest via $gateway table $number" >> \${VARDIR}/undo_${provider}_routing ) if $ number >= DEFAULT_TABLE ;
2010-11-17 17:35:20 +01:00
}
2010-11-17 05:38:54 +01:00
} else {
2010-11-27 19:28:44 +01:00
fatal_error "You must specify a device for this route" unless $ physical ;
2011-08-25 02:37:39 +02:00
push @$ routes , qq( run_ip route add $dest dev $physical table $number ) ;
emit qq( echo "\$IP -$family route del $dest dev $physical table $number" >> \${VARDIR}/undo_${provider}_routing ) if $ number >= DEFAULT_TABLE ;
2010-11-17 05:38:54 +01:00
}
progress_message " Route \"$currentline\" $done" ;
}
2009-02-22 18:30:14 +01:00
sub setup_null_routing () {
save_progress_message "Null Routing the RFC 1918 subnets" ;
2012-03-27 16:46:53 +02:00
emit "> \${VARDIR}/undo_rfc1918_routing\n" ;
2009-02-22 18:30:14 +01:00
for ( rfc1918_networks ) {
2010-11-10 00:20:23 +01:00
emit ( qq( if ! \$IP -4 route ls | grep -q '^$_.* dev '; then ) ,
2012-05-18 19:50:13 +02:00
qq( run_ip route replace blackhole $_ ) ,
qq( echo "qt \$IP -4 route del blackhole $_" >> \${VARDIR}/undo_rfc1918_routing ) ,
2010-11-10 00:20:23 +01:00
qq( fi\n ) ) ;
2009-08-20 23:32:15 +02:00
}
2009-02-22 18:30:14 +01:00
}
2009-05-22 22:55:39 +02:00
sub start_providers () {
emit ( '#' ,
'# Undo any changes made since the last time that we [re]started -- this will not restore the default route' ,
'#' ,
'undo_routing' ) ;
unless ( $ config { KEEP_RT_TABLES } ) {
emit (
'#' ,
'# Save current routing table database so that it can be restored later' ,
'#' ,
'cp /etc/iproute2/rt_tables ${VARDIR}/' ) ;
2009-08-20 23:32:15 +02:00
2009-05-22 22:55:39 +02:00
}
2009-02-22 18:30:14 +01:00
2009-05-22 22:55:39 +02:00
emit ( '#' ,
'# Capture the default route(s) if we don\'t have it (them) already.' ,
'#' ,
2011-08-30 18:31:06 +02:00
"[ -f \${VARDIR}/default_route ] || \$IP -$family route list | save_default_route > \${VARDIR}/default_route" ) ;
2009-08-20 23:32:15 +02:00
2009-05-22 22:55:39 +02:00
save_progress_message 'Adding Providers...' ;
2009-08-20 23:32:15 +02:00
2009-05-22 22:55:39 +02:00
emit 'DEFAULT_ROUTE=' ;
emit 'FALLBACK_ROUTE=' ;
emit '' ;
2012-04-24 23:52:57 +02:00
2011-08-30 18:31:06 +02:00
for my $ provider ( qw/main default/ ) {
2011-08-29 19:05:36 +02:00
emit '' ;
2011-08-30 18:31:06 +02:00
emit qq( > \${VARDIR}/undo_${provider}_routing ) ;
2011-08-29 19:05:36 +02:00
emit '' ;
2011-08-30 18:31:06 +02:00
emit $ _ for @ { $ providers { $ provider } { routes } } ;
2011-08-29 19:05:36 +02:00
emit '' ;
2011-08-30 18:31:06 +02:00
emit $ _ for @ { $ providers { $ provider } { rules } } ;
2011-08-29 19:05:36 +02:00
}
2009-05-22 22:55:39 +02:00
}
2009-02-22 18:30:14 +01:00
2009-05-22 22:55:39 +02:00
sub finish_providers () {
2012-01-17 22:00:34 +01:00
my $ table = MAIN_TABLE ;
2012-04-24 23:52:57 +02:00
2012-01-17 22:00:34 +01:00
if ( $ config { USE_DEFAULT_RT } ) {
emit ( 'run_ip rule add from ' . ALLIP . ' table ' . MAIN_TABLE . ' pref 999' ,
'run_ip rule add from ' . ALLIP . ' table ' . BALANCE_TABLE . ' pref 32765' ,
"\$IP -$family rule del from " . ALLIP . ' table ' . MAIN_TABLE . ' pref 32766' ,
qq( echo "qt \$IP -$family rule add from ) . ALLIP . ' table ' . MAIN_TABLE . ' pref 32766" >> ${VARDIR}/undo_main_routing' ,
qq( echo "qt \$IP -$family rule del from ) . ALLIP . ' table ' . MAIN_TABLE . ' pref 999" >> ${VARDIR}/undo_main_routing' ,
qq( echo "qt \$IP -$family rule del from ) . ALLIP . ' table ' . BALANCE_TABLE . ' pref 32765" >> ${VARDIR}/undo_balance_routing' ,
'' ) ;
$ table = BALANCE_TABLE ;
}
2009-02-22 18:30:14 +01:00
2012-01-17 22:00:34 +01:00
if ( $ balancing ) {
2009-05-22 22:55:39 +02:00
emit ( 'if [ -n "$DEFAULT_ROUTE" ]; then' ) ;
2011-04-19 19:56:59 +02:00
if ( $ family == F_IPV4 ) {
emit ( " run_ip route replace default scope global table $table \$DEFAULT_ROUTE" ) ;
} else {
emit ( " qt \$IP -6 route del default scope global table $table \$DEFAULT_ROUTE" ) ;
emit ( " run_ip route add default scope global table $table \$DEFAULT_ROUTE" ) ;
}
2011-04-14 21:17:46 +02:00
if ( $ config { USE_DEFAULT_RT } ) {
emit ( " while qt \$IP -$family route del default table " . MAIN_TABLE . '; do' ,
' true' ,
' done' ,
''
) ;
}
2012-04-24 23:52:57 +02:00
2009-05-22 22:55:39 +02:00
emit ( " progress_message \"Default route '\$(echo \$DEFAULT_ROUTE | sed 's/\$\\s*//')' Added\"" ,
'else' ,
' error_message "WARNING: No Default route added (all \'balance\' providers are down)"' ) ;
2009-02-22 18:30:14 +01:00
2009-05-22 22:55:39 +02:00
if ( $ config { RESTORE_DEFAULT_ROUTE } ) {
2011-04-14 21:17:46 +02:00
emit qq( restore_default_route $config{USE_DEFAULT_RT} && error_message "NOTICE: Default route restored" )
2009-05-22 22:55:39 +02:00
} else {
emit qq( qt \$IP -$family route del default table $table && error_message "WARNING: Default route deleted from table $table" ) ;
}
2009-08-20 23:32:15 +02:00
2009-05-22 22:55:39 +02:00
emit ( 'fi' ,
'' ) ;
} else {
emit ( '#' ,
'# We don\'t have any \'balance\' providers so we restore any default route that we\'ve saved' ,
'#' ,
2011-04-14 21:17:46 +02:00
"restore_default_route $config{USE_DEFAULT_RT}" ,
2012-05-11 20:28:06 +02:00
'#' ,
'# And delete any routes in the \'balance\' table' ,
'#' ,
"qt \$IP -$family route del default table " . BALANCE_TABLE ,
2009-05-22 22:55:39 +02:00
'' ) ;
2009-02-22 18:30:14 +01:00
}
2009-05-22 22:55:39 +02:00
if ( $ fallback ) {
2011-04-19 19:56:59 +02:00
emit ( 'if [ -n "$FALLBACK_ROUTE" ]; then' ) ;
if ( $ family == F_IPV4 ) {
emit ( " run_ip route replace default scope global table " . DEFAULT_TABLE . " \$FALLBACK_ROUTE" ) ;
} else {
emit ( " qt \$IP -6 route del default scope global table " . DEFAULT_TABLE . " \$FALLBACK_ROUTE" ) ;
emit ( " run_ip route add default scope global table " . DEFAULT_TABLE . " \$FALLBACK_ROUTE" ) ;
}
emit ( " progress_message \"Fallback route '\$(echo \$FALLBACK_ROUTE | sed 's/\$\\s*//')' Added\"" ,
2012-05-20 18:00:22 +02:00
'else' ,
2012-06-12 01:57:49 +02:00
' #' ,
' # We don\'t have any \'fallback\' providers so we delete any default routes in the default table' ,
' #' ,
' delete_default_routes ' . DEFAULT_TABLE ,
2011-04-19 19:56:59 +02:00
'fi' ,
'' ) ;
2011-10-09 18:00:14 +02:00
} elsif ( $ config { USE_DEFAULT_RT } ) {
2012-06-12 01:57:49 +02:00
emit ( 'delete_default_routes ' . DEFAULT_TABLE ,
''
) ;
2009-05-22 22:55:39 +02:00
}
2009-02-22 18:30:14 +01:00
2009-05-22 22:55:39 +02:00
unless ( $ config { KEEP_RT_TABLES } ) {
emit ( 'if [ -w /etc/iproute2/rt_tables ]; then' ,
' cat > /etc/iproute2/rt_tables <<EOF' ) ;
2009-02-22 18:30:14 +01:00
2009-05-22 22:55:39 +02:00
emit_unindented join ( "\n" ,
'#' ,
'# reserved values' ,
'#' ,
LOCAL_TABLE . "\tlocal" ,
MAIN_TABLE . "\tmain" ,
2011-10-09 18:00:14 +02:00
$ config { USE_DEFAULT_RT } ? ( DEFAULT_TABLE . "\tdefault\n" . BALANCE_TABLE . "\tbalance" ) : DEFAULT_TABLE . "\tdefault" ,
2009-05-22 22:55:39 +02:00
"0\tunspec" ,
'#' ,
'# local' ,
2009-07-15 21:22:31 +02:00
'#' ) ;
emit_unindented "$providers{$_}{number}\t$_" for @ providers ;
emit_unindented "EOF\n" ;
2009-05-22 22:55:39 +02:00
emit "fi\n" ;
}
}
2009-02-22 18:30:14 +01:00
2011-08-27 17:29:55 +02:00
sub process_providers ( $ ) {
my $ tcdevices = shift ;
2011-08-25 02:37:39 +02:00
our $ providers = 0 ;
2012-11-16 18:48:21 +01:00
our $ pseudoproviders = 0 ;
2009-02-22 18:30:14 +01:00
2010-01-11 23:22:01 +01:00
$ lastmark = 0 ;
2010-09-28 19:48:44 +02:00
if ( my $ fn = open_file 'providers' ) {
2012-04-24 23:52:57 +02:00
first_entry "$doing $fn..." ;
2012-11-20 16:06:27 +01:00
$ providers += process_a_provider ( 0 ) while read_a_line ( NORMAL_READ ) ;
2012-11-16 18:48:21 +01:00
}
#
# Treat optional interfaces as pseudo-providers
#
for ( grep interface_is_optional ( $ _ ) && ! $ provider_interfaces { $ _ } , all_real_interfaces ) {
#
2012-12-28 17:04:06 +01:00
# TABLE NUMBER MARK DUPLICATE INTERFACE GATEWAY OPTIONS COPY
2012-12-28 19:39:19 +01:00
$ currentline = var_base ( $ _ ) . " 0 - - $_ - - -" ;
2012-11-16 18:48:21 +01:00
#
2012-11-20 16:06:27 +01:00
$ pseudoproviders += process_a_provider ( 1 ) ;
2010-09-28 19:48:44 +02:00
}
2009-02-22 18:30:14 +01:00
2009-05-22 22:55:39 +02:00
if ( $ providers ) {
2012-06-11 22:53:53 +02:00
fatal_error q( Either all 'fallback' providers must specify a weight or non of them can specify a weight ) if $ fallback && $ metrics ;
2012-01-12 16:10:16 +01:00
my $ fn = open_file ( 'route_rules' ) ;
if ( $ fn ) {
if ( - f ( my $ fn1 = find_file 'rtrules' ) ) {
2012-08-01 22:13:18 +02:00
warning_message "Both $fn and $fn1 exist: $fn1 will be ignored" ;
2012-01-12 16:10:16 +01:00
}
} else {
$ fn = open_file ( 'rtrules' ) ;
}
2010-11-17 05:38:54 +01:00
if ( $ fn ) {
first_entry "$doing $fn..." ;
2012-04-24 23:52:57 +02:00
2010-11-17 05:38:54 +01:00
emit '' ;
2012-04-14 17:04:28 +02:00
add_an_rtrule while read_a_line ( NORMAL_READ ) ;
2010-11-17 05:38:54 +01:00
}
2012-11-16 18:48:21 +01:00
}
2010-11-17 05:38:54 +01:00
2012-11-16 18:48:21 +01:00
if ( $ providers || $ pseudoproviders ) {
my $ fn = open_file 'routes' ;
2009-02-22 18:30:14 +01:00
if ( $ fn ) {
first_entry "$doing $fn..." ;
emit '' ;
2012-04-14 17:04:28 +02:00
add_a_route while read_a_line ( NORMAL_READ ) ;
2011-08-25 02:37:39 +02:00
}
2009-08-20 23:32:15 +02:00
2012-11-16 18:48:21 +01:00
add_a_provider ( $ providers { $ _ } , $ tcdevices ) for @ providers ;
}
2012-04-24 23:52:57 +02:00
2011-08-26 01:00:27 +02:00
emit << 'EOF' ; ;
#
# Enable an optional provider
#
enable_provider ( ) {
g_interface = $ 1 ;
case $ g_interface in
EOF
push_indent ;
push_indent ;
for my $ provider ( @ providers ) {
my $ providerref = $ providers { $ provider } ;
2011-12-01 19:30:42 +01:00
if ( $ providerref - > { optional } ) {
if ( $ providerref - > { shared } || $ providerref - > { physical } eq $ provider ) {
2012-11-16 18:48:21 +01:00
emit "$provider)" ;
2011-12-01 19:30:42 +01:00
} else {
emit ( "$providerref->{physical}|$provider)" ) ;
}
2012-11-16 18:48:21 +01:00
if ( $ providerref - > { pseudo } ) {
emit ( " if [ ! -f \${VARDIR}/$product/undo_${provider}_routing ]; then" ,
" start_interface_$provider" ) ;
} else {
emit ( " if [ -z \"`\$IP -$family route ls table $providerref->{number}`\" ]; then" ,
" start_provider_$provider" ) ;
}
emit ( ' else' ,
2012-01-16 04:23:44 +01:00
" startup_error \"Interface $providerref->{physical} is already enabled\"" ,
2011-12-01 19:30:42 +01:00
' fi' ,
' ;;'
) ;
}
2011-08-26 01:00:27 +02:00
}
pop_indent ;
pop_indent ;
emit << 'EOF' ; ;
* )
2012-11-16 18:48:21 +01:00
startup_error "$g_interface is not an optional provider or interface"
2011-08-26 01:00:27 +02:00
; ;
esac
2012-06-01 20:27:57 +02:00
2011-08-26 01:00:27 +02:00
}
#
# Disable an optional provider
#
disable_provider ( ) {
g_interface = $ 1 ;
case $ g_interface in
EOF
push_indent ;
push_indent ;
for my $ provider ( @ providers ) {
my $ providerref = $ providers { $ provider } ;
2012-11-20 22:27:15 +01:00
if ( $ providerref - > { optional } ) {
if ( $ provider eq $ providerref - > { physical } ) {
emit ( "$provider)" ) ;
} else {
emit ( "$providerref->{physical}|$provider)" ) ;
}
2012-11-16 18:48:21 +01:00
2012-11-20 22:27:15 +01:00
if ( $ providerref - > { pseudo } ) {
emit ( " if [ -f \${VARDIR}/$product/undo_${provider}_routing ]; then" ) ;
} else {
emit ( " if [ -n \"`\$IP -$family route ls table $providerref->{number}`\" ]; then" ) ;
}
2012-11-16 18:48:21 +01:00
emit ( " stop_$providerref->{what}_$provider" ,
' else' ,
" startup_error \"Interface $providerref->{physical} is already disabled\"" ,
' fi' ,
' ;;'
) ;
}
2011-08-26 01:00:27 +02:00
}
pop_indent ;
pop_indent ;
emit << 'EOF' ; ;
* )
startup_error "$g_interface is not an optional provider interface"
; ;
esac
}
EOF
2011-08-25 02:37:39 +02:00
}
2012-07-07 17:02:57 +02:00
sub have_providers () {
return our $ providers ;
}
2011-08-25 02:37:39 +02:00
sub setup_providers () {
our $ providers ;
if ( $ providers ) {
emit "\nif [ -z \"\$g_noroutes\" ]; then" ;
2012-04-24 23:52:57 +02:00
2011-08-25 02:37:39 +02:00
push_indent ;
start_providers ;
2012-04-24 23:52:57 +02:00
2011-08-29 19:05:36 +02:00
emit '' ;
2012-11-16 18:48:21 +01:00
emit "start_$providers{$_}->{what}_$_" for @ providers ;
2011-08-25 02:37:39 +02:00
emit '' ;
finish_providers ;
2009-02-22 18:30:14 +01:00
setup_null_routing if $ config { NULL_ROUTE_RFC1918 } ;
emit "\nrun_ip route flush cache" ;
2011-08-29 19:05:36 +02:00
2009-02-22 18:30:14 +01:00
pop_indent ;
emit "fi\n" ;
2012-01-16 04:23:44 +01:00
setup_route_marking if @ routemarked_interfaces || @ load_interfaces ;
2009-02-22 18:30:14 +01:00
} else {
2010-03-03 18:50:07 +01:00
emit "\nif [ -z \"\$g_noroutes\" ]; then" ;
2009-07-15 21:32:26 +02:00
push_indent ;
2009-08-20 23:32:15 +02:00
2009-02-22 18:30:14 +01:00
emit "\nundo_routing" ;
2011-04-14 21:17:46 +02:00
emit "restore_default_route $config{USE_DEFAULT_RT}" ;
2009-08-20 23:32:15 +02:00
2009-02-22 18:30:14 +01:00
if ( $ config { NULL_ROUTE_RFC1918 } ) {
setup_null_routing ;
emit "\nrun_ip route flush cache" ;
2009-07-15 21:32:26 +02:00
}
2009-02-22 18:30:14 +01:00
2009-07-15 21:32:26 +02:00
pop_indent ;
2009-02-22 18:30:14 +01:00
2009-07-15 21:32:26 +02:00
emit "fi\n" ;
2009-02-22 18:30:14 +01:00
}
2009-05-22 22:55:39 +02:00
2009-02-22 18:30:14 +01:00
}
2012-06-01 17:12:07 +02:00
#
# Emit the updown() function
#
sub compile_updown () {
emit ( '' ,
'#' ,
'# Handle the "up" and "down" commands' ,
'#' ,
'updown() # $1 = interface' ,
'{' ,
) ;
push_indent ;
emit ( 'local state' ,
'state=cleared' ,
2012-06-01 20:27:57 +02:00
''
) ;
2012-06-01 17:12:07 +02:00
emit 'progress_message3 "$g_product $COMMAND triggered by $1"' ;
emit '' ;
if ( $ family == F_IPV4 ) {
emit 'if shorewall_is_started; then' ;
} else {
emit 'if shorewall6_is_started; then' ;
}
emit ( ' state=started' ,
'elif [ -f ${VARDIR}/state ]; then' ,
' case "$(cat ${VARDIR}/state)" in' ,
' Stopped*)' ,
' state=stopped' ,
' ;;' ,
' Cleared*)' ,
' ;;' ,
' *)' ,
' state=unknown' ,
' ;;' ,
' esac' ,
'else' ,
' state=unknown' ,
'fi' ,
''
) ;
emit ( 'case $1 in' ) ;
push_indent ;
2012-06-05 16:23:23 +02:00
my $ ignore = find_interfaces_by_option 'ignore' , 1 ;
2012-06-01 17:12:07 +02:00
my $ required = find_interfaces_by_option 'required' ;
my $ optional = find_interfaces_by_option 'optional' ;
if ( @$ ignore ) {
my $ interfaces = join '|' , map get_physical ( $ _ ) , @$ ignore ;
$ interfaces =~ s/\+/*/g ;
emit ( "$interfaces)" ,
' progress_message3 "$COMMAND on interface $1 ignored"' ,
' exit 0' ,
' ;;'
) ;
}
2012-06-01 20:27:57 +02:00
my @ nonshared = ( grep $ providers { $ _ } - > { optional } ,
sort ( { $ providers { $ a } - > { number } <=> $ providers { $ b } - > { number } } values % provider_interfaces ) ) ;
if ( @ nonshared ) {
my $ interfaces = join ( '|' , map $ providers { $ _ } - > { physical } , @ nonshared ) ;
emit "$interfaces)" ;
push_indent ;
emit ( q( if [ "$state" = started ]; then ) ,
q( if [ "$COMMAND" = up ]; then ) ,
q( progress_message3 "Attempting enable on interface $1" ) ,
q( COMMAND=enable ) ,
q( detect_configuration ) ,
q( enable_provider $1 ) ,
2012-06-02 18:26:00 +02:00
q( elif [ "$PHASE" != post-down ]; then # pre-down or not Debian ) ,
2012-06-01 20:27:57 +02:00
q( progress_message3 "Attempting disable on interface $1" ) ,
q( COMMAND=disable ) ,
q( detect_configuration ) ,
q( disable_provider $1 ) ,
q( fi ) ,
q( elif [ "$COMMAND" = up ]; then ) ,
2012-06-02 02:14:08 +02:00
q( echo 0 > ${VARDIR}/${1}.status ) ,
2012-06-01 20:27:57 +02:00
q( COMMAND=start ) ,
q( progress_message3 "$g_product attempting start" ) ,
q( detect_configuration ) ,
q( define_firewall ) ,
q( else ) ,
2012-06-02 00:55:22 +02:00
q( progress_message3 "$COMMAND on interface $1 ignored" ) ,
2012-06-01 20:27:57 +02:00
q( fi ) ,
q( ;; ) ) ;
pop_indent ;
}
2012-06-01 17:12:07 +02:00
if ( @$ required ) {
my $ interfaces = join '|' , map get_physical ( $ _ ) , @$ required ;
my $ wildcard = ( $ interfaces =~ s/\+/*/g ) ;
emit ( "$interfaces)" ,
' if [ "$COMMAND" = up ]; then' ) ;
if ( $ wildcard ) {
emit ( ' if [ "$state" = started ]; then' ,
' COMMAND=restart' ,
' else' ,
' COMMAND=start' ,
' fi' ) ;
} else {
emit ( ' COMMAND=start' ) ;
}
emit ( ' progress_message3 "$g_product attempting $COMMAND"' ,
' detect_configuration' ,
2012-06-02 18:26:00 +02:00
' define_firewall' ,
' elif [ "$PHASE" != pre-down ]; then # Not Debian pre-down phase'
) ;
push_indent ;
2012-06-01 17:12:07 +02:00
if ( $ wildcard ) {
2012-06-02 18:26:00 +02:00
emit ( ' if [ "$state" = started ]; then' ,
2012-06-01 17:12:07 +02:00
' progress_message3 "$g_product attempting restart"' ,
' COMMAND=restart' ,
' detect_configuration' ,
2012-06-02 18:26:00 +02:00
' define_firewall' ,
' fi' ) ;
2012-06-01 17:12:07 +02:00
} else {
2012-06-02 18:26:00 +02:00
emit ( ' COMMAND=stop' ,
' progress_message3 "$g_product attempting stop"' ,
' detect_configuration' ,
' stop_firewall' ) ;
2012-06-01 17:12:07 +02:00
}
2012-06-02 18:26:00 +02:00
pop_indent ;
2012-06-01 17:12:07 +02:00
emit ( ' fi' ,
' ;;'
) ;
}
if ( @$ optional ) {
2012-06-01 20:27:57 +02:00
my @ interfaces = map ( get_physical ( $ _ ) , grep ( ! $ provider_interfaces { $ _ } , @$ optional ) ) ;
2012-06-01 17:12:07 +02:00
my $ interfaces = join '|' , @ interfaces ;
2012-06-01 20:27:57 +02:00
if ( $ interfaces ) {
if ( $ interfaces =~ s/\+/*/g || @ interfaces > 1 ) {
emit ( "$interfaces)" ,
' if [ "$COMMAND" = up ]; then' ,
' echo 0 > ${VARDIR}/${1}.state' ,
' else' ,
' echo 1 > ${VARDIR}/${1}.state' ,
' fi' ) ;
} else {
emit ( "$interfaces)" ,
' if [ "$COMMAND" = up ]; then' ,
" echo 0 > \${VARDIR}/$interfaces.state" ,
' else' ,
" echo 1 > \${VARDIR}/$interfaces.state" ,
' fi' ) ;
}
emit ( '' ,
' if [ "$state" = started ]; then' ,
' COMMAND=restart' ,
' progress_message3 "$g_product attempting restart"' ,
' detect_configuration' ,
' define_firewall' ,
' elif [ "$state" = stopped ]; then' ,
' COMMAND=start' ,
' progress_message3 "$g_product attempting start"' ,
' detect_configuration' ,
' define_firewall' ,
2012-06-01 17:12:07 +02:00
' else' ,
2012-06-01 20:27:57 +02:00
' progress_message3 "$COMMAND on interface $1 ignored"' ,
' fi' ,
' ;;' ,
) ;
2012-06-01 17:12:07 +02:00
}
}
2012-06-02 20:17:10 +02:00
if ( my @ plain_interfaces = all_plain_interfaces ) {
my $ interfaces = join ( '|' , @ plain_interfaces ) ;
2012-06-01 23:01:58 +02:00
$ interfaces =~ s/\+/*/g ;
emit ( "$interfaces)" ,
' case $state in' ,
' started)' ,
' COMMAND=restart' ,
' progress_message3 "$g_product attempting restart"' ,
' detect_configuration' ,
' define_firewall' ,
' ;;' ,
' *)' ,
' progress_message3 "$COMMAND on interface $1 ignored"' ,
' ;;' ,
' esac' ,
) ;
}
2012-06-01 17:12:07 +02:00
pop_indent ;
emit ( 'esac' ) ;
pop_indent ;
emit ( '}' ,
'' ,
) ;
}
2009-02-22 18:30:14 +01:00
sub lookup_provider ( $ ) {
my $ provider = $ _ [ 0 ] ;
my $ providerref = $ providers { $ provider } ;
unless ( $ providerref ) {
fatal_error "Unknown provider ($provider)" unless $ provider =~ /^(0x[a-f0-9]+|0[0-7]*|[0-9]*)$/ ;
my $ provider_number = numeric_value $ provider ;
2009-06-17 00:52:38 +02:00
for ( values % providers ) {
$ providerref = $ _ , last if $ _ - > { number } == $ provider_number ;
2009-02-22 18:30:14 +01:00
}
fatal_error "Unknown provider ($provider)" unless $ providerref ;
}
$ providerref - > { shared } ? $ providerref - > { number } : 0 ;
}
2009-06-16 23:03:15 +02:00
#
2009-10-24 17:50:15 +02:00
# This function is called by the compiler when it is generating the detect_configuration() function.
2010-05-15 18:04:32 +02:00
# The function calls Shorewall::Zones::verify_required_interfaces then emits code to set the
# ..._IS_USABLE interface variables appropriately for the optional interfaces
2009-06-16 23:03:15 +02:00
#
2010-05-15 18:04:32 +02:00
# Returns true if there were required or optional interfaces
2009-10-25 00:55:56 +02:00
#
2010-06-04 19:35:45 +02:00
sub handle_optional_interfaces ( $ ) {
2009-06-16 23:03:15 +02:00
2010-08-30 21:29:39 +02:00
my ( $ interfaces , $ wildcards ) = find_interfaces_by_option1 'optional' ;
2010-08-24 02:15:57 +02:00
2009-06-17 00:39:04 +02:00
if ( @$ interfaces ) {
2010-08-30 21:29:39 +02:00
my $ require = $ config { REQUIRE_INTERFACE } ;
2010-09-27 20:16:18 +02:00
2010-08-30 21:29:39 +02:00
verify_required_interfaces ( shift ) ;
emit ( 'HAVE_INTERFACE=' , '' ) if $ require ;
2010-08-29 21:32:44 +02:00
#
# Clear the '_IS_USABLE' variables
#
2012-12-28 19:39:19 +01:00
emit ( join ( '_' , 'SW' , uc var_base ( get_physical ( $ _ ) ) , 'IS_USABLE=' ) ) for @$ interfaces ;
2009-06-16 23:03:15 +02:00
2010-08-29 21:32:44 +02:00
if ( $ wildcards ) {
2010-08-30 05:13:56 +02:00
#
2010-09-27 20:16:18 +02:00
# We must consider all interfaces with an address in $family -- generate a list of such addresses.
2010-08-30 05:13:56 +02:00
#
2010-09-27 20:16:18 +02:00
emit ( '' ,
2010-08-30 05:13:56 +02:00
'for interface in $(find_all_interfaces1); do' ,
2010-08-29 21:32:44 +02:00
) ;
2010-05-19 16:32:02 +02:00
2010-08-29 21:32:44 +02:00
push_indent ;
2010-08-30 05:13:56 +02:00
emit ( 'case "$interface" in' ) ;
2010-08-29 21:32:44 +02:00
push_indent ;
} else {
emit '' ;
}
for my $ interface ( grep $ provider_interfaces { $ _ } , @$ interfaces ) {
my $ provider = $ provider_interfaces { $ interface } ;
my $ physical = get_physical $ interface ;
2012-12-28 19:39:19 +01:00
my $ base = uc var_base ( $ physical ) ;
2010-08-29 21:32:44 +02:00
my $ providerref = $ providers { $ provider } ;
2010-08-30 05:13:56 +02:00
emit ( "$physical)" ) , push_indent if $ wildcards ;
2010-08-29 21:32:44 +02:00
if ( $ providerref - > { gatewaycase } eq 'detect' ) {
emit qq( if interface_is_usable $physical && [ -n "$providerref->{gateway}" ]; then ) ;
2009-06-16 23:03:15 +02:00
} else {
2009-11-08 16:00:43 +01:00
emit qq( if interface_is_usable $physical; then ) ;
2009-06-16 23:03:15 +02:00
}
2010-08-29 21:32:44 +02:00
emit ( ' HAVE_INTERFACE=Yes' ) if $ require ;
2010-05-19 16:32:02 +02:00
2010-02-22 19:27:59 +01:00
emit ( " SW_${base}_IS_USABLE=Yes" ,
2009-06-16 23:03:15 +02:00
'fi' ) ;
2010-08-29 21:32:44 +02:00
emit ( ';;' ) , pop_indent if $ wildcards ;
}
for my $ interface ( grep ! $ provider_interfaces { $ _ } , @$ interfaces ) {
my $ physical = get_physical $ interface ;
2012-12-28 19:39:19 +01:00
my $ base = uc var_base ( $ physical ) ;
2010-08-29 21:32:44 +02:00
my $ case = $ physical ;
my $ wild = $ case =~ s/\+$/*/ ;
if ( $ wildcards ) {
emit ( "$case)" ) ;
push_indent ;
2010-09-27 20:16:18 +02:00
2010-08-29 21:32:44 +02:00
if ( $ wild ) {
emit ( qq( if [ -z "\$SW_${base}_IS_USABLE" ]; then ) ) ;
2010-09-27 20:16:18 +02:00
push_indent ;
2010-08-29 21:32:44 +02:00
emit ( 'if interface_is_usable $interface; then' ) ;
} else {
emit ( "if interface_is_usable $physical; then" ) ;
}
} else {
emit ( "if interface_is_usable $physical; then" ) ;
}
emit ( ' HAVE_INTERFACE=Yes' ) if $ require ;
emit ( " SW_${base}_IS_USABLE=Yes" ,
'fi' ) ;
if ( $ wildcards ) {
pop_indent , emit ( 'fi' ) if $ wild ;
emit ( ';;' ) ;
pop_indent ;
}
}
if ( $ wildcards ) {
2010-08-30 05:13:56 +02:00
emit ( '*)' ,
' ;;'
) ;
pop_indent ;
2010-08-29 21:32:44 +02:00
emit ( 'esac' ) ;
pop_indent ;
emit ( 'done' ) ;
2009-06-16 23:03:15 +02:00
}
2009-10-24 21:05:44 +02:00
2010-08-29 21:32:44 +02:00
if ( $ require ) {
2010-06-07 16:30:56 +02:00
emit ( '' ,
2010-05-19 16:32:02 +02:00
'if [ -z "$HAVE_INTERFACE" ]; then' ,
' case "$COMMAND" in' ,
' start|restart|restore|refresh)'
) ;
if ( $ family == F_IPV4 ) {
emit ( ' if shorewall_is_started; then' ) ;
} else {
emit ( ' if shorewall6_is_started; then' ) ;
}
2010-06-07 16:30:56 +02:00
2010-05-19 16:32:02 +02:00
emit ( ' fatal_error "No network interface available"' ,
' else' ,
2010-07-05 18:47:03 +02:00
' startup_error "No network interface available"' ,
2010-05-19 16:32:02 +02:00
' fi' ,
' ;;' ,
' esac' ,
'fi'
) ;
}
2010-08-30 21:29:39 +02:00
return 1 ;
2009-06-16 23:03:15 +02:00
}
2010-05-15 18:04:32 +02:00
2010-08-30 21:29:39 +02:00
verify_required_interfaces ( shift ) ;
2009-06-16 23:03:15 +02:00
}
2009-02-25 17:56:48 +01:00
#
2009-02-25 22:45:26 +01:00
# The Tc module has collected the 'sticky' rules in the 'tcpre' and 'tcout' chains. In this function, we apply them
2009-02-25 17:56:48 +01:00
# to the 'tracked' providers
#
2009-02-27 17:19:36 +01:00
sub handle_stickiness ( $ ) {
my $ havesticky = shift ;
2010-01-11 23:22:01 +01:00
my $ mask = in_hex ( $ globals { PROVIDER_MASK } ) ;
2009-02-25 18:23:55 +01:00
my $ setstickyref = $ mangle_table - > { setsticky } ;
2009-02-25 22:04:17 +01:00
my $ setstickoref = $ mangle_table - > { setsticko } ;
2009-02-25 18:23:55 +01:00
my $ tcpreref = $ mangle_table - > { tcpre } ;
2009-02-25 22:04:17 +01:00
my $ tcoutref = $ mangle_table - > { tcout } ;
2009-02-25 17:56:48 +01:00
my % marked_interfaces ;
my $ sticky = 1 ;
2009-02-27 17:19:36 +01:00
if ( $ havesticky ) {
fatal_error "There are SAME tcrules but no 'track' providers" unless @ routemarked_providers ;
2009-08-20 23:32:15 +02:00
2009-02-27 17:19:36 +01:00
for my $ providerref ( @ routemarked_providers ) {
2009-11-08 16:00:43 +01:00
my $ interface = $ providerref - > { physical } ;
2012-12-28 19:39:19 +01:00
my $ base = uc var_base $ interface ;
2009-02-27 17:19:36 +01:00
my $ mark = $ providerref - > { mark } ;
2009-08-20 23:32:15 +02:00
2011-07-16 18:41:53 +02:00
for ( grep rule_target ( $ _ ) eq 'sticky' , @ { $ tcpreref - > { rules } } ) {
2009-02-27 17:19:36 +01:00
my $ stickyref = ensure_mangle_chain 'sticky' ;
my ( $ rule1 , $ rule2 ) ;
my $ list = sprintf "sticky%03d" , $ sticky + + ;
2009-08-20 23:32:15 +02:00
2009-02-27 17:19:36 +01:00
for my $ chainref ( $ stickyref , $ setstickyref ) {
if ( $ chainref - > { name } eq 'sticky' ) {
2011-11-26 18:36:02 +01:00
$ rule1 = clone_rule ( $ _ ) ;
2011-07-16 18:41:53 +02:00
set_rule_target ( $ rule1 , 'MARK' , "--set-mark $mark" ) ;
set_rule_option ( $ rule1 , 'recent' , "--name $list --update --seconds 300" ) ;
2011-11-26 18:36:02 +01:00
$ rule2 = clone_rule ( $ _ ) ;
2011-07-16 18:41:53 +02:00
clear_rule_target ( $ rule2 ) ;
set_rule_option ( $ rule2 , 'mark' , "--mark 0/$mask -m recent --name $list --remove" ) ;
2009-02-27 17:19:36 +01:00
} else {
2011-11-26 18:36:02 +01:00
$ rule1 = clone_rule ( $ _ ) ;
2011-07-16 18:41:53 +02:00
clear_rule_target ( $ rule1 ) ;
2012-04-24 23:52:57 +02:00
set_rule_option ( $ rule1 , 'mark' , "--mark $mark\/$mask -m recent --name $list --set" ) ;
2011-07-16 18:41:53 +02:00
2010-09-12 00:24:01 +02:00
$ rule2 = '' ;
2009-02-27 17:19:36 +01:00
}
2009-08-20 23:32:15 +02:00
2011-07-17 17:35:09 +02:00
add_trule $ chainref , $ rule1 ;
2009-02-25 17:56:48 +01:00
2009-02-27 17:19:36 +01:00
if ( $ rule2 ) {
2011-07-17 17:35:09 +02:00
add_trule $ chainref , $ rule2 ;
2009-02-27 17:19:36 +01:00
}
}
2009-02-25 17:56:48 +01:00
}
2009-02-25 22:04:17 +01:00
2011-07-16 18:41:53 +02:00
for ( grep rule_target ( $ _ ) eq 'sticko' , , @ { $ tcoutref - > { rules } } ) {
2009-02-27 17:19:36 +01:00
my ( $ rule1 , $ rule2 ) ;
my $ list = sprintf "sticky%03d" , $ sticky + + ;
my $ stickoref = ensure_mangle_chain 'sticko' ;
for my $ chainref ( $ stickoref , $ setstickoref ) {
if ( $ chainref - > { name } eq 'sticko' ) {
2011-11-26 16:48:03 +01:00
$ rule1 = { } ;
while ( my ( $ key , $ value ) = each %$ _ ) {
$ rule1 - > { $ key } = $ value ;
}
2011-07-16 18:41:53 +02:00
set_rule_target ( $ rule1 , 'MARK' , "--set-mark $mark" ) ;
2011-11-26 16:48:03 +01:00
set_rule_option ( $ rule1 , 'recent' , " --name $list --rdest --update --seconds 300" ) ;
$ rule2 = { } ;
2011-07-16 18:41:53 +02:00
2011-11-26 16:48:03 +01:00
while ( my ( $ key , $ value ) = each %$ _ ) {
$ rule2 - > { $ key } = $ value ;
}
2012-04-24 23:52:57 +02:00
2011-07-16 18:41:53 +02:00
clear_rule_target ( $ rule2 ) ;
set_rule_option ( $ rule2 , 'mark' , "--mark 0\/$mask -m recent --name $list --rdest --remove" ) ;
2009-02-27 17:19:36 +01:00
} else {
2011-11-26 16:48:03 +01:00
$ rule1 = { } ;
while ( my ( $ key , $ value ) = each %$ _ ) {
$ rule1 - > { $ key } = $ value ;
}
2011-07-16 18:41:53 +02:00
clear_rule_target ( $ rule1 ) ;
set_rule_option ( $ rule1 , 'mark' , "--mark $mark -m recent --name $list --rdest --set" ) ;
2010-09-12 01:15:09 +02:00
$ rule2 = '' ;
2009-02-27 17:19:36 +01:00
}
2009-08-20 23:32:15 +02:00
2011-07-17 17:35:09 +02:00
add_trule $ chainref , $ rule1 ;
2009-02-25 22:04:17 +01:00
2009-02-27 17:19:36 +01:00
if ( $ rule2 ) {
2011-07-17 17:35:09 +02:00
add_trule $ chainref , $ rule2 ;
2009-02-27 17:19:36 +01:00
}
}
2009-02-25 22:04:17 +01:00
}
}
2009-02-25 17:56:48 +01:00
}
2012-01-16 04:23:44 +01:00
if ( @ routemarked_providers || @ load_interfaces ) {
2010-04-10 17:37:17 +02:00
delete_jumps $ mangle_table - > { PREROUTING } , $ setstickyref unless @ { $ setstickyref - > { rules } } ;
delete_jumps $ mangle_table - > { OUTPUT } , $ setstickoref unless @ { $ setstickoref - > { rules } } ;
2009-02-27 17:19:36 +01:00
}
}
2010-04-10 17:37:17 +02:00
2012-01-16 04:23:44 +01:00
sub setup_load_distribution () {
emit ( '' ,
2012-11-30 16:49:42 +01:00
"distribute_load $maxload @load_interfaces" ,
2012-04-24 23:52:57 +02:00
''
2012-01-16 04:23:44 +01:00
) if @ load_interfaces ;
}
2009-02-22 18:30:14 +01:00
1 ;