Make wait and required work on wildcard interfaces

Signed-off-by: Tom Eastep <teastep@shorewall.net>
This commit is contained in:
Tom Eastep 2010-06-04 10:35:45 -07:00
parent 82a74d7534
commit 742a3b2eef
6 changed files with 115 additions and 35 deletions

View File

@ -43,7 +43,7 @@ use Shorewall::Raw;
our @ISA = qw(Exporter); our @ISA = qw(Exporter);
our @EXPORT = qw( compiler ); our @EXPORT = qw( compiler );
our @EXPORT_OK = qw( $export ); our @EXPORT_OK = qw( $export );
our $VERSION = '4.4_9'; our $VERSION = '4.4_10';
our $export; our $export;
@ -271,7 +271,7 @@ sub generate_script_2() {
set_global_variables(1); set_global_variables(1);
handle_optional_interfaces; handle_optional_interfaces(0);
emit ';;'; emit ';;';
@ -284,7 +284,7 @@ sub generate_script_2() {
set_global_variables(0); set_global_variables(0);
handle_optional_interfaces; handle_optional_interfaces(0);
emit ';;'; emit ';;';
} }
@ -294,7 +294,7 @@ sub generate_script_2() {
emit ( 'esac' ) , emit ( 'esac' ) ,
} else { } else {
emit( 'true' ) unless handle_optional_interfaces; emit( 'true' ) unless handle_optional_interfaces(1);
} }
pop_indent; pop_indent;

View File

@ -35,7 +35,7 @@ use strict;
our @ISA = qw(Exporter); our @ISA = qw(Exporter);
our @EXPORT = qw( setup_providers @routemarked_interfaces handle_stickiness handle_optional_interfaces ); our @EXPORT = qw( setup_providers @routemarked_interfaces handle_stickiness handle_optional_interfaces );
our @EXPORT_OK = qw( initialize lookup_provider ); our @EXPORT_OK = qw( initialize lookup_provider );
our $VERSION = '4.4_9'; our $VERSION = '4.4_10';
use constant { LOCAL_TABLE => 255, use constant { LOCAL_TABLE => 255,
MAIN_TABLE => 254, MAIN_TABLE => 254,
@ -841,9 +841,9 @@ sub lookup_provider( $ ) {
# #
# Returns true if there were required or optional interfaces # Returns true if there were required or optional interfaces
# #
sub handle_optional_interfaces() { sub handle_optional_interfaces( $ ) {
my $returnvalue = verify_required_interfaces; my $returnvalue = verify_required_interfaces( shift );
my $interfaces = find_interfaces_by_option1 'optional'; my $interfaces = find_interfaces_by_option1 'optional';

View File

@ -79,7 +79,7 @@ our @EXPORT = qw( NOTHING
); );
our @EXPORT_OK = qw( initialize ); our @EXPORT_OK = qw( initialize );
our $VERSION = '4.4_9'; our $VERSION = '4.4_10';
# #
# IPSEC Option types # IPSEC Option types
@ -735,6 +735,18 @@ sub is_a_bridge( $ ) {
which 'brctl' && qt( "brctl show | tail -n+2 | grep -q '^$_[0]\[\[:space:\]\]'" ); which 'brctl' && qt( "brctl show | tail -n+2 | grep -q '^$_[0]\[\[:space:\]\]'" );
} }
#
# Transform the passed interface name into a legal shell variable name.
#
sub chain_base($) {
my $chain = $_[0];
$chain =~ s/^@/at_/;
$chain =~ tr/[.\-%@]/_/;
$chain =~ s/\+$//;
$chain;
}
# #
# Process a record in the interfaces file # Process a record in the interfaces file
# #
@ -940,7 +952,6 @@ sub process_interface( $$ ) {
$hostoptions{routeback} = $options{routeback} = is_a_bridge( $physical ) unless $export || $options{routeback}; $hostoptions{routeback} = $options{routeback} = is_a_bridge( $physical ) unless $export || $options{routeback};
fatal_error "Required Interfaces may not have wildcard names ($physical)" if $options{required} && $physical =~ /\+/;
$hostoptionsref = \%hostoptions; $hostoptionsref = \%hostoptions;
} else { } else {
@ -1206,29 +1217,52 @@ sub set_interface_option( $$$ ) {
# #
# Verify that all required interfaces are available after waiting for any that specify the 'wait' option. # Verify that all required interfaces are available after waiting for any that specify the 'wait' option.
# #
sub verify_required_interfaces() { sub verify_required_interfaces( $ ) {
my $generate_case = shift;
my $returnvalue = 0; my $returnvalue = 0;
my $interfaces = find_interfaces_by_option 'wait'; my $interfaces = find_interfaces_by_option 'wait';
if ( @$interfaces ) { if ( @$interfaces ) {
emit "local waittime\n";
for my $interface (@$interfaces ) { for my $interface (@$interfaces ) {
my $wait = $interfaces{$interface}{options}{wait}; my $wait = $interfaces{$interface}{options}{wait};
if ( $wait ) { if ( $wait ) {
my $physical = get_physical $interface; my $physical = get_physical $interface;
emit qq(if ! interface_is_usable $physical; then); if ( $physical =~ /\+$/ ) {
emit q( local waittime); my $base = uc chain_base $physical;
emit qq( waittime=$wait);
emit ''; $physical =~ s/\+$/*/;
emit q( while [ $waittime -gt 0 ]; do);
emit qq( interface_is_usable $physical && break); emit( 'for interface in $(find_all_interfaces); do',
emit q( sleep 1); ' case $interface in',
emit ' waittime=$(($waittime - 1))'; " $physical)",
emit q( done); " waittime=$wait",
emit qq(fi\n); ' while [ $waittime -gt 0 ]; do',
' interface_is_usable $interface && break',
' waittime=$(($waittime - 1))',
' done',
' ;;',
' esac',
'done',
'',
);
} else {
emit qq(if ! interface_is_usable $physical; then);
emit qq( waittime=$wait);
emit '';
emit q( while [ $waittime -gt 0 ]; do);
emit qq( interface_is_usable $physical && break);
emit q( sleep 1);
emit ' waittime=$(($waittime - 1))';
emit q( done);
emit qq(fi\n);
}
$returnvalue = 1; $returnvalue = 1;
} }
@ -1238,22 +1272,48 @@ sub verify_required_interfaces() {
$interfaces = find_interfaces_by_option 'required'; $interfaces = find_interfaces_by_option 'required';
if ( @$interfaces ) { if ( @$interfaces ) {
emit( 'case "$COMMAND" in' );
push_indent; if ( $generate_case ) {
emit( 'start|restart|restore|refresh)' ); emit( 'case "$COMMAND" in' );
push_indent; push_indent;
for my $interface (@$interfaces ) { emit( 'start|restart|restore|refresh)' );
my $physical = get_physical $interface; push_indent;
emit qq(if ! interface_is_usable $physical; then);
emit qq( startup_error "Required interface $physical not available");
emit qq(fi\n);
} }
emit( ';;' ); for my $interface (@$interfaces ) {
pop_indent; my $physical = get_physical $interface;
pop_indent;
emit( 'esac' ); if ( $physical =~ /\+$/ ) {
my $base = uc chain_base $physical;
$physical =~ s/\+$/*/;
emit( "${base}_IS_UP=\n",
'for interface in $(find_all_interfaces); do',
' case $interface in',
" $physical)",
" interface_is_usable \$interface && ${base}_IS_UP=Yes && break",
' ;;',
' esac',
'done',
'',
"if [ -z \"\$${base}_IS_UP\" ]; then",
" startup_error \"None of the required interfaces $physical are available\"",
"fi\n"
);
} else {
emit qq(if ! interface_is_usable $physical; then);
emit qq( startup_error "Required interface $physical not available");
emit qq(fi\n);
}
}
if ( $generate_case ) {
emit( ';;' );
pop_indent;
pop_indent;
emit( 'esac' );
}
$returnvalue = 1; $returnvalue = 1;
} }
@ -1325,6 +1385,8 @@ sub compile_updown() {
if ( @$required ) { if ( @$required ) {
my $interfaces = join '|', map $interfaces{$_}->{physical}, @$required; my $interfaces = join '|', map $interfaces{$_}->{physical}, @$required;
$interfaces =~ s/\+/*/;
emit( "$interfaces)", emit( "$interfaces)",
' if [ "$COMMAND" = up ]; then', ' if [ "$COMMAND" = up ]; then',
' COMMAND=start', ' COMMAND=start',

View File

@ -120,6 +120,13 @@ deleteallchains() {
run_iptables -X run_iptables -X
} }
#
# Generate a list of all network interfaces on the system
#
find_all_interfaces() {
${IP:-ip} link list | egrep '^[[:digit:]]+:' | cut -d ' ' -f2 | sed 's/:$//'
}
# #
# Find the value 'dev' in the passed arguments then echo the next value # Find the value 'dev' in the passed arguments then echo the next value
# #

View File

@ -112,6 +112,13 @@ deleteallchains() {
run_iptables -X run_iptables -X
} }
#
# Generate a list of all network interfaces on the system
#
find_all_interfaces() {
${IP:-ip} link list | egrep '^[[:digit:]]+:' | cut -d ' ' -f2 | sed 's/:$//'
}
# #
# Find the value 'dev' in the passed arguments then echo the next value # Find the value 'dev' in the passed arguments then echo the next value
# #

View File

@ -333,7 +333,11 @@ None.
b) In your Shorewall interfaces file(s), set the 'required' option b) In your Shorewall interfaces file(s), set the 'required' option
on any interfaces that must be up in order for the firewall to on any interfaces that must be up in order for the firewall to
start. At least one interface must have the 'required' or start. At least one interface must have the 'required' or
'optional' option if you perform the next optional step. 'optional' option if you perform the next optional step. If
'required' is specified on an interface with a wildcard name
(the physical name ends with '+'), then at least one interface
that matches the name must be in a usable state for the
firewall to start successfully.
c) (Optional) -- If you have specified at least one 'required' c) (Optional) -- If you have specified at least one 'required'
or 'optional interface, you can then disable automatic firewall or 'optional interface, you can then disable automatic firewall