First timid step toward IPv6 support

git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@7313 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
This commit is contained in:
teastep 2007-09-10 22:28:06 +00:00
parent 6141995184
commit 5819589cb0
5 changed files with 77 additions and 41 deletions

View File

@ -1245,7 +1245,7 @@ sub match_ipsec_in( $$ ) {
my $zoneref = find_zone( $zone ); my $zoneref = find_zone( $zone );
my $optionsref = $zoneref->{options}; my $optionsref = $zoneref->{options};
if ( $zoneref->{type} eq 'ipsec4' ) { if ( $zoneref->{type} & ZT_IPSEC ) {
$match .= "ipsec $optionsref->{in_out}{ipsec}$optionsref->{in}{ipsec}"; $match .= "ipsec $optionsref->{in_out}{ipsec}$optionsref->{in}{ipsec}";
} elsif ( $capabilities{POLICY_MATCH} ) { } elsif ( $capabilities{POLICY_MATCH} ) {
$match .= "$hostref->{ipsec} $optionsref->{in_out}{ipsec}$optionsref->{in}{ipsec}"; $match .= "$hostref->{ipsec} $optionsref->{in_out}{ipsec}$optionsref->{in}{ipsec}";
@ -1263,7 +1263,7 @@ sub match_ipsec_out( $$ ) {
my $zoneref = find_zone( $zone ); my $zoneref = find_zone( $zone );
my $optionsref = $zoneref->{options}; my $optionsref = $zoneref->{options};
if ( $zoneref->{type} eq 'ipsec4' ) { if ( $zoneref->{type} & ZT_IPSEC ) {
$match .= "ipsec $optionsref->{in_out}{ipsec}$optionsref->{out}{ipsec}"; $match .= "ipsec $optionsref->{in_out}{ipsec}$optionsref->{out}{ipsec}";
} elsif ( $capabilities{POLICY_MATCH} ) { } elsif ( $capabilities{POLICY_MATCH} ) {
$match .= "$hostref->{ipsec} $optionsref->{in_out}{ipsec}$optionsref->{out}{ipsec}" $match .= "$hostref->{ipsec} $optionsref->{in_out}{ipsec}$optionsref->{out}{ipsec}"

View File

@ -266,11 +266,11 @@ sub validate_policy()
fatal_error "NONE policy not allowed with \"all\"" fatal_error "NONE policy not allowed with \"all\""
if $clientwild || $serverwild; if $clientwild || $serverwild;
fatal_error "NONE policy not allowed to/from firewall zone" fatal_error "NONE policy not allowed to/from firewall zone"
if ( zone_type( $client ) eq 'firewall' ) || ( zone_type( $server ) eq 'firewall' ); if ( zone_type( $client ) == ZT_FIREWALL ) || ( zone_type( $server ) == ZT_FIREWALL );
} }
unless ( $clientwild || $serverwild ) { unless ( $clientwild || $serverwild ) {
if ( zone_type( $server ) eq 'bport4' ) { if ( zone_type( $server ) & ZT_BPORT ) {
fatal_error "Invalid policy - DEST zone is a Bridge Port zone but the SOURCE zone is not associated with the same bridge" fatal_error "Invalid policy - DEST zone is a Bridge Port zone but the SOURCE zone is not associated with the same bridge"
unless find_zone( $client )->{bridge} eq find_zone( $server)->{bridge} || single_interface( $client ) eq find_zone( $server )->{bridge}; unless find_zone( $client )->{bridge} eq find_zone( $server)->{bridge} || single_interface( $client ) eq find_zone( $server )->{bridge};
} }

View File

@ -1051,7 +1051,7 @@ sub process_rule1 ( $$$$$$$$$$$ ) {
# #
# Check for illegal bridge port rule # Check for illegal bridge port rule
# #
if ( $destref->{type} eq 'bport4' ) { if ( $destref->{type} & ZT_BPORT ) {
unless ( $sourceref->{bridge} eq $destref->{bridge} || single_interface( $sourcezone ) eq $destref->{bridge} ) { unless ( $sourceref->{bridge} eq $destref->{bridge} || single_interface( $sourcezone ) eq $destref->{bridge} ) {
return 1 if $wildcard; return 1 if $wildcard;
fatal_error "Rules with a DESTINATION Bridge Port zone must have a SOURCE zone on the same bridge"; fatal_error "Rules with a DESTINATION Bridge Port zone must have a SOURCE zone on the same bridge";
@ -1175,7 +1175,7 @@ sub process_rule1 ( $$$$$$$$$$$ ) {
# #
# And generate the nat table rule(s) # And generate the nat table rule(s)
# #
expand_rule ( ensure_chain ('nat' , $sourceref->{type} eq 'firewall' ? 'OUTPUT' : dnat_chain $sourcezone ), expand_rule ( ensure_chain ('nat' , $sourceref->{type} == ZT_FIREWALL ? 'OUTPUT' : dnat_chain $sourcezone ),
PREROUTE_RESTRICT , PREROUTE_RESTRICT ,
$rule , $rule ,
$source , $source ,
@ -1212,7 +1212,7 @@ sub process_rule1 ( $$$$$$$$$$$ ) {
$origdest = $interfaces ? "detect:$interfaces" : ALLIPv4; $origdest = $interfaces ? "detect:$interfaces" : ALLIPv4;
} }
expand_rule( ensure_chain ('nat' , $sourceref->{type} eq 'firewall' ? 'OUTPUT' : dnat_chain $sourcezone) , expand_rule( ensure_chain ('nat' , $sourceref->{type} == ZT_FIREWALL ? 'OUTPUT' : dnat_chain $sourcezone) ,
PREROUTE_RESTRICT , PREROUTE_RESTRICT ,
$rule , $rule ,
$source , $source ,
@ -1315,10 +1315,10 @@ sub process_rule ( $$$$$$$$$$ ) {
if ( $source eq 'all' ) { if ( $source eq 'all' ) {
for my $zone ( all_zones ) { for my $zone ( all_zones ) {
if ( $includesrcfw || ( zone_type( $zone ) ne 'firewall' ) ) { if ( $includesrcfw || ( zone_type( $zone ) != ZT_FIREWALL ) ) {
if ( $dest eq 'all' ) { if ( $dest eq 'all' ) {
for my $zone1 ( all_zones ) { for my $zone1 ( all_zones ) {
if ( $includedstfw || ( zone_type( $zone1 ) ne 'firewall' ) ) { if ( $includedstfw || ( zone_type( $zone1 ) != ZT_FIREWALL ) ) {
if ( $intrazone || ( $zone ne $zone1 ) ) { if ( $intrazone || ( $zone ne $zone1 ) ) {
process_rule1 $target, $zone, $zone1 , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, 1; process_rule1 $target, $zone, $zone1 , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, 1;
} }
@ -1336,7 +1336,7 @@ sub process_rule ( $$$$$$$$$$ ) {
} elsif ( $dest eq 'all' ) { } elsif ( $dest eq 'all' ) {
for my $zone ( all_zones ) { for my $zone ( all_zones ) {
my $sourcezone = ( split( /:/, $source, 2 ) )[0]; my $sourcezone = ( split( /:/, $source, 2 ) )[0];
if ( ( $includedstfw || ( zone_type( $zone ) ne 'firewall') ) && ( ( $sourcezone ne $zone ) || $intrazone) ) { if ( ( $includedstfw || ( zone_type( $zone ) != ZT_FIREWALL ) ) && ( ( $sourcezone ne $zone ) || $intrazone) ) {
process_rule1 $target, $source, $zone , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, 1; process_rule1 $target, $source, $zone , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, 1;
} }
} }
@ -1528,11 +1528,11 @@ sub generate_matrix() {
if ( $capabilities{POLICY_MATCH} ) { if ( $capabilities{POLICY_MATCH} ) {
my $type = $zoneref->{type}; my $type = $zoneref->{type};
my $source_ref = ( $zoneref->{hosts}{ipsec4} ) || {}; my $source_ref = ( $zoneref->{hosts}{+ZT_IPSEC4} ) || {};
if ( $config{DYNAMIC_ZONES} ) { if ( $config{DYNAMIC_ZONES} ) {
no warnings; no warnings;
create_zone_dyn_chain $zone, $frwd_ref if (%$source_ref || $type eq 'ipsec4' ); create_zone_dyn_chain $zone, $frwd_ref if (%$source_ref || $type & ZT_IPSEC );
} }
for my $interface ( keys %$source_ref ) { for my $interface ( keys %$source_ref ) {
@ -1671,7 +1671,7 @@ sub generate_matrix() {
next if ( scalar ( keys( %{ $zoneref->{interfaces}} ) ) < 2 ) && ! ( $zoneref->{options}{in_out}{routeback} || @$exclusions ); next if ( scalar ( keys( %{ $zoneref->{interfaces}} ) ) < 2 ) && ! ( $zoneref->{options}{in_out}{routeback} || @$exclusions );
} }
if ( $zone1ref->{type} eq 'bport4' ) { if ( $zone1ref->{type} & ZT_BPORT ) {
next unless $zoneref->{bridge} eq $zone1ref->{bridge}; next unless $zoneref->{bridge} eq $zone1ref->{bridge};
} }
@ -1736,7 +1736,7 @@ sub generate_matrix() {
} }
} }
if ( $zone1ref->{type} eq 'bport4' ) { if ( $zone1ref->{type} & ZT_BPORT ) {
next ZONE1 unless $zoneref->{bridge} eq $zone1ref->{bridge}; next ZONE1 unless $zoneref->{bridge} eq $zone1ref->{bridge};
} }

View File

@ -82,7 +82,7 @@ sub setup_tunnels() {
unless ( $gatewayzones eq '-' ) { unless ( $gatewayzones eq '-' ) {
for my $zone ( split /,/, $gatewayzones ) { for my $zone ( split /,/, $gatewayzones ) {
my $type = zone_type( $zone ); my $type = zone_type( $zone );
fatal_error "Invalid zone ($zone) for GATEWAY ZONE" if $type eq 'firewall' || $type eq 'bport4'; fatal_error "Invalid zone ($zone) for GATEWAY ZONE" if $type == ZT_FIREWALL || $type & ZT_BPORT;
$inchainref = ensure_filter_chain "${zone}2${fw}", 1; $inchainref = ensure_filter_chain "${zone}2${fw}", 1;
$outchainref = ensure_filter_chain "${fw}2${zone}", 1; $outchainref = ensure_filter_chain "${fw}2${zone}", 1;
@ -228,7 +228,7 @@ sub setup_tunnels() {
my $zonetype = zone_type( $zone ); my $zonetype = zone_type( $zone );
fatal_error "Invalid zone ($zone) for tunnel ZONE" if $zonetype eq 'firewall' || $zonetype eq 'bport4'; fatal_error "Invalid zone ($zone) for tunnel ZONE" if $zonetype == ZT_FIREWALL || $zonetype & ZT_BPORT;
my $inchainref = ensure_filter_chain "${zone}2${fw}", 1; my $inchainref = ensure_filter_chain "${zone}2${fw}", 1;
my $outchainref = ensure_filter_chain "${fw}2${zone}", 1; my $outchainref = ensure_filter_chain "${fw}2${zone}", 1;

View File

@ -37,6 +37,16 @@ our @EXPORT = qw( NOTHING
IPSECPROTO IPSECPROTO
IPSECMODE IPSECMODE
ZT_IPV4
ZT_IPSEC
ZT_BPORT
ZT_IPV6
ZT_IPSEC4
ZT_IPSEC6
ZT_BPORT4
ZT_BPORT6
ZT_FIREWALL
numeric_value numeric_value
determine_zones determine_zones
zone_report zone_report
@ -81,7 +91,7 @@ use constant { NOTHING => 'NOTHING',
# #
# @zones contains the ordered list of zones with sub-zones appearing before their parents. # @zones contains the ordered list of zones with sub-zones appearing before their parents.
# #
# %zones{<zone1> => {type = > <zone type> 'firewall', 'ipv4', 'ipsec4', 'bport4'; # %zones{<zone1> => {type = > <zone type> (see above).
# options => { complex => 0|1 # options => { complex => 0|1
# in_out => < policy match string > # in_out => < policy match string >
# in => < policy match string > # in => < policy match string >
@ -116,6 +126,27 @@ our %reservedName = ( all => 1,
DEST => 1 ); DEST => 1 );
# #
# Zone Types
#
use constant { ZT_IPV4 => 1,
ZT_IPSEC => 2,
ZT_BPORT => 4,
ZT_IPV6 => 8,
ZT_FIREWALL => 16,
ZT_IPSEC4 => 3,
ZT_IPSEC6 => 10,
ZT_BPORT4 => 5,
ZT_BPORT6 => 13,
};
our %zonetypes = ( 1 => 'ipv4' ,
3 => 'ipsec4' ,
5 => 'bport4' ,
8 => 'ipv6' ,
10 => 'ipsec6' ,
13 => 'bport6' ,
16 => 'firewall' );
#
# Interface Table. # Interface Table.
# #
# @interfaces lists the interface names in the order that they appear in the interfaces file. # @interfaces lists the interface names in the order that they appear in the interfaces file.
@ -223,7 +254,7 @@ sub parse_zone_option_list($$)
if ( $key{$e} ) { if ( $key{$e} ) {
$h{$e} = $val; $h{$e} = $val;
} else { } else {
fatal_error "The \"$e\" option may only be specified for ipsec zones" unless $zonetype eq 'ipsec4'; fatal_error "The \"$e\" option may only be specified for ipsec zones" unless ( $zonetype & ZT_IPSEC );
$options .= $invert; $options .= $invert;
$options .= "--$e "; $options .= "--$e ";
$options .= "$val "if defined $val; $options .= "$val "if defined $val;
@ -265,7 +296,7 @@ sub determine_zones()
for my $p ( @parents ) { for my $p ( @parents ) {
fatal_error "Invalid Parent List ($2)" unless $p; fatal_error "Invalid Parent List ($2)" unless $p;
fatal_error "Unknown parent zone ($p)" unless $zones{$p}; fatal_error "Unknown parent zone ($p)" unless $zones{$p};
fatal_error 'Subzones of firewall zone not allowed' if $zones{$p}{type} eq 'firewall'; fatal_error 'Subzones of firewall zone not allowed' if $zones{$p}{type} == ZT_FIREWALL;
push @{$zones{$p}{children}}, $zone; push @{$zones{$p}{children}}, $zone;
} }
} }
@ -277,20 +308,25 @@ sub determine_zones()
$type = "ipv4" unless $type; $type = "ipv4" unless $type;
if ( $type =~ /ipv4/i ) { if ( $type =~ /ipv4/i ) {
$type = 'ipv4'; $type = ZT_IPV4;
} elsif ( $type =~ /^ipsec4?$/i ) { } elsif ( $type =~ /^ipsec4?$/i ) {
$type = 'ipsec4'; $type = ZT_IPSEC4;
} elsif ( $type =~ /^ipsec6$/i ) {
$type = ZT_IPSEC6;
} elsif ( $type =~ /^bport4?$/i ) { } elsif ( $type =~ /^bport4?$/i ) {
warning_message "Bridge Port zones should have a parent zone" unless @parents; warning_message "Bridge Port zones should have a parent zone" unless @parents;
$type = 'bport4'; $type = ZT_BPORT4;
} elsif ( $type =~ /^bport6$/i ) {
warning_message "Bridge Port zones should have a parent zone" unless @parents;
$type = ZT_BPORT6;
} elsif ( $type eq 'firewall' ) { } elsif ( $type eq 'firewall' ) {
fatal_error 'Firewall zone may not be nested' if @parents; fatal_error 'Firewall zone may not be nested' if @parents;
fatal_error "Only one firewall zone may be defined ($zone)" if $firewall_zone; fatal_error "Only one firewall zone may be defined ($zone)" if $firewall_zone;
$firewall_zone = $zone; $firewall_zone = $zone;
$ENV{FW} = $zone; $ENV{FW} = $zone;
$type = "firewall"; $type = ZT_FIREWALL;
} elsif ( $type eq '-' ) { } elsif ( $type eq '-' ) {
$type = 'ipv4'; $type = ZT_IPV4;
} else { } else {
fatal_error "Invalid zone type ($type)" ; fatal_error "Invalid zone type ($type)" ;
} }
@ -306,7 +342,7 @@ sub determine_zones()
options => { in_out => parse_zone_option_list( $options || '', $type ) , options => { in_out => parse_zone_option_list( $options || '', $type ) ,
in => parse_zone_option_list( $in_options || '', $type ) , in => parse_zone_option_list( $in_options || '', $type ) ,
out => parse_zone_option_list( $out_options || '', $type ) , out => parse_zone_option_list( $out_options || '', $type ) ,
complex => ($type eq 'ipsec4' || $options || $in_options || $out_options ? 1 : 0) } , complex => ( ( $type & ZT_IPSEC ) || $options || $in_options || $out_options ? 1 : 0) } ,
interfaces => {} , interfaces => {} ,
children => [] , children => [] ,
hosts => {} hosts => {}
@ -341,7 +377,7 @@ sub determine_zones()
# #
sub haveipseczones() { sub haveipseczones() {
for my $zoneref ( values %zones ) { for my $zoneref ( values %zones ) {
return 1 if $zoneref->{type} eq 'ipsec4'; return 1 if ( $zoneref->{type} & ZT_IPSEC );
} }
0; 0;
@ -361,7 +397,7 @@ sub zone_report()
my $type = $zoneref->{type}; my $type = $zoneref->{type};
my $optionref = $zoneref->{options}; my $optionref = $zoneref->{options};
progress_message " $zone ($type)"; progress_message " $zone ($zonetypes{$type})";
my $printed = 0; my $printed = 0;
@ -385,8 +421,8 @@ sub zone_report()
} }
unless ( $printed ) { unless ( $printed ) {
fatal_error "No bridge has been associated with zone $zone" if $type eq 'bport4' && ! $zoneref->{bridge}; fatal_error "No bridge has been associated with zone $zone" if ( $type & ZT_BPORT ) && ! $zoneref->{bridge};
warning_message "*** $zone is an EMPTY ZONE ***" unless $type eq 'firewall'; warning_message "*** $zone is an EMPTY ZONE ***" unless $type == ZT_FIREWALL;
} }
} }
@ -401,9 +437,9 @@ sub dump_zone_contents()
my $type = $zoneref->{type}; my $type = $zoneref->{type};
my $optionref = $zoneref->{options}; my $optionref = $zoneref->{options};
my $exclusions = $zoneref->{exclusions}; my $exclusions = $zoneref->{exclusions};
my $entry = "$zone $type"; my $entry = "$zone $zonetypes{$type}";
$entry .= ":$zoneref->{bridge}" if $type eq 'bport4'; $entry .= ":$zoneref->{bridge}" if $type & ZT_BPORT;
if ( $hostref ) { if ( $hostref ) {
for my $type ( sort keys %$hostref ) { for my $type ( sort keys %$hostref ) {
@ -478,7 +514,7 @@ sub add_group_to_zone($$$$$)
} }
unless ( $switched ) { unless ( $switched ) {
if ( $type eq $zonetype ) { if ( $type == $zonetype ) {
fatal_error "Duplicate Host Group ($interface:$host) in zone $zone" if $ifacezone eq $zone; fatal_error "Duplicate Host Group ($interface:$host) in zone $zone" if $ifacezone eq $zone;
$ifacezone = $zone if $host eq ALLIPv4; $ifacezone = $zone if $host eq ALLIPv4;
} }
@ -505,7 +541,7 @@ sub add_group_to_zone($$$$$)
push @{$arrayref}, { options => $options, push @{$arrayref}, { options => $options,
hosts => \@newnetworks, hosts => \@newnetworks,
ipsec => $type eq 'ipsec4' ? 'ipsec' : 'none' }; ipsec => $type & ZT_IPSEC ? 'ipsec' : 'none' };
} }
# #
@ -535,7 +571,7 @@ sub all_zones() {
} }
sub non_firewall_zones() { sub non_firewall_zones() {
grep ( $zones{$_}{type} ne 'firewall' , @zones ); grep ( $zones{$_}{type} != ZT_FIREWALL , @zones );
} }
sub complex_zones() { sub complex_zones() {
@ -631,7 +667,7 @@ sub validate_interfaces_file( $ )
$zoneref = $zones{$zone}; $zoneref = $zones{$zone};
fatal_error "Unknown zone ($zone)" unless $zoneref; fatal_error "Unknown zone ($zone)" unless $zoneref;
fatal_error "Firewall zone not allowed in ZONE column of interface record" if $zoneref->{type} eq 'firewall'; fatal_error "Firewall zone not allowed in ZONE column of interface record" if $zoneref->{type} == ZT_FIREWALL;
} }
$networks = '' if $networks eq '-'; $networks = '' if $networks eq '-';
@ -648,7 +684,7 @@ sub validate_interfaces_file( $ )
require_capability( 'KLUDGEFREE', 'Bridge Ports', ''); require_capability( 'KLUDGEFREE', 'Bridge Ports', '');
fatal_error "Duplicate Interface ($port)" if $interfaces{$port}; fatal_error "Duplicate Interface ($port)" if $interfaces{$port};
fatal_error "$interface is not a defined bridge" unless $interfaces{$interface} && $interfaces{$interface}{options}{bridge}; fatal_error "$interface is not a defined bridge" unless $interfaces{$interface} && $interfaces{$interface}{options}{bridge};
fatal_error "Bridge Ports may only be associated with 'bport' zones" if $zone && $zoneref->{type} ne 'bport4'; fatal_error "Bridge Ports may only be associated with 'bport' zones" if $zone && ! ( $zoneref->{type} & ZT_BPORT );
if ( $zone ) { if ( $zone ) {
if ( $zoneref->{bridge} ) { if ( $zoneref->{bridge} ) {
@ -668,7 +704,7 @@ sub validate_interfaces_file( $ )
$interface = $port; $interface = $port;
} else { } else {
fatal_error "Duplicate Interface ($interface)" if $interfaces{$interface}; fatal_error "Duplicate Interface ($interface)" if $interfaces{$interface};
fatal_error "Zones of type 'bport' may only be associated with bridge ports" if $zone && $zoneref->{type} eq 'bport4'; fatal_error "Zones of type 'bport' may only be associated with bridge ports" if $zone && $zoneref->{type} & ZT_BPORT;
$interfaces{$interface}{bridge} = $interface; $interfaces{$interface}{bridge} = $interface;
} }
@ -934,7 +970,7 @@ sub validate_hosts_file()
my $type = $zoneref->{type}; my $type = $zoneref->{type};
fatal_error "Unknown ZONE ($zone)" unless $type; fatal_error "Unknown ZONE ($zone)" unless $type;
fatal_error 'Firewall zone not allowed in ZONE column of hosts record' if $type eq 'firewall'; fatal_error 'Firewall zone not allowed in ZONE column of hosts record' if $type == ZT_FIREWALL;
my $interface; my $interface;
@ -947,7 +983,7 @@ sub validate_hosts_file()
fatal_error "Invalid HOST(S) column contents: $hosts"; fatal_error "Invalid HOST(S) column contents: $hosts";
} }
if ( $type eq 'bport4' ) { if ( $type & ZT_BPORT ) {
if ( $zoneref->{bridge} eq '' ) { if ( $zoneref->{bridge} eq '' ) {
fatal_error 'Bridge Port Zones may only be associated with bridge ports' unless $interfaces{$interface}{options}{port}; fatal_error 'Bridge Port Zones may only be associated with bridge ports' unless $interfaces{$interface}{options}{port};
$zoneref->{bridge} = $interfaces{$interface}{bridge}; $zoneref->{bridge} = $interfaces{$interface}{bridge};
@ -965,7 +1001,7 @@ sub validate_hosts_file()
for my $option ( @options ) for my $option ( @options )
{ {
if ( $option eq 'ipsec' ) { if ( $option eq 'ipsec' ) {
$type = 'ipsec4'; $type = ZT_IPSEC4;
$zoneref->{options}{complex} = 1; $zoneref->{options}{complex} = 1;
$ipsec = 1; $ipsec = 1;
} elsif ( $validoptions{$option}) { } elsif ( $validoptions{$option}) {
@ -1008,7 +1044,7 @@ sub find_hosts_by_option( $ ) {
my $option = $_[0]; my $option = $_[0];
my @hosts; my @hosts;
for my $zone ( grep $zones{$_}{type} ne 'firewall' , @zones ) { for my $zone ( grep $zones{$_}{type} != ZT_FIREWALL , @zones ) {
while ( my ($type, $interfaceref) = each %{$zones{$zone}{hosts}} ) { while ( my ($type, $interfaceref) = each %{$zones{$zone}{hosts}} ) {
while ( my ( $interface, $arrayref) = ( each %{$interfaceref} ) ) { while ( my ( $interface, $arrayref) = ( each %{$interfaceref} ) ) {
for my $host ( @{$arrayref} ) { for my $host ( @{$arrayref} ) {