forked from extern/shorewall_code
Consolidate Perl Modules
git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@6888 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
This commit is contained in:
parent
d1d664ed97
commit
bddf520436
@ -25,11 +25,9 @@
|
|||||||
#
|
#
|
||||||
package Shorewall::Accounting;
|
package Shorewall::Accounting;
|
||||||
require Exporter;
|
require Exporter;
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
use Shorewall::Config;
|
||||||
use Shorewall::IPAddrs;
|
use Shorewall::IPAddrs;
|
||||||
use Shorewall::Zones;
|
use Shorewall::Zones;
|
||||||
use Shorewall::Interfaces;
|
|
||||||
use Shorewall::Chains;
|
use Shorewall::Chains;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
@ -21,15 +21,13 @@
|
|||||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
|
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
|
||||||
#
|
#
|
||||||
# This module contains the code for dealing with actions (built-in,
|
# This module contains the code for dealing with actions (built-in,
|
||||||
# standard and user-defined).
|
# standard and user-defined) and Macros.
|
||||||
#
|
#
|
||||||
package Shorewall::Actions;
|
package Shorewall::Actions;
|
||||||
require Exporter;
|
require Exporter;
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
use Shorewall::Config;
|
||||||
use Shorewall::Zones;
|
use Shorewall::Zones;
|
||||||
use Shorewall::Chains;
|
use Shorewall::Chains;
|
||||||
use Shorewall::Macros;
|
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
|
||||||
@ -44,9 +42,17 @@ our @EXPORT = qw( merge_levels
|
|||||||
process_actions2
|
process_actions2
|
||||||
process_actions3
|
process_actions3
|
||||||
|
|
||||||
|
find_macro
|
||||||
|
split_action
|
||||||
|
substitute_param
|
||||||
|
merge_macro_source_dest
|
||||||
|
merge_macro_column
|
||||||
|
|
||||||
%usedactions
|
%usedactions
|
||||||
%default_actions
|
%default_actions
|
||||||
%actions
|
%actions
|
||||||
|
|
||||||
|
%macros
|
||||||
);
|
);
|
||||||
our @EXPORT_OK = qw( initialize );
|
our @EXPORT_OK = qw( initialize );
|
||||||
our $VERSION = 4.00;
|
our $VERSION = 4.00;
|
||||||
@ -73,6 +79,9 @@ our %actions;
|
|||||||
# Contains an entry for each used <action>:<level>[:<tag>] that maps to the associated chain.
|
# Contains an entry for each used <action>:<level>[:<tag>] that maps to the associated chain.
|
||||||
#
|
#
|
||||||
our %logactionchains;
|
our %logactionchains;
|
||||||
|
|
||||||
|
our %macros;
|
||||||
|
|
||||||
#
|
#
|
||||||
# Initialize globals -- we take this novel approach to globals initialization to allow
|
# Initialize globals -- we take this novel approach to globals initialization to allow
|
||||||
# the compiler to run multiple times in the same process. The
|
# the compiler to run multiple times in the same process. The
|
||||||
@ -108,6 +117,84 @@ sub merge_levels ($$) {
|
|||||||
my $subparts = @subparts;
|
my $subparts = @subparts;
|
||||||
|
|
||||||
my $target = $subparts[0];
|
my $target = $subparts[0];
|
||||||
|
#
|
||||||
|
# Try to find a macro file -- RETURNS false if the file doesn't exist or MACRO if it does.
|
||||||
|
# If the file exists, the macro is entered into the 'targets' table and the fully-qualified
|
||||||
|
# name of the file is stored in the 'macro' table.
|
||||||
|
#
|
||||||
|
sub find_macro( $ )
|
||||||
|
{
|
||||||
|
my $macro = $_[0];
|
||||||
|
my $macrofile = find_file "macro.$macro";
|
||||||
|
|
||||||
|
if ( -f $macrofile ) {
|
||||||
|
$macros{$macro} = $macrofile;
|
||||||
|
$targets{$macro} = MACRO;
|
||||||
|
} else {
|
||||||
|
0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Return ( action, level[:tag] ) from passed full action
|
||||||
|
#
|
||||||
|
sub split_action ( $ ) {
|
||||||
|
my $action = $_[0];
|
||||||
|
my @a = split( /:/ , $action, 4 );
|
||||||
|
fatal_error "Invalid ACTION ($action)" if ( $action =~ /::/ ) || ( @a > 3 );
|
||||||
|
( shift @a, join ":", @a );
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# This function substitutes the second argument for the first part of the first argument up to the first colon (":")
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# substitute_param DNAT PARAM:info:FTP
|
||||||
|
#
|
||||||
|
# produces "DNAT:info:FTP"
|
||||||
|
#
|
||||||
|
sub substitute_param( $$ ) {
|
||||||
|
my ( $param, $action ) = @_;
|
||||||
|
|
||||||
|
if ( $action =~ /:/ ) {
|
||||||
|
my $logpart = (split_action $action)[1];
|
||||||
|
$logpart =~ s!/$!!;
|
||||||
|
return "$param:$logpart";
|
||||||
|
}
|
||||||
|
|
||||||
|
$param;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Combine fields from a macro body with one from the macro invocation
|
||||||
|
#
|
||||||
|
sub merge_macro_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 ) = @_;
|
||||||
|
|
||||||
|
if ( defined $invocation && $invocation ne '' && $invocation ne '-' ) {
|
||||||
|
$invocation;
|
||||||
|
} else {
|
||||||
|
$body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
push @subparts, '' while @subparts < 3; #Avoid undefined values
|
push @subparts, '' while @subparts < 3; #Avoid undefined values
|
||||||
|
|
||||||
|
@ -27,11 +27,9 @@
|
|||||||
package Shorewall::Chains;
|
package Shorewall::Chains;
|
||||||
require Exporter;
|
require Exporter;
|
||||||
|
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
use Shorewall::Config;
|
||||||
use Shorewall::Ports;
|
use Shorewall::Ports;
|
||||||
use Shorewall::Zones;
|
use Shorewall::Zones;
|
||||||
use Shorewall::Interfaces;
|
|
||||||
use Shorewall::IPAddrs;
|
use Shorewall::IPAddrs;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
@ -1,367 +0,0 @@
|
|||||||
#
|
|
||||||
# Shorewall-perl 4.0 -- /usr/share/shorewall-perl/Shorewall/Common.pm
|
|
||||||
#
|
|
||||||
# This program is under GPL [http://www.gnu.org/copyleft/gpl.htm]
|
|
||||||
#
|
|
||||||
# (c) 2007 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Complete documentation is available at http://shorewall.net
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of Version 2 of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
|
|
||||||
#
|
|
||||||
# This is the lowes level Shorewall module. It provides very basic
|
|
||||||
# services such as creation of temporary 'object' files, writing
|
|
||||||
# into those files (emitters) and finalizing those files (renaming
|
|
||||||
# them to their final name and setting their mode appropriately).
|
|
||||||
#
|
|
||||||
package Shorewall::Common;
|
|
||||||
require Exporter;
|
|
||||||
use File::Basename;
|
|
||||||
use File::Temp qw/ tempfile tempdir /;
|
|
||||||
use Cwd 'abs_path';
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
our @ISA = qw(Exporter);
|
|
||||||
our @EXPORT = qw(
|
|
||||||
create_temp_object
|
|
||||||
finalize_object
|
|
||||||
emit
|
|
||||||
emitj
|
|
||||||
emit_unindented
|
|
||||||
save_progress_message
|
|
||||||
save_progress_message_short
|
|
||||||
set_timestamp
|
|
||||||
set_verbose
|
|
||||||
progress_message
|
|
||||||
progress_message2
|
|
||||||
progress_message3
|
|
||||||
push_indent
|
|
||||||
pop_indent
|
|
||||||
copy
|
|
||||||
copy1
|
|
||||||
create_temp_aux_config
|
|
||||||
finalize_aux_config
|
|
||||||
|
|
||||||
$command
|
|
||||||
$doing
|
|
||||||
$done
|
|
||||||
$verbose
|
|
||||||
);
|
|
||||||
our @EXPORT_OK = qw( $timestamp initialize );
|
|
||||||
our $VERSION = 4.00;
|
|
||||||
|
|
||||||
our ($command, $doing, $done );
|
|
||||||
our $verbose;
|
|
||||||
our $timestamp;
|
|
||||||
our $object;
|
|
||||||
our $lastlineblank;
|
|
||||||
our $indent;
|
|
||||||
our ( $dir, $file ); # Object's Directory and File
|
|
||||||
our $tempfile; # Temporary File Name
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initialize globals -- we take this novel approach to globals initialization to allow
|
|
||||||
# the compiler to run multiple times in the same process. The
|
|
||||||
# initialize() function does globals initialization for this
|
|
||||||
# module and is called from an INIT block below. The function is
|
|
||||||
# also called by Shorewall::Compiler::compiler at the beginning of
|
|
||||||
# the second and subsequent calls to that function.
|
|
||||||
#
|
|
||||||
|
|
||||||
sub initialize() {
|
|
||||||
( $command, $doing, $done ) = qw/ compile Compiling Compiled/; #describe the current command, it's present progressive, and it's completion.
|
|
||||||
|
|
||||||
$verbose = 0; # Verbosity setting. 0 = almost silent, 1 = major progress messages only, 2 = all progress messages (very noisy)
|
|
||||||
$timestamp = ''; # If true, we are to timestamp each progress message
|
|
||||||
$object = 0; # Object (script) file Handle Reference
|
|
||||||
$lastlineblank = 0; # Avoid extra blank lines in the output
|
|
||||||
$indent = ''; # Current indentation
|
|
||||||
( $dir, $file ) = ('',''); # Object's Directory and File
|
|
||||||
$tempfile = ''; # Temporary File Name
|
|
||||||
}
|
|
||||||
|
|
||||||
INIT {
|
|
||||||
initialize;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Fatal Error
|
|
||||||
#
|
|
||||||
sub fatal_error
|
|
||||||
{
|
|
||||||
die " ERROR: @_\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Write the argument to the object file (if any) with the current indentation.
|
|
||||||
#
|
|
||||||
# Replaces leading spaces with tabs as appropriate and suppresses consecutive blank lines.
|
|
||||||
#
|
|
||||||
sub emit ( $ ) {
|
|
||||||
if ( $object ) {
|
|
||||||
#
|
|
||||||
# 'compile' as opposed to 'check'
|
|
||||||
#
|
|
||||||
my $line = $_[0]; # This copy is necessary because the actual arguments are almost always read-only.
|
|
||||||
|
|
||||||
unless ( $line =~ /^\s*$/ ) {
|
|
||||||
$line =~ s/^\n// if $lastlineblank;
|
|
||||||
$line =~ s/^/$indent/gm if $indent;
|
|
||||||
$line =~ s/ /\t/gm;
|
|
||||||
print $object "$line\n";
|
|
||||||
$lastlineblank = ( substr( $line, -1, 1 ) eq "\n" );
|
|
||||||
} else {
|
|
||||||
print $object "\n" unless $lastlineblank;
|
|
||||||
$lastlineblank = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Version of emit() that accepts an indefinite number of scalar arguments; each argument will be emitted as a separate line
|
|
||||||
#
|
|
||||||
sub emitj {
|
|
||||||
if ( $object ) {
|
|
||||||
#
|
|
||||||
# 'compile' as opposed to 'check'
|
|
||||||
#
|
|
||||||
for ( @_ ) {
|
|
||||||
unless ( /^\s*$/ ) {
|
|
||||||
my $line = $_; # This copy is necessary because the actual arguments are almost always read-only.
|
|
||||||
$line =~ s/^\n// if $lastlineblank;
|
|
||||||
$line =~ s/^/$indent/gm if $indent;
|
|
||||||
$line =~ s/ /\t/gm;
|
|
||||||
print $object "$line\n";
|
|
||||||
$lastlineblank = ( substr( $line, -1, 1 ) eq "\n" );
|
|
||||||
} else {
|
|
||||||
print $object "\n" unless $lastlineblank;
|
|
||||||
$lastlineblank = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Write passed message to the object with newline but no indentation.
|
|
||||||
#
|
|
||||||
|
|
||||||
sub emit_unindented( $ ) {
|
|
||||||
print $object "$_[0]\n" if $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Write a progress_message2 command with surrounding blank lines to the output file.
|
|
||||||
#
|
|
||||||
sub save_progress_message( $ ) {
|
|
||||||
emit "\nprogress_message2 @_\n" if $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Write a progress_message command to the output file.
|
|
||||||
#
|
|
||||||
sub save_progress_message_short( $ ) {
|
|
||||||
emit "progress_message $_[0]" if $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Set $timestamp
|
|
||||||
#
|
|
||||||
sub set_timestamp( $ ) {
|
|
||||||
$timestamp = shift;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Set $verbose
|
|
||||||
#
|
|
||||||
sub set_verbose( $ ) {
|
|
||||||
$verbose = shift;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Print the current TOD to STDOUT.
|
|
||||||
#
|
|
||||||
sub timestamp() {
|
|
||||||
my ($sec, $min, $hr) = ( localtime ) [0,1,2];
|
|
||||||
printf '%02d:%02d:%02d ', $hr, $min, $sec;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Write a message if $verbose >= 2
|
|
||||||
#
|
|
||||||
sub progress_message {
|
|
||||||
if ( $verbose > 1 ) {
|
|
||||||
timestamp if $timestamp;
|
|
||||||
#
|
|
||||||
# We use this function to display messages containing raw config file images which may contains tabs (including multiple tabs in succession).
|
|
||||||
# The following makes such messages look more readable and uniform
|
|
||||||
#
|
|
||||||
my $line = "@_";
|
|
||||||
$line =~ s/\s+/ /g;
|
|
||||||
print "$line\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Write a message if $verbose >= 1
|
|
||||||
#
|
|
||||||
sub progress_message2 {
|
|
||||||
if ( $verbose > 0 ) {
|
|
||||||
timestamp if $timestamp;
|
|
||||||
print "@_\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Write a message if $verbose >= 0
|
|
||||||
#
|
|
||||||
sub progress_message3 {
|
|
||||||
if ( $verbose >= 0 ) {
|
|
||||||
timestamp if $timestamp;
|
|
||||||
print "@_\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Push/Pop Indent
|
|
||||||
#
|
|
||||||
sub push_indent() {
|
|
||||||
$indent = "$indent ";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub pop_indent() {
|
|
||||||
$indent = substr( $indent , 0 , ( length $indent ) - 4 );
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Functions for copying files into the object
|
|
||||||
#
|
|
||||||
sub copy( $ ) {
|
|
||||||
if ( $object ) {
|
|
||||||
my $file = $_[0];
|
|
||||||
|
|
||||||
open IF , $file or fatal_error "Unable to open $file: $!";
|
|
||||||
|
|
||||||
while ( <IF> ) {
|
|
||||||
s/^/$indent/ if $indent;
|
|
||||||
print $object $_;
|
|
||||||
}
|
|
||||||
|
|
||||||
close IF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# This one handles line continuation.
|
|
||||||
|
|
||||||
sub copy1( $ ) {
|
|
||||||
if ( $object ) {
|
|
||||||
my $file = $_[0];
|
|
||||||
|
|
||||||
open IF , $file or fatal_error "Unable to open $file: $!";
|
|
||||||
|
|
||||||
my $do_indent = 1;
|
|
||||||
|
|
||||||
while ( <IF> ) {
|
|
||||||
if ( /^\s*$/ ) {
|
|
||||||
print $object "\n";
|
|
||||||
$do_indent = 1;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
s/^/$indent/ if $indent && $do_indent;
|
|
||||||
print $object $_;
|
|
||||||
$do_indent = ! ( /\\$/ );
|
|
||||||
}
|
|
||||||
|
|
||||||
close IF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Create the temporary object file -- the passed file name is the name of the final file.
|
|
||||||
# We create a temporary file in the same directory so that we can use rename to finalize it.
|
|
||||||
#
|
|
||||||
sub create_temp_object( $ ) {
|
|
||||||
my $objectfile = $_[0];
|
|
||||||
my $suffix;
|
|
||||||
|
|
||||||
eval {
|
|
||||||
( $file, $dir, $suffix ) = fileparse( $objectfile );
|
|
||||||
};
|
|
||||||
|
|
||||||
die if $@;
|
|
||||||
|
|
||||||
fatal_error "Directory $dir does not exist" unless -d $dir;
|
|
||||||
fatal_error "Directory $dir is not writable" unless -w _;
|
|
||||||
fatal_error "$dir is a Symbolic Link" if -l $dir;
|
|
||||||
fatal_error "$objectfile is a Directory" if -d $objectfile;
|
|
||||||
fatal_error "$dir is a Symbolic Link" if -l $objectfile;
|
|
||||||
fatal_error "$objectfile exists and is not a compiled script" if -e _ && ! -x _;
|
|
||||||
|
|
||||||
eval {
|
|
||||||
$dir = abs_path $dir;
|
|
||||||
( $object, $tempfile ) = tempfile ( 'tempfileXXXX' , DIR => $dir );
|
|
||||||
};
|
|
||||||
|
|
||||||
fatal_error "Unable to create temporary file in directory $dir" if $@;
|
|
||||||
|
|
||||||
$file = "$file.$suffix" if $suffix;
|
|
||||||
$dir .= '/' unless substr( $dir, -1, 1 ) eq '/';
|
|
||||||
$file = $dir . $file;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Finalize the object file
|
|
||||||
#
|
|
||||||
sub finalize_object( $ ) {
|
|
||||||
my $export = $_[0];
|
|
||||||
close $object;
|
|
||||||
$object = 0;
|
|
||||||
rename $tempfile, $file or fatal_error "Cannot Rename $tempfile to $file: $!";
|
|
||||||
chmod 0700, $file or fatal_error "Cannot secure $file for execute access";
|
|
||||||
progress_message3 "Shorewall configuration compiled to $file" unless $export;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Create the temporary aux config file.
|
|
||||||
#
|
|
||||||
sub create_temp_aux_config() {
|
|
||||||
eval {
|
|
||||||
( $object, $tempfile ) = tempfile ( 'tempfileXXXX' , DIR => $dir );
|
|
||||||
};
|
|
||||||
|
|
||||||
die if $@;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Finalize the aux config file.
|
|
||||||
#
|
|
||||||
sub finalize_aux_config() {
|
|
||||||
close $object;
|
|
||||||
$object = 0;
|
|
||||||
rename $tempfile, "$file.conf" or fatal_error "Cannot Rename $tempfile to $file.conf: $!";
|
|
||||||
progress_message3 "Shorewall configuration compiled to $file";
|
|
||||||
}
|
|
||||||
|
|
||||||
END {
|
|
||||||
if ( $object ) {
|
|
||||||
close $object;
|
|
||||||
unlink $tempfile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -24,18 +24,14 @@
|
|||||||
|
|
||||||
package Shorewall::Compiler;
|
package Shorewall::Compiler;
|
||||||
require Exporter;
|
require Exporter;
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
use Shorewall::Config;
|
||||||
use Shorewall::Chains;
|
use Shorewall::Chains;
|
||||||
use Shorewall::Zones;
|
use Shorewall::Zones;
|
||||||
use Shorewall::Interfaces;
|
|
||||||
use Shorewall::Hosts;
|
|
||||||
use Shorewall::Policy;
|
use Shorewall::Policy;
|
||||||
use Shorewall::Nat;
|
use Shorewall::Nat;
|
||||||
use Shorewall::Providers;
|
use Shorewall::Providers;
|
||||||
use Shorewall::Tc;
|
use Shorewall::Tc;
|
||||||
use Shorewall::Tunnels;
|
use Shorewall::Tunnels;
|
||||||
use Shorewall::Macros;
|
|
||||||
use Shorewall::Actions;
|
use Shorewall::Actions;
|
||||||
use Shorewall::Accounting;
|
use Shorewall::Accounting;
|
||||||
use Shorewall::Rules;
|
use Shorewall::Rules;
|
||||||
@ -59,15 +55,12 @@ use constant { EXPORT => 0x01 ,
|
|||||||
# Reinitilize the package-globals in the other modules
|
# Reinitilize the package-globals in the other modules
|
||||||
#
|
#
|
||||||
sub reinitialize() {
|
sub reinitialize() {
|
||||||
Shorewall::Common::initialize;
|
|
||||||
Shorewall::Config::initialize;
|
Shorewall::Config::initialize;
|
||||||
Shorewall::Chains::initialize;
|
Shorewall::Chains::initialize;
|
||||||
Shorewall::Zones::initialize;
|
Shorewall::Zones::initialize;
|
||||||
Shorewall::Interfaces::initialize;
|
|
||||||
Shorewall::Nat::initialize;
|
Shorewall::Nat::initialize;
|
||||||
Shorewall::Providers::initialize;
|
Shorewall::Providers::initialize;
|
||||||
Shorewall::Tc::initialize;
|
Shorewall::Tc::initialize;
|
||||||
Shorewall::Macros::initialize;
|
|
||||||
Shorewall::Actions::initialize;
|
Shorewall::Actions::initialize;
|
||||||
Shorewall::Accounting::initialize;
|
Shorewall::Accounting::initialize;
|
||||||
Shorewall::Rules::initialize;
|
Shorewall::Rules::initialize;
|
||||||
|
@ -23,18 +23,40 @@
|
|||||||
# This module is responsible for lower level configuration file handling.
|
# This module is responsible for lower level configuration file handling.
|
||||||
# It also exports functions for generating warning and error messages.
|
# It also exports functions for generating warning and error messages.
|
||||||
# The get_configuration function parses the shorewall.conf, capabilities and
|
# The get_configuration function parses the shorewall.conf, capabilities and
|
||||||
# modules files during compiler startup.
|
# modules files during compiler startup. The module also provides very basic
|
||||||
|
# services such as creation of temporary 'object' files, writing
|
||||||
|
# into those files (emitters) and finalizing those files (renaming
|
||||||
|
# them to their final name and setting their mode appropriately).
|
||||||
#
|
#
|
||||||
package Shorewall::Config;
|
package Shorewall::Config;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Shorewall::Common;
|
|
||||||
use File::Basename;
|
use File::Basename;
|
||||||
|
use File::Temp qw/ tempfile tempdir /;
|
||||||
|
use Cwd 'abs_path';
|
||||||
use autouse 'Carp' => qw(longmess confess);
|
use autouse 'Carp' => qw(longmess confess);
|
||||||
|
|
||||||
our @ISA = qw(Exporter);
|
our @ISA = qw(Exporter);
|
||||||
our @EXPORT = qw(
|
our @EXPORT = qw(
|
||||||
|
create_temp_object
|
||||||
|
finalize_object
|
||||||
|
emit
|
||||||
|
emitj
|
||||||
|
emit_unindented
|
||||||
|
save_progress_message
|
||||||
|
save_progress_message_short
|
||||||
|
set_timestamp
|
||||||
|
set_verbose
|
||||||
|
progress_message
|
||||||
|
progress_message2
|
||||||
|
progress_message3
|
||||||
|
push_indent
|
||||||
|
pop_indent
|
||||||
|
copy
|
||||||
|
create_temp_aux_config
|
||||||
|
finalize_aux_config
|
||||||
|
|
||||||
warning_message
|
warning_message
|
||||||
fatal_error
|
fatal_error
|
||||||
set_shorewall_dir
|
set_shorewall_dir
|
||||||
@ -61,6 +83,11 @@ our @EXPORT = qw(
|
|||||||
run_user_exit2
|
run_user_exit2
|
||||||
generate_aux_config
|
generate_aux_config
|
||||||
|
|
||||||
|
$command
|
||||||
|
$doing
|
||||||
|
$done
|
||||||
|
$verbose
|
||||||
|
|
||||||
$currentline
|
$currentline
|
||||||
%config
|
%config
|
||||||
%globals
|
%globals
|
||||||
@ -69,6 +96,15 @@ our @EXPORT = qw(
|
|||||||
our @EXPORT_OK = qw( $shorewall_dir initialize read_a_line1 set_config_path );
|
our @EXPORT_OK = qw( $shorewall_dir initialize read_a_line1 set_config_path );
|
||||||
our $VERSION = 4.00;
|
our $VERSION = 4.00;
|
||||||
|
|
||||||
|
our ($command, $doing, $done );
|
||||||
|
our $verbose;
|
||||||
|
our $timestamp;
|
||||||
|
our $object;
|
||||||
|
our $lastlineblank;
|
||||||
|
our $indent;
|
||||||
|
our ( $dir, $file ); # Object's Directory and File
|
||||||
|
our $tempfile; # Temporary File Name
|
||||||
|
|
||||||
#
|
#
|
||||||
# Misc Globals
|
# Misc Globals
|
||||||
#
|
#
|
||||||
@ -121,6 +157,16 @@ our $debug;
|
|||||||
# the second and subsequent calls to that function.
|
# the second and subsequent calls to that function.
|
||||||
#
|
#
|
||||||
sub initialize() {
|
sub initialize() {
|
||||||
|
( $command, $doing, $done ) = qw/ compile Compiling Compiled/; #describe the current command, it's present progressive, and it's completion.
|
||||||
|
|
||||||
|
$verbose = 0; # Verbosity setting. 0 = almost silent, 1 = major progress messages only, 2 = all progress messages (very noisy)
|
||||||
|
$timestamp = ''; # If true, we are to timestamp each progress message
|
||||||
|
$object = 0; # Object (script) file Handle Reference
|
||||||
|
$lastlineblank = 0; # Avoid extra blank lines in the output
|
||||||
|
$indent = ''; # Current indentation
|
||||||
|
( $dir, $file ) = ('',''); # Object's Directory and File
|
||||||
|
$tempfile = ''; # Temporary File Name
|
||||||
|
|
||||||
#
|
#
|
||||||
# Misc Globals
|
# Misc Globals
|
||||||
#
|
#
|
||||||
@ -343,6 +389,259 @@ sub fatal_error {
|
|||||||
die " ERROR: @_$currentlineinfo\n";
|
die " ERROR: @_$currentlineinfo\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Write the argument to the object file (if any) with the current indentation.
|
||||||
|
#
|
||||||
|
# Replaces leading spaces with tabs as appropriate and suppresses consecutive blank lines.
|
||||||
|
#
|
||||||
|
sub emit ( $ ) {
|
||||||
|
if ( $object ) {
|
||||||
|
#
|
||||||
|
# 'compile' as opposed to 'check'
|
||||||
|
#
|
||||||
|
my $line = $_[0]; # This copy is necessary because the actual arguments are almost always read-only.
|
||||||
|
|
||||||
|
unless ( $line =~ /^\s*$/ ) {
|
||||||
|
$line =~ s/^\n// if $lastlineblank;
|
||||||
|
$line =~ s/^/$indent/gm if $indent;
|
||||||
|
$line =~ s/ /\t/gm;
|
||||||
|
print $object "$line\n";
|
||||||
|
$lastlineblank = ( substr( $line, -1, 1 ) eq "\n" );
|
||||||
|
} else {
|
||||||
|
print $object "\n" unless $lastlineblank;
|
||||||
|
$lastlineblank = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Version of emit() that accepts an indefinite number of scalar arguments; each argument will be emitted as a separate line
|
||||||
|
#
|
||||||
|
sub emitj {
|
||||||
|
if ( $object ) {
|
||||||
|
#
|
||||||
|
# 'compile' as opposed to 'check'
|
||||||
|
#
|
||||||
|
for ( @_ ) {
|
||||||
|
unless ( /^\s*$/ ) {
|
||||||
|
my $line = $_; # This copy is necessary because the actual arguments are almost always read-only.
|
||||||
|
$line =~ s/^\n// if $lastlineblank;
|
||||||
|
$line =~ s/^/$indent/gm if $indent;
|
||||||
|
$line =~ s/ /\t/gm;
|
||||||
|
print $object "$line\n";
|
||||||
|
$lastlineblank = ( substr( $line, -1, 1 ) eq "\n" );
|
||||||
|
} else {
|
||||||
|
print $object "\n" unless $lastlineblank;
|
||||||
|
$lastlineblank = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Write passed message to the object with newline but no indentation.
|
||||||
|
#
|
||||||
|
|
||||||
|
sub emit_unindented( $ ) {
|
||||||
|
print $object "$_[0]\n" if $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Write a progress_message2 command with surrounding blank lines to the output file.
|
||||||
|
#
|
||||||
|
sub save_progress_message( $ ) {
|
||||||
|
emit "\nprogress_message2 @_\n" if $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Write a progress_message command to the output file.
|
||||||
|
#
|
||||||
|
sub save_progress_message_short( $ ) {
|
||||||
|
emit "progress_message $_[0]" if $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set $timestamp
|
||||||
|
#
|
||||||
|
sub set_timestamp( $ ) {
|
||||||
|
$timestamp = shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set $verbose
|
||||||
|
#
|
||||||
|
sub set_verbose( $ ) {
|
||||||
|
$verbose = shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Print the current TOD to STDOUT.
|
||||||
|
#
|
||||||
|
sub timestamp() {
|
||||||
|
my ($sec, $min, $hr) = ( localtime ) [0,1,2];
|
||||||
|
printf '%02d:%02d:%02d ', $hr, $min, $sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Write a message if $verbose >= 2
|
||||||
|
#
|
||||||
|
sub progress_message {
|
||||||
|
if ( $verbose > 1 ) {
|
||||||
|
timestamp if $timestamp;
|
||||||
|
#
|
||||||
|
# We use this function to display messages containing raw config file images which may contains tabs (including multiple tabs in succession).
|
||||||
|
# The following makes such messages look more readable and uniform
|
||||||
|
#
|
||||||
|
my $line = "@_";
|
||||||
|
$line =~ s/\s+/ /g;
|
||||||
|
print "$line\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Write a message if $verbose >= 1
|
||||||
|
#
|
||||||
|
sub progress_message2 {
|
||||||
|
if ( $verbose > 0 ) {
|
||||||
|
timestamp if $timestamp;
|
||||||
|
print "@_\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Write a message if $verbose >= 0
|
||||||
|
#
|
||||||
|
sub progress_message3 {
|
||||||
|
if ( $verbose >= 0 ) {
|
||||||
|
timestamp if $timestamp;
|
||||||
|
print "@_\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Push/Pop Indent
|
||||||
|
#
|
||||||
|
sub push_indent() {
|
||||||
|
$indent = "$indent ";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pop_indent() {
|
||||||
|
$indent = substr( $indent , 0 , ( length $indent ) - 4 );
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Functions for copying files into the object
|
||||||
|
#
|
||||||
|
sub copy( $ ) {
|
||||||
|
if ( $object ) {
|
||||||
|
my $file = $_[0];
|
||||||
|
|
||||||
|
open IF , $file or fatal_error "Unable to open $file: $!";
|
||||||
|
|
||||||
|
while ( <IF> ) {
|
||||||
|
s/^/$indent/ if $indent;
|
||||||
|
print $object $_;
|
||||||
|
}
|
||||||
|
|
||||||
|
close IF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# This one handles line continuation.
|
||||||
|
|
||||||
|
sub copy1( $ ) {
|
||||||
|
if ( $object ) {
|
||||||
|
my $file = $_[0];
|
||||||
|
|
||||||
|
open IF , $file or fatal_error "Unable to open $file: $!";
|
||||||
|
|
||||||
|
my $do_indent = 1;
|
||||||
|
|
||||||
|
while ( <IF> ) {
|
||||||
|
if ( /^\s*$/ ) {
|
||||||
|
print $object "\n";
|
||||||
|
$do_indent = 1;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
s/^/$indent/ if $indent && $do_indent;
|
||||||
|
print $object $_;
|
||||||
|
$do_indent = ! ( /\\$/ );
|
||||||
|
}
|
||||||
|
|
||||||
|
close IF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create the temporary object file -- the passed file name is the name of the final file.
|
||||||
|
# We create a temporary file in the same directory so that we can use rename to finalize it.
|
||||||
|
#
|
||||||
|
sub create_temp_object( $ ) {
|
||||||
|
my $objectfile = $_[0];
|
||||||
|
my $suffix;
|
||||||
|
|
||||||
|
eval {
|
||||||
|
( $file, $dir, $suffix ) = fileparse( $objectfile );
|
||||||
|
};
|
||||||
|
|
||||||
|
die if $@;
|
||||||
|
|
||||||
|
fatal_error "Directory $dir does not exist" unless -d $dir;
|
||||||
|
fatal_error "Directory $dir is not writable" unless -w _;
|
||||||
|
fatal_error "$dir is a Symbolic Link" if -l $dir;
|
||||||
|
fatal_error "$objectfile is a Directory" if -d $objectfile;
|
||||||
|
fatal_error "$dir is a Symbolic Link" if -l $objectfile;
|
||||||
|
fatal_error "$objectfile exists and is not a compiled script" if -e _ && ! -x _;
|
||||||
|
|
||||||
|
eval {
|
||||||
|
$dir = abs_path $dir;
|
||||||
|
( $object, $tempfile ) = tempfile ( 'tempfileXXXX' , DIR => $dir );
|
||||||
|
};
|
||||||
|
|
||||||
|
fatal_error "Unable to create temporary file in directory $dir" if $@;
|
||||||
|
|
||||||
|
$file = "$file.$suffix" if $suffix;
|
||||||
|
$dir .= '/' unless substr( $dir, -1, 1 ) eq '/';
|
||||||
|
$file = $dir . $file;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Finalize the object file
|
||||||
|
#
|
||||||
|
sub finalize_object( $ ) {
|
||||||
|
my $export = $_[0];
|
||||||
|
close $object;
|
||||||
|
$object = 0;
|
||||||
|
rename $tempfile, $file or fatal_error "Cannot Rename $tempfile to $file: $!";
|
||||||
|
chmod 0700, $file or fatal_error "Cannot secure $file for execute access";
|
||||||
|
progress_message3 "Shorewall configuration compiled to $file" unless $export;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create the temporary aux config file.
|
||||||
|
#
|
||||||
|
sub create_temp_aux_config() {
|
||||||
|
eval {
|
||||||
|
( $object, $tempfile ) = tempfile ( 'tempfileXXXX' , DIR => $dir );
|
||||||
|
};
|
||||||
|
|
||||||
|
die if $@;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Finalize the aux config file.
|
||||||
|
#
|
||||||
|
sub finalize_aux_config() {
|
||||||
|
close $object;
|
||||||
|
$object = 0;
|
||||||
|
rename $tempfile, "$file.conf" or fatal_error "Cannot Rename $tempfile to $file.conf: $!";
|
||||||
|
progress_message3 "Shorewall configuration compiled to $file";
|
||||||
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
# Set $globals{CONFIG_PATH}
|
# Set $globals{CONFIG_PATH}
|
||||||
#
|
#
|
||||||
@ -1368,4 +1667,11 @@ sub generate_aux_config() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
END {
|
||||||
|
if ( $object ) {
|
||||||
|
close $object;
|
||||||
|
unlink $tempfile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -1,171 +0,0 @@
|
|||||||
#
|
|
||||||
# Shorewall-perl 4.0 -- /usr/share/shorewall-perl/Shorewall/Hosts.pm
|
|
||||||
#
|
|
||||||
# This program is under GPL [http://www.gnu.org/copyleft/gpl.htm]
|
|
||||||
#
|
|
||||||
# (c) 2007 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Complete documentation is available at http://shorewall.net
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of Version 2 of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
|
|
||||||
#
|
|
||||||
# This module contains the code for dealing with the /etc/shorewall/hosts
|
|
||||||
# file.
|
|
||||||
#
|
|
||||||
package Shorewall::Hosts;
|
|
||||||
require Exporter;
|
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
|
||||||
use Shorewall::IPAddrs;
|
|
||||||
use Shorewall::Zones;
|
|
||||||
use Shorewall::Interfaces;
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
our @ISA = qw(Exporter);
|
|
||||||
our @EXPORT = qw( validate_hosts_file find_hosts_by_option );
|
|
||||||
our @EXPORT_OK = ();
|
|
||||||
our $VERSION = 4.00;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Validates the hosts file. Generates entries in %zone{..}{hosts}
|
|
||||||
#
|
|
||||||
sub validate_hosts_file()
|
|
||||||
{
|
|
||||||
my %validoptions = (
|
|
||||||
blacklist => 1,
|
|
||||||
maclist => 1,
|
|
||||||
norfc1918 => 1,
|
|
||||||
nosmurfs => 1,
|
|
||||||
routeback => 1,
|
|
||||||
routefilter => 1,
|
|
||||||
tcpflags => 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
my $ipsec = 0;
|
|
||||||
my $first_entry = 1;
|
|
||||||
|
|
||||||
my $fn = open_file 'hosts';
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
if ( $first_entry ) {
|
|
||||||
progress_message2 "$doing $fn...";
|
|
||||||
$first_entry = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
my ($zone, $hosts, $options ) = split_line 2, 3, 'hosts 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';
|
|
||||||
|
|
||||||
my $interface;
|
|
||||||
|
|
||||||
if ( $hosts =~ /^([\w.@%-]+\+?):(.*)$/ ) {
|
|
||||||
$interface = $1;
|
|
||||||
$hosts = $2;
|
|
||||||
$zoneref->{options}{complex} = 1 if $hosts =~ /^\+/;
|
|
||||||
fatal_error "Unknown interface ($interface)" unless $interfaces{$interface}{root};
|
|
||||||
} else {
|
|
||||||
fatal_error "Invalid HOST(S) column contents: $hosts";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $type eq 'bport4' ) {
|
|
||||||
if ( $zoneref->{bridge} eq '' ) {
|
|
||||||
fatal_error 'Bridge Port Zones may only be associated with bridge ports' unless $interfaces{$interface}{options}{port};
|
|
||||||
$zoneref->{bridge} = $interfaces{$interface}{bridge};
|
|
||||||
} elsif ( $zoneref->{bridge} ne $interfaces{$interface}{bridge} ) {
|
|
||||||
fatal_error "Interface $interface is not a port on bridge $zoneref->{bridge}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my $optionsref = {};
|
|
||||||
|
|
||||||
if ( $options ne '-' ) {
|
|
||||||
my @options = split ',', $options;
|
|
||||||
my %options;
|
|
||||||
|
|
||||||
for my $option ( @options )
|
|
||||||
{
|
|
||||||
if ( $option eq 'ipsec' ) {
|
|
||||||
$type = 'ipsec';
|
|
||||||
$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( '', ALLIPv4 , $hosts ) if substr($hosts, 0, 2 ) eq ',!';
|
|
||||||
|
|
||||||
add_group_to_zone( $zone, $type , $interface, [ split( ',', $hosts ) ] , $optionsref);
|
|
||||||
|
|
||||||
progress_message " Host \"$currentline\" validated";
|
|
||||||
}
|
|
||||||
|
|
||||||
$capabilities{POLICY_MATCH} = '' unless $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 );
|
|
||||||
#
|
|
||||||
sub find_hosts_by_option( $ ) {
|
|
||||||
my $option = $_[0];
|
|
||||||
my @hosts;
|
|
||||||
|
|
||||||
for my $zone ( grep $zones{$_}{type} ne 'firewall' , @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 ( @interfaces ) {
|
|
||||||
if ( ! $interfaces{$interface}{zone} && $interfaces{$interface}{options}{$option} ) {
|
|
||||||
push @hosts, [ $interface, 'none', ALLIPv4 ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
\@hosts;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -24,7 +24,6 @@
|
|||||||
#
|
#
|
||||||
package Shorewall::IPAddrs;
|
package Shorewall::IPAddrs;
|
||||||
require Exporter;
|
require Exporter;
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
use Shorewall::Config;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
@ -1,469 +0,0 @@
|
|||||||
#
|
|
||||||
# Shorewall-perl 4.0 -- /usr/share/shorewall-perl/Shorewall/Interfaces.pm
|
|
||||||
#
|
|
||||||
# This program is under GPL [http://www.gnu.org/copyleft/gpl.htm]
|
|
||||||
#
|
|
||||||
# (c) 2007 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Complete documentation is available at http://shorewall.net
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of Version 2 of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
|
|
||||||
#
|
|
||||||
# This Module contains the code for processing the /etc/shorewall/interfaces
|
|
||||||
# file. It also exports 'add_group_to_zone()' which other modules call to
|
|
||||||
# alter zone membership.
|
|
||||||
#
|
|
||||||
|
|
||||||
package Shorewall::Interfaces;
|
|
||||||
require Exporter;
|
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
|
||||||
use Shorewall::IPAddrs;
|
|
||||||
use Shorewall::Zones;
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
our @ISA = qw(Exporter);
|
|
||||||
our @EXPORT = qw( add_group_to_zone
|
|
||||||
validate_interfaces_file
|
|
||||||
known_interface
|
|
||||||
port_to_bridge
|
|
||||||
source_port_to_bridge
|
|
||||||
interface_is_optional
|
|
||||||
find_interfaces_by_option
|
|
||||||
get_interface_option
|
|
||||||
|
|
||||||
@interfaces
|
|
||||||
@bridges );
|
|
||||||
our @EXPORT_OK = qw( initialize );
|
|
||||||
our $VERSION = 4.00;
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Interface Table.
|
|
||||||
#
|
|
||||||
# @interfaces lists the interface names in the order that they appear in the interfaces file.
|
|
||||||
#
|
|
||||||
# %interfaces { <interface1> => { root => <name without trailing '+'>
|
|
||||||
# options => { <option1> = <val1> ,
|
|
||||||
# ...
|
|
||||||
# }
|
|
||||||
# zone => <zone name>
|
|
||||||
# bridge => <bridge>
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
our @interfaces;
|
|
||||||
our %interfaces;
|
|
||||||
our @bridges;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initialize globals -- we take this novel approach to globals initialization to allow
|
|
||||||
# the compiler to run multiple times in the same process. The
|
|
||||||
# initialize() function does globals initialization for this
|
|
||||||
# module and is called from an INIT block below. The function is
|
|
||||||
# also called by Shorewall::Compiler::compiler at the beginning of
|
|
||||||
# the second and subsequent calls to that function.
|
|
||||||
#
|
|
||||||
|
|
||||||
sub initialize() {
|
|
||||||
@interfaces = ();
|
|
||||||
%interfaces = ();
|
|
||||||
@bridges = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
INIT {
|
|
||||||
initialize;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub add_group_to_zone($$$$$)
|
|
||||||
{
|
|
||||||
my ($zone, $type, $interface, $networks, $options) = @_;
|
|
||||||
my $typeref;
|
|
||||||
my $interfaceref;
|
|
||||||
my $arrayref;
|
|
||||||
my $zoneref = $zones{$zone};
|
|
||||||
my $zonetype = $zoneref->{type};
|
|
||||||
my $ifacezone = $interfaces{$interface}{zone};
|
|
||||||
|
|
||||||
$zoneref->{interfaces}{$interface} = 1;
|
|
||||||
|
|
||||||
my @newnetworks;
|
|
||||||
my @exclusions;
|
|
||||||
my $new = \@newnetworks;
|
|
||||||
my $switched = 0;
|
|
||||||
|
|
||||||
$ifacezone = '' unless defined $ifacezone;
|
|
||||||
|
|
||||||
for my $host ( @$networks ) {
|
|
||||||
fatal_error "Invalid Host List" unless defined $host and $host ne '';
|
|
||||||
|
|
||||||
if ( substr( $host, 0, 1 ) eq '!' ) {
|
|
||||||
fatal_error "Only one exclusion allowed in a host list" if $switched;
|
|
||||||
$switched = 1;
|
|
||||||
$host = substr( $host, 1 );
|
|
||||||
$new = \@exclusions;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( substr( $host, 0, 1 ) eq '+' ) {
|
|
||||||
fatal_error "Invalid ipset name ($host)" unless $host =~ /^\+[a-zA-Z]\w*$/;
|
|
||||||
} else {
|
|
||||||
validate_host $host;
|
|
||||||
}
|
|
||||||
|
|
||||||
push @$new, $switched ? "$interface:$host" : $host;
|
|
||||||
}
|
|
||||||
|
|
||||||
$zoneref->{options}{in_out}{routeback} = 1 if $options->{routeback};
|
|
||||||
|
|
||||||
$typeref = ( $zoneref->{hosts} || ( $zoneref->{hosts} = {} ) );
|
|
||||||
$interfaceref = ( $typeref->{$type} || ( $interfaceref = $typeref->{$type} = {} ) );
|
|
||||||
$arrayref = ( $interfaceref->{$interface} || ( $interfaceref->{$interface} = [] ) );
|
|
||||||
|
|
||||||
$zoneref->{options}{complex} = 1 if @$arrayref || ( @newnetworks > 1 ) || ( @exclusions );
|
|
||||||
|
|
||||||
push @{$zoneref->{exclusions}}, @exclusions;
|
|
||||||
|
|
||||||
push @{$arrayref}, { options => $options,
|
|
||||||
hosts => \@newnetworks,
|
|
||||||
ipsec => $type eq 'ipsec4' ? 'ipsec' : 'none' };
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Return a list of networks routed out of the passed interface
|
|
||||||
#
|
|
||||||
sub get_routed_networks ( $$ ) {
|
|
||||||
my ( $interface , $error_message ) = @_;
|
|
||||||
my @networks;
|
|
||||||
|
|
||||||
if ( open IP , '-|' , "/sbin/ip route show dev $interface 2> /dev/null" ) {
|
|
||||||
while ( my $route = <IP> ) {
|
|
||||||
$route =~ s/^\s+//;
|
|
||||||
my $network = ( split /\s+/, $route )[0];
|
|
||||||
if ( $network eq 'default' ) {
|
|
||||||
fatal_error $error_message if $error_message;
|
|
||||||
warning_message "default route ignored on interface $interface";
|
|
||||||
} else {
|
|
||||||
my ( $address, $vlsm ) = split '/', $network;
|
|
||||||
$vlsm = 32 unless defined $vlsm;
|
|
||||||
push @networks, "$address/$vlsm";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close IP
|
|
||||||
}
|
|
||||||
|
|
||||||
@networks;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Parse the interfaces file.
|
|
||||||
#
|
|
||||||
|
|
||||||
sub validate_interfaces_file( $ )
|
|
||||||
{
|
|
||||||
my $export = shift;
|
|
||||||
|
|
||||||
use constant { SIMPLE_IF_OPTION => 1,
|
|
||||||
BINARY_IF_OPTION => 2,
|
|
||||||
ENUM_IF_OPTION => 3,
|
|
||||||
MASK_IF_OPTION => 3,
|
|
||||||
|
|
||||||
IF_OPTION_ZONEONLY => 4 };
|
|
||||||
|
|
||||||
my %validoptions = (arp_filter => BINARY_IF_OPTION,
|
|
||||||
arp_ignore => ENUM_IF_OPTION,
|
|
||||||
blacklist => SIMPLE_IF_OPTION,
|
|
||||||
bridge => SIMPLE_IF_OPTION,
|
|
||||||
detectnets => SIMPLE_IF_OPTION,
|
|
||||||
dhcp => SIMPLE_IF_OPTION,
|
|
||||||
maclist => SIMPLE_IF_OPTION,
|
|
||||||
logmartians => BINARY_IF_OPTION,
|
|
||||||
norfc1918 => SIMPLE_IF_OPTION,
|
|
||||||
nosmurfs => SIMPLE_IF_OPTION,
|
|
||||||
optional => SIMPLE_IF_OPTION,
|
|
||||||
proxyarp => BINARY_IF_OPTION,
|
|
||||||
routeback => SIMPLE_IF_OPTION + IF_OPTION_ZONEONLY,
|
|
||||||
routefilter => BINARY_IF_OPTION,
|
|
||||||
sourceroute => BINARY_IF_OPTION,
|
|
||||||
tcpflags => SIMPLE_IF_OPTION,
|
|
||||||
upnp => SIMPLE_IF_OPTION,
|
|
||||||
);
|
|
||||||
|
|
||||||
my $fn = open_file 'interfaces';
|
|
||||||
|
|
||||||
my $first_entry = 1;
|
|
||||||
|
|
||||||
my @ifaces;
|
|
||||||
|
|
||||||
while ( read_a_line ) {
|
|
||||||
|
|
||||||
if ( $first_entry ) {
|
|
||||||
progress_message2 "$doing $fn...";
|
|
||||||
$first_entry = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
my ($zone, $interface, $networks, $options ) = split_line 2, 4, 'interfaces 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';
|
|
||||||
}
|
|
||||||
|
|
||||||
$networks = '' if $networks eq '-';
|
|
||||||
$options = '' if $options eq '-';
|
|
||||||
|
|
||||||
( $interface, my ($port, $extra) ) = split /:/ , $interface, 3;
|
|
||||||
|
|
||||||
fatal_error "Invalid INTERFACE" if defined $extra || ! $interface;
|
|
||||||
|
|
||||||
fatal_error "Invalid Interface Name ($interface)" if $interface eq '+';
|
|
||||||
|
|
||||||
if ( defined $port ) {
|
|
||||||
require_capability( 'PHYSDEV_MATCH', 'Bridge Ports', '');
|
|
||||||
require_capability( 'KLUDGEFREE', 'Bridge Ports', '');
|
|
||||||
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.@%-]+\+?$/;
|
|
||||||
|
|
||||||
$interfaces{$port}{bridge} = $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';
|
|
||||||
$interfaces{$interface}{bridge} = $interface;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $wildcard = 0;
|
|
||||||
|
|
||||||
if ( $interface =~ /\+$/ ) {
|
|
||||||
$wildcard = 1;
|
|
||||||
$interfaces{$interface}{root} = substr( $interface, 0, -1 );
|
|
||||||
} else {
|
|
||||||
$interfaces{$interface}{root} = $interface;
|
|
||||||
}
|
|
||||||
|
|
||||||
unless ( $networks eq '' || $networks eq 'detect' ) {
|
|
||||||
|
|
||||||
for my $address ( split /,/, $networks ) {
|
|
||||||
fatal_error 'Invalid BROADCAST address' unless $address =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
|
|
||||||
}
|
|
||||||
|
|
||||||
warning_message 'Shorewall no longer uses broadcast addresses in rule generation';
|
|
||||||
}
|
|
||||||
|
|
||||||
my $optionsref = {};
|
|
||||||
|
|
||||||
my %options;
|
|
||||||
|
|
||||||
if ( $options ) {
|
|
||||||
|
|
||||||
for my $option (split ',', $options ) {
|
|
||||||
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";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$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;
|
|
||||||
push @bridges, $interface;
|
|
||||||
}
|
|
||||||
} elsif ( $port ) {
|
|
||||||
$options{port} = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$interfaces{$interface}{options} = $optionsref = \%options;
|
|
||||||
|
|
||||||
push @ifaces, $interface;
|
|
||||||
|
|
||||||
my @networks;
|
|
||||||
|
|
||||||
if ( $options{detectnets} ) {
|
|
||||||
fatal_error "The 'detectnets' option is not allowed on a multi-zone interface" unless $zone;
|
|
||||||
fatal_error "The 'detectnets' option may not be used with a wild-card interface name" if $wildcard;
|
|
||||||
fatal_error "The 'detectnets' option may not be used with the '-e' compiler option" if $export;
|
|
||||||
@networks = get_routed_networks( $interface, 'detectnets not allowed on interface with default route' );
|
|
||||||
fatal_error "No routes found through 'detectnets' interface $interface" unless @networks || $options{optional};
|
|
||||||
delete $options{maclist} unless @networks;
|
|
||||||
} else {
|
|
||||||
@networks = @allipv4;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_group_to_zone( $zone, $zoneref->{type}, $interface, \@networks, $optionsref ) if $zone && @networks;
|
|
||||||
|
|
||||||
$interfaces{$interface}{zone} = $zone; #Must follow the call to add_group_to_zone()
|
|
||||||
|
|
||||||
progress_message " Interface \"$currentline\" Validated";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# We now assemble the @interfaces array such that bridge ports immediately precede their associated bridge
|
|
||||||
#
|
|
||||||
for my $interface ( @ifaces ) {
|
|
||||||
my $interfaceref = $interfaces{$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};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# 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_interface($)
|
|
||||||
{
|
|
||||||
my $interface = $_[0];
|
|
||||||
|
|
||||||
return 1 if $interfaces{$interface};
|
|
||||||
|
|
||||||
for my $i ( @interfaces ) {
|
|
||||||
my $interfaceref = $interfaces{$i};
|
|
||||||
my $val = $interfaceref->{root};
|
|
||||||
next if $val eq $i;
|
|
||||||
if ( substr( $interface, 0, length $val ) eq $val ) {
|
|
||||||
#
|
|
||||||
# Cache this result for future reference
|
|
||||||
#
|
|
||||||
$interfaces{$interface} = { options => $interfaceref->{options}, bridge => $interfaceref->{bridge} };
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Return the bridge associated with the passed interface. If the interface is not a bridge port,
|
|
||||||
# return ''
|
|
||||||
#
|
|
||||||
sub port_to_bridge( $ ) {
|
|
||||||
my $portref = $interfaces{$_[0]};
|
|
||||||
return $portref && $portref->{options}{port} ? $portref->{bridge} : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Return the bridge associated with the passed interface.
|
|
||||||
#
|
|
||||||
sub source_port_to_bridge( $ ) {
|
|
||||||
my $portref = $interfaces{$_[0]};
|
|
||||||
return $portref ? $portref->{bridge} : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Return the 'optional' setting of the passed interface
|
|
||||||
#
|
|
||||||
sub interface_is_optional($) {
|
|
||||||
my $optionsref = $interfaces{$_[0]}{options};
|
|
||||||
$optionsref && $optionsref->{optional};
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Returns reference to array of interfaces with the passed option
|
|
||||||
#
|
|
||||||
sub find_interfaces_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
|
|
||||||
#
|
|
||||||
sub get_interface_option( $$ ) {
|
|
||||||
my ( $interface, $option ) = @_;
|
|
||||||
|
|
||||||
$interfaces{$interface}{options}{$option};
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,143 +0,0 @@
|
|||||||
#
|
|
||||||
# Shorewall-perl 4.0 -- /usr/share/shorewall-perl/Shorewall/Macros.pm
|
|
||||||
#
|
|
||||||
# This program is under GPL [http://www.gnu.org/copyleft/gpl.htm]
|
|
||||||
#
|
|
||||||
# (c) 2007 - Tom Eastep (teastep@shorewall.net)
|
|
||||||
#
|
|
||||||
# Complete documentation is available at http://shorewall.net
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of Version 2 of the GNU General Public License
|
|
||||||
# as published by the Free Software Foundation.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
|
|
||||||
#
|
|
||||||
# This module exports some low-level module-oriented functions.
|
|
||||||
#
|
|
||||||
package Shorewall::Macros;
|
|
||||||
require Exporter;
|
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
|
||||||
use Shorewall::Zones;
|
|
||||||
use Shorewall::Chains;
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
our @ISA = qw(Exporter);
|
|
||||||
our @EXPORT = qw( find_macro
|
|
||||||
split_action
|
|
||||||
substitute_param
|
|
||||||
merge_macro_source_dest
|
|
||||||
merge_macro_column
|
|
||||||
|
|
||||||
%macros );
|
|
||||||
our @EXPORT_OK = qw( initialize );
|
|
||||||
our $VERSION = 4.00;
|
|
||||||
|
|
||||||
|
|
||||||
our %macros;
|
|
||||||
|
|
||||||
#
|
|
||||||
# Initialize globals -- we take this novel approach to globals initialization to allow
|
|
||||||
# the compiler to run multiple times in the same process. The
|
|
||||||
# initialize() function does globals initialization for this
|
|
||||||
# module and is called from an INIT block below. The function is
|
|
||||||
# also called by Shorewall::Compiler::compiler at the beginning of
|
|
||||||
# the second and subsequent calls to that function.
|
|
||||||
#
|
|
||||||
|
|
||||||
sub initialize() {
|
|
||||||
%macros = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
INIT {
|
|
||||||
initialize;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Try to find a macro file -- RETURNS false if the file doesn't exist or MACRO if it does.
|
|
||||||
# If the file exists, the macro is entered into the 'targets' table and the fully-qualified
|
|
||||||
# name of the file is stored in the 'macro' table.
|
|
||||||
#
|
|
||||||
sub find_macro( $ )
|
|
||||||
{
|
|
||||||
my $macro = $_[0];
|
|
||||||
my $macrofile = find_file "macro.$macro";
|
|
||||||
|
|
||||||
if ( -f $macrofile ) {
|
|
||||||
$macros{$macro} = $macrofile;
|
|
||||||
$targets{$macro} = MACRO;
|
|
||||||
} else {
|
|
||||||
0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Return ( action, level[:tag] ) from passed full action
|
|
||||||
#
|
|
||||||
sub split_action ( $ ) {
|
|
||||||
my $action = $_[0];
|
|
||||||
my @a = split( /:/ , $action, 4 );
|
|
||||||
fatal_error "Invalid ACTION ($action)" if ( $action =~ /::/ ) || ( @a > 3 );
|
|
||||||
( shift @a, join ":", @a );
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# This function substitutes the second argument for the first part of the first argument up to the first colon (":")
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
#
|
|
||||||
# substitute_param DNAT PARAM:info:FTP
|
|
||||||
#
|
|
||||||
# produces "DNAT:info:FTP"
|
|
||||||
#
|
|
||||||
sub substitute_param( $$ ) {
|
|
||||||
my ( $param, $action ) = @_;
|
|
||||||
|
|
||||||
if ( $action =~ /:/ ) {
|
|
||||||
my $logpart = (split_action $action)[1];
|
|
||||||
$logpart =~ s!/$!!;
|
|
||||||
return "$param:$logpart";
|
|
||||||
}
|
|
||||||
|
|
||||||
$param;
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Combine fields from a macro body with one from the macro invocation
|
|
||||||
#
|
|
||||||
sub merge_macro_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 ) = @_;
|
|
||||||
|
|
||||||
if ( defined $invocation && $invocation ne '' && $invocation ne '-' ) {
|
|
||||||
$invocation;
|
|
||||||
} else {
|
|
||||||
$body;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -25,11 +25,9 @@
|
|||||||
#
|
#
|
||||||
package Shorewall::Nat;
|
package Shorewall::Nat;
|
||||||
require Exporter;
|
require Exporter;
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
use Shorewall::Config;
|
||||||
use Shorewall::IPAddrs;
|
use Shorewall::IPAddrs;
|
||||||
use Shorewall::Zones;
|
use Shorewall::Zones;
|
||||||
use Shorewall::Interfaces;
|
|
||||||
use Shorewall::Chains;
|
use Shorewall::Chains;
|
||||||
use Shorewall::IPAddrs;
|
use Shorewall::IPAddrs;
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#
|
#
|
||||||
package Shorewall::Policy;
|
package Shorewall::Policy;
|
||||||
require Exporter;
|
require Exporter;
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
use Shorewall::Config;
|
||||||
use Shorewall::Zones;
|
use Shorewall::Zones;
|
||||||
use Shorewall::Chains;
|
use Shorewall::Chains;
|
||||||
|
@ -27,11 +27,9 @@
|
|||||||
#
|
#
|
||||||
package Shorewall::Proc;
|
package Shorewall::Proc;
|
||||||
require Exporter;
|
require Exporter;
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
use Shorewall::Config;
|
||||||
use Shorewall::Zones;
|
use Shorewall::Zones;
|
||||||
use Shorewall::Chains;
|
use Shorewall::Chains;
|
||||||
use Shorewall::Interfaces;
|
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
#
|
#
|
||||||
package Shorewall::Providers;
|
package Shorewall::Providers;
|
||||||
require Exporter;
|
require Exporter;
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
use Shorewall::Config;
|
||||||
use Shorewall::IPAddrs;
|
use Shorewall::IPAddrs;
|
||||||
use Shorewall::Zones;
|
use Shorewall::Zones;
|
||||||
|
@ -23,9 +23,8 @@
|
|||||||
#
|
#
|
||||||
package Shorewall::Proxyarp;
|
package Shorewall::Proxyarp;
|
||||||
require Exporter;
|
require Exporter;
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
use Shorewall::Config;
|
||||||
use Shorewall::Interfaces;
|
use Shorewall::Zones;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
|
||||||
|
@ -24,15 +24,11 @@
|
|||||||
#
|
#
|
||||||
package Shorewall::Rules;
|
package Shorewall::Rules;
|
||||||
require Exporter;
|
require Exporter;
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
use Shorewall::Config;
|
||||||
use Shorewall::IPAddrs;
|
use Shorewall::IPAddrs;
|
||||||
use Shorewall::Zones;
|
use Shorewall::Zones;
|
||||||
use Shorewall::Interfaces;
|
|
||||||
use Shorewall::Chains;
|
use Shorewall::Chains;
|
||||||
use Shorewall::Hosts;
|
|
||||||
use Shorewall::Actions;
|
use Shorewall::Actions;
|
||||||
use Shorewall::Macros;
|
|
||||||
use Shorewall::Policy;
|
use Shorewall::Policy;
|
||||||
use Shorewall::Proc;
|
use Shorewall::Proc;
|
||||||
|
|
||||||
|
@ -29,11 +29,9 @@
|
|||||||
#
|
#
|
||||||
package Shorewall::Tc;
|
package Shorewall::Tc;
|
||||||
require Exporter;
|
require Exporter;
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
use Shorewall::Config;
|
||||||
use Shorewall::Zones;
|
use Shorewall::Zones;
|
||||||
use Shorewall::Chains;
|
use Shorewall::Chains;
|
||||||
use Shorewall::Interfaces;
|
|
||||||
use Shorewall::Providers;
|
use Shorewall::Providers;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#
|
#
|
||||||
package Shorewall::Tunnels;
|
package Shorewall::Tunnels;
|
||||||
require Exporter;
|
require Exporter;
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
use Shorewall::Config;
|
||||||
use Shorewall::Zones;
|
use Shorewall::Zones;
|
||||||
use Shorewall::Chains;
|
use Shorewall::Chains;
|
||||||
|
@ -20,12 +20,13 @@
|
|||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
|
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
|
||||||
#
|
#
|
||||||
# This module contains the code which deals with /etc/shorewall/zones.
|
# This module contains the code which deals with /etc/shorewall/zones,
|
||||||
|
# /etc/shorewall/interfaces and /etc/shorewall/hosts.
|
||||||
#
|
#
|
||||||
package Shorewall::Zones;
|
package Shorewall::Zones;
|
||||||
require Exporter;
|
require Exporter;
|
||||||
use Shorewall::Common;
|
|
||||||
use Shorewall::Config;
|
use Shorewall::Config;
|
||||||
|
use Shorewall::IPAddrs;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
|
||||||
@ -39,13 +40,23 @@ our @EXPORT = qw( NOTHING
|
|||||||
determine_zones
|
determine_zones
|
||||||
zone_report
|
zone_report
|
||||||
dump_zone_contents
|
dump_zone_contents
|
||||||
haveipseczones
|
|
||||||
single_interface
|
single_interface
|
||||||
|
validate_interfaces_file
|
||||||
|
known_interface
|
||||||
|
port_to_bridge
|
||||||
|
source_port_to_bridge
|
||||||
|
interface_is_optional
|
||||||
|
find_interfaces_by_option
|
||||||
|
get_interface_option
|
||||||
|
validate_hosts_file
|
||||||
|
find_hosts_by_option
|
||||||
|
|
||||||
@zones
|
@zones
|
||||||
%zones
|
%zones
|
||||||
$firewall_zone
|
$firewall_zone
|
||||||
%interfaces );
|
%interfaces
|
||||||
|
@interfaces
|
||||||
|
@bridges );
|
||||||
|
|
||||||
our @EXPORT_OK = qw( initialize );
|
our @EXPORT_OK = qw( initialize );
|
||||||
our $VERSION = 4.00;
|
our $VERSION = 4.00;
|
||||||
@ -99,6 +110,24 @@ our %reservedName = ( all => 1,
|
|||||||
SOURCE => 1,
|
SOURCE => 1,
|
||||||
DEST => 1 );
|
DEST => 1 );
|
||||||
|
|
||||||
|
#
|
||||||
|
# Interface Table.
|
||||||
|
#
|
||||||
|
# @interfaces lists the interface names in the order that they appear in the interfaces file.
|
||||||
|
#
|
||||||
|
# %interfaces { <interface1> => { root => <name without trailing '+'>
|
||||||
|
# options => { <option1> = <val1> ,
|
||||||
|
# ...
|
||||||
|
# }
|
||||||
|
# zone => <zone name>
|
||||||
|
# bridge => <bridge>
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
our @interfaces;
|
||||||
|
our %interfaces;
|
||||||
|
our @bridges;
|
||||||
|
|
||||||
#
|
#
|
||||||
# Initialize globals -- we take this novel approach to globals initialization to allow
|
# Initialize globals -- we take this novel approach to globals initialization to allow
|
||||||
# the compiler to run multiple times in the same process. The
|
# the compiler to run multiple times in the same process. The
|
||||||
@ -112,6 +141,10 @@ sub initialize() {
|
|||||||
@zones = ();
|
@zones = ();
|
||||||
%zones = ();
|
%zones = ();
|
||||||
$firewall_zone = '';
|
$firewall_zone = '';
|
||||||
|
|
||||||
|
@interfaces = ();
|
||||||
|
%interfaces = ();
|
||||||
|
@bridges = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
INIT {
|
INIT {
|
||||||
@ -404,4 +437,513 @@ sub single_interface( $ ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub add_group_to_zone($$$$$)
|
||||||
|
{
|
||||||
|
my ($zone, $type, $interface, $networks, $options) = @_;
|
||||||
|
my $typeref;
|
||||||
|
my $interfaceref;
|
||||||
|
my $arrayref;
|
||||||
|
my $zoneref = $zones{$zone};
|
||||||
|
my $zonetype = $zoneref->{type};
|
||||||
|
my $ifacezone = $interfaces{$interface}{zone};
|
||||||
|
|
||||||
|
$zoneref->{interfaces}{$interface} = 1;
|
||||||
|
|
||||||
|
my @newnetworks;
|
||||||
|
my @exclusions;
|
||||||
|
my $new = \@newnetworks;
|
||||||
|
my $switched = 0;
|
||||||
|
|
||||||
|
$ifacezone = '' unless defined $ifacezone;
|
||||||
|
|
||||||
|
for my $host ( @$networks ) {
|
||||||
|
fatal_error "Invalid Host List" unless defined $host and $host ne '';
|
||||||
|
|
||||||
|
if ( substr( $host, 0, 1 ) eq '!' ) {
|
||||||
|
fatal_error "Only one exclusion allowed in a host list" if $switched;
|
||||||
|
$switched = 1;
|
||||||
|
$host = substr( $host, 1 );
|
||||||
|
$new = \@exclusions;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( substr( $host, 0, 1 ) eq '+' ) {
|
||||||
|
fatal_error "Invalid ipset name ($host)" unless $host =~ /^\+[a-zA-Z]\w*$/;
|
||||||
|
} else {
|
||||||
|
validate_host $host;
|
||||||
|
}
|
||||||
|
|
||||||
|
push @$new, $switched ? "$interface:$host" : $host;
|
||||||
|
}
|
||||||
|
|
||||||
|
$zoneref->{options}{in_out}{routeback} = 1 if $options->{routeback};
|
||||||
|
|
||||||
|
$typeref = ( $zoneref->{hosts} || ( $zoneref->{hosts} = {} ) );
|
||||||
|
$interfaceref = ( $typeref->{$type} || ( $interfaceref = $typeref->{$type} = {} ) );
|
||||||
|
$arrayref = ( $interfaceref->{$interface} || ( $interfaceref->{$interface} = [] ) );
|
||||||
|
|
||||||
|
$zoneref->{options}{complex} = 1 if @$arrayref || ( @newnetworks > 1 ) || ( @exclusions );
|
||||||
|
|
||||||
|
push @{$zoneref->{exclusions}}, @exclusions;
|
||||||
|
|
||||||
|
push @{$arrayref}, { options => $options,
|
||||||
|
hosts => \@newnetworks,
|
||||||
|
ipsec => $type eq 'ipsec4' ? 'ipsec' : 'none' };
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Return a list of networks routed out of the passed interface
|
||||||
|
#
|
||||||
|
sub get_routed_networks ( $$ ) {
|
||||||
|
my ( $interface , $error_message ) = @_;
|
||||||
|
my @networks;
|
||||||
|
|
||||||
|
if ( open IP , '-|' , "/sbin/ip route show dev $interface 2> /dev/null" ) {
|
||||||
|
while ( my $route = <IP> ) {
|
||||||
|
$route =~ s/^\s+//;
|
||||||
|
my $network = ( split /\s+/, $route )[0];
|
||||||
|
if ( $network eq 'default' ) {
|
||||||
|
fatal_error $error_message if $error_message;
|
||||||
|
warning_message "default route ignored on interface $interface";
|
||||||
|
} else {
|
||||||
|
my ( $address, $vlsm ) = split '/', $network;
|
||||||
|
$vlsm = 32 unless defined $vlsm;
|
||||||
|
push @networks, "$address/$vlsm";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close IP
|
||||||
|
}
|
||||||
|
|
||||||
|
@networks;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Parse the interfaces file.
|
||||||
|
#
|
||||||
|
|
||||||
|
sub validate_interfaces_file( $ )
|
||||||
|
{
|
||||||
|
my $export = shift;
|
||||||
|
|
||||||
|
use constant { SIMPLE_IF_OPTION => 1,
|
||||||
|
BINARY_IF_OPTION => 2,
|
||||||
|
ENUM_IF_OPTION => 3,
|
||||||
|
MASK_IF_OPTION => 3,
|
||||||
|
|
||||||
|
IF_OPTION_ZONEONLY => 4 };
|
||||||
|
|
||||||
|
my %validoptions = (arp_filter => BINARY_IF_OPTION,
|
||||||
|
arp_ignore => ENUM_IF_OPTION,
|
||||||
|
blacklist => SIMPLE_IF_OPTION,
|
||||||
|
bridge => SIMPLE_IF_OPTION,
|
||||||
|
detectnets => SIMPLE_IF_OPTION,
|
||||||
|
dhcp => SIMPLE_IF_OPTION,
|
||||||
|
maclist => SIMPLE_IF_OPTION,
|
||||||
|
logmartians => BINARY_IF_OPTION,
|
||||||
|
norfc1918 => SIMPLE_IF_OPTION,
|
||||||
|
nosmurfs => SIMPLE_IF_OPTION,
|
||||||
|
optional => SIMPLE_IF_OPTION,
|
||||||
|
proxyarp => BINARY_IF_OPTION,
|
||||||
|
routeback => SIMPLE_IF_OPTION + IF_OPTION_ZONEONLY,
|
||||||
|
routefilter => BINARY_IF_OPTION,
|
||||||
|
sourceroute => BINARY_IF_OPTION,
|
||||||
|
tcpflags => SIMPLE_IF_OPTION,
|
||||||
|
upnp => SIMPLE_IF_OPTION,
|
||||||
|
);
|
||||||
|
|
||||||
|
my $fn = open_file 'interfaces';
|
||||||
|
|
||||||
|
my $first_entry = 1;
|
||||||
|
|
||||||
|
my @ifaces;
|
||||||
|
|
||||||
|
while ( read_a_line ) {
|
||||||
|
|
||||||
|
if ( $first_entry ) {
|
||||||
|
progress_message2 "$doing $fn...";
|
||||||
|
$first_entry = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
my ($zone, $interface, $networks, $options ) = split_line 2, 4, 'interfaces 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';
|
||||||
|
}
|
||||||
|
|
||||||
|
$networks = '' if $networks eq '-';
|
||||||
|
$options = '' if $options eq '-';
|
||||||
|
|
||||||
|
( $interface, my ($port, $extra) ) = split /:/ , $interface, 3;
|
||||||
|
|
||||||
|
fatal_error "Invalid INTERFACE" if defined $extra || ! $interface;
|
||||||
|
|
||||||
|
fatal_error "Invalid Interface Name ($interface)" if $interface eq '+';
|
||||||
|
|
||||||
|
if ( defined $port ) {
|
||||||
|
require_capability( 'PHYSDEV_MATCH', 'Bridge Ports', '');
|
||||||
|
require_capability( 'KLUDGEFREE', 'Bridge Ports', '');
|
||||||
|
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.@%-]+\+?$/;
|
||||||
|
|
||||||
|
$interfaces{$port}{bridge} = $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';
|
||||||
|
$interfaces{$interface}{bridge} = $interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $wildcard = 0;
|
||||||
|
|
||||||
|
if ( $interface =~ /\+$/ ) {
|
||||||
|
$wildcard = 1;
|
||||||
|
$interfaces{$interface}{root} = substr( $interface, 0, -1 );
|
||||||
|
} else {
|
||||||
|
$interfaces{$interface}{root} = $interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
unless ( $networks eq '' || $networks eq 'detect' ) {
|
||||||
|
|
||||||
|
for my $address ( split /,/, $networks ) {
|
||||||
|
fatal_error 'Invalid BROADCAST address' unless $address =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
|
||||||
|
}
|
||||||
|
|
||||||
|
warning_message 'Shorewall no longer uses broadcast addresses in rule generation';
|
||||||
|
}
|
||||||
|
|
||||||
|
my $optionsref = {};
|
||||||
|
|
||||||
|
my %options;
|
||||||
|
|
||||||
|
if ( $options ) {
|
||||||
|
|
||||||
|
for my $option (split ',', $options ) {
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$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;
|
||||||
|
push @bridges, $interface;
|
||||||
|
}
|
||||||
|
} elsif ( $port ) {
|
||||||
|
$options{port} = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$interfaces{$interface}{options} = $optionsref = \%options;
|
||||||
|
|
||||||
|
push @ifaces, $interface;
|
||||||
|
|
||||||
|
my @networks;
|
||||||
|
|
||||||
|
if ( $options{detectnets} ) {
|
||||||
|
fatal_error "The 'detectnets' option is not allowed on a multi-zone interface" unless $zone;
|
||||||
|
fatal_error "The 'detectnets' option may not be used with a wild-card interface name" if $wildcard;
|
||||||
|
fatal_error "The 'detectnets' option may not be used with the '-e' compiler option" if $export;
|
||||||
|
@networks = get_routed_networks( $interface, 'detectnets not allowed on interface with default route' );
|
||||||
|
fatal_error "No routes found through 'detectnets' interface $interface" unless @networks || $options{optional};
|
||||||
|
delete $options{maclist} unless @networks;
|
||||||
|
} else {
|
||||||
|
@networks = @allipv4;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_group_to_zone( $zone, $zoneref->{type}, $interface, \@networks, $optionsref ) if $zone && @networks;
|
||||||
|
|
||||||
|
$interfaces{$interface}{zone} = $zone; #Must follow the call to add_group_to_zone()
|
||||||
|
|
||||||
|
progress_message " Interface \"$currentline\" Validated";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# We now assemble the @interfaces array such that bridge ports immediately precede their associated bridge
|
||||||
|
#
|
||||||
|
for my $interface ( @ifaces ) {
|
||||||
|
my $interfaceref = $interfaces{$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};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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_interface($)
|
||||||
|
{
|
||||||
|
my $interface = $_[0];
|
||||||
|
|
||||||
|
return 1 if $interfaces{$interface};
|
||||||
|
|
||||||
|
for my $i ( @interfaces ) {
|
||||||
|
my $interfaceref = $interfaces{$i};
|
||||||
|
my $val = $interfaceref->{root};
|
||||||
|
next if $val eq $i;
|
||||||
|
if ( substr( $interface, 0, length $val ) eq $val ) {
|
||||||
|
#
|
||||||
|
# Cache this result for future reference
|
||||||
|
#
|
||||||
|
$interfaces{$interface} = { options => $interfaceref->{options}, bridge => $interfaceref->{bridge} };
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Return the bridge associated with the passed interface. If the interface is not a bridge port,
|
||||||
|
# return ''
|
||||||
|
#
|
||||||
|
sub port_to_bridge( $ ) {
|
||||||
|
my $portref = $interfaces{$_[0]};
|
||||||
|
return $portref && $portref->{options}{port} ? $portref->{bridge} : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Return the bridge associated with the passed interface.
|
||||||
|
#
|
||||||
|
sub source_port_to_bridge( $ ) {
|
||||||
|
my $portref = $interfaces{$_[0]};
|
||||||
|
return $portref ? $portref->{bridge} : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Return the 'optional' setting of the passed interface
|
||||||
|
#
|
||||||
|
sub interface_is_optional($) {
|
||||||
|
my $optionsref = $interfaces{$_[0]}{options};
|
||||||
|
$optionsref && $optionsref->{optional};
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Returns reference to array of interfaces with the passed option
|
||||||
|
#
|
||||||
|
sub find_interfaces_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
|
||||||
|
#
|
||||||
|
sub get_interface_option( $$ ) {
|
||||||
|
my ( $interface, $option ) = @_;
|
||||||
|
|
||||||
|
$interfaces{$interface}{options}{$option};
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Validates the hosts file. Generates entries in %zone{..}{hosts}
|
||||||
|
#
|
||||||
|
sub validate_hosts_file()
|
||||||
|
{
|
||||||
|
my %validoptions = (
|
||||||
|
blacklist => 1,
|
||||||
|
maclist => 1,
|
||||||
|
norfc1918 => 1,
|
||||||
|
nosmurfs => 1,
|
||||||
|
routeback => 1,
|
||||||
|
routefilter => 1,
|
||||||
|
tcpflags => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
my $ipsec = 0;
|
||||||
|
my $first_entry = 1;
|
||||||
|
|
||||||
|
my $fn = open_file 'hosts';
|
||||||
|
|
||||||
|
while ( read_a_line ) {
|
||||||
|
|
||||||
|
if ( $first_entry ) {
|
||||||
|
progress_message2 "$doing $fn...";
|
||||||
|
$first_entry = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
my ($zone, $hosts, $options ) = split_line 2, 3, 'hosts 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';
|
||||||
|
|
||||||
|
my $interface;
|
||||||
|
|
||||||
|
if ( $hosts =~ /^([\w.@%-]+\+?):(.*)$/ ) {
|
||||||
|
$interface = $1;
|
||||||
|
$hosts = $2;
|
||||||
|
$zoneref->{options}{complex} = 1 if $hosts =~ /^\+/;
|
||||||
|
fatal_error "Unknown interface ($interface)" unless $interfaces{$interface}{root};
|
||||||
|
} else {
|
||||||
|
fatal_error "Invalid HOST(S) column contents: $hosts";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $type eq 'bport4' ) {
|
||||||
|
if ( $zoneref->{bridge} eq '' ) {
|
||||||
|
fatal_error 'Bridge Port Zones may only be associated with bridge ports' unless $interfaces{$interface}{options}{port};
|
||||||
|
$zoneref->{bridge} = $interfaces{$interface}{bridge};
|
||||||
|
} elsif ( $zoneref->{bridge} ne $interfaces{$interface}{bridge} ) {
|
||||||
|
fatal_error "Interface $interface is not a port on bridge $zoneref->{bridge}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my $optionsref = {};
|
||||||
|
|
||||||
|
if ( $options ne '-' ) {
|
||||||
|
my @options = split ',', $options;
|
||||||
|
my %options;
|
||||||
|
|
||||||
|
for my $option ( @options )
|
||||||
|
{
|
||||||
|
if ( $option eq 'ipsec' ) {
|
||||||
|
$type = 'ipsec';
|
||||||
|
$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( '', ALLIPv4 , $hosts ) if substr($hosts, 0, 2 ) eq ',!';
|
||||||
|
|
||||||
|
add_group_to_zone( $zone, $type , $interface, [ split( ',', $hosts ) ] , $optionsref);
|
||||||
|
|
||||||
|
progress_message " Host \"$currentline\" validated";
|
||||||
|
}
|
||||||
|
|
||||||
|
$capabilities{POLICY_MATCH} = '' unless $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 );
|
||||||
|
#
|
||||||
|
sub find_hosts_by_option( $ ) {
|
||||||
|
my $option = $_[0];
|
||||||
|
my @hosts;
|
||||||
|
|
||||||
|
for my $zone ( grep $zones{$_}{type} ne 'firewall' , @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 ( @interfaces ) {
|
||||||
|
if ( ! $interfaces{$interface}{zone} && $interfaces{$interface}{options}{$option} ) {
|
||||||
|
push @hosts, [ $interface, 'none', ALLIPv4 ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\@hosts;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -70,12 +70,9 @@ fi
|
|||||||
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Accounting.pm
|
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Accounting.pm
|
||||||
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Actions.pm
|
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Actions.pm
|
||||||
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Chains.pm
|
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Chains.pm
|
||||||
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Common.pm
|
|
||||||
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Compiler.pm
|
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Compiler.pm
|
||||||
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Config.pm
|
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Config.pm
|
||||||
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/FallbackPorts.pm
|
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/FallbackPorts.pm
|
||||||
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Hosts.pm
|
|
||||||
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Interfaces.pm
|
|
||||||
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/IPAddrs.pm
|
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/IPAddrs.pm
|
||||||
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Macros.pm
|
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Macros.pm
|
||||||
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Nat.pm
|
%attr(0644,root,root) /usr/share/shorewall-perl/Shorewall/Nat.pm
|
||||||
|
Loading…
Reference in New Issue
Block a user