forked from extern/shorewall_code
Move pic of house to web/images
git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@8853 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
This commit is contained in:
parent
c2cc895b3a
commit
8b5792052b
@ -35,7 +35,7 @@
|
||||
#
|
||||
|
||||
SHOREWALL_LIBVERSION=40000
|
||||
SHOREWALL_CAPVERSION=40200
|
||||
SHOREWALL_CAPVERSION=40202
|
||||
|
||||
[ -n "${VARDIR:=/var/lib/shorewall}" ]
|
||||
[ -n "${SHAREDIR:=/usr/share/shorewall}" ]
|
||||
@ -1047,6 +1047,7 @@ determine_capabilities() {
|
||||
|
||||
CONNTRACK_MATCH=
|
||||
NEW_CONNTRACK_MATCH=
|
||||
OLD_CONNTRACK_MATCH=
|
||||
MULTIPORT=
|
||||
XMULTIPORT=
|
||||
POLICY_MATCH=
|
||||
@ -1105,6 +1106,7 @@ determine_capabilities() {
|
||||
|
||||
if [ -n "$CONNTRACK_MATCH" ]; then
|
||||
qt $IPTABLES -A $chain -m conntrack -p tcp --ctorigdstport 22 -j ACCEPT && NEW_CONNTRACK_MATCH=Yes
|
||||
qt $IPTABLES -A $chain -m conntrack ! --ctorigdst 1.2.3.4 || OLD_CONNTRACK_MATCH=Yes
|
||||
fi
|
||||
|
||||
if qt $IPTABLES -A $chain -p tcp -m multiport --dports 21,22 -j ACCEPT; then
|
||||
@ -1211,7 +1213,10 @@ report_capabilities() {
|
||||
report_capability "Multi-port Match" $MULTIPORT
|
||||
[ -n "$MULTIPORT" ] && report_capability "Extended Multi-port Match" $XMULTIPORT
|
||||
report_capability "Connection Tracking Match" $CONNTRACK_MATCH
|
||||
[ -n "$CONNTRACK_MATCH" ] && report_capability "Extended Connection Tracking Match Support" $NEW_CONNTRACK_MATCH
|
||||
if [ -n "$CONNTRACK_MATCH" ]; then
|
||||
report_capability "Extended Connection Tracking Match Support" $NEW_CONNTRACK_MATCH
|
||||
report_capability "Old Connection Tracking Match Syntax" $OLD_CONNTRACK_MATCH
|
||||
fi
|
||||
report_capability "Packet Type Match" $USEPKTTYPE
|
||||
report_capability "Policy Match" $POLICY_MATCH
|
||||
report_capability "Physdev Match" $PHYSDEV_MATCH
|
||||
@ -1263,6 +1268,7 @@ report_capabilities1() {
|
||||
report_capability1 XMULTIPORT
|
||||
report_capability1 CONNTRACK_MATCH
|
||||
report_capability1 NEW_CONNTRACK_MATCH
|
||||
report_capability1 OLD_CONNTRACK_MATCH
|
||||
report_capability1 USEPKTTYPE
|
||||
report_capability1 POLICY_MATCH
|
||||
report_capability1 PHYSDEV_MATCH
|
||||
|
@ -43,9 +43,11 @@ our @EXPORT = qw( merge_levels
|
||||
process_actions3
|
||||
|
||||
find_macro
|
||||
find_6macro
|
||||
split_action
|
||||
substitute_param
|
||||
merge_macro_source_dest
|
||||
merge_6macro_source_dest
|
||||
merge_macro_column
|
||||
|
||||
%usedactions
|
||||
@ -53,6 +55,7 @@ our @EXPORT = qw( merge_levels
|
||||
%actions
|
||||
|
||||
%macros
|
||||
%macros6
|
||||
$macro_commands
|
||||
);
|
||||
our @EXPORT_OK = qw( initialize );
|
||||
@ -82,6 +85,7 @@ our %actions;
|
||||
our %logactionchains;
|
||||
|
||||
our %macros;
|
||||
our %macros6;
|
||||
|
||||
#
|
||||
# Commands that can be embedded in a macro file and how many total tokens on the line (0 => unlimited).
|
||||
@ -105,6 +109,8 @@ sub initialize() {
|
||||
QUEUE => 'none' );
|
||||
%actions = ();
|
||||
%logactionchains = ();
|
||||
%macros = ();
|
||||
%macros6 = ();
|
||||
}
|
||||
|
||||
INIT {
|
||||
@ -162,6 +168,19 @@ sub find_macro( $ )
|
||||
}
|
||||
}
|
||||
|
||||
sub find_6macro( $ )
|
||||
{
|
||||
my $macro = $_[0];
|
||||
my $macrofile = find_file "macro.$macro";
|
||||
|
||||
if ( -f $macrofile ) {
|
||||
$macros6{$macro} = $macrofile;
|
||||
$targets6{$macro} = MACRO;
|
||||
} else {
|
||||
0;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Return ( action, level[:tag] ) from passed full action
|
||||
#
|
||||
@ -212,6 +231,22 @@ sub merge_macro_source_dest( $$ ) {
|
||||
$body || '';
|
||||
}
|
||||
|
||||
sub merge_6macro_source_dest( $$ ) {
|
||||
my ( $body, $invocation ) = @_;
|
||||
|
||||
if ( $invocation ) {
|
||||
if ( $body ) {
|
||||
return $body if $invocation eq '-';
|
||||
return "$body;$invocation" if $invocation =~ /:|.*?\.*?\.|^\+|^~|^!~/;
|
||||
return "$invocation;$body";
|
||||
}
|
||||
|
||||
return $invocation;
|
||||
}
|
||||
|
||||
$body || '';
|
||||
}
|
||||
|
||||
sub merge_macro_column( $$ ) {
|
||||
my ( $body, $invocation ) = @_;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -41,7 +41,7 @@ use Shorewall::Proxyarp;
|
||||
our @ISA = qw(Exporter);
|
||||
our @EXPORT = qw( compiler EXPORT TIMESTAMP DEBUG );
|
||||
our @EXPORT_OK = qw( $export );
|
||||
our $VERSION = 4.1.4;
|
||||
our $VERSION = 4.3.0;
|
||||
|
||||
our $export;
|
||||
|
||||
@ -168,6 +168,13 @@ sub generate_script_1() {
|
||||
emit( 'IPTABLES_RESTORE=${IPTABLES}-restore',
|
||||
'[ -x "$IPTABLES_RESTORE" ] || startup_error "$IPTABLES_RESTORE does not exist or is not executable"' );
|
||||
|
||||
if ( $config{IPV6} eq 'On' ) {
|
||||
emit( 'IP6TABLES=$(dirname ${IPTABLES})/ip6tables',
|
||||
'[ -x "$IPTABLES_RESTORE" ] || startup_error "$IP6TABLES_RESTORE does not exist or is not executable"' );
|
||||
emit( 'IP6TABLES_RESTORE=$(dirname ${IPTABLES})/ip6tables-restore',
|
||||
'[ -x "$IP6TABLES_RESTORE" ] || startup_error "$IP6TABLES_RESTORE does not exist or is not executable"' );
|
||||
}
|
||||
|
||||
append_file 'params' if $config{EXPORTPARAMS};
|
||||
|
||||
emit ( '',
|
||||
|
@ -114,7 +114,7 @@ our %EXPORT_TAGS = ( internal => [ qw( create_temp_object
|
||||
|
||||
Exporter::export_ok_tags('internal');
|
||||
|
||||
our $VERSION = 4.2.0;
|
||||
our $VERSION = 4.3.0;
|
||||
|
||||
#
|
||||
# describe the current command, it's present progressive, and it's completion.
|
||||
@ -163,7 +163,7 @@ our %config;
|
||||
#
|
||||
# Config options and global settings that are to be copied to object script
|
||||
#
|
||||
our @propagateconfig = qw/ DISABLE_IPV6 MODULESDIR MODULE_SUFFIX LOGFORMAT SUBSYSLOCK LOCKFILE /;
|
||||
our @propagateconfig = qw/ IPV6 MODULESDIR MODULE_SUFFIX LOGFORMAT SUBSYSLOCK LOCKFILE /;
|
||||
our @propagateenv = qw/ LOGLIMIT LOGTAGONLY LOGRULENUMBERS /;
|
||||
#
|
||||
# From parsing the capabilities file
|
||||
@ -177,6 +177,8 @@ our %capdesc = ( NAT_ENABLED => 'NAT',
|
||||
MULTIPORT => 'Multi-port Match' ,
|
||||
XMULTIPORT => 'Extended Multi-port Match',
|
||||
CONNTRACK_MATCH => 'Connection Tracking Match',
|
||||
OLD_CONNTRACK_MATCH =>
|
||||
'Old conntrack match syntax',
|
||||
NEW_CONNTRACK_MATCH =>
|
||||
'Extended Connection Tracking Match',
|
||||
USEPKTTYPE => 'Packet Type Match',
|
||||
@ -271,7 +273,7 @@ sub initialize() {
|
||||
LOGPARMS => '',
|
||||
TC_SCRIPT => '',
|
||||
VERSION => "4.2.1",
|
||||
CAPVERSION => 40200 ,
|
||||
CAPVERSION => 40202 ,
|
||||
);
|
||||
#
|
||||
# From shorewall.conf file
|
||||
@ -348,6 +350,7 @@ sub initialize() {
|
||||
DELAYBLACKLISTLOAD => undef,
|
||||
MODULE_SUFFIX => undef,
|
||||
DISABLE_IPV6 => undef,
|
||||
IPV6 => undef,
|
||||
DYNAMIC_ZONES => undef,
|
||||
PKTTYPE=> undef,
|
||||
RFC1918_STRICT => undef,
|
||||
@ -389,6 +392,7 @@ sub initialize() {
|
||||
XMULTIPORT => undef,
|
||||
CONNTRACK_MATCH => undef,
|
||||
NEW_CONNTRACK_MATCH => undef,
|
||||
OLD_CONNTRACK_MATCH => undef,
|
||||
USEPKTTYPE => undef,
|
||||
POLICY_MATCH => undef,
|
||||
PHYSDEV_MATCH => undef,
|
||||
@ -765,12 +769,14 @@ sub copy( $ ) {
|
||||
open IF , $file or fatal_error "Unable to open $file: $!";
|
||||
|
||||
while ( <IF> ) {
|
||||
chomp;
|
||||
if ( /^\s*$/ ) {
|
||||
print $object "\n" unless $lastlineblank;
|
||||
$lastlineblank = 1;
|
||||
} else {
|
||||
s/^/$indent/ if $indent;
|
||||
print $object $_;
|
||||
print $object "\n";
|
||||
$lastlineblank = 0;
|
||||
}
|
||||
}
|
||||
@ -791,6 +797,7 @@ sub copy1( $ ) {
|
||||
my $do_indent = 1;
|
||||
|
||||
while ( <IF> ) {
|
||||
chomp;
|
||||
if ( /^\s*$/ ) {
|
||||
print $object "\n";
|
||||
$do_indent = 1;
|
||||
@ -799,6 +806,7 @@ sub copy1( $ ) {
|
||||
|
||||
s/^/$indent/ if $indent && $do_indent;
|
||||
print $object $_;
|
||||
print $object "\n";
|
||||
$do_indent = ! ( /\\$/ );
|
||||
}
|
||||
|
||||
@ -1557,8 +1565,9 @@ sub determine_capabilities( $ ) {
|
||||
|
||||
$capabilities{CONNTRACK_MATCH} = qt1( "$iptables -A $sillyname -m conntrack --ctorigdst 192.168.1.1 -j ACCEPT" );
|
||||
|
||||
if ( $capabilities{CONNTRACL_MATCH} ) {
|
||||
if ( $capabilities{CONNTRACK_MATCH} ) {
|
||||
$capabilities{NEW_CONNTRACK_MATCH} = qt1( "$iptables -A $sillyname -m conntrack -p tcp --ctorigdstport 22 -j ACCEPT" );
|
||||
$capabilities{OLD_CONNTRACK_MATCH} = ! qt1( "$iptables -A $sillyname -m conntrack ! --ctorigdstport 1.2.3.4" );
|
||||
}
|
||||
|
||||
if ( qt1( "$iptables -A $sillyname -p tcp -m multiport --dports 21,22 -j ACCEPT" ) ) {
|
||||
@ -1892,7 +1901,22 @@ sub get_configuration( $ ) {
|
||||
|
||||
default_yes_no 'ADMINISABSENTMINDED' , '';
|
||||
default_yes_no 'BLACKLISTNEWONLY' , '';
|
||||
default_yes_no 'DISABLE_IPV6' , '';
|
||||
|
||||
if ( defined $config{IPV6} ) {
|
||||
if ( $config{IPV6} =~ /on/i ) {
|
||||
$config{IPV6} = 'On';
|
||||
} elsif ( $config{IPV6} =~ /off/i ) {
|
||||
$config{IPV6} = 'Off';
|
||||
} elsif ( $config{IPV6} =~ /keep/i ) {
|
||||
$config{IPV6} = '';
|
||||
}
|
||||
}
|
||||
|
||||
default_yes_no 'DISABLE_IPV6' , '';
|
||||
|
||||
fatal_error "Incompatible settings of IPV6 (On) and DISABLE_IPV6 (Yes)" if $config{IPV6} eq 'On' && $config{DISABLE_IPV6} eq 'Yes';
|
||||
|
||||
$config{IPV6} = $config{DISABLE_IPV6} ? 'Off' : '' unless defined $config{IPV6};
|
||||
|
||||
unsupported_yes_no 'DYNAMIC_ZONES';
|
||||
unsupported_yes_no 'BRIDGING';
|
||||
|
@ -26,25 +26,36 @@
|
||||
#
|
||||
package Shorewall::IPAddrs;
|
||||
require Exporter;
|
||||
use Socket6;
|
||||
use Shorewall::Config qw( :DEFAULT split_list require_capability in_hex8);
|
||||
|
||||
use strict;
|
||||
|
||||
our @ISA = qw(Exporter);
|
||||
our @EXPORT = qw( ALLIPv4
|
||||
ALLIPv6
|
||||
TCP
|
||||
UDP
|
||||
ICMP
|
||||
IPv6_ICMP
|
||||
SCTP
|
||||
|
||||
F_INET
|
||||
F_INET6
|
||||
|
||||
validate_address
|
||||
validate_6address
|
||||
validate_net
|
||||
validate_6net
|
||||
decompose_net
|
||||
validate_host
|
||||
validate_6host
|
||||
validate_range
|
||||
validate_6range
|
||||
ip_range_explicit
|
||||
expand_port_range
|
||||
allipv4
|
||||
allipv6
|
||||
rfc1918_networks
|
||||
resolve_proto
|
||||
proto_name
|
||||
@ -54,14 +65,23 @@ our @EXPORT = qw( ALLIPv4
|
||||
validate_icmp
|
||||
);
|
||||
our @EXPORT_OK = qw( );
|
||||
our $VERSION = 4.1.5;
|
||||
our $VERSION = 4.3.0;
|
||||
|
||||
#
|
||||
# Some IPv4 useful stuff
|
||||
# Some IPv4/6 useful stuff
|
||||
#
|
||||
our @allipv4 = ( '0.0.0.0/0' );
|
||||
our @allipv6 = ( '::/0' );
|
||||
|
||||
use constant { ALLIPv4 => '0.0.0.0/0' , ICMP => 1, TCP => 6, UDP => 17 , SCTP => 132 };
|
||||
use constant { ALLIPv4 => '0.0.0.0/0' ,
|
||||
ALLIPv6 => '::/0' ,
|
||||
F_INET => 1,
|
||||
F_INET6 => 2,
|
||||
ICMP => 1,
|
||||
TCP => 6,
|
||||
UDP => 17,
|
||||
ICMPv6_ICMP => 58,
|
||||
SCTP => 132 };
|
||||
|
||||
our @rfc1918_networks = ( "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16" );
|
||||
|
||||
@ -95,8 +115,7 @@ sub validate_address( $$ ) {
|
||||
if ( defined wantarray ) {
|
||||
shift @addrs for (1..4);
|
||||
for ( @addrs ) {
|
||||
my (@a) = unpack('C4',$_);
|
||||
$_ = join('.', @a );
|
||||
$_ = inet_htoa $_;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -223,6 +242,10 @@ sub allipv4() {
|
||||
@allipv4;
|
||||
}
|
||||
|
||||
sub allipv6() {
|
||||
@allipv6;
|
||||
}
|
||||
|
||||
sub rfc1918_networks() {
|
||||
@rfc1918_networks
|
||||
}
|
||||
@ -231,7 +254,7 @@ sub rfc1918_networks() {
|
||||
# Protocol/port validation
|
||||
#
|
||||
|
||||
our %nametoproto = ( all => 0, ALL => 0, icmp => 1, ICMP => 1, tcp => 6, TCP => 6, udp => 17, UDP => 17 );
|
||||
our %nametoproto = ( all => 0, ALL => 0, icmp => 1, ICMP => 1, tcp => 6, TCP => 6, udp => 17, UDP => 17 );
|
||||
our @prototoname = ( 'all', 'icmp', '', '', '', '', 'tcp', '', '', '', '', '', '', '', '', '', '', 'udp' );
|
||||
|
||||
#
|
||||
@ -419,4 +442,121 @@ sub expand_port_range( $$ ) {
|
||||
}
|
||||
}
|
||||
|
||||
sub valid_6address( $ ) {
|
||||
my $address = $_[0];
|
||||
|
||||
my @address = split /:/, $address;
|
||||
|
||||
return 0 if @address > 8;
|
||||
return 0 if @address < 8 && ! $address =~ /::/;
|
||||
return 0 if $address =~ /:::/ || $address =~ /::.*::/;
|
||||
|
||||
if ( $address =~ /^:/ ) {
|
||||
unless ( $address eq '::' ) {
|
||||
return 0 if $address =~ /:$/ || $address =~ /^:.*::/;
|
||||
}
|
||||
} elsif ( $address =~ /:$/ ) {
|
||||
return 0 if $address =~ /::.*:$/;
|
||||
}
|
||||
|
||||
for my $a ( @address ) {
|
||||
return 0 unless $a eq '' || ( $a =~ /^[a-fA-f\d]+$/ && oct "0x$a" < 65536 );
|
||||
}
|
||||
|
||||
1;
|
||||
}
|
||||
|
||||
sub validate_6address( $$ ) {
|
||||
my ( $addr, $allow_name ) = @_;
|
||||
|
||||
my @addrs = ( $addr );
|
||||
|
||||
unless ( valid_6address $addr ) {
|
||||
fatal_error "Invalid IPv6 Address ($addr)" unless $allow_name;
|
||||
fatal_error "Unknown Host ($addr)" unless (@addrs = gethostbyname2 $addr, AF_INET6);
|
||||
|
||||
if ( defined wantarray ) {
|
||||
shift @addrs for (1..4);
|
||||
for ( @addrs ) {
|
||||
$_ = inet_ntop AF_INET6, $_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defined wantarray ? wantarray ? @addrs : $addrs[0] : undef;
|
||||
}
|
||||
}
|
||||
|
||||
sub validate_6net( $ ) {
|
||||
my ($net, $vlsm, $rest) = split( '/', $_[0], 3 );
|
||||
|
||||
fatal_error "An ipset name ($net) is not allowed in this context" if substr( $net, 0, 1 ) eq '+';
|
||||
|
||||
if ( defined $vlsm ) {
|
||||
fatal_error "Invalid VLSM ($vlsm)" unless $vlsm =~ /^\d+$/ && $vlsm <= 64;
|
||||
fatal_error "Invalid Network address ($_[0])" if defined $rest;
|
||||
fatal_error "Invalid IPv6 address ($net)" unless valid_6address $net;
|
||||
} else {
|
||||
fatal_error "Invalid Network address ($_[0])" if $_[0] =~ '/' || ! defined $net;
|
||||
validate_6address $net;
|
||||
}
|
||||
}
|
||||
|
||||
sub validate_6range( $$ ) {
|
||||
my ( $low, $high ) = @_;
|
||||
|
||||
validate_6address $low, 0;
|
||||
validate_6address $high, 0;
|
||||
|
||||
my @low = split ":", $low;
|
||||
my @high = split ":", $high;
|
||||
|
||||
if ( @low == @high ) {
|
||||
my ( $l, $h) = ( pop @low, pop @high );
|
||||
|
||||
return 1 if hex "0x$l" <= hex "0x$h" && join( ":", @low ) eq join( ":", @high );
|
||||
}
|
||||
|
||||
fatal_error "Invalid IPv6 Range ($low-$high)";
|
||||
}
|
||||
|
||||
my %ipv6_icmp_types = ( any => 'any',
|
||||
'destination-unreachable' => 1,
|
||||
'no-route' => '1/0',
|
||||
'communication-prohibited' => '1/1',
|
||||
'address-unreachable' => '1/2',
|
||||
'port-unreachable' => '1/3',
|
||||
'packet-too-big' => 2,
|
||||
'time-exceeded' => 3,
|
||||
'ttl-exceeded' => 3,
|
||||
'ttl-zero-during-transit' => '3/0',
|
||||
'ttl-zero-during-reassembly' => '3/1',
|
||||
'parameter-problem' => 4
|
||||
'bad-header' => '4/0',
|
||||
'unknown-header-type' => '4/1',
|
||||
'unknown-option' => '4/2',
|
||||
'echo-request' => 128,
|
||||
'echo-reply' => 129,
|
||||
'router-solicitation' => 133,
|
||||
'router-advertisement' => 134,
|
||||
'neighbour-solicitation' => 135,
|
||||
'neighbour-advertisement' => 136,
|
||||
redirect => 137 );
|
||||
|
||||
|
||||
sub validate_icmp6( $ ) {
|
||||
my $type = $_[0];
|
||||
|
||||
my $value = $ipv6_icmp_types{$type};
|
||||
|
||||
return $value if defined $value;
|
||||
|
||||
if ( $type =~ /^(\d+)(\/(\d+))?$/ ) {
|
||||
return $type if $1 < 256 && ( ! $2 || $3 < 256 );
|
||||
}
|
||||
|
||||
fatal_error "Invalid IPv6 ICMP Type ($type)"
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
@ -26,20 +26,33 @@ package Shorewall::Policy;
|
||||
require Exporter;
|
||||
use Shorewall::Config qw(:DEFAULT :internal);
|
||||
use Shorewall::Zones;
|
||||
use Shorewall::IPAddrs;
|
||||
use Shorewall::Chains qw( :DEFAULT :internal) ;
|
||||
use Shorewall::Actions;
|
||||
|
||||
use strict;
|
||||
|
||||
our @ISA = qw(Exporter);
|
||||
our @EXPORT = qw( validate_policy apply_policy_rules complete_standard_chain sub setup_syn_flood_chains );
|
||||
our @EXPORT = qw( validate_policy
|
||||
validate_6policy
|
||||
apply_policy_rules
|
||||
apply_6policy_rules
|
||||
complete_standard_chain
|
||||
complete_standard_6chain
|
||||
setup_syn_flood_chains
|
||||
setup_syn_flood_6chains );
|
||||
|
||||
our @EXPORT_OK = qw( );
|
||||
our $VERSION = 4.1.1;
|
||||
our $VERSION = 4.3.0;
|
||||
|
||||
# @policy_chains is a list of references to policy chains in the filter table
|
||||
|
||||
our @policy_chains;
|
||||
|
||||
# @policy_6chains is a list of references to policy chains in the filter6 table
|
||||
|
||||
our @policy_6chains;
|
||||
|
||||
#
|
||||
# Initialize globals -- we take this novel approach to globals initialization to allow
|
||||
# the compiler to run multiple times in the same process. The
|
||||
@ -51,6 +64,7 @@ our @policy_chains;
|
||||
|
||||
sub initialize() {
|
||||
@policy_chains = ();
|
||||
@policy_6chains = ();
|
||||
}
|
||||
|
||||
INIT {
|
||||
@ -85,6 +99,20 @@ sub new_policy_chain($$$$)
|
||||
$chainref;
|
||||
}
|
||||
|
||||
#
|
||||
# Create a new policy 6chain and return a reference to it.
|
||||
#
|
||||
sub new_policy_6chain($$$$)
|
||||
{
|
||||
my ($source, $dest, $policy, $optional) = @_;
|
||||
|
||||
my $chainref = new_6chain( 'filter', "${source}2${dest}" );
|
||||
|
||||
convert_to_policy_chain( $chainref, $source, $dest, $policy, $optional );
|
||||
|
||||
$chainref;
|
||||
}
|
||||
|
||||
#
|
||||
# Set the passed chain's policychain and policy to the passed values.
|
||||
#
|
||||
@ -142,6 +170,21 @@ sub add_or_modify_policy_chain( $$ ) {
|
||||
}
|
||||
}
|
||||
|
||||
sub add_or_modify_policy_6chain( $$ ) {
|
||||
my ( $zone, $zone1 ) = @_;
|
||||
my $chain = "${zone}2${zone1}";
|
||||
my $chainref = $filter6_table->{$chain};
|
||||
|
||||
if ( $chainref ) {
|
||||
unless( $chainref->{is_policy} ) {
|
||||
convert_to_policy_chain( $chainref, $zone, $zone1, 'CONTINUE', OPTIONAL );
|
||||
push @policy_6chains, $chainref;
|
||||
}
|
||||
} else {
|
||||
push @policy_6chains, ( new_policy_chain $zone, $zone1, 'CONTINUE', OPTIONAL );
|
||||
}
|
||||
}
|
||||
|
||||
sub print_policy($$$$) {
|
||||
my ( $source, $dest, $policy , $chain ) = @_;
|
||||
unless ( ( $source eq 'all' ) || ( $dest eq 'all' ) ) {
|
||||
@ -220,11 +263,17 @@ sub validate_policy()
|
||||
|
||||
my $clientwild = ( "\L$client" eq 'all' );
|
||||
|
||||
fatal_error "Undefined zone ($client)" unless $clientwild || defined_zone( $client );
|
||||
unless ( $clientwild ) {
|
||||
fatal_error "Undefined zone ($client)" unless defined_zone( $client );
|
||||
fatal_error "IPv6 zone ($client) not permitted in policy file" unless zone_family($client) & F_INET;
|
||||
}
|
||||
|
||||
my $serverwild = ( "\L$server" eq 'all' );
|
||||
|
||||
fatal_error "Undefined zone ($server)" unless $serverwild || defined_zone( $server );
|
||||
unless ( $serverwild ) {
|
||||
fatal_error "Undefined zone ($server)" unless defined_zone( $server );
|
||||
fatal_error "IPv6 zone ($server) not permitted in policy file" unless zone_family($server) & F_INET;
|
||||
}
|
||||
|
||||
my ( $policy, $default, $remainder ) = split( /:/, $originalpolicy, 3 );
|
||||
|
||||
@ -344,6 +393,205 @@ sub validate_policy()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub validate_6policy()
|
||||
{
|
||||
my %validpolicies = (
|
||||
ACCEPT => undef,
|
||||
REJECT => undef,
|
||||
DROP => undef,
|
||||
CONTINUE => undef,
|
||||
QUEUE => undef,
|
||||
NFQUEUE => undef,
|
||||
NONE => undef
|
||||
);
|
||||
|
||||
my %map = ( DROP_DEFAULT => 'DROP' ,
|
||||
REJECT_DEFAULT => 'REJECT' ,
|
||||
ACCEPT_DEFAULT => 'ACCEPT' ,
|
||||
QUEUE_DEFAULT => 'QUEUE' ,
|
||||
NFQUEUE_DEFAULT => 'NFQUEUE' );
|
||||
|
||||
my $zone;
|
||||
my @zonelist = $config{EXPAND_POLICIES} ? all_6zones : ( all_6zones, 'all' );
|
||||
|
||||
for my $option qw/DROP_DEFAULT REJECT_DEFAULT ACCEPT_DEFAULT QUEUE_DEFAULT NFQUEUE_DEFAULT/ {
|
||||
my $action = $config{$option};
|
||||
next if $action eq 'none';
|
||||
my $actiontype = $targets{$action};
|
||||
|
||||
if ( defined $actiontype ) {
|
||||
fatal_error "Invalid setting ($action) for $option" unless $actiontype & ACTION;
|
||||
} else {
|
||||
fatal_error "Default Action $option=$action not found";
|
||||
}
|
||||
|
||||
unless ( $usedactions{$action} ) {
|
||||
$usedactions{$action} = 1;
|
||||
createactionchain $action;
|
||||
}
|
||||
|
||||
$default_actions{$map{$option}} = $action;
|
||||
}
|
||||
|
||||
for $zone ( all_6zones ) {
|
||||
push @policy_6chains, ( new_policy_6chain $zone, $zone, 'ACCEPT', OPTIONAL );
|
||||
|
||||
if ( $config{IMPLICIT_CONTINUE} && ( @{find_zone( $zone )->{parents}} ) ) {
|
||||
for my $zone1 ( all_6zones ) {
|
||||
unless( $zone eq $zone1 ) {
|
||||
add_or_modify_policy_chain( $zone, $zone1 );
|
||||
add_or_modify_policy_chain( $zone1, $zone );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $fn = open_file '6policy';
|
||||
|
||||
first_entry "$doing $fn...";
|
||||
|
||||
while ( read_a_line ) {
|
||||
|
||||
my ( $client, $server, $originalpolicy, $loglevel, $synparams, $connlimit ) = split_line 3, 6, '6policy file';
|
||||
|
||||
$loglevel = '' if $loglevel eq '-';
|
||||
$synparams = '' if $synparams eq '-';
|
||||
$connlimit = '' if $connlimit eq '-';
|
||||
|
||||
my $clientwild = ( "\L$client" eq 'all' );
|
||||
|
||||
unless ( $clientwild ) {
|
||||
fatal_error "Undefined zone ($client)" unless defined_zone( $client );
|
||||
fatal_error "IPv4 zone ($client) not permitted in policy file" unless zone_family($client) & F_INET6;
|
||||
}
|
||||
|
||||
my $serverwild = ( "\L$server" eq 'all' );
|
||||
|
||||
unless ( $serverwild ) {
|
||||
fatal_error "Undefined zone ($server)" unless defined_zone( $server );
|
||||
fatal_error "IPv4 zone ($server) not permitted in policy file" unless zone_family($server) & F_INET6;
|
||||
}
|
||||
|
||||
my ( $policy, $default, $remainder ) = split( /:/, $originalpolicy, 3 );
|
||||
|
||||
fatal_error "Invalid or missing POLICY ($originalpolicy)" unless $policy;
|
||||
|
||||
fatal_error "Invalid default action ($default:$remainder)" if defined $remainder;
|
||||
|
||||
( $policy , my $queue ) = get_target_param $policy;
|
||||
|
||||
if ( $default ) {
|
||||
if ( "\L$default" eq 'none' ) {
|
||||
$default = 'none';
|
||||
} else {
|
||||
my $defaulttype = $targets6{$default} || 0;
|
||||
|
||||
if ( $defaulttype & ACTION ) {
|
||||
unless ( $usedactions{$default} ) {
|
||||
$usedactions{$default} = 1;
|
||||
createactionchain $default;
|
||||
}
|
||||
} else {
|
||||
fatal_error "Unknown Default Action ($default)";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$default = $default_actions{$policy} || '';
|
||||
}
|
||||
|
||||
fatal_error "Invalid policy ($policy)" unless exists $validpolicies{$policy};
|
||||
|
||||
if ( defined $queue ) {
|
||||
fatal_error "Invalid policy ($policy($queue))" unless $policy eq 'NFQUEUE';
|
||||
require_capability( 'NFQUEUE_TARGET', 'An NFQUEUE Policy', 's' );
|
||||
my $queuenum = numeric_value( $queue );
|
||||
fatal_error "Invalid NFQUEUE queue number ($queue)" unless defined( $queuenum) && $queuenum <= 65535;
|
||||
$policy = "NFQUEUE --queue-num $queuenum";
|
||||
} elsif ( $policy eq 'NONE' ) {
|
||||
fatal_error "NONE policy not allowed with \"all\""
|
||||
if $clientwild || $serverwild;
|
||||
fatal_error "NONE policy not allowed to/from firewall zone"
|
||||
if ( zone_type( $client ) eq 'firewall' ) || ( zone_type( $server ) eq 'firewall' );
|
||||
}
|
||||
|
||||
unless ( $clientwild || $serverwild ) {
|
||||
if ( zone_type( $server ) eq 'bport6' ) {
|
||||
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};
|
||||
}
|
||||
}
|
||||
|
||||
my $chain = "${client}2${server}";
|
||||
my $chainref;
|
||||
|
||||
if ( defined $filter_table->{$chain} ) {
|
||||
$chainref = $filter_table->{$chain};
|
||||
|
||||
if ( $chainref->{is_policy} ) {
|
||||
if ( $chainref->{is_optional} ) {
|
||||
$chainref->{is_optional} = 0;
|
||||
$chainref->{policy} = $policy;
|
||||
} else {
|
||||
fatal_error qq(Policy "$client $server $policy" duplicates earlier policy "@{$chainref->{policypair}} $chainref->{policy}");
|
||||
}
|
||||
} elsif ( $chainref->{policy} ) {
|
||||
fatal_error qq(Policy "$client $server $policy" duplicates earlier policy "@{$chainref->{policypair}} $chainref->{policy}");
|
||||
} else {
|
||||
convert_to_policy_chain( $chainref, $client, $server, $policy, 0 );
|
||||
push @policy_6chains, ( $chainref ) unless $config{EXPAND_POLICIES} && ( $clientwild || $serverwild );
|
||||
}
|
||||
} else {
|
||||
$chainref = new_policy_6chain $client, $server, $policy, 0;
|
||||
push @policy_6chains, ( $chainref ) unless $config{EXPAND_POLICIES} && ( $clientwild || $serverwild );
|
||||
}
|
||||
|
||||
$chainref->{loglevel} = validate_level( $loglevel ) if defined $loglevel && $loglevel ne '';
|
||||
|
||||
if ( $synparams ne '' || $connlimit ne '' ) {
|
||||
my $value = '';
|
||||
fatal_error "Invalid CONNLIMIT ($connlimit)" if $connlimit =~ /^!/;
|
||||
$value = do_ratelimit $synparams, 'ACCEPT' if $synparams ne '';
|
||||
$value .= do_connlimit $connlimit if $connlimit ne '';
|
||||
$chainref->{synparams} = $value;
|
||||
$chainref->{synchain} = $chain
|
||||
}
|
||||
|
||||
$chainref->{default} = $default if $default;
|
||||
|
||||
if ( $clientwild ) {
|
||||
if ( $serverwild ) {
|
||||
for my $zone ( @zonelist ) {
|
||||
for my $zone1 ( @zonelist ) {
|
||||
set_policy_chain $client, $server, "${zone}2${zone1}", $chainref, $policy;
|
||||
print_policy $zone, $zone1, $policy, $chain;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for my $zone ( all_zones ) {
|
||||
set_policy_chain $client, $server, "${zone}2${server}", $chainref, $policy;
|
||||
print_policy $zone, $server, $policy, $chain;
|
||||
}
|
||||
}
|
||||
} elsif ( $serverwild ) {
|
||||
for my $zone ( @zonelist ) {
|
||||
set_policy_chain $client, $server, "${client}2${zone}", $chainref, $policy;
|
||||
print_policy $client, $zone, $policy, $chain;
|
||||
}
|
||||
|
||||
} else {
|
||||
print_policy $client, $server, $policy, $chain;
|
||||
}
|
||||
}
|
||||
|
||||
for $zone ( all_zones ) {
|
||||
for my $zone1 ( all_zones ) {
|
||||
fatal_error "No policy defined from zone $zone to zone $zone1" unless $filter_table->{"${zone}2${zone1}"}{policy};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Policy Rule application
|
||||
#
|
||||
@ -361,6 +609,19 @@ sub policy_rules( $$$$$ ) {
|
||||
}
|
||||
}
|
||||
|
||||
sub policy_6rules( $$$$$ ) {
|
||||
my ( $chainref , $target, $loglevel, $default, $dropmulticast ) = @_;
|
||||
|
||||
unless ( $target eq 'NONE' ) {
|
||||
add_rule $chainref, "-j $default" if $default && $default ne 'none';
|
||||
log_rule $loglevel , $chainref , $target , '' if $loglevel ne '';
|
||||
fatal_error "Null target in policy_rules()" unless $target;
|
||||
$target = 'reject' if $target eq 'REJECT';
|
||||
|
||||
add_jump( $chainref , $target ) unless $target eq 'CONTINUE';
|
||||
}
|
||||
}
|
||||
|
||||
sub report_syn_flood_protection() {
|
||||
progress_message ' Enabled SYN flood protection';
|
||||
}
|
||||
@ -400,8 +661,43 @@ sub default_policy( $$$ ) {
|
||||
|
||||
}
|
||||
|
||||
sub default_6policy( $$$ ) {
|
||||
my $chainref = $_[0];
|
||||
my $policyref = $filter6_table->{$chainref->{policychain}};
|
||||
my $synparams = $policyref->{synparams};
|
||||
my $default = $policyref->{default};
|
||||
my $policy = $policyref->{policy};
|
||||
my $loglevel = $policyref->{loglevel};
|
||||
|
||||
fatal_error "Internal error in default_6policy()" unless $policyref;
|
||||
|
||||
if ( $chainref eq $policyref ) {
|
||||
policy_6rules $chainref , $policy, $loglevel , $default, $config{MULTICAST};
|
||||
} else {
|
||||
if ( $policy eq 'ACCEPT' || $policy eq 'QUEUE' || $policy =~ /^NFQUEUE/ ) {
|
||||
if ( $synparams ) {
|
||||
report_syn_flood_protection;
|
||||
policy_6rules $chainref , $policy , $loglevel , $default, $config{MULTICAST};
|
||||
} else {
|
||||
add_jump $chainref, $policyref;
|
||||
$chainref = $policyref;
|
||||
}
|
||||
} elsif ( $policy eq 'CONTINUE' ) {
|
||||
report_syn_flood_protection if $synparams;
|
||||
policy_6rules $chainref , $policy , $loglevel , $default, $config{MULTICAST};
|
||||
} else {
|
||||
report_syn_flood_protection if $synparams;
|
||||
add_jump $chainref , $policyref;
|
||||
$chainref = $policyref;
|
||||
}
|
||||
}
|
||||
|
||||
progress_message " Policy $policy from $_[1] to $_[2] using chain $chainref->{name}";
|
||||
|
||||
}
|
||||
|
||||
sub apply_policy_rules() {
|
||||
progress_message2 'Applying Policies...';
|
||||
progress_message2 'Applying IPv4 Policies...';
|
||||
|
||||
for my $chainref ( @policy_chains ) {
|
||||
my $policy = $chainref->{policy};
|
||||
@ -434,6 +730,40 @@ sub apply_policy_rules() {
|
||||
}
|
||||
}
|
||||
|
||||
sub apply_6policy_rules() {
|
||||
progress_message2 'Applying IPv6 Policies...';
|
||||
|
||||
for my $chainref ( @policy_6chains ) {
|
||||
my $policy = $chainref->{policy};
|
||||
my $loglevel = $chainref->{loglevel};
|
||||
my $optional = $chainref->{is_optional};
|
||||
my $default = $chainref->{default};
|
||||
my $name = $chainref->{name};
|
||||
|
||||
if ( $policy ne 'NONE' ) {
|
||||
if ( ! $chainref->{referenced} && ( ! $optional && $policy ne 'CONTINUE' ) ) {
|
||||
ensure_filter_6chain $name, 1;
|
||||
}
|
||||
|
||||
if ( $name =~ /^all2|2all$/ ) {
|
||||
run_user_exit $chainref;
|
||||
policy_6rules $chainref , $policy, $loglevel , $default, $config{MULTICAST};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for my $zone ( all_6zones ) {
|
||||
for my $zone1 ( all_6zones ) {
|
||||
my $chainref = $filter6_table->{"${zone}2${zone1}"};
|
||||
|
||||
if ( $chainref->{referenced} ) {
|
||||
run_user_exit $chainref;
|
||||
default_6policy $chainref, $zone, $zone1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Complete a standard chain
|
||||
#
|
||||
@ -461,6 +791,33 @@ sub complete_standard_chain ( $$$$ ) {
|
||||
policy_rules $stdchainref , $policy , $loglevel, $defaultaction, 0;
|
||||
}
|
||||
|
||||
#
|
||||
# Complete a standard chain
|
||||
#
|
||||
# - run any supplied user exit
|
||||
# - search the policy file for an applicable policy and add rules as
|
||||
# appropriate
|
||||
# - If no applicable policy is found, add rules for an assummed
|
||||
# policy of DROP INFO
|
||||
#
|
||||
sub complete_standard_6chain ( $$$$ ) {
|
||||
my ( $stdchainref, $zone, $zone2, $default ) = @_;
|
||||
|
||||
add_rule $stdchainref, '-m state --state ESTABLISHED,RELATED -j ACCEPT' unless $config{FASTACCEPT};
|
||||
|
||||
run_user_exit $stdchainref;
|
||||
|
||||
my $ruleschainref = $filter6_table->{"${zone}2${zone2}"};
|
||||
my ( $policy, $loglevel, $defaultaction ) = ( $default , 6, $config{$default . '_DEFAULT'} );
|
||||
my $policychainref;
|
||||
|
||||
$policychainref = $filter6_table->{$ruleschainref->{policychain}} if $ruleschainref;
|
||||
|
||||
( $policy, $loglevel, $defaultaction ) = @{$policychainref}{'policy', 'loglevel', 'default' } if $policychainref;
|
||||
|
||||
policy_rules $stdchainref , $policy , $loglevel, $defaultaction, 0;
|
||||
}
|
||||
|
||||
#
|
||||
# Create and populate the synflood chains corresponding to entries in /etc/shorewall/policy
|
||||
#
|
||||
@ -478,4 +835,21 @@ sub setup_syn_flood_chains() {
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Create and populate the synflood chains corresponding to entries in /etc/shorewall/policy
|
||||
#
|
||||
sub setup_syn_flood_6chains() {
|
||||
for my $chainref ( @policy_6chains ) {
|
||||
my $limit = $chainref->{synparams};
|
||||
if ( $limit && ! $filter6_table->{syn_flood_chain $chainref} ) {
|
||||
my $level = $chainref->{loglevel};
|
||||
my $synchainref = new_6chain 'filter' , syn_flood_chain $chainref;
|
||||
add_rule $synchainref , "${limit}-j RETURN";
|
||||
log_rule_limit $level , $synchainref , $chainref->{name} , 'DROP', '-m limit --limit 5/min --limit-burst 5 ' , '' , 'add' , ''
|
||||
if $level ne '';
|
||||
add_rule $synchainref, '-j DROP';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -52,6 +52,7 @@ our $VERSION = 4.1.5;
|
||||
# Set to one if we find a SECTION
|
||||
#
|
||||
our $sectioned;
|
||||
our $sectioned6;
|
||||
our $macro_nest_level;
|
||||
our $current_param;
|
||||
our @param_stack;
|
||||
@ -74,6 +75,7 @@ my %rules_commands = ( COMMENT => 0,
|
||||
|
||||
sub initialize() {
|
||||
$sectioned = 0;
|
||||
$sectioned6 = 0;
|
||||
$macro_nest_level = 0;
|
||||
$current_param = '';
|
||||
@param_stack = ();
|
||||
@ -386,6 +388,125 @@ sub process_criticalhosts() {
|
||||
\@critical;
|
||||
}
|
||||
|
||||
sub setup_6blacklist() {
|
||||
|
||||
my $hosts = find_hosts_by_option '6blacklist';
|
||||
my $chainref;
|
||||
my ( $level, $disposition ) = @config{'BLACKLIST_LOGLEVEL', 'BLACKLIST_DISPOSITION' };
|
||||
my $target = $disposition eq 'REJECT' ? 'reject' : $disposition;
|
||||
|
||||
if ( @$hosts ) {
|
||||
$chainref = new_standard_6chain 'blacklst';
|
||||
|
||||
if ( defined $level && $level ne '' ) {
|
||||
my $logchainref = new_standard_6chain 'blacklog';
|
||||
|
||||
log_rule_limit( $level , $logchainref , 'blacklst' , $disposition , "$globals{LOGLIMIT}" , '', 'add', '' );
|
||||
|
||||
add_rule $logchainref, "-j $target" ;
|
||||
|
||||
$target = 'blacklog';
|
||||
}
|
||||
}
|
||||
|
||||
BLACKLIST:
|
||||
{
|
||||
if ( my $fn = open_file '6blacklist' ) {
|
||||
|
||||
my $first_entry = 1;
|
||||
|
||||
first_entry "$doing $fn...";
|
||||
|
||||
while ( read_a_line ) {
|
||||
|
||||
if ( $first_entry ) {
|
||||
unless ( @$hosts ) {
|
||||
warning_message q(The entries in $fn have been ignored because there are no 'blacklist' interfaces);
|
||||
close_file;
|
||||
last BLACKLIST;
|
||||
}
|
||||
|
||||
$first_entry = 0;
|
||||
}
|
||||
|
||||
my ( $networks, $protocol, $ports ) = split_line 1, 3, 'blacklist file';
|
||||
|
||||
expand_rule(
|
||||
$chainref ,
|
||||
NO_RESTRICT ,
|
||||
do_proto6( $protocol , $ports, '' ) ,
|
||||
$networks ,
|
||||
'' ,
|
||||
'' ,
|
||||
'' ,
|
||||
"-j $target" ,
|
||||
'' ,
|
||||
$disposition ,
|
||||
'' );
|
||||
|
||||
progress_message " \"$currentline\" added to blacklist";
|
||||
}
|
||||
}
|
||||
|
||||
my $state = $config{BLACKLISTNEWONLY} ? '-m state --state NEW,INVALID ' : '';
|
||||
|
||||
for my $hostref ( @$hosts ) {
|
||||
my $interface = $hostref->[0];
|
||||
my $ipsec = $hostref->[1];
|
||||
my $policy = $capabilities{POLICY_MATCH} ? "-m policy --pol $ipsec --dir in " : '';
|
||||
my $network = $hostref->[2];
|
||||
my $source = match_source_6net $network;
|
||||
|
||||
for my $chain ( first_chains $interface ) {
|
||||
add_rule $filter_table->{$chain} , "${source}${state}${policy}-j blacklst";
|
||||
}
|
||||
|
||||
progress_message " Blacklisting enabled on ${interface};${network}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub process_critical6hosts() {
|
||||
|
||||
my @critical = ();
|
||||
|
||||
my $fn = open_file '6routestopped';
|
||||
|
||||
first_entry "$doing $fn for critical IPv6 hosts...";
|
||||
|
||||
while ( read_a_line ) {
|
||||
|
||||
my $routeback = 0;
|
||||
|
||||
my ($interface, $hosts, $options ) = split_line 1, 3, 'routestopped file';
|
||||
|
||||
fatal_error "Unknown interface ($interface)" unless known_6interface $interface;
|
||||
|
||||
$hosts = ALLIPv6 unless $hosts ne '-';
|
||||
|
||||
my @hosts;
|
||||
|
||||
for my $host ( split_list $hosts, 'host' ) {
|
||||
validate_host $host, 1;
|
||||
push @hosts, "$interface;$host";
|
||||
}
|
||||
|
||||
unless ( $options eq '-' ) {
|
||||
for my $option (split_list $options, 'option' ) {
|
||||
unless ( $option eq 'routeback' || $option eq 'source' || $option eq 'dest' ) {
|
||||
if ( $option eq 'critical' ) {
|
||||
push @critical, @hosts;
|
||||
} else {
|
||||
warning_message "Unknown routestopped option ( $option ) ignored";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
\@critical;
|
||||
}
|
||||
|
||||
sub process_routestopped() {
|
||||
|
||||
my ( @allhosts, %source, %dest );
|
||||
@ -480,6 +601,100 @@ sub process_routestopped() {
|
||||
}
|
||||
}
|
||||
|
||||
sub process_6routestopped() {
|
||||
|
||||
my ( @allhosts, %source, %dest );
|
||||
|
||||
my $fn = open_file '6routestopped';
|
||||
|
||||
first_entry "$doing $fn...";
|
||||
|
||||
while ( read_a_line ) {
|
||||
|
||||
my $routeback = 0;
|
||||
|
||||
my ($interface, $hosts, $options ) = split_line 1, 3, '6routestopped file';
|
||||
|
||||
fatal_error "Unknown interface ($interface)" unless known_6interface $interface;
|
||||
|
||||
$hosts = ALLIPv6 unless $hosts && $hosts ne '-';
|
||||
|
||||
my @hosts;
|
||||
|
||||
for my $host ( split /,/, $hosts ) {
|
||||
validate_6host $host, 1;
|
||||
push @hosts, "$interface;$host";
|
||||
}
|
||||
|
||||
unless ( $options eq '-' ) {
|
||||
for my $option (split /,/, $options ) {
|
||||
if ( $option eq 'routeback' ) {
|
||||
if ( $routeback ) {
|
||||
warning_message "Duplicate 'routeback' option ignored";
|
||||
} else {
|
||||
$routeback = 1;
|
||||
|
||||
for my $host ( split /,/, $hosts ) {
|
||||
my $source = match_source_6net $host;
|
||||
my $dest = match_dest_6net $host;
|
||||
|
||||
emit "run_ip6tables -A FORWARD -i $interface -o $interface $source $dest -j ACCEPT";
|
||||
clearrule;
|
||||
}
|
||||
}
|
||||
} elsif ( $option eq 'source' ) {
|
||||
for my $host ( split /,/, $hosts ) {
|
||||
$source{"$interface;$host"} = 1;
|
||||
}
|
||||
} elsif ( $option eq 'dest' ) {
|
||||
for my $host ( split /,/, $hosts ) {
|
||||
$dest{"$interface;$host"} = 1;
|
||||
}
|
||||
} else {
|
||||
warning_message "Unknown 6routestopped option ( $option ) ignored" unless $option eq 'critical';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
push @allhosts, @hosts;
|
||||
}
|
||||
|
||||
for my $host ( @allhosts ) {
|
||||
my ( $interface, $h ) = split /;/, $host;
|
||||
my $source = match_source_6net $h;
|
||||
my $dest = match_dest_6net $h;
|
||||
my $sourcei = match_source_6dev $interface;
|
||||
my $desti = match_dest_6dev $interface;
|
||||
|
||||
emit "\$IP6TABLES -A INPUT $sourcei $source -j ACCEPT";
|
||||
emit "\$IP6TABLES -A OUTPUT $desti $dest -j ACCEPT" unless $config{ADMINISABSENTMINDED};
|
||||
|
||||
my $matched = 0;
|
||||
|
||||
if ( $source{$host} ) {
|
||||
emit "\$IP6TABLES -A FORWARD $sourcei $source -j ACCEPT";
|
||||
$matched = 1;
|
||||
}
|
||||
|
||||
if ( $dest{$host} ) {
|
||||
emit "\$IP6TABLES -A FORWARD $desti $dest -j ACCEPT";
|
||||
$matched = 1;
|
||||
}
|
||||
|
||||
unless ( $matched ) {
|
||||
for my $host1 ( @allhosts ) {
|
||||
unless ( $host eq $host1 ) {
|
||||
my ( $interface1, $h1 ) = split /;/, $host1;
|
||||
my $dest1 = match_dest_6net $h1;
|
||||
my $desti1 = match_dest_6dev $interface1;
|
||||
emit "\$IP6TABLES -A FORWARD $sourcei $desti1 $source $dest1 -j ACCEPT";
|
||||
clearrule;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub setup_mss();
|
||||
|
||||
sub add_common_rules() {
|
||||
@ -1447,6 +1662,642 @@ sub process_rules() {
|
||||
$section = 'DONE';
|
||||
}
|
||||
|
||||
sub process_6rule1 ( $$$$$$$$$$$$ );
|
||||
|
||||
#
|
||||
# Expand a macro rule from the rules file
|
||||
#
|
||||
sub process_6macro ( $$$$$$$$$$$$$$ ) {
|
||||
my ($macro, $target, $param, $source, $dest, $proto, $ports, $sports, $rate, $user, $mark, $connlimit, $time, $wildcard ) = @_;
|
||||
|
||||
my $nocomment = no_comment;
|
||||
|
||||
my $format = 1;
|
||||
|
||||
macro_comment $macro;
|
||||
|
||||
my $macrofile = $macros{$macro};
|
||||
|
||||
progress_message "..Expanding Macro $macrofile...";
|
||||
|
||||
push_open $macrofile;
|
||||
|
||||
while ( read_a_line ) {
|
||||
|
||||
my ( $mtarget, $msource, $mdest, $mproto, $mports, $msports, $morigdest, $mrate, $muser );
|
||||
|
||||
if ( $format == 1 ) {
|
||||
( $mtarget, $msource, $mdest, $mproto, $mports, $msports, $mrate, $muser, $morigdest ) = split_line1 1, 9, 'macro file', $macro_commands;
|
||||
} else {
|
||||
( $mtarget, $msource, $mdest, $mproto, $mports, $msports, $morigdest, $mrate, $muser ) = split_line1 1, 9, 'macro file', $macro_commands;
|
||||
}
|
||||
|
||||
if ( $mtarget eq 'COMMENT' ) {
|
||||
process_comment unless $nocomment;
|
||||
next;
|
||||
}
|
||||
|
||||
if ( $mtarget eq 'FORMAT' ) {
|
||||
fatal_error "Invalid FORMAT ($msource)" unless $msource =~ /^[12]$/;
|
||||
$format = $msource;
|
||||
next;
|
||||
}
|
||||
|
||||
if ( $morigdest ne '-' ) {
|
||||
fatal_error "Invalid macro file entry (too many columns)" if $format == 1;
|
||||
fatal_error "A macro with ORIGINAL DEST cannot be used with IPv6";
|
||||
}
|
||||
|
||||
$mtarget = merge_levels $target, $mtarget;
|
||||
|
||||
if ( $mtarget =~ /^PARAM(:.*)?$/ ) {
|
||||
fatal_error 'PARAM requires a parameter to be supplied in macro invocation' unless $param ne '';
|
||||
$mtarget = substitute_param $param, $mtarget;
|
||||
}
|
||||
|
||||
my $action = isolate_basic_target $mtarget;
|
||||
|
||||
fatal_error "Invalid or missing ACTION ($mtarget)" unless defined $action;
|
||||
|
||||
my $actiontype = $targets6{$action} || find_6macro( $action );
|
||||
|
||||
fatal_error "Invalid Action ($mtarget) in macro" unless $actiontype & ( ACTION + STANDARD + NATRULE + MACRO );
|
||||
|
||||
if ( $msource ) {
|
||||
if ( $msource eq '-' ) {
|
||||
$msource = $source || '';
|
||||
} elsif ( $msource =~ s/^DEST:?// ) {
|
||||
$msource = merge_6macro_source_dest $msource, $dest;
|
||||
} else {
|
||||
$msource =~ s/^SOURCE:?//;
|
||||
$msource = merge_6macro_source_dest $msource, $source;
|
||||
}
|
||||
} else {
|
||||
$msource = '';
|
||||
}
|
||||
|
||||
if ( $mdest ) {
|
||||
if ( $mdest eq '-' ) {
|
||||
$mdest = $dest || '';
|
||||
} elsif ( $mdest =~ s/^SOURCE:?// ) {
|
||||
$mdest = merge_6macro_source_dest $mdest , $source;
|
||||
} else {
|
||||
$mdest =~ s/DEST:?//;
|
||||
$mdest = merge_6macro_source_dest $mdest, $dest;
|
||||
}
|
||||
} else {
|
||||
$mdest = '';
|
||||
}
|
||||
|
||||
process_6rule1(
|
||||
$mtarget,
|
||||
$msource,
|
||||
$mdest,
|
||||
merge_macro_column( $mproto, $proto ) ,
|
||||
merge_macro_column( $mports, $ports ) ,
|
||||
merge_macro_column( $msports, $sports ) ,
|
||||
merge_macro_column( $mrate, $rate ) ,
|
||||
merge_macro_column( $muser, $user ) ,
|
||||
$mark,
|
||||
$connlimit,
|
||||
$time,
|
||||
$wildcard
|
||||
);
|
||||
|
||||
progress_message " IPv6 Rule \"$currentline\" $done";
|
||||
}
|
||||
|
||||
pop_open;
|
||||
|
||||
progress_message "..End Macro $macrofile";
|
||||
|
||||
clear_comment unless $nocomment;
|
||||
|
||||
}
|
||||
#
|
||||
# Once a rule has been expanded via wildcards (source and/or dest zone == 'all'), it is processed by this function. If
|
||||
# the target is a macro, the macro is expanded and this function is called recursively for each rule in the expansion.
|
||||
#
|
||||
sub process_rule1 ( $$$$$$$$$$$$$ ) {
|
||||
my ( $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $connlimit, $time, $wildcard ) = @_;
|
||||
my ( $action, $loglevel) = split_action $target;
|
||||
my ( $basictarget, $param ) = get_target_param $action;
|
||||
my $rule = '';
|
||||
my $actionchainref;
|
||||
my $optimize = $wildcard ? ( $basictarget =~ /!$/ ? 0 : $config{OPTIMIZE} ) : 0;
|
||||
|
||||
unless ( defined $param ) {
|
||||
( $basictarget, $param ) = ( $1, $2 ) if $action =~ /^(\w+)[(](.*)[)]$/;
|
||||
}
|
||||
|
||||
$param = '' unless defined $param;
|
||||
|
||||
#
|
||||
# Determine the validity of the action
|
||||
#
|
||||
my $actiontype = $targets{$basictarget} || find_macro( $basictarget );
|
||||
|
||||
fatal_error "Unknown action ($action)" unless $actiontype;
|
||||
|
||||
if ( $actiontype == MACRO ) {
|
||||
#
|
||||
# process_macro() will call process_rule1() recursively for each rule in the macro body
|
||||
#
|
||||
fatal_error "Macro invocations nested too deeply" if ++$macro_nest_level > MAX_MACRO_NEST_LEVEL;
|
||||
|
||||
if ( $param ne '' ) {
|
||||
push @param_stack, $current_param;
|
||||
$current_param = $param;
|
||||
}
|
||||
|
||||
process_macro( $basictarget,
|
||||
$target ,
|
||||
$current_param,
|
||||
$source,
|
||||
$dest,
|
||||
$proto,
|
||||
$ports,
|
||||
$sports,
|
||||
$origdest,
|
||||
$ratelimit,
|
||||
$user,
|
||||
$mark,
|
||||
$connlimit,
|
||||
$time,
|
||||
$wildcard );
|
||||
|
||||
$macro_nest_level--;
|
||||
|
||||
$current_param = pop @param_stack if $param ne '';
|
||||
|
||||
return;
|
||||
|
||||
} elsif ( $actiontype & NFQ ) {
|
||||
require_capability( 'NFQUEUE_TARGET', 'NFQUEUE Rules', '' );
|
||||
my $paramval = $param eq '' ? 0 : numeric_value( $param );
|
||||
fatal_error "Invalid value ($param) for NFQUEUE queue number" unless defined($paramval) && $paramval <= 65535;
|
||||
$action = "NFQUEUE --queue-num $paramval";
|
||||
} else {
|
||||
fatal_error "The $basictarget TARGET does not accept a parameter" unless $param eq '';
|
||||
}
|
||||
#
|
||||
# We can now dispense with the postfix character
|
||||
#
|
||||
$action =~ s/[\+\-!]$//;
|
||||
#
|
||||
# Mark target as used
|
||||
#
|
||||
if ( $actiontype & ACTION ) {
|
||||
unless ( $usedactions{$target} ) {
|
||||
$usedactions{$target} = 1;
|
||||
createactionchain $target;
|
||||
}
|
||||
}
|
||||
#
|
||||
# Take care of irregular syntax and targets
|
||||
#
|
||||
if ( $actiontype & REDIRECT ) {
|
||||
my $z = $actiontype & NATONLY ? '' : firewall_zone;
|
||||
if ( $dest eq '-' ) {
|
||||
$dest = join( '', $z, '::' , $ports =~ /[:,]/ ? '' : $ports );
|
||||
} else {
|
||||
$dest = join( '', $z, '::', $dest ) unless $dest =~ /:/;
|
||||
}
|
||||
} elsif ( $action eq 'REJECT' ) {
|
||||
$action = 'reject';
|
||||
} elsif ( $action eq 'CONTINUE' ) {
|
||||
$action = 'RETURN';
|
||||
} elsif ( $actiontype & LOGRULE ) {
|
||||
fatal_error 'LOG requires a log level' unless defined $loglevel and $loglevel ne '';
|
||||
}
|
||||
#
|
||||
# Isolate and validate source and destination zones
|
||||
#
|
||||
my $sourcezone;
|
||||
my $destzone;
|
||||
my $sourceref;
|
||||
my $destref;
|
||||
my $origdstports;
|
||||
|
||||
if ( $source =~ /^(.+?):(.*)/ ) {
|
||||
fatal_error "Missing SOURCE Qualifier ($source)" if $2 eq '';
|
||||
$sourcezone = $1;
|
||||
$source = $2;
|
||||
} else {
|
||||
$sourcezone = $source;
|
||||
$source = ALLIPv4;
|
||||
}
|
||||
|
||||
if ( $dest =~ /^(.*?):(.*)/ ) {
|
||||
fatal_error "Missing DEST Qualifier ($dest)" if $2 eq '';
|
||||
$destzone = $1;
|
||||
$dest = $2;
|
||||
} else {
|
||||
$destzone = $dest;
|
||||
$dest = ALLIPv4;
|
||||
}
|
||||
|
||||
fatal_error "Missing source zone" if $sourcezone eq '-' || $sourcezone =~ /^:/;
|
||||
fatal_error "Unknown source zone ($sourcezone)" unless $sourceref = defined_zone( $sourcezone );
|
||||
|
||||
if ( $actiontype & NATONLY ) {
|
||||
warning_message "Destination zone ($destzone) ignored" unless $destzone eq '-' || $destzone eq '';
|
||||
} else {
|
||||
fatal_error "Missing destination zone" if $destzone eq '-' || $destzone eq '';
|
||||
fatal_error "Unknown destination zone ($destzone)" unless $destref = defined_zone( $destzone );
|
||||
}
|
||||
|
||||
my $restriction = NO_RESTRICT;
|
||||
|
||||
if ( $sourcezone eq firewall_zone ) {
|
||||
$restriction = $destzone eq firewall_zone ? ALL_RESTRICT : OUTPUT_RESTRICT;
|
||||
} else {
|
||||
$restriction = INPUT_RESTRICT if $destzone eq firewall_zone;
|
||||
}
|
||||
|
||||
my ( $chain, $chainref, $policy );
|
||||
#
|
||||
# For compatibility with older Shorewall versions
|
||||
#
|
||||
$origdest = ALLIPv4 if $origdest eq 'all';
|
||||
|
||||
#
|
||||
# Take care of chain
|
||||
#
|
||||
|
||||
unless ( $actiontype & NATONLY ) {
|
||||
#
|
||||
# Check for illegal bridge port rule
|
||||
#
|
||||
if ( $destref->{type} eq 'bport4' ) {
|
||||
unless ( $sourceref->{bridge} eq $destref->{bridge} || single_interface( $sourcezone ) eq $destref->{bridge} ) {
|
||||
return 1 if $wildcard;
|
||||
fatal_error "Rules with a DESTINATION Bridge Port zone must have a SOURCE zone on the same bridge";
|
||||
}
|
||||
}
|
||||
|
||||
$chain = "${sourcezone}2${destzone}";
|
||||
$chainref = ensure_chain 'filter', $chain;
|
||||
$policy = $chainref->{policy};
|
||||
|
||||
if ( $policy eq 'NONE' ) {
|
||||
return 1 if $wildcard;
|
||||
fatal_error "Rules may not override a NONE policy";
|
||||
}
|
||||
#
|
||||
# Handle Optimization
|
||||
#
|
||||
if ( $optimize > 0 ) {
|
||||
my $loglevel = $filter_table->{$chainref->{policychain}}{loglevel};
|
||||
if ( $loglevel ne '' ) {
|
||||
return 1 if $target eq "${policy}:$loglevel}";
|
||||
} else {
|
||||
return 1 if $basictarget eq $policy;
|
||||
}
|
||||
}
|
||||
#
|
||||
# Mark the chain as referenced and add appropriate rules from earlier sections.
|
||||
#
|
||||
$chainref = ensure_filter_chain $chain, 1;
|
||||
}
|
||||
|
||||
#
|
||||
# Generate Fixed part of the rule
|
||||
#
|
||||
$rule = join( '', do_proto($proto, $ports, $sports), do_ratelimit( $ratelimit, $basictarget ) , do_user( $user ) , do_test( $mark , 0xFF ) , do_connlimit( $connlimit ), do_time( $time ) );
|
||||
|
||||
unless ( $section eq 'NEW' ) {
|
||||
fatal_error "Entries in the $section SECTION of the rules file not permitted with FASTACCEPT=Yes" if $config{FASTACCEPT};
|
||||
fatal_error "$basictarget rules are not allowed in the $section SECTION" if $actiontype & ( NATRULE | NONAT );
|
||||
$rule .= "-m state --state $section "
|
||||
}
|
||||
|
||||
#
|
||||
# Generate NAT rule(s), if any
|
||||
#
|
||||
if ( $actiontype & NATRULE ) {
|
||||
my ( $server, $serverport );
|
||||
my $randomize = $dest =~ s/:random$// ? '--random ' : '';
|
||||
|
||||
require_capability( 'NAT_ENABLED' , "$basictarget rules", '' );
|
||||
#
|
||||
# Isolate server port
|
||||
#
|
||||
if ( $dest =~ /^(.*)(:(.+))$/ ) {
|
||||
#
|
||||
# Server IP and Port
|
||||
#
|
||||
$server = $1; # May be empty
|
||||
$serverport = $3; # Not Empty due to RE
|
||||
$origdstports = $ports;
|
||||
if ( $serverport =~ /^(\d+)-(\d+)$/ ) {
|
||||
#
|
||||
# Server Port Range
|
||||
#
|
||||
fatal_error "Invalid port range ($serverport)" unless $1 < $2;
|
||||
my @ports = ( $1, $2 );
|
||||
$_ = validate_port( proto_name( $proto ), $_) for ( @ports );
|
||||
( $ports = $serverport ) =~ tr/-/:/;
|
||||
} else {
|
||||
$serverport = $ports = validate_port( proto_name( $proto ), $serverport );
|
||||
}
|
||||
} elsif ( $dest eq ':' ) {
|
||||
#
|
||||
# Rule with no server IP or port ( zone:: )
|
||||
#
|
||||
$server = $serverport = '';
|
||||
} else {
|
||||
#
|
||||
# Simple server IP address (may be empty or "-")
|
||||
#
|
||||
$server = $dest;
|
||||
$serverport = '';
|
||||
}
|
||||
|
||||
#
|
||||
# Generate the target
|
||||
#
|
||||
my $target = '';
|
||||
|
||||
if ( $actiontype & REDIRECT ) {
|
||||
fatal_error "A server IP address may not be specified in a REDIRECT rule" if $server;
|
||||
$target = '-j REDIRECT ';
|
||||
$target .= "--to-port $serverport " if $serverport;
|
||||
if ( $origdest eq '' || $origdest eq '-' ) {
|
||||
$origdest = ALLIPv4;
|
||||
} elsif ( $origdest eq 'detect' ) {
|
||||
if ( $config{DETECT_DNAT_IPADDRS} && $sourcezone ne firewall_zone ) {
|
||||
my $interfacesref = $sourceref->{interfaces};
|
||||
my @interfaces = keys %$interfacesref;
|
||||
$origdest = @interfaces ? "detect:@interfaces" : ALLIPv4;
|
||||
} else {
|
||||
$origdest = ALLIPv4;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fatal_error "A server must be specified in the DEST column in $action rules" if $server eq '';
|
||||
|
||||
if ( $server =~ /^(.+)-(.+)$/ ) {
|
||||
validate_range( $1, $2 );
|
||||
} else {
|
||||
$server = validate_address $server, 1;
|
||||
}
|
||||
|
||||
if ( $action eq 'SAME' ) {
|
||||
fatal_error 'Port mapping not allowed in SAME rules' if $serverport;
|
||||
fatal_error 'SAME not allowed with SOURCE=$FW' if $sourcezone eq firewall_zone;
|
||||
fatal_error "':random' is not supported by the SAME target" if $randomize;
|
||||
warning_message 'Netfilter support for SAME is being dropped in early 2008';
|
||||
$target = '-j SAME ';
|
||||
for my $serv ( split /,/, $server ) {
|
||||
$target .= "--to $serv ";
|
||||
}
|
||||
} elsif ( $action eq 'DNAT' ) {
|
||||
$target = '-j DNAT ';
|
||||
$serverport = ":$serverport" if $serverport;
|
||||
for my $serv ( split /,/, $server ) {
|
||||
$target .= "--to-destination ${serv}${serverport} ";
|
||||
}
|
||||
}
|
||||
|
||||
unless ( $origdest && $origdest ne '-' && $origdest ne 'detect' ) {
|
||||
if ( $config{DETECT_DNAT_IPADDRS} && $sourcezone ne firewall_zone ) {
|
||||
my $interfacesref = $sourceref->{interfaces};
|
||||
my @interfaces = keys %$interfacesref;
|
||||
$origdest = @interfaces ? "detect:@interfaces" : ALLIPv4;
|
||||
} else {
|
||||
$origdest = ALLIPv4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$target .= $randomize;
|
||||
|
||||
#
|
||||
# And generate the nat table rule(s)
|
||||
#
|
||||
expand_rule ( ensure_chain ('nat' , $sourceref->{type} eq 'firewall' ? 'OUTPUT' : dnat_chain $sourcezone ),
|
||||
PREROUTE_RESTRICT ,
|
||||
$rule ,
|
||||
$source ,
|
||||
$origdest ,
|
||||
'' ,
|
||||
'' ,
|
||||
$target ,
|
||||
$loglevel ,
|
||||
$action ,
|
||||
$serverport ? do_proto( $proto, '', '' ) : '' );
|
||||
#
|
||||
# After NAT:
|
||||
# - the destination port will be the server port ($ports) -- we did that above
|
||||
# - the destination IP will be the server IP ($dest)
|
||||
# - there will be no log level (we log NAT rules in the nat table rather than in the filter table).
|
||||
# - the target will be ACCEPT.
|
||||
#
|
||||
unless ( $actiontype & NATONLY ) {
|
||||
$rule = join( '', do_proto( $proto, $ports, $sports ), do_ratelimit( $ratelimit, 'ACCEPT' ), do_user $user , do_test( $mark , 0xFF ) );
|
||||
$loglevel = '';
|
||||
$dest = $server;
|
||||
$action = 'ACCEPT';
|
||||
}
|
||||
} elsif ( $actiontype & NONAT ) {
|
||||
#
|
||||
# NONAT or ACCEPT+ -- May not specify a destination interface
|
||||
#
|
||||
fatal_error "Invalid DEST ($dest) in $action rule" if $dest =~ /:/;
|
||||
|
||||
$origdest = '' unless $origdest and $origdest ne '-';
|
||||
|
||||
if ( $origdest eq 'detect' ) {
|
||||
my $interfacesref = $sourceref->{interfaces};
|
||||
my $interfaces = "@$interfacesref";
|
||||
$origdest = $interfaces ? "detect:$interfaces" : ALLIPv4;
|
||||
}
|
||||
|
||||
expand_rule( ensure_chain ('nat' , $sourceref->{type} eq 'firewall' ? 'OUTPUT' : dnat_chain $sourcezone) ,
|
||||
PREROUTE_RESTRICT ,
|
||||
$rule ,
|
||||
$source ,
|
||||
$dest ,
|
||||
$origdest ,
|
||||
'',
|
||||
'-j RETURN ' ,
|
||||
$loglevel ,
|
||||
$action ,
|
||||
'' );
|
||||
}
|
||||
|
||||
#
|
||||
# Add filter table rule, unless this is a NATONLY rule type
|
||||
#
|
||||
unless ( $actiontype & NATONLY ) {
|
||||
|
||||
if ( $actiontype & ACTION ) {
|
||||
$action = (find_logactionchain $target)->{name};
|
||||
$loglevel = '';
|
||||
}
|
||||
|
||||
unless ( $origdest eq '-' ) {
|
||||
require_capability( 'CONNTRACK_MATCH', 'ORIGINAL DEST in a non-NAT rule', 's' ) unless $actiontype & NATRULE;
|
||||
} else {
|
||||
$origdest = '';
|
||||
}
|
||||
|
||||
expand_rule( ensure_chain( 'filter', $chain ) ,
|
||||
$restriction ,
|
||||
$rule ,
|
||||
$source ,
|
||||
$dest ,
|
||||
$origdest ,
|
||||
$origdstports ,
|
||||
"-j $action " ,
|
||||
$loglevel ,
|
||||
$action ,
|
||||
'' );
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Process a Record in the rules file
|
||||
#
|
||||
# Deals with the ugliness of wildcard zones ('all' in SOURCE and/or DEST column).
|
||||
#
|
||||
sub process_rule ( $$$$$$$$$$$$ ) {
|
||||
my ( $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $connlimit , $time ) = @_;
|
||||
my $intrazone = 0;
|
||||
my $includesrcfw = 1;
|
||||
my $includedstfw = 1;
|
||||
my $thisline = $currentline;
|
||||
#
|
||||
# Section Names are optional so once we get to an actual rule, we need to be sure that
|
||||
# we close off any missing sections.
|
||||
#
|
||||
unless ( $sectioned ) {
|
||||
finish_section 'ESTABLISHED,RELATED';
|
||||
$sections{$section = 'NEW'} = 1;
|
||||
$sectioned = 1;
|
||||
}
|
||||
|
||||
#
|
||||
# Handle Wildcards
|
||||
#
|
||||
if ( $source =~ /^all[-+]/ ) {
|
||||
if ( $source eq 'all+' ) {
|
||||
$source = 'all';
|
||||
$intrazone = 1;
|
||||
} elsif ( ( $source eq 'all+-' ) || ( $source eq 'all-+' ) ) {
|
||||
$source = 'all';
|
||||
$intrazone = 1;
|
||||
$includesrcfw = 0;
|
||||
} elsif ( $source eq 'all-' ) {
|
||||
$source = 'all';
|
||||
$includesrcfw = 0;
|
||||
} else {
|
||||
fatal_error "Invalid SOURCE ($source)";
|
||||
}
|
||||
}
|
||||
|
||||
if ( $dest =~ /^all[-+]/ ) {
|
||||
if ( $dest eq 'all+' ) {
|
||||
$dest = 'all';
|
||||
$intrazone = 1;
|
||||
} elsif ( ( $dest eq 'all+-' ) || ( $dest eq 'all-+' ) ) {
|
||||
$dest = 'all';
|
||||
$intrazone = 1;
|
||||
$includedstfw = 0;
|
||||
} elsif ( $dest eq 'all-' ) {
|
||||
$dest = 'all';
|
||||
$includedstfw = 0;
|
||||
} else {
|
||||
fatal_error "Invalid DEST ($dest)";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
my $action = isolate_basic_target $target;
|
||||
|
||||
fatal_error "Invalid or missing ACTION ($target)" unless defined $action;
|
||||
|
||||
if ( $source eq 'all' ) {
|
||||
for my $zone ( all_zones ) {
|
||||
if ( $includesrcfw || ( zone_type( $zone ) ne 'firewall' ) ) {
|
||||
if ( $dest eq 'all' ) {
|
||||
for my $zone1 ( all_zones ) {
|
||||
if ( $includedstfw || ( zone_type( $zone1 ) ne 'firewall' ) ) {
|
||||
if ( $intrazone || ( $zone ne $zone1 ) ) {
|
||||
process_rule1 $target, $zone, $zone1 , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $connlimit, $time, 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
my $destzone = (split( /:/, $dest, 2 ) )[0];
|
||||
$destzone = firewall_zone unless defined_zone( $destzone ); # We do this to allow 'REDIRECT all ...'; process_rule1 will catch the case where the dest zone is invalid
|
||||
if ( $intrazone || ( $zone ne $destzone ) ) {
|
||||
process_rule1 $target, $zone, $dest , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $connlimit, $time, 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} elsif ( $dest eq 'all' ) {
|
||||
for my $zone ( all_zones ) {
|
||||
my $sourcezone = ( split( /:/, $source, 2 ) )[0];
|
||||
if ( ( $includedstfw || ( zone_type( $zone ) ne 'firewall') ) && ( ( $sourcezone ne $zone ) || $intrazone) ) {
|
||||
process_rule1 $target, $source, $zone , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $connlimit, $time, 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
process_rule1 $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $connlimit, $time, 0;
|
||||
}
|
||||
|
||||
progress_message " Rule \"$thisline\" $done";
|
||||
}
|
||||
|
||||
#
|
||||
# Process the Rules File
|
||||
#
|
||||
sub process_rules() {
|
||||
|
||||
my $fn = open_file 'rules';
|
||||
|
||||
first_entry "$doing $fn...";
|
||||
|
||||
while ( read_a_line ) {
|
||||
|
||||
my ( $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $connlimit, $time ) = split_line1 1, 12, 'rules file', \%rules_commands;
|
||||
|
||||
if ( $target eq 'COMMENT' ) {
|
||||
process_comment;
|
||||
} elsif ( $target eq 'SECTION' ) {
|
||||
#
|
||||
# read_a_line has already verified that there are exactly two tokens on the line
|
||||
#
|
||||
fatal_error "Invalid SECTION ($source)" unless defined $sections{$source};
|
||||
fatal_error "Duplicate or out of order SECTION $source" if $sections{$source};
|
||||
$sectioned = 1;
|
||||
$sections{$source} = 1;
|
||||
|
||||
if ( $source eq 'RELATED' ) {
|
||||
$sections{ESTABLISHED} = 1;
|
||||
finish_section 'ESTABLISHED';
|
||||
} elsif ( $source eq 'NEW' ) {
|
||||
@sections{'ESTABLISHED','RELATED'} = ( 1, 1 );
|
||||
finish_section ( ( $section eq 'RELATED' ) ? 'RELATED' : 'ESTABLISHED,RELATED' );
|
||||
}
|
||||
|
||||
$section = $source;
|
||||
} else {
|
||||
if ( "\L$source" =~ /^none(:.*)?$/ || "\L$dest" =~ /^none(:.*)?$/ ) {
|
||||
progress_message "Rule \"$currentline\" ignored."
|
||||
} else {
|
||||
process_rule $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $connlimit, $time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clear_comment;
|
||||
$section = 'DONE';
|
||||
}
|
||||
|
||||
#
|
||||
# To quote an old comment, "generate_matrix makes a sow's ear out of a silk purse".
|
||||
#
|
||||
|
@ -44,28 +44,44 @@ our @EXPORT = qw( NOTHING
|
||||
firewall_zone
|
||||
defined_zone
|
||||
zone_type
|
||||
zone_family
|
||||
all_zones
|
||||
all_6zones
|
||||
complex_zones
|
||||
non_firewall_zones
|
||||
non_firewall_6zones
|
||||
single_interface
|
||||
validate_interfaces_file
|
||||
validate_6interfaces_file
|
||||
all_interfaces
|
||||
all_6interfaces
|
||||
interface_number
|
||||
find_interface
|
||||
find_6interface
|
||||
known_interface
|
||||
known_6interface
|
||||
have_bridges
|
||||
have_6bridges
|
||||
port_to_bridge
|
||||
port_to_6bridge
|
||||
source_port_to_bridge
|
||||
source_port_to_6bridge
|
||||
interface_is_optional
|
||||
interface6_is_optional
|
||||
find_interfaces_by_option
|
||||
find_6interfaces_by_option
|
||||
get_interface_option
|
||||
get_6interface_option
|
||||
set_interface_option
|
||||
set_6interface_option
|
||||
validate_hosts_file
|
||||
validate_6hosts_file
|
||||
find_hosts_by_option
|
||||
find_6hosts_by_option
|
||||
);
|
||||
|
||||
our @EXPORT_OK = qw( initialize );
|
||||
our $VERSION = 4.1.5;
|
||||
our $VERSION = 4.3.0;
|
||||
|
||||
#
|
||||
# IPSEC Option types
|
||||
@ -82,7 +98,7 @@ use constant { NOTHING => 'NOTHING',
|
||||
#
|
||||
# @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> 'firewall', 'ipv4', 'ipsec4', 'bport4', 'ipv6', 'ipsec6', 'bport6';
|
||||
# options => { complex => 0|1
|
||||
# nested => 0|1
|
||||
# in_out => < policy match string >
|
||||
@ -93,6 +109,7 @@ use constant { NOTHING => 'NOTHING',
|
||||
# children => [ <children> ]
|
||||
# interfaces => [ <interfaces> ]
|
||||
# bridge => <bridge>
|
||||
# family => 1 = IPv4, 2 = IPv6, 3 = firewall
|
||||
# hosts { <type> } => [ { <interface1> => { ipsec => 'ipsec'|'none'
|
||||
# options => { <option1> => <value1>
|
||||
# ...
|
||||
@ -120,14 +137,15 @@ our %reservedName = ( all => 1,
|
||||
#
|
||||
# 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.
|
||||
# @interfaces6 lists the interface names in the order that they appear in the interfaces6 file.
|
||||
#
|
||||
# %interfaces { <interface1> => { name => <name of interface>
|
||||
# root => <name without trailing '+'>
|
||||
# options => { <option1> = <val1> ,
|
||||
# ...
|
||||
# }
|
||||
# zone4 => <zone name>
|
||||
# zone => <zone name>
|
||||
# nets => <number of nets in interface/hosts records referring to this interface>
|
||||
# bridge => <bridge>
|
||||
# broadcasts => 'none', 'detect' or [ <addr1>, <addr2>, ... ]
|
||||
@ -135,9 +153,25 @@ our %reservedName = ( all => 1,
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# %interfaces6 { <interface1> => { name => <name of interface>
|
||||
# root => <name without trailing '+'>
|
||||
# options => { <option1> = <val1> ,
|
||||
# ...
|
||||
# }
|
||||
# zone => <zone name>
|
||||
# nets => <number of nets in interface/hosts records referring to this interface>
|
||||
# bridge => <bridge>
|
||||
# broadcasts => 'none', 'detect' or [ <addr1>, <addr2>, ... ]
|
||||
# number => <ordinal position in the interfaces file>
|
||||
# }
|
||||
# }
|
||||
#
|
||||
our @interfaces;
|
||||
our %interfaces;
|
||||
our @interfaces6;
|
||||
our %interfaces6;
|
||||
our @bport_zones;
|
||||
our @bport_6zones;
|
||||
|
||||
#
|
||||
# Initialize globals -- we take this novel approach to globals initialization to allow
|
||||
@ -156,6 +190,9 @@ sub initialize() {
|
||||
@interfaces = ();
|
||||
%interfaces = ();
|
||||
@bport_zones = ();
|
||||
@interfaces6 = ();
|
||||
%interfaces6 = ();
|
||||
@bport_6zones = ();
|
||||
}
|
||||
|
||||
INIT {
|
||||
@ -219,7 +256,7 @@ sub parse_zone_option_list($$)
|
||||
if ( $key{$e} ) {
|
||||
$h{$e} = $val;
|
||||
} 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 =~ /^ipsec/;
|
||||
$options .= $invert;
|
||||
$options .= "--$e ";
|
||||
$options .= "$val "if defined $val;
|
||||
@ -240,6 +277,7 @@ sub determine_zones()
|
||||
my @z;
|
||||
|
||||
my $ipv4 = 0;
|
||||
my $ipv6 = 0;
|
||||
|
||||
my $fn = open_file 'zones';
|
||||
|
||||
@ -262,28 +300,43 @@ sub determine_zones()
|
||||
push @{$zones{$p}{children}}, $zone;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fatal_error "Invalid zone name ($zone)" unless "\L$zone" =~ /^[a-z]\w*$/ && length $zone <= $globals{MAXZONENAMELENGTH};
|
||||
fatal_error "Invalid zone name ($zone)" if $reservedName{$zone} || $zone =~ /^all2|2all$/;
|
||||
fatal_error( "Duplicate zone name ($zone)" ) if $zones{$zone};
|
||||
|
||||
$type = "ipv4" unless $type;
|
||||
|
||||
my $family = F_INET;
|
||||
|
||||
if ( $type =~ /ipv4/i ) {
|
||||
$type = 'ipv4';
|
||||
$ipv4 = 1;
|
||||
} elsif ( $type =~ /ipv6/i ) {
|
||||
$type = 'ipv6';
|
||||
$ipv6 = 1;
|
||||
$family = F_INET6;
|
||||
} elsif ( $type =~ /^ipsec4?$/i ) {
|
||||
$type = 'ipsec4';
|
||||
} elsif ( $type =~ /^ipsec6?$/i ) {
|
||||
$type = 'ipsec6';
|
||||
$family = F_INET6;
|
||||
} elsif ( $type =~ /^bport4?$/i ) {
|
||||
warning_message "Bridge Port zones should have a parent zone" unless @parents;
|
||||
$type = 'bport4';
|
||||
push @bport_zones, $zone;
|
||||
} elsif ( $type =~ /^bport6?$/i ) {
|
||||
warning_message "Bridge Port zones should have a parent zone" unless @parents;
|
||||
$type = 'bport6';
|
||||
$family = F_INET6;
|
||||
push @bport_6zones, $zone;
|
||||
} 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;
|
||||
$firewall_zone = $zone;
|
||||
$ENV{FW} = $zone;
|
||||
$type = "firewall";
|
||||
$family = F_INET | F_INET6;
|
||||
} elsif ( $type eq '-' ) {
|
||||
$type = 'ipv4';
|
||||
$ipv4 = 1;
|
||||
@ -291,6 +344,10 @@ sub determine_zones()
|
||||
fatal_error "Invalid zone type ($type)" ;
|
||||
}
|
||||
|
||||
for ( @parents ) {
|
||||
fatal_error "Incompatible Parent/Child Zones Types ($_)" unless $zones{$_}{family} == $family
|
||||
}
|
||||
|
||||
for ( $options, $in_options, $out_options ) {
|
||||
$_ = '' if $_ eq '-';
|
||||
}
|
||||
@ -299,10 +356,11 @@ sub determine_zones()
|
||||
parents => \@parents,
|
||||
exclusions => [],
|
||||
bridge => '',
|
||||
family => $family,
|
||||
options => { in_out => parse_zone_option_list( $options || '', $type ) ,
|
||||
in => parse_zone_option_list( $in_options || '', $type ) ,
|
||||
out => parse_zone_option_list( $out_options || '', $type ) ,
|
||||
complex => ($type eq 'ipsec4' || $options || $in_options || $out_options ? 1 : 0) ,
|
||||
complex => ($type =~ /^ipsec/ || $options || $in_options || $out_options ? 1 : 0) ,
|
||||
nested => @parents > 0 } ,
|
||||
interfaces => {} ,
|
||||
children => [] ,
|
||||
@ -311,8 +369,8 @@ sub determine_zones()
|
||||
push @z, $zone;
|
||||
}
|
||||
|
||||
fatal_error "No firewall zone defined" unless $firewall_zone;
|
||||
fatal_error "No IPv4 zones defined" unless $ipv4;
|
||||
fatal_error "No firewall zone defined" unless $firewall_zone;
|
||||
fatal_error "No IPv4 or IPv6 zones defined" unless $ipv4 || $ipv6;
|
||||
|
||||
my %ordered;
|
||||
|
||||
@ -336,7 +394,7 @@ sub determine_zones()
|
||||
}
|
||||
|
||||
#
|
||||
# Return true of we have any ipsec zones
|
||||
# Return true of we have any ipse4c zones
|
||||
#
|
||||
sub haveipseczones() {
|
||||
for my $zoneref ( values %zones ) {
|
||||
@ -346,6 +404,17 @@ sub haveipseczones() {
|
||||
0;
|
||||
}
|
||||
|
||||
#
|
||||
# Return true of we have any ipse4c zones
|
||||
#
|
||||
sub haveipsec6zones() {
|
||||
for my $zoneref ( values %zones ) {
|
||||
return 1 if $zoneref->{type} eq 'ipsec6';
|
||||
}
|
||||
|
||||
0;
|
||||
}
|
||||
|
||||
#
|
||||
# Report about zones.
|
||||
#
|
||||
@ -374,7 +443,7 @@ sub zone_report()
|
||||
my $hosts = $groupref->{hosts};
|
||||
if ( $hosts ) {
|
||||
my $grouplist = join ',', ( @$hosts );
|
||||
progress_message " $interface:$grouplist";
|
||||
progress_message " $interface $grouplist";
|
||||
$printed = 1;
|
||||
}
|
||||
}
|
||||
@ -384,7 +453,7 @@ sub zone_report()
|
||||
}
|
||||
|
||||
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 =~ /^bport/ && ! $zoneref->{bridge};
|
||||
warning_message "*** $zone is an EMPTY ZONE ***" unless $type eq 'firewall';
|
||||
}
|
||||
|
||||
@ -402,7 +471,7 @@ sub dump_zone_contents()
|
||||
my $exclusions = $zoneref->{exclusions};
|
||||
my $entry = "$zone $type";
|
||||
|
||||
$entry .= ":$zoneref->{bridge}" if $type eq 'bport4';
|
||||
$entry .= ":$zoneref->{bridge}" if $type =~ /^bport/;
|
||||
|
||||
if ( $hostref ) {
|
||||
for my $type ( sort keys %$hostref ) {
|
||||
@ -414,7 +483,7 @@ sub dump_zone_contents()
|
||||
my $hosts = $groupref->{hosts};
|
||||
if ( $hosts ) {
|
||||
my $grouplist = join ',', ( @$hosts );
|
||||
$entry .= " $interface:$grouplist";
|
||||
$entry .= " $interface\($grouplist\)";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -455,7 +524,7 @@ sub add_group_to_zone($$$$$)
|
||||
my $arrayref;
|
||||
my $zoneref = $zones{$zone};
|
||||
my $zonetype = $zoneref->{type};
|
||||
my $ifacezone = $interfaces{$interface}{zone4};
|
||||
my $ifacezone = $interfaces{$interface}{zone};
|
||||
|
||||
$zoneref->{interfaces}{$interface} = 1;
|
||||
|
||||
@ -481,7 +550,7 @@ sub add_group_to_zone($$$$$)
|
||||
unless ( $switched ) {
|
||||
if ( $type eq $zonetype ) {
|
||||
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 || $host eq ALLIPv6;
|
||||
}
|
||||
}
|
||||
|
||||
@ -506,7 +575,7 @@ sub add_group_to_zone($$$$$)
|
||||
|
||||
push @{$arrayref}, { options => $options,
|
||||
hosts => \@newnetworks,
|
||||
ipsec => $type eq 'ipsec4' ? 'ipsec' : 'none' };
|
||||
ipsec => $type =~ /^ipsec/ ? 'ipsec' : 'none' };
|
||||
}
|
||||
|
||||
#
|
||||
@ -527,20 +596,36 @@ sub zone_type( $ ) {
|
||||
find_zone( $_[0] )->{type};
|
||||
}
|
||||
|
||||
sub zone_family( $ ) {
|
||||
find_zone( $_[0] )->{family};
|
||||
}
|
||||
|
||||
sub defined_zone( $ ) {
|
||||
$zones{$_[0]};
|
||||
}
|
||||
|
||||
sub all_zones() {
|
||||
@zones;
|
||||
grep ( ! $zones{$_}{family} & F_INET , @zones );
|
||||
}
|
||||
|
||||
sub all_6zones() {
|
||||
grep ( ! $zones{$_}{family} & F_INET6 , @zones );
|
||||
}
|
||||
|
||||
sub non_firewall_zones() {
|
||||
grep ( $zones{$_}{type} ne 'firewall' , @zones );
|
||||
grep ( $zones{$_}{family} == F_INET , @zones );
|
||||
}
|
||||
|
||||
sub non_firewall_6zones() {
|
||||
grep ( $zones{$_}{family} == F_INET6 , @zones );
|
||||
}
|
||||
|
||||
sub complex_zones() {
|
||||
grep( $zones{$_}{options}{complex} , @zones );
|
||||
grep( $zones{$_}{options}{complex} && $zones{$_}{family} == F_INET , @zones );
|
||||
}
|
||||
|
||||
sub complex_6zones() {
|
||||
grep( $zones{$_}{options}{complex} && $zones{$_}{family} == F_INET6 , @zones );
|
||||
}
|
||||
|
||||
sub firewall_zone() {
|
||||
@ -551,20 +636,19 @@ sub firewall_zone() {
|
||||
# Parse the interfaces file.
|
||||
#
|
||||
|
||||
use constant { SIMPLE_IF_OPTION => 1,
|
||||
BINARY_IF_OPTION => 2,
|
||||
ENUM_IF_OPTION => 3,
|
||||
NUMERIC_IF_OPTION => 4,
|
||||
OBSOLETE_IF_OPTION => 5,
|
||||
MASK_IF_OPTION => 7,
|
||||
IF_OPTION_ZONEONLY => 8 };
|
||||
|
||||
sub validate_interfaces_file( $ )
|
||||
{
|
||||
my $export = shift;
|
||||
my $num = 0;
|
||||
|
||||
use constant { SIMPLE_IF_OPTION => 1,
|
||||
BINARY_IF_OPTION => 2,
|
||||
ENUM_IF_OPTION => 3,
|
||||
NUMERIC_IF_OPTION => 4,
|
||||
OBSOLETE_IF_OPTION => 5,
|
||||
MASK_IF_OPTION => 7,
|
||||
|
||||
IF_OPTION_ZONEONLY => 8 };
|
||||
|
||||
my %validoptions = (arp_filter => BINARY_IF_OPTION,
|
||||
arp_ignore => ENUM_IF_OPTION,
|
||||
blacklist => SIMPLE_IF_OPTION,
|
||||
@ -609,6 +693,7 @@ sub validate_interfaces_file( $ )
|
||||
|
||||
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 "IPv6 Zones not allowed in the interfaces file ($zone}" if $zoneref->{type} =~ /6/;
|
||||
}
|
||||
|
||||
$networks = '' if $networks eq '-';
|
||||
@ -752,7 +837,7 @@ sub validate_interfaces_file( $ )
|
||||
|
||||
add_group_to_zone( $zone, $zoneref->{type}, $interface, \@networks, $optionsref ) if $zone;
|
||||
|
||||
$interfaces{$interface}{zone4} = $zone; #Must follow the call to add_group_to_zone()
|
||||
$interfaces{$interface}{zone} = $zone; #Must follow the call to add_group_to_zone()
|
||||
|
||||
progress_message " Interface \"$currentline\" Validated";
|
||||
|
||||
@ -782,6 +867,225 @@ sub validate_interfaces_file( $ )
|
||||
fatal_error "No network interfaces defined" unless @interfaces;
|
||||
}
|
||||
|
||||
#
|
||||
# Parse the interfaces file.
|
||||
#
|
||||
|
||||
sub validate_6interfaces_file( $ )
|
||||
{
|
||||
my $export = shift;
|
||||
my $num = 0;
|
||||
|
||||
my %validoptions = (blacklist => SIMPLE_IF_OPTION,
|
||||
bridge => SIMPLE_IF_OPTION,
|
||||
maclist => SIMPLE_IF_OPTION,
|
||||
nosmurfs => SIMPLE_IF_OPTION,
|
||||
optional => SIMPLE_IF_OPTION,
|
||||
proxyndp => BINARY_IF_OPTION,
|
||||
routeback => SIMPLE_IF_OPTION + IF_OPTION_ZONEONLY,
|
||||
sourceroute => BINARY_IF_OPTION,
|
||||
tcpflags => SIMPLE_IF_OPTION,
|
||||
mss => NUMERIC_IF_OPTION,
|
||||
);
|
||||
|
||||
my $fn = open_file '6interfaces';
|
||||
|
||||
my $first_entry = 1;
|
||||
|
||||
my @ifaces;
|
||||
|
||||
while ( read_a_line ) {
|
||||
|
||||
if ( $first_entry ) {
|
||||
progress_message2 "$doing $fn...";
|
||||
$first_entry = 0;
|
||||
}
|
||||
|
||||
my ($zone, $originalinterface, $networks, $options ) = split_line 2, 4, '6interfaces file';
|
||||
my $zoneref;
|
||||
my $bridge = '';
|
||||
|
||||
if ( $zone eq '-' ) {
|
||||
$zone = '';
|
||||
} else {
|
||||
$zoneref = $zones{$zone};
|
||||
|
||||
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 "IPv4 Zones not allowed in the 6interfaces file ($zone}" if $zoneref->{type} =~ /4/;
|
||||
}
|
||||
|
||||
$networks = '' if $networks eq '-';
|
||||
$options = '' if $options eq '-';
|
||||
|
||||
my ($interface, $port, $extra) = split /:/ , $originalinterface, 3;
|
||||
|
||||
fatal_error "Invalid INTERFACE ($originalinterface)" if ! $interface || defined $extra;
|
||||
|
||||
fatal_error "Invalid Interface Name (+)" if $interface eq '+';
|
||||
|
||||
if ( defined $port ) {
|
||||
fatal_error qq("Virtual" interfaces are not supported -- see http://www.shorewall.net/Shorewall_and_Aliased_Interfaces.html) if $port =~ /^\d+$/;
|
||||
require_capability( 'PHYSDEV_MATCH', 'Bridge Ports', '');
|
||||
fatal_error "Your iptables is not recent enough to support bridge ports" unless $capabilities{KLUDGEFREE};
|
||||
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 "Bridge Ports may only be associated with 'bport' zones" if $zone && $zoneref->{type} ne 'bport4';
|
||||
|
||||
if ( $zone ) {
|
||||
if ( $zoneref->{bridge} ) {
|
||||
fatal_error "Bridge Port zones may only be associated with a single bridge" if $zoneref->{bridge} ne $interface;
|
||||
} else {
|
||||
$zoneref->{bridge} = $interface;
|
||||
}
|
||||
}
|
||||
|
||||
fatal_error "Bridge Ports may not have options" if $options && $options ne '-';
|
||||
|
||||
next if $port eq '';
|
||||
|
||||
fatal_error "Invalid Interface Name ($interface:$port)" unless $port =~ /^[\w.@%-]+\+?$/;
|
||||
|
||||
$bridge = $interface;
|
||||
$interface = $port;
|
||||
} else {
|
||||
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';
|
||||
$bridge = $interface;
|
||||
}
|
||||
|
||||
my $wildcard = 0;
|
||||
my $root;
|
||||
|
||||
if ( $interface =~ /\+$/ ) {
|
||||
$wildcard = 1;
|
||||
$root = substr( $interface, 0, -1 );
|
||||
} else {
|
||||
$root = $interface;
|
||||
}
|
||||
|
||||
my $broadcasts;
|
||||
|
||||
unless ( $networks eq '' || $networks eq 'detect' ) {
|
||||
my @broadcasts = split $networks, 'address';
|
||||
|
||||
for my $address ( @broadcasts ) {
|
||||
fatal_error 'Invalid BROADCAST address' unless $address =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
|
||||
}
|
||||
|
||||
if ( $capabilities{ADDRTYPE} ) {
|
||||
warning_message 'Shorewall no longer uses broadcast addresses in rule generation when Address Type Match is available';
|
||||
} else {
|
||||
$broadcasts = \@broadcasts;
|
||||
}
|
||||
}
|
||||
|
||||
my $optionsref = {};
|
||||
|
||||
my %options;
|
||||
|
||||
if ( $options ) {
|
||||
|
||||
for my $option (split_list $options, 'option' ) {
|
||||
next if $option eq '-';
|
||||
|
||||
( $option, my $value ) = split /=/, $option;
|
||||
|
||||
fatal_error "Invalid Interface option ($option)" unless my $type = $validoptions{$option};
|
||||
|
||||
fatal_error "The \"$option\" option may not be specified on a multi-zone interface" if $type & IF_OPTION_ZONEONLY && ! $zone;
|
||||
|
||||
$type &= MASK_IF_OPTION;
|
||||
|
||||
if ( $type == SIMPLE_IF_OPTION ) {
|
||||
fatal_error "Option $option does not take a value" if defined $value;
|
||||
$options{$option} = 1;
|
||||
} elsif ( $type == BINARY_IF_OPTION ) {
|
||||
$value = 1 unless defined $value;
|
||||
fatal_error "Option value for $option must be 0 or 1" unless ( $value eq '0' || $value eq '1' );
|
||||
fatal_error "The $option option may not be used with a wild-card interface name" if $wildcard;
|
||||
$options{$option} = $value;
|
||||
} elsif ( $type == ENUM_IF_OPTION ) {
|
||||
fatal_error "The $option option may not be used with a wild-card interface name" if $wildcard;
|
||||
if ( $option eq 'arp_ignore' ) {
|
||||
if ( defined $value ) {
|
||||
if ( $value =~ /^[1-3,8]$/ ) {
|
||||
$options{arp_ignore} = $value;
|
||||
} else {
|
||||
fatal_error "Invalid value ($value) for arp_ignore";
|
||||
}
|
||||
} else {
|
||||
$options{arp_ignore} = 1;
|
||||
}
|
||||
} else {
|
||||
fatal_error "Internal Error in validate_interfaces_file";
|
||||
}
|
||||
} elsif ( $type == NUMERIC_IF_OPTION ) {
|
||||
fatal_error "The $option option requires a value" unless defined $value;
|
||||
my $numval = numeric_value $value;
|
||||
fatal_error "Invalid value ($value) for option $option" unless defined $numval;
|
||||
$options{$option} = $numval;
|
||||
} else {
|
||||
warning_message "Support for the $option interface option has been removed from Shorewall-perl";
|
||||
}
|
||||
}
|
||||
|
||||
$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 ( $port ) {
|
||||
$options{port} = 1;
|
||||
}
|
||||
|
||||
$optionsref = \%options;
|
||||
|
||||
$interfaces6{$interface} = { name => $interface ,
|
||||
bridge => $bridge ,
|
||||
nets => 0 ,
|
||||
number => ++$num ,
|
||||
root => $root ,
|
||||
broadcasts => $broadcasts ,
|
||||
options => $optionsref };
|
||||
|
||||
push @ifaces, $interface;
|
||||
|
||||
my @networks = allipv4;
|
||||
|
||||
add_group_to_zone( $zone, $zoneref->{type}, $interface, \@networks, $optionsref ) if $zone;
|
||||
|
||||
$interfaces6{$interface}{zone6} = $zone; #Must follow the call to add_group_to_zone()
|
||||
|
||||
progress_message " Interface \"$currentline\" Validated";
|
||||
|
||||
}
|
||||
|
||||
#
|
||||
# We now assemble the @interfaces6 array such that bridge ports immediately precede their associated bridge
|
||||
#
|
||||
for my $interface ( @ifaces ) {
|
||||
my $interfaceref = $interfaces6{$interface};
|
||||
|
||||
if ( $interfaceref->{options}{bridge} ) {
|
||||
my @ports = grep $interfaces{$_}{options}{port} && $interfaces{$_}{bridge} eq $interface, @ifaces;
|
||||
|
||||
if ( @ports ) {
|
||||
push @interfaces, @ports;
|
||||
} else {
|
||||
$interfaceref->{options}{routeback} = 1; #so the bridge will work properly
|
||||
}
|
||||
}
|
||||
|
||||
push @interfaces, $interface unless $interfaceref->{options}{port};
|
||||
}
|
||||
#
|
||||
# Be sure that we have at least one interface
|
||||
#
|
||||
fatal_error "No network interfaces defined" unless @interfaces;
|
||||
}
|
||||
|
||||
#
|
||||
# Returns true if passed interface matches an entry in /etc/shorewall/interfaces
|
||||
#
|
||||
@ -809,6 +1113,33 @@ sub known_interface($)
|
||||
0;
|
||||
}
|
||||
|
||||
#
|
||||
# Returns true if passed interface matches an entry in /etc/shorewall/interfaces
|
||||
#
|
||||
# If the passed name matches a wildcard, a entry for the name is added in %interfaces to speed up validation of other references to that name.
|
||||
#
|
||||
sub known_6interface($)
|
||||
{
|
||||
my $interface = $_[0];
|
||||
my $interfaceref = $interfaces6{$interface};
|
||||
|
||||
return $interfaceref if $interfaceref;
|
||||
|
||||
for my $i ( @interfaces6 ) {
|
||||
$interfaceref = $interfaces6{$i};
|
||||
my $val = $interfaceref->{root};
|
||||
next if $val eq $i;
|
||||
if ( substr( $interface, 0, length $val ) eq $val ) {
|
||||
#
|
||||
# Cache this result for future reference. We set the 'name' to the name of the entry that appears in /etc/shorewall/interfaces.
|
||||
#
|
||||
return $interfaces6{$interface} = { options => $interfaceref->{options}, bridge => $interfaceref->{bridge} , name => $i , number => $interfaceref->{number} };
|
||||
}
|
||||
}
|
||||
|
||||
0;
|
||||
}
|
||||
|
||||
#
|
||||
# Return interface number
|
||||
#
|
||||
@ -823,12 +1154,38 @@ sub all_interfaces() {
|
||||
@interfaces;
|
||||
}
|
||||
|
||||
#
|
||||
# Return 6interface number
|
||||
#
|
||||
sub interface6_number( $ ) {
|
||||
$interfaces6{$_[0]}{number} || 256;
|
||||
}
|
||||
|
||||
#
|
||||
# Return the 6interfaces list
|
||||
#
|
||||
sub all_interfaces6() {
|
||||
@interfaces6;
|
||||
}
|
||||
|
||||
#
|
||||
# Return a reference to the interfaces table entry for an interface
|
||||
#
|
||||
sub find_interface( $ ) {
|
||||
my $interface = $_[0];
|
||||
my $interfaceref = $interfaces{ $interface };
|
||||
my $interfaceref = $interfaces6{ $interface };
|
||||
|
||||
fatal_error "Unknown Interface ($interface)" unless $interfaceref;
|
||||
|
||||
$interfaceref;
|
||||
}
|
||||
|
||||
#
|
||||
# Return a reference to the interfaces6 table entry for an interface
|
||||
#
|
||||
sub find_interface6( $ ) {
|
||||
my $interface = $_[0];
|
||||
my $interfaceref = $interfaces6{ $interface };
|
||||
|
||||
fatal_error "Unknown Interface ($interface)" unless $interfaceref;
|
||||
|
||||
@ -842,6 +1199,13 @@ sub have_bridges() {
|
||||
@bport_zones > 0;
|
||||
}
|
||||
|
||||
#
|
||||
# Returns true if there are bridge port zones defined in the config
|
||||
#
|
||||
sub have_6bridges() {
|
||||
@bport_6zones > 0;
|
||||
}
|
||||
|
||||
#
|
||||
# Return the bridge associated with the passed interface. If the interface is not a bridge port,
|
||||
# return ''
|
||||
@ -851,6 +1215,15 @@ sub port_to_bridge( $ ) {
|
||||
return $portref && $portref->{options}{port} ? $portref->{bridge} : '';
|
||||
}
|
||||
|
||||
#
|
||||
# Return the bridge associated with the passed interface. If the interface is not a bridge port,
|
||||
# return ''
|
||||
#
|
||||
sub port_to_6bridge( $ ) {
|
||||
my $portref = $interfaces6{$_[0]};
|
||||
return $portref && $portref->{options}{port} ? $portref->{bridge} : '';
|
||||
}
|
||||
|
||||
#
|
||||
# Return the bridge associated with the passed interface.
|
||||
#
|
||||
@ -859,6 +1232,14 @@ sub source_port_to_bridge( $ ) {
|
||||
return $portref ? $portref->{bridge} : '';
|
||||
}
|
||||
|
||||
#
|
||||
# Return the bridge associated with the passed 6interface.
|
||||
#
|
||||
sub source_port_to_6bridge( $ ) {
|
||||
my $portref = $interfaces6{$_[0]};
|
||||
return $portref ? $portref->{bridge} : '';
|
||||
}
|
||||
|
||||
#
|
||||
# Return the 'optional' setting of the passed interface
|
||||
#
|
||||
@ -867,6 +1248,14 @@ sub interface_is_optional($) {
|
||||
$optionsref && $optionsref->{optional};
|
||||
}
|
||||
|
||||
#
|
||||
# Return the 'optional' setting of the passed interface
|
||||
#
|
||||
sub interface6_is_optional($) {
|
||||
my $optionsref = $interfaces6{$_[0]}{options};
|
||||
$optionsref && $optionsref->{optional};
|
||||
}
|
||||
|
||||
#
|
||||
# Returns reference to array of interfaces with the passed option
|
||||
#
|
||||
@ -884,6 +1273,23 @@ sub find_interfaces_by_option( $ ) {
|
||||
\@ints;
|
||||
}
|
||||
|
||||
#
|
||||
# Returns reference to array of interfaces6 with the passed option
|
||||
#
|
||||
sub find_interfaces6_by_option( $ ) {
|
||||
my $option = $_[0];
|
||||
my @ints = ();
|
||||
|
||||
for my $interface ( @interfaces ) {
|
||||
my $optionsref = $interfaces{$interface}{options};
|
||||
if ( $optionsref && defined $optionsref->{$option} ) {
|
||||
push @ints , $interface
|
||||
}
|
||||
}
|
||||
|
||||
\@ints;
|
||||
}
|
||||
|
||||
#
|
||||
# Return the value of an option for an interface
|
||||
#
|
||||
@ -902,6 +1308,24 @@ sub set_interface_option( $$$ ) {
|
||||
$interfaces{$interface}{options}{$option} = $value;
|
||||
}
|
||||
|
||||
#
|
||||
# Return the value of an option for an interface6
|
||||
#
|
||||
sub get_interface6_option( $$ ) {
|
||||
my ( $interface, $option ) = @_;
|
||||
|
||||
$interfaces6{$interface}{options}{$option};
|
||||
}
|
||||
|
||||
#
|
||||
# Set an option for an interface6
|
||||
#
|
||||
sub set_interface6_option( $$$ ) {
|
||||
my ( $interface, $option, $value ) = @_;
|
||||
|
||||
$interfaces6{$interface}{options}{$option} = $value;
|
||||
}
|
||||
|
||||
#
|
||||
# Validates the hosts file. Generates entries in %zone{..}{hosts}
|
||||
#
|
||||
@ -910,10 +1334,8 @@ sub validate_hosts_file()
|
||||
my %validoptions = (
|
||||
blacklist => 1,
|
||||
maclist => 1,
|
||||
norfc1918 => 1,
|
||||
nosmurfs => 1,
|
||||
routeback => 1,
|
||||
routefilter => 1,
|
||||
tcpflags => 1,
|
||||
broadcast => 1,
|
||||
destonly => 1,
|
||||
@ -939,6 +1361,7 @@ sub validate_hosts_file()
|
||||
|
||||
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 'IPv6 zones not allowed in ZONE column of hosts record' if $type =~ /6/;
|
||||
|
||||
my $interface;
|
||||
|
||||
@ -951,7 +1374,7 @@ sub validate_hosts_file()
|
||||
fatal_error "Invalid HOST(S) column contents: $hosts";
|
||||
}
|
||||
|
||||
if ( $type eq 'bport4' ) {
|
||||
if ( $type eq 'bport6' ) {
|
||||
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};
|
||||
@ -969,7 +1392,7 @@ sub validate_hosts_file()
|
||||
for my $option ( @options )
|
||||
{
|
||||
if ( $option eq 'ipsec' ) {
|
||||
$type = 'ipsec4';
|
||||
$type = 'ipsec6';
|
||||
$zoneref->{options}{complex} = 1;
|
||||
$ipsec = 1;
|
||||
} elsif ( $validoptions{$option}) {
|
||||
@ -995,7 +1418,7 @@ sub validate_hosts_file()
|
||||
#
|
||||
# Take care of case where the hosts list begins with '!'
|
||||
#
|
||||
$hosts = join( '', ALLIPv4 , $hosts ) if substr($hosts, 0, 2 ) eq ',!';
|
||||
$hosts = join( '', ALLIPv6 , $hosts ) if substr($hosts, 0, 2 ) eq ',!';
|
||||
|
||||
add_group_to_zone( $zone, $type , $interface, [ split_list( $hosts, 'host' ) ] , $optionsref);
|
||||
|
||||
@ -1005,6 +1428,108 @@ sub validate_hosts_file()
|
||||
$capabilities{POLICY_MATCH} = '' unless $ipsec || haveipseczones;
|
||||
}
|
||||
|
||||
#
|
||||
# Validates the 6hosts file. Generates entries in %zone{..}{hosts}
|
||||
#
|
||||
sub validate_6hosts_file()
|
||||
{
|
||||
my %validoptions = (
|
||||
blacklist => 1,
|
||||
maclist => 1,
|
||||
nosmurfs => 1,
|
||||
routeback => 1,
|
||||
tcpflags => 1,
|
||||
broadcast => 1,
|
||||
destonly => 1,
|
||||
sourceonly => 1,
|
||||
);
|
||||
|
||||
my $ipsec = 0;
|
||||
my $first_entry = 1;
|
||||
|
||||
my $fn = open_file '6hosts';
|
||||
|
||||
while ( read_a_line ) {
|
||||
|
||||
if ( $first_entry ) {
|
||||
progress_message2 "$doing $fn...";
|
||||
$first_entry = 0;
|
||||
}
|
||||
|
||||
my ($zone, $hosts, $options ) = split_line 2, 3, '6hosts file';
|
||||
|
||||
my $zoneref = $zones{$zone};
|
||||
my $type = $zoneref->{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 'IPv4 zonea not allowed in ZONE column of 6hosts record' if $type =~ /4/;
|
||||
|
||||
my $interface;
|
||||
|
||||
if ( $hosts =~ /^([\w.@%-]+\+?)\[(.*)\]$/ ) {
|
||||
$interface = $1;
|
||||
$hosts = $2;
|
||||
$zoneref->{options}{complex} = 1 if $hosts =~ /^\+/;
|
||||
fatal_error "Unknown 6interface ($interface)" unless $interfaces6{$interface}{root};
|
||||
} else {
|
||||
fatal_error "Invalid HOST(S) column contents: $hosts";
|
||||
}
|
||||
|
||||
if ( $type eq 'bport6' ) {
|
||||
if ( $zoneref->{bridge} eq '' ) {
|
||||
fatal_error 'Bridge Port Zones may only be associated with bridge ports' unless $interfaces6{$interface}{options}{port};
|
||||
$zoneref->{bridge} = $interfaces6{$interface}{bridge};
|
||||
} elsif ( $zoneref->{bridge} ne $interfaces6{$interface}{bridge} ) {
|
||||
fatal_error "Interface $interface is not a port on bridge $zoneref->{bridge}";
|
||||
}
|
||||
}
|
||||
|
||||
my $optionsref = {};
|
||||
|
||||
if ( $options ne '-' ) {
|
||||
my @options = split_list $options, 'option';
|
||||
my %options;
|
||||
|
||||
for my $option ( @options )
|
||||
{
|
||||
if ( $option eq 'ipsec' ) {
|
||||
$type = 'ipsec6';
|
||||
$zoneref->{options}{complex} = 1;
|
||||
$ipsec = 1;
|
||||
} elsif ( $validoptions{$option}) {
|
||||
$options{$option} = 1;
|
||||
} else {
|
||||
fatal_error "Invalid option ($option)";
|
||||
}
|
||||
}
|
||||
|
||||
$optionsref = \%options;
|
||||
}
|
||||
|
||||
#
|
||||
# Looking for the '!' at the beginning of a list element is more straight-foward than looking for it in the middle.
|
||||
#
|
||||
# Be sure we don't have a ',!' in the original
|
||||
#
|
||||
fatal_error "Invalid hosts list" if $hosts =~ /,!/;
|
||||
#
|
||||
# Now add a comma before '!'. Do it globally - add_group_to_zone() correctly checks for multiple exclusions
|
||||
#
|
||||
$hosts =~ s/!/,!/g;
|
||||
#
|
||||
# Take care of case where the hosts list begins with '!'
|
||||
#
|
||||
$hosts = join( '', ALLIPv6 , $hosts ) if substr($hosts, 0, 2 ) eq ',!';
|
||||
|
||||
add_group_to_zone( $zone, $type , $interface, [ split_list( $hosts, 'host' ) ] , $optionsref);
|
||||
|
||||
progress_message " Host \"$currentline\" validated";
|
||||
}
|
||||
|
||||
$capabilities{POLICY_MATCH} = 'Yes' if $ipsec || haveipseczones;
|
||||
}
|
||||
|
||||
#
|
||||
# Returns a reference to a array of host entries. Each entry is a
|
||||
# reference to an array containing ( interface , polciy match type {ipsec|none} , network );
|
||||
@ -1013,7 +1538,7 @@ sub find_hosts_by_option( $ ) {
|
||||
my $option = $_[0];
|
||||
my @hosts;
|
||||
|
||||
for my $zone ( grep $zones{$_}{type} ne 'firewall' , @zones ) {
|
||||
for my $zone ( grep $zones{$_}{family} == F_INET , @zones ) {
|
||||
while ( my ($type, $interfaceref) = each %{$zones{$zone}{hosts}} ) {
|
||||
while ( my ( $interface, $arrayref) = ( each %{$interfaceref} ) ) {
|
||||
for my $host ( @{$arrayref} ) {
|
||||
@ -1028,7 +1553,7 @@ sub find_hosts_by_option( $ ) {
|
||||
}
|
||||
|
||||
for my $interface ( @interfaces ) {
|
||||
if ( ! $interfaces{$interface}{zone4} && $interfaces{$interface}{options}{$option} ) {
|
||||
if ( ! $interfaces{$interface}{zone} && $interfaces{$interface}{options}{$option} ) {
|
||||
push @hosts, [ $interface, 'none', ALLIPv4 ];
|
||||
}
|
||||
}
|
||||
@ -1036,4 +1561,35 @@ sub find_hosts_by_option( $ ) {
|
||||
\@hosts;
|
||||
}
|
||||
|
||||
#
|
||||
# Returns a reference to a array of host entries. Each entry is a
|
||||
# reference to an array containing ( interface , polciy match type {ipsec|none} , network );
|
||||
#
|
||||
sub find_6hosts_by_option( $ ) {
|
||||
my $option = $_[0];
|
||||
my @hosts;
|
||||
|
||||
for my $zone ( grep $zones{$_}{family} == F_INET6 , @zones ) {
|
||||
while ( my ($type, $interfaceref) = each %{$zones{$zone}{hosts}} ) {
|
||||
while ( my ( $interface, $arrayref) = ( each %{$interfaceref} ) ) {
|
||||
for my $host ( @{$arrayref} ) {
|
||||
if ( $host->{options}{$option} ) {
|
||||
for my $net ( @{$host->{hosts}} ) {
|
||||
push @hosts, [ $interface, $host->{ipsec} , $net ];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for my $interface ( @interfaces6 ) {
|
||||
if ( ! $interfaces6{$interface}{zone} && $interfaces6{$interface}{options}{$option} ) {
|
||||
push @hosts, [ $interface, 'none', ALLIPv6 ];
|
||||
}
|
||||
}
|
||||
|
||||
\@hosts;
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -1,4 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
||||
<refentry>
|
||||
<refmeta>
|
||||
<refentrytitle>shorewall-interfaces</refentrytitle>
|
||||
@ -95,9 +97,9 @@ loc eth2 -</programlisting>
|
||||
|
||||
<listitem>
|
||||
<para>The broadcast address(es) for the network(s) to which the
|
||||
interface belongs. For P-T-P interfaces, this column is left
|
||||
blank. If the interface has multiple addresses on multiple subnets
|
||||
then list the broadcast addresses as a comma-separated list.</para>
|
||||
interface belongs. For P-T-P interfaces, this column is left blank.
|
||||
If the interface has multiple addresses on multiple subnets then
|
||||
list the broadcast addresses as a comma-separated list.</para>
|
||||
|
||||
<para>If you use the special value <emphasis
|
||||
role="bold">detect</emphasis>, Shorewall will detect the broadcast
|
||||
@ -257,8 +259,8 @@ loc eth2 -</programlisting>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>you have a static IP but are on a LAN segment with
|
||||
lots of DHCP clients.</para>
|
||||
<para>the interface has a static IP but is on a LAN
|
||||
segment with lots of DHCP clients.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
@ -266,6 +268,9 @@ loc eth2 -</programlisting>
|
||||
port and DHCP clients on another port.</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
|
||||
<para>This option allows DHCP datagrams to enter and leave the
|
||||
interface.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 150 KiB |
Loading…
Reference in New Issue
Block a user