First installment of New Bridge Code

git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@6468 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
This commit is contained in:
teastep 2007-06-06 00:47:27 +00:00
parent 61638c996c
commit a8cb589333
4 changed files with 140 additions and 54 deletions

View File

@ -84,6 +84,15 @@ sub validate_hosts_file()
fatal_error "Invalid HOST(S) column contents: $hosts";
}
if ( $type eq 'bport4' ) {
if ( $zoneref->{bridge} eq '' ) {
fatal_error 'Bridge Port Zones may only be associated with bridge ports' unless $interfaces{$interface}{options}{port};
$zoneref->{bridge} = $interfaces{$interface}{bridge};
} elsif ( $zoneref->{bridge} ne $interfaces{$interface}{bridge} ) {
fatal_error "Interface $interface is not a port on bridge $zoneref->{bridge}";
}
}
my $optionsref = {};
if ( $options ne '-' ) {

View File

@ -56,6 +56,7 @@ our @VERSION = 1.00;
# ...
# }
# zone => <zone name>
# bridge => <bridge>
# }
# }
#
@ -161,6 +162,7 @@ sub validate_interfaces_file()
my %validoptions = (arp_filter => BINARY_IF_OPTION,
arp_ignore => ENUM_IF_OPTION,
blacklist => SIMPLE_IF_OPTION,
bridge => SIMPLE_IF_OPTION,
detectnets => SIMPLE_IF_OPTION,
dhcp => SIMPLE_IF_OPTION,
maclist => SIMPLE_IF_OPTION,
@ -189,6 +191,7 @@ sub validate_interfaces_file()
my ($zone, $interface, $networks, $options ) = split_line 2, 4, 'interfaces file';
my $zoneref;
my $bridge = '';
if ( $zone eq '-' ) {
$zone = '';
@ -202,9 +205,26 @@ sub validate_interfaces_file()
$networks = '' if $networks eq '-';
$options = '' if $options eq '-';
( $interface, my ($port, $extra) ) = split /:/ , $interface, 3;
fatal_error "Invalid INTERFACE" if defined $extra || ! $interface;
fatal_error "Duplicate Interface ($interface)" if $interfaces{$interface};
fatal_error "Invalid Interface Name: $interface" if $interface =~ /:|^\+$/;
fatal_error "Invalid Interface Name: $interface" if $interface eq '+';
if ( defined $port ) {
require_capability( 'PHYSDEV_MATCH', 'Bridge Ports', '');
require_capability( 'KLUDGEFREE', 'Bridge Ports', '');
fatal_error "$interface is not a defined bridge" unless $interfaces{$interface} && $interfaces{$interface}{options}{bridge};
fatal_error "Invalid Bridge Port Name ($port)" unless $port =~ /^([\w.@%-]+\+?)$/;
fatal_error "Bridge Ports may only be associated with 'bport' zones" if $zone && $zoneref->{type} ne 'bport4';
$interfaces{$port}{bridge} = $bridge = $interface;
$interface = $port;
} else {
fatal_error "Zones of type 'bport' may only be associated with bridge ports" if $zone && $zoneref->{type} eq 'bport4';
$interfaces{$interface}{bridge} = $interface;
}
my $wildcard = 0;
@ -229,6 +249,8 @@ sub validate_interfaces_file()
my %options;
if ( $options ) {
fatal_error "Bridge Ports may not have options" if defined $port;
for my $option (split ',', $options ) {
next if $option eq '-';
@ -266,7 +288,14 @@ sub validate_interfaces_file()
}
}
$zoneref->{options}{in_out}{routeback} = 1 if $options{routeback};
$zoneref->{options}{in_out}{routeback} = 1 if $zoneref && $options{routeback};
if ( $options{bridge} ) {
require_capability( 'PHYSDEV_MATCH', 'The "bridge" option', 's');
fatal_error "Bridges may not have wildcard names" if $wildcard;
}
} elsif ( defined $port ) {
$options{port} = 1;
}
$interfaces{$interface}{options} = $optionsref = \%options;

View File

@ -782,13 +782,13 @@ sub setup_mac_lists( $ ) {
}
}
sub process_rule1 ( $$$$$$$$$$ );
sub process_rule1 ( $$$$$$$$$$$ );
#
# Expand a macro rule from the rules file
#
sub process_macro ( $$$$$$$$$$$$ ) {
my ($macrofile, $target, $param, $source, $dest, $proto, $ports, $sports, $origdest, $rate, $user, $mark ) = @_;
sub process_macro ( $$$$$$$$$$$$$ ) {
my ($macrofile, $target, $param, $source, $dest, $proto, $ports, $sports, $origdest, $rate, $user, $mark, $wildcard ) = @_;
progress_message "..Expanding Macro $macrofile...";
@ -847,7 +847,7 @@ sub process_macro ( $$$$$$$$$$$$ ) {
$mrate = merge_macro_column $mrate, $rate;
$muser = merge_macro_column $muser, $user;
process_rule1 $mtarget, $msource, $mdest, $mproto, $mports, $msports, $origdest, $mrate, $muser, $mark;
process_rule1 $mtarget, $msource, $mdest, $mproto, $mports, $msports, $origdest, $mrate, $muser, $mark, $wildcard;
progress_message " Rule \"$line\" $done";
}
@ -864,8 +864,8 @@ my @param_stack;
#
# Once a rule has been completely resolved by macro expansion and wildcard (source and/or dest zone == 'all'), it is processed by this function.
#
sub process_rule1 ( $$$$$$$$$$ ) {
my ( $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark ) = @_;
sub process_rule1 ( $$$$$$$$$$$ ) {
my ( $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $wildcard ) = @_;
my ( $action, $loglevel) = split_action $target;
my ( $basictarget, $param ) = split '/', $action;
my $rule = '';
@ -902,7 +902,8 @@ sub process_rule1 ( $$$$$$$$$$ ) {
$origdest,
$ratelimit,
$user,
$mark );
$mark,
$wildcard );
$macro_nest_level--;
@ -974,6 +975,15 @@ sub process_rule1 ( $$$$$$$$$$ ) {
$restriction = INPUT_RESTRICT if $destzone eq $firewall_zone;
}
#
# Check for illegal bridge port rule
#
if ( $zones{$sourcezone}->{type} eq 'bport4' ) {
unless ( $zones{$sourcezone}{bridge} eq $zones{$destzone}{bridge} ) {
return 1 if $wildcard;
fatal_error "Rules with a DESTINATION Bridge Port zone must have a SOURCE zone on the same bridge";
}
}
#
# Take care of chain
#
my $chain = "${sourcezone}2${destzone}";
@ -982,8 +992,13 @@ sub process_rule1 ( $$$$$$$$$$ ) {
# Validate Policy
#
my $policy = $chainref->{policy};
fatal_error "No policy defined from zone $sourcezone to zone $destzone" unless $policy;
fatal_error "Rules may not override a NONE policy" if $policy eq 'NONE';
if ( $policy eq 'NONE' ) {
return 1 if $wildcard;
fatal_error "Rules may not override a NONE policy";
}
#
# For compatibility with older Shorewall versions
#
@ -1211,17 +1226,15 @@ sub process_rule ( $$$$$$$$$$ ) {
my $policychainref = $filter_table->{"${zone}2${zone1}"}{policychain};
fatal_error "No policy from zone $zone to zone $zone1" unless $policychainref;
my $policy = $policychainref->{policy};
unless ( $policy eq 'NONE' ) {
if ( $optimize > 0 ) {
my $loglevel = $policychainref->{loglevel};
if ( $loglevel ne '' ) {
next if $target eq "${policy}:$loglevel}";
} else {
next if $action eq $policy;
}
if ( $optimize > 0 ) {
my $loglevel = $policychainref->{loglevel};
if ( $loglevel ne '' ) {
next if $target eq "${policy}:$loglevel}";
} else {
next if $action eq $policy;
}
process_rule1 $target, $zone, $zone1 , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark;
}
process_rule1 $target, $zone, $zone1 , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, 1;
}
}
}
@ -1232,17 +1245,15 @@ sub process_rule ( $$$$$$$$$$ ) {
if ( $intrazone || ( $zone ne $destzone ) ) {
fatal_error "No policy from zone $zone to zone $destzone" unless $policychainref;
my $policy = $policychainref->{policy};
unless ( $policy eq 'NONE' ) {
if ( $optimize > 0 ) {
my $loglevel = $policychainref->{loglevel};
if ( $loglevel ne '') {
next if $target eq "${policy}:$loglevel}";
} else {
next if $action eq $policy;
}
if ( $optimize > 0 ) {
my $loglevel = $policychainref->{loglevel};
if ( $loglevel ne '') {
next if $target eq "${policy}:$loglevel}";
} else {
next if $action eq $policy;
}
process_rule1 $target, $zone, $dest , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark;
}
process_rule1 $target, $zone, $dest , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, 1;
}
}
}
@ -1254,21 +1265,19 @@ sub process_rule ( $$$$$$$$$$ ) {
fatal_error "Unknown source zone ($sourcezone)" unless $zones{$sourcezone};
my $policychainref = $filter_table->{"${sourcezone}2${zone}"}{policychain};
my $policy = $policychainref->{policy};
unless ( $policy eq 'NONE' ) {
if ( $optimize > 0 ) {
my $loglevel = $policychainref->{loglevel};
if ( $loglevel ne '' ) {
next if $target eq "${policy}:$loglevel}";
} else {
next if $action eq $policy;
}
if ( $optimize > 0 ) {
my $loglevel = $policychainref->{loglevel};
if ( $loglevel ne '' ) {
next if $target eq "${policy}:$loglevel}";
} else {
next if $action eq $policy;
}
}
process_rule1 $target, $source, $zone , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark;
process_rule1 $target, $source, $zone , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, 1;
}
}
} else {
process_rule1 $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark;
process_rule1 $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, 0;
}
progress_message " Rule \"$thisline\" $done";
@ -1365,6 +1374,32 @@ sub generate_matrix() {
add_rule $chainref, "-j $name";
}
#
# Match Source Interface
#
sub match_source_dev( $ ) {
my $interface = shift;
my $interfaceref = $interfaces{$interface};
if ( $interfaceref->{options}{port} ) {
"-i $interfaceref->{bridge} -m physdev --physdev-in $interface ";
} else {
"-i $interface ";
}
}
#
# Match Dest device
#
sub match_dest_dev( $ ) {
my $interface = shift;
my $interfaceref = $interfaces{$interface};
if ( $interfaceref->{options}{port} ) {
"-o $interfaceref->{bridge} -m physdev --physdev-out $interface ";
} else {
"-o $interface ";
}
}
#
# Insert the passed exclusions at the front of the passed chain.
#
@ -1375,7 +1410,7 @@ sub generate_matrix() {
for my $host ( @{$exclusionsref} ) {
my ( $interface, $net ) = split /:/, $host;
insert_rule $chainref , $num++, join( '', "-i $interface ", match_source_net( $net ), '-j RETURN' );
insert_rule $chainref , $num++, join( '', match_source_dev $interface , match_source_net( $net ), '-j RETURN' );
}
}
@ -1387,7 +1422,7 @@ sub generate_matrix() {
for my $host ( @{$exclusionsref} ) {
my ( $interface, $net ) = split /:/, $host;
add_rule $chainref , join( '', "-i $interface ", match_source_net( $net ), '-j RETURN' );
add_rule $chainref , join( '', match_source_dev $interface, match_source_net( $net ), '-j RETURN' );
}
}
@ -1409,12 +1444,12 @@ sub generate_matrix() {
my %policy_exclusions;
for my $interface ( @interfaces ) {
addnatjump 'POSTROUTING' , snat_chain( $interface ), "-o $interface ";
addnatjump 'POSTROUTING' , snat_chain( $interface ), match_dest_dev( $interface );
}
if ( $config{DYNAMIC_ZONES} ) {
for my $interface ( @interfaces ) {
addnatjump 'PREROUTING' , dynamic_in( $interface ), "-i $interface ";
addnatjump 'PREROUTING' , dynamic_in( $interface ), match_source_dev( $interface );
}
}
@ -1422,8 +1457,8 @@ sub generate_matrix() {
addnatjump 'POSTROUTING' , 'nat_out' , '';
for my $interface ( @interfaces ) {
addnatjump 'PREROUTING' , input_chain( $interface ) , "-i $interface ";
addnatjump 'POSTROUTING' , output_chain( $interface ) , "-o $interface ";
addnatjump 'PREROUTING' , input_chain( $interface ) , match_source_dev( $interface );
addnatjump 'POSTROUTING' , output_chain( $interface ) , match_dest_dev( $interface );
}
for my $zone ( grep $zones{$_}{options}{complex} , @zones ) {
@ -1440,9 +1475,10 @@ sub generate_matrix() {
for my $host ( @$exclusions ) {
my ( $interface, $net ) = split /:/, $host;
add_rule $frwd_ref , "-i $interface -s $net -j RETURN";
add_rule $in_ref , "-i $interface -s $net -j RETURN";
add_rule $out_ref , "-i $interface -s $net -j RETURN";
my $rule = match_source_interface( $interface ) . "-s $net -j RETURN";
add_rule $frwd_ref , $rule;
add_rule $in_ref , $rule;
add_rule $out_ref , $rule;
}
}
@ -1520,7 +1556,7 @@ sub generate_matrix() {
my $source = match_source_net $net;
insertnatjump 'PREROUTING' , dnat_chain $zone, \$prerouting_rule, join( '', "-i $interface ", $source, $ipsec_in_match );
insertnatjump 'PREROUTING' , dnat_chain $zone, \$prerouting_rule, join( '', match_source_dev( $interface), $source, $ipsec_in_match );
if ( $chain2 ) {
if ( @$exclusions ) {
@ -1665,7 +1701,7 @@ sub generate_matrix() {
if ( $zone ne $zone1 || $num_ifaces > 1 || $hostref->{options}{routeback} ) {
my $ipsec_out_match = match_ipsec_out $zone1 , $hostref;
for my $net ( @{$hostref->{hosts}} ) {
add_rule $frwd_ref, join( '', "-o $interface ", match_dest_net($net), $ipsec_out_match, "-j $chain" );
add_rule $frwd_ref, join( '', match_dest_dev( $interface) , match_dest_net($net), $ipsec_out_match, "-j $chain" );
}
}
}
@ -1690,7 +1726,7 @@ sub generate_matrix() {
#
add_rule(
$chain3ref ,
join( '', "-o $interface1 ", match_source_net($net), match_dest_net($net1), $ipsec_out_match, "-j $chain" )
join( '', match_dest_dev($interface), match_source_net($net), match_dest_net($net1), $ipsec_out_match, "-j $chain" )
);
}
}
@ -1730,10 +1766,10 @@ sub generate_matrix() {
# Now add the jumps to the interface chains from FORWARD, INPUT, OUTPUT and POSTROUTING
#
for my $interface ( @interfaces ) {
add_rule $filter_table->{FORWARD} , "-i $interface -j " . forward_chain $interface;
add_rule $filter_table->{INPUT} , "-i $interface -j " . input_chain $interface;
add_rule $filter_table->{OUTPUT} , "-o $interface -j " . output_chain $interface;
addnatjump 'POSTROUTING' , masq_chain( $interface ) , "-o $interface ";
add_rule $filter_table->{FORWARD} , match_source_dev( $interface ) . "-j " . forward_chain $interface;
add_rule $filter_table->{INPUT} , match_source_dev( $interface ) . "-j " . input_chain $interface;
add_rule $filter_table->{OUTPUT} , "-o $interface -j " . output_chain $interface unless $interfaces{$interface}{options}{port};
addnatjump 'POSTROUTING' , masq_chain( $interface ) , match_dest_dev( $interface );
}
my $chainref = $filter_table->{"${firewall_zone}2${firewall_zone}"};

View File

@ -73,6 +73,7 @@ use constant { NOTHING => 'NOTHING',
# parents => [ <parents> ] Parents, Children and interfaces are listed by name
# children => [ <children> ]
# interfaces => [ <interfaces> ]
# bridge => <bridge>
# hosts { <type> } => [ { <interface1> => { ipsec => 'ipsec'|'none'
# options => { <option1> => <value1>
# ...
@ -223,6 +224,7 @@ sub determine_zones()
my $zoneref = $zones{$zone} = {};
$zoneref->{parents} = \@parents;
$zoneref->{exclusions} = [];
$zoneref->{bridge} = '';
$type = "ipv4" unless $type;
@ -230,6 +232,16 @@ sub determine_zones()
$zoneref->{type} = 'ipv4';
} elsif ( $type =~ /^ipsec4?$/i ) {
$zoneref->{type} = 'ipsec4';
} elsif ( $type =~ /^bport4?$/i ) {
fatal_error "Bridge Port zones must have a single parent zone" unless @parents == 1;
for my $p ( @parents ) {
my $interfaceref = $interfaces{$1};
fatal_error "Parent Zone $p is not associated with device $1" unless $interfaceref && $interfaceref->{zone} eq $zone;
}
$zoneref->{type} = 'bport4';
} elsif ( $type eq 'firewall' ) {
fatal_error 'Firewall zone may not be nested' if @parents;
fatal_error "Only one firewall zone may be defined: $zone" if $firewall_zone;