mirror of
https://gitlab.com/shorewall/code.git
synced 2025-06-22 18:51:24 +02:00
'shared' providers -- phase I
git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@7669 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
This commit is contained in:
parent
4db0dc2667
commit
e9d2f2f915
@ -187,6 +187,7 @@ our %capdesc = ( NAT_ENABLED => 'NAT',
|
|||||||
TCPMSS_MATCH => 'TCPMSS Match',
|
TCPMSS_MATCH => 'TCPMSS Match',
|
||||||
HASHLIMIT_MATCH => 'Hashlimit Match',
|
HASHLIMIT_MATCH => 'Hashlimit Match',
|
||||||
NFQUEUE_TARGET => 'NFQUEUE Target',
|
NFQUEUE_TARGET => 'NFQUEUE Target',
|
||||||
|
REALM_MATCH => 'Realm Match',
|
||||||
CAPVERSION => 'Capability Version',
|
CAPVERSION => 'Capability Version',
|
||||||
);
|
);
|
||||||
#
|
#
|
||||||
@ -244,7 +245,7 @@ sub initialize() {
|
|||||||
LOGPARMS => '',
|
LOGPARMS => '',
|
||||||
TC_SCRIPT => '',
|
TC_SCRIPT => '',
|
||||||
VERSION => '4.0.6',
|
VERSION => '4.0.6',
|
||||||
CAPVERSION => 40006 ,
|
CAPVERSION => 40007 ,
|
||||||
);
|
);
|
||||||
#
|
#
|
||||||
# From shorewall.conf file
|
# From shorewall.conf file
|
||||||
@ -381,6 +382,7 @@ sub initialize() {
|
|||||||
TCPMSS_MATCH => undef,
|
TCPMSS_MATCH => undef,
|
||||||
HASHLIMIT_MATCH => undef,
|
HASHLIMIT_MATCH => undef,
|
||||||
NFQUEUE_TARGET => undef,
|
NFQUEUE_TARGET => undef,
|
||||||
|
REALM_MATCH => undef,
|
||||||
CAPVERSION => undef,
|
CAPVERSION => undef,
|
||||||
);
|
);
|
||||||
#
|
#
|
||||||
@ -1414,6 +1416,8 @@ sub determine_capabilities( $ ) {
|
|||||||
$capabilities{HASHLIMIT_MATCH} = qt( "$iptables -A $sillyname -m hashlimit --hashlimit 4 --hashlimit-burst 5 --hashlimit-name fooX1234 --hashlimit-mode dstip -j ACCEPT" );
|
$capabilities{HASHLIMIT_MATCH} = qt( "$iptables -A $sillyname -m hashlimit --hashlimit 4 --hashlimit-burst 5 --hashlimit-name fooX1234 --hashlimit-mode dstip -j ACCEPT" );
|
||||||
$capabilities{NFQUEUE_TARGET} = qt( "$iptables -A $sillyname -j NFQUEUE --queue-num 4" );
|
$capabilities{NFQUEUE_TARGET} = qt( "$iptables -A $sillyname -j NFQUEUE --queue-num 4" );
|
||||||
|
|
||||||
|
$capabilities{REALM_MATCH} = qt( "$iptables -A $sillyname -m realm --realm 1" );
|
||||||
|
|
||||||
qt( "$iptables -F $sillyname" );
|
qt( "$iptables -F $sillyname" );
|
||||||
qt( "$iptables -X $sillyname" );
|
qt( "$iptables -X $sillyname" );
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ use constant { LOCAL_NUMBER => 255,
|
|||||||
UNSPEC_NUMBER => 0
|
UNSPEC_NUMBER => 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
our @routemarked_providers;
|
||||||
our %routemarked_interfaces;
|
our %routemarked_interfaces;
|
||||||
our @routemarked_interfaces;
|
our @routemarked_interfaces;
|
||||||
|
|
||||||
@ -53,6 +54,8 @@ our %providers;
|
|||||||
|
|
||||||
our @providers;
|
our @providers;
|
||||||
|
|
||||||
|
our $maccount;
|
||||||
|
|
||||||
#
|
#
|
||||||
# Initialize globals -- we take this novel approach to globals initialization to allow
|
# Initialize globals -- we take this novel approach to globals initialization to allow
|
||||||
# the compiler to run multiple times in the same process. The
|
# the compiler to run multiple times in the same process. The
|
||||||
@ -63,9 +66,11 @@ our @providers;
|
|||||||
#
|
#
|
||||||
|
|
||||||
sub initialize() {
|
sub initialize() {
|
||||||
|
@routemarked_providers = ();
|
||||||
%routemarked_interfaces = ();
|
%routemarked_interfaces = ();
|
||||||
@routemarked_interfaces = ();
|
@routemarked_interfaces = ();
|
||||||
$balance = 0;
|
$balance = 0;
|
||||||
|
$maccount = 0;
|
||||||
$first_default_route = 1;
|
$first_default_route = 1;
|
||||||
|
|
||||||
%providers = ( 'local' => { number => LOCAL_NUMBER , mark => 0 , optional => 0 } ,
|
%providers = ( 'local' => { number => LOCAL_NUMBER , mark => 0 , optional => 0 } ,
|
||||||
@ -93,31 +98,46 @@ sub setup_route_marking() {
|
|||||||
|
|
||||||
my $chainref = new_chain 'mangle', 'routemark';
|
my $chainref = new_chain 'mangle', 'routemark';
|
||||||
|
|
||||||
while ( my ( $interface, $mark ) = ( each %routemarked_interfaces ) ) {
|
my %marked_interfaces;
|
||||||
|
|
||||||
|
for my $providerref ( @routemarked_providers ) {
|
||||||
|
my $interface = $providerref->{interface};
|
||||||
|
|
||||||
|
unless ( $marked_interfaces{$interface} ) {
|
||||||
add_rule $mangle_table->{PREROUTING} , "-i $interface -m mark --mark 0/$mask -j routemark";
|
add_rule $mangle_table->{PREROUTING} , "-i $interface -m mark --mark 0/$mask -j routemark";
|
||||||
add_rule $chainref, " -i $interface -j MARK --set-mark $mark";
|
$marked_interfaces{$interface} = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $providerref->{shared} ) {
|
||||||
|
my $provider = $providerref->{provider};
|
||||||
|
add_command( $chainref, qq(if [ -n "${provider}_is_up" ]; then) ), incr_cmd_level( $chainref ) if $providerref->{optional};
|
||||||
|
add_rule $chainref, " -m mac --mac-source $providerref->{mac} -j MARK --set-mark $providerref->{mark}";
|
||||||
|
decr_cmd_level( $chainref), add_command( $chainref, "fi" ) if $providerref->{optional};
|
||||||
|
} else {
|
||||||
|
add_rule $chainref, " -i $interface -j MARK --set-mark $providerref->{mark}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add_rule $chainref, "-m mark ! --mark 0/$mask -j CONNMARK --save-mark --mask $mask";
|
add_rule $chainref, "-m mark ! --mark 0/$mask -j CONNMARK --save-mark --mask $mask";
|
||||||
}
|
}
|
||||||
|
|
||||||
sub copy_table( $$ ) {
|
sub copy_table( $$$ ) {
|
||||||
my ( $duplicate, $number ) = @_;
|
my ( $duplicate, $number, $realm ) = @_;
|
||||||
|
|
||||||
emit ( "ip route show table $duplicate | while read net route; do",
|
emit ( "ip route show table $duplicate | while read net route; do",
|
||||||
' case $net in',
|
' case $net in',
|
||||||
' default|nexthop)',
|
' default|nexthop)',
|
||||||
' ;;',
|
' ;;',
|
||||||
' *)',
|
' *)',
|
||||||
" run_ip route add table $number \$net \$route",
|
" run_ip route add table $number \$net \$route $realm",
|
||||||
' ;;',
|
' ;;',
|
||||||
' esac',
|
' esac',
|
||||||
"done\n"
|
"done\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub copy_and_edit_table( $$$ ) {
|
sub copy_and_edit_table( $$$$ ) {
|
||||||
my ( $duplicate, $number, $copy ) = @_;
|
my ( $duplicate, $number, $copy, $realm) = @_;
|
||||||
|
|
||||||
emit ( "ip route show table $duplicate | while read net route; do",
|
emit ( "ip route show table $duplicate | while read net route; do",
|
||||||
' case $net in',
|
' case $net in',
|
||||||
@ -126,7 +146,7 @@ sub copy_and_edit_table( $$$ ) {
|
|||||||
' *)',
|
' *)',
|
||||||
' case $(find_device $route) in',
|
' case $(find_device $route) in',
|
||||||
" $copy)",
|
" $copy)",
|
||||||
" run_ip route add table $number \$net \$route",
|
" run_ip route add table $number \$net \$route $realm",
|
||||||
' ;;',
|
' ;;',
|
||||||
' esac',
|
' esac',
|
||||||
' ;;',
|
' ;;',
|
||||||
@ -181,37 +201,18 @@ sub add_a_provider( $$$$$$$$ ) {
|
|||||||
emit "qt ip route flush table $number";
|
emit "qt ip route flush table $number";
|
||||||
emit "echo \"qt ip route flush table $number\" >> \${VARDIR}/undo_routing";
|
emit "echo \"qt ip route flush table $number\" >> \${VARDIR}/undo_routing";
|
||||||
|
|
||||||
if ( $duplicate ne '-' ) {
|
my $variable;
|
||||||
if ( $copy eq '-' ) {
|
|
||||||
copy_table ( $duplicate, $number );
|
|
||||||
} else {
|
|
||||||
if ( $copy eq 'none' ) {
|
|
||||||
$copy = $interface;
|
|
||||||
} else {
|
|
||||||
$copy =~ tr/,/|/;
|
|
||||||
}
|
|
||||||
|
|
||||||
copy_and_edit_table( $duplicate, $number ,$copy );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fatal_error 'A non-empty COPY column requires that a routing table be specified in the DUPLICATE column' if $copy ne '-';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $gateway eq 'detect' ) {
|
if ( $gateway eq 'detect' ) {
|
||||||
my $variable = get_interface_address $interface;
|
$variable = get_interface_address $interface;
|
||||||
emit ( "gateway=\$(detect_gateway $interface)\n",
|
emit ( "gateway=\$(detect_gateway $interface)\n",
|
||||||
'if [ -n "$gateway" ]; then',
|
'if [ -z "$gateway" ]; then',
|
||||||
" run_ip route replace $variable dev $interface table $number",
|
|
||||||
" run_ip route add default via \$gateway dev $interface table $number",
|
|
||||||
'else',
|
|
||||||
" fatal_error \"Unable to detect the gateway through interface $interface\"",
|
" fatal_error \"Unable to detect the gateway through interface $interface\"",
|
||||||
"fi\n" );
|
"fi\n" );
|
||||||
$gateway = '$gateway';
|
$gateway = '$gateway';
|
||||||
} elsif ( $gateway && $gateway ne '-' ) {
|
} elsif ( $gateway && $gateway ne '-' ) {
|
||||||
validate_address $gateway, 0;
|
validate_address $gateway, 0;
|
||||||
my $variable = get_interface_address $interface;
|
$variable = get_interface_address $interface;
|
||||||
emit "run_ip route replace $gateway src $variable dev $interface table $number";
|
|
||||||
emit "run_ip route add default via $gateway dev $interface table $number";
|
|
||||||
} else {
|
} else {
|
||||||
$gateway = '';
|
$gateway = '';
|
||||||
emit "run_ip route add default dev $interface table $number";
|
emit "run_ip route add default dev $interface table $number";
|
||||||
@ -244,15 +245,12 @@ sub add_a_provider( $$$$$$$$ ) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
my ( $loose, $optional ) = (0,0);
|
my ( $loose, $optional, $track, $shared ) = (0,0,0,0);
|
||||||
|
|
||||||
unless ( $options eq '-' ) {
|
unless ( $options eq '-' ) {
|
||||||
for my $option ( split /,/, $options ) {
|
for my $option ( split /,/, $options ) {
|
||||||
if ( $option eq 'track' ) {
|
if ( $option eq 'track' ) {
|
||||||
fatal_error "Interface $interface is tracked through an earlier provider" if $routemarked_interfaces{$interface};
|
$track = 1;
|
||||||
fatal_error "The 'track' option requires a numeric value in the MARK column" if $mark eq '-';
|
|
||||||
$routemarked_interfaces{$interface} = $mark;
|
|
||||||
push @routemarked_interfaces, $interface;
|
|
||||||
} elsif ( $option =~ /^balance=(\d+)$/ ) {
|
} elsif ( $option =~ /^balance=(\d+)$/ ) {
|
||||||
balance_default_route $1 , $gateway, $interface;
|
balance_default_route $1 , $gateway, $interface;
|
||||||
} elsif ( $option eq 'balance' ) {
|
} elsif ( $option eq 'balance' ) {
|
||||||
@ -261,13 +259,64 @@ sub add_a_provider( $$$$$$$$ ) {
|
|||||||
$loose = 1;
|
$loose = 1;
|
||||||
} elsif ( $option eq 'optional' ) {
|
} elsif ( $option eq 'optional' ) {
|
||||||
$optional = 1;
|
$optional = 1;
|
||||||
|
} elsif ( $option eq 'shared' ) {
|
||||||
|
require_capability 'REALM_MATCH', "The 'shared' option", "s";
|
||||||
|
$shared = 1;
|
||||||
} else {
|
} else {
|
||||||
fatal_error "Invalid option ($option)";
|
fatal_error "Invalid option ($option)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$providers{$table} = { number => $number , mark => $val , optional => $optional };
|
$providers{$table} = { provider => $table, number => $number , mark => $val , optional => $optional , interface => $interface , gateway => $gateway, shared => $shared };
|
||||||
|
|
||||||
|
if ( $track ) {
|
||||||
|
fatal_error "The 'track' option requires a numeric value in the MARK column" if $mark eq '-';
|
||||||
|
|
||||||
|
if ( $routemarked_interfaces{$interface} ) {
|
||||||
|
fatal_error "Interface $interface is tracked through an earlier provider" if $routemarked_interfaces{$interface} > 1;
|
||||||
|
fatal_error "Multiple providers through the same interface must have the 'share' option" unless $shared;
|
||||||
|
} else {
|
||||||
|
$routemarked_interfaces{$interface} = $shared ? 1 : 2;
|
||||||
|
push @routemarked_interfaces, $interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
push @routemarked_providers, $providers{$table};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
my $realm = '';
|
||||||
|
|
||||||
|
if ( $shared ) {
|
||||||
|
fatal_error "The 'shared' option requires a gateway" unless $gateway;
|
||||||
|
|
||||||
|
my $variable = uc( "${interface}_MAC_" . ++$maccount );
|
||||||
|
|
||||||
|
emit "$variable=\$(find_mac $gateway $interface)\n";
|
||||||
|
|
||||||
|
$providers{$table}{mac} = "\$$variable";
|
||||||
|
|
||||||
|
$realm = "realm $number";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $duplicate ne '-' ) {
|
||||||
|
if ( $copy eq '-' ) {
|
||||||
|
copy_table ( $duplicate, $number, $realm );
|
||||||
|
} else {
|
||||||
|
if ( $copy eq 'none' ) {
|
||||||
|
$copy = $interface;
|
||||||
|
} else {
|
||||||
|
$copy =~ tr/,/|/;
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_and_edit_table( $duplicate, $number ,$copy , $realm);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fatal_error 'A non-empty COPY column requires that a routing table be specified in the DUPLICATE column' if $copy ne '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
emit "run_ip route replace $gateway src $variable dev $interface table $number $realm";
|
||||||
|
emit "run_ip route add default via $gateway dev $interface table $number $realm";
|
||||||
|
|
||||||
if ( $loose ) {
|
if ( $loose ) {
|
||||||
if ( $config{DELETE_THEN_ADD} ) {
|
if ( $config{DELETE_THEN_ADD} ) {
|
||||||
|
@ -904,6 +904,21 @@ find_echo() {
|
|||||||
|
|
||||||
echo echo
|
echo echo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Determine the MAC address of the passed IP through the passed interface
|
||||||
|
#
|
||||||
|
find_mac() # $1 = IP address, $2 = interface
|
||||||
|
{
|
||||||
|
qt ping -nc 1 -t 2 -I $2 $1
|
||||||
|
|
||||||
|
local result=$(arp -na | awk "/[(]$1[)].* on $2$/ {print \$4}")
|
||||||
|
|
||||||
|
[ -n "$result" -a "$result" != "<incomplete>" ] || fatal_error "Cannot determine the MAC address of $1 through $2"
|
||||||
|
|
||||||
|
echo $result
|
||||||
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# End of functions imported from /usr/share/shorewall/lib.base
|
# End of functions imported from /usr/share/shorewall/lib.base
|
||||||
################################################################################
|
################################################################################
|
||||||
|
Loading…
x
Reference in New Issue
Block a user