diff --git a/Shorewall-perl/README.txt b/Shorewall-perl/README.txt index 5a2cc54b9..5c2c3eddc 100644 --- a/Shorewall-perl/README.txt +++ b/Shorewall-perl/README.txt @@ -1,2 +1,2 @@ -This is the Shorewall-perl stable 4.2 branch of SVN. +This is the Shorewall-perl development 4.2 branch of SVN. diff --git a/Shorewall-perl/Shorewall/Chains.pm b/Shorewall-perl/Shorewall/Chains.pm index 65ce76d19..b56847b18 100644 --- a/Shorewall-perl/Shorewall/Chains.pm +++ b/Shorewall-perl/Shorewall/Chains.pm @@ -34,7 +34,7 @@ use Shorewall::IPAddrs; use strict; our @ISA = qw(Exporter); -our @EXPORT = qw( +our @EXPORT = qw( add_rule add_jump insert_rule @@ -68,6 +68,7 @@ our %EXPORT_TAGS = ( POSTROUTE_RESTRICT ALL_RESTRICT + chain_family add_command add_commands move_rules @@ -247,6 +248,8 @@ use constant { NULL_MODE => 0 , # Generating neither shell commands nor iptabl our $mode; +our $family; + # # Initialize globals -- we take this novel approach to globals initialization to allow # the compiler to run multiple times in the same process. The @@ -256,7 +259,7 @@ our $mode; # the second and subsequent calls to that function. # -sub initialize() { +sub initialize( $ ) { %chain_table = ( raw => {} , mangle => {}, nat => {}, @@ -282,40 +285,6 @@ sub initialize() { # $comment = ''; # - # As new targets (Actions, Macros and Manual Chains) are discovered, they are added to the table - # - %targets = ('ACCEPT' => STANDARD, - 'ACCEPT+' => STANDARD + NONAT, - 'ACCEPT!' => STANDARD, - 'NONAT' => STANDARD + NONAT + NATONLY, - 'DROP' => STANDARD, - 'DROP!' => STANDARD, - 'REJECT' => STANDARD, - 'REJECT!' => STANDARD, - 'DNAT' => NATRULE, - 'DNAT-' => NATRULE + NATONLY, - 'REDIRECT' => NATRULE + REDIRECT, - 'REDIRECT-' => NATRULE + REDIRECT + NATONLY, - 'LOG' => STANDARD + LOGRULE, - 'CONTINUE' => STANDARD, - 'CONTINUE!' => STANDARD, - 'QUEUE' => STANDARD, - 'QUEUE!' => STANDARD, - 'NFQUEUE' => STANDARD + NFQ, - 'NFQUEUE!' => STANDARD + NFQ, - 'SAME' => NATRULE, - 'SAME-' => NATRULE + NATONLY, - 'dropBcast' => BUILTIN + ACTION, - 'allowBcast' => BUILTIN + ACTION, - 'dropNotSyn' => BUILTIN + ACTION, - 'rejNotSyn' => BUILTIN + ACTION, - 'dropInvalid' => BUILTIN + ACTION, - 'allowInvalid' => BUILTIN + ACTION, - 'allowinUPnP' => BUILTIN + ACTION, - 'forwardUPnP' => BUILTIN + ACTION, - 'Limit' => BUILTIN + ACTION, - ); - # # Used to sequence 'exclusion' chains with names 'excl0', 'excl1', ... # $exclseq = 0; @@ -336,10 +305,12 @@ sub initialize() { %interfacemacs = (); %interfacebcasts = (); %interfacegateways = (); + + $family = shift; } INIT { - initialize; + initialize( F_IPV4 ); } # @@ -915,29 +886,108 @@ sub ensure_manual_chain($) { # sub initialize_chain_table() { - for my $chain qw(OUTPUT PREROUTING) { - new_builtin_chain 'raw', $chain, 'ACCEPT'; - } + if ( $family == F_IPV4 ) { + # + # As new targets (Actions, Macros and Manual Chains) are discovered, they are added to the table + # + %targets = ('ACCEPT' => STANDARD, + 'ACCEPT+' => STANDARD + NONAT, + 'ACCEPT!' => STANDARD, + 'NONAT' => STANDARD + NONAT + NATONLY, + 'DROP' => STANDARD, + 'DROP!' => STANDARD, + 'REJECT' => STANDARD, + 'REJECT!' => STANDARD, + 'DNAT' => NATRULE, + 'DNAT-' => NATRULE + NATONLY, + 'REDIRECT' => NATRULE + REDIRECT, + 'REDIRECT-' => NATRULE + REDIRECT + NATONLY, + 'LOG' => STANDARD + LOGRULE, + 'CONTINUE' => STANDARD, + 'CONTINUE!' => STANDARD, + 'QUEUE' => STANDARD, + 'QUEUE!' => STANDARD, + 'NFQUEUE' => STANDARD + NFQ, + 'NFQUEUE!' => STANDARD + NFQ, + 'SAME' => NATRULE, + 'SAME-' => NATRULE + NATONLY, + 'dropBcast' => BUILTIN + ACTION, + 'allowBcast' => BUILTIN + ACTION, + 'dropNotSyn' => BUILTIN + ACTION, + 'rejNotSyn' => BUILTIN + ACTION, + 'dropInvalid' => BUILTIN + ACTION, + 'allowInvalid' => BUILTIN + ACTION, + 'allowinUPnP' => BUILTIN + ACTION, + 'forwardUPnP' => BUILTIN + ACTION, + 'Limit' => BUILTIN + ACTION, + ); - for my $chain qw(INPUT OUTPUT FORWARD) { - new_builtin_chain 'filter', $chain, 'DROP'; - } + for my $chain qw(OUTPUT PREROUTING) { + new_builtin_chain 'raw', $chain, 'ACCEPT'; + } - for my $chain qw(PREROUTING POSTROUTING OUTPUT) { - new_builtin_chain 'nat', $chain, 'ACCEPT'; - } + for my $chain qw(INPUT OUTPUT FORWARD) { + new_builtin_chain 'filter', $chain, 'DROP'; + } + + for my $chain qw(PREROUTING POSTROUTING OUTPUT) { + new_builtin_chain 'nat', $chain, 'ACCEPT'; + } - for my $chain qw(PREROUTING INPUT OUTPUT ) { - new_builtin_chain 'mangle', $chain, 'ACCEPT'; - } + for my $chain qw(PREROUTING INPUT OUTPUT ) { + new_builtin_chain 'mangle', $chain, 'ACCEPT'; + } - if ( $capabilities{MANGLE_FORWARD} ) { - for my $chain qw( FORWARD POSTROUTING ) { + if ( $capabilities{MANGLE_FORWARD} ) { + for my $chain qw( FORWARD POSTROUTING ) { + new_builtin_chain 'mangle', $chain, 'ACCEPT'; + } + } + } else { + # + # As new targets (Actions, Macros and Manual Chains) are discovered, they are added to the table + # + %targets = ('ACCEPT' => STANDARD, + 'ACCEPT!' => STANDARD, + 'DROP' => STANDARD, + 'DROP!' => STANDARD, + 'REJECT' => STANDARD, + 'REJECT!' => STANDARD, + 'LOG' => STANDARD + LOGRULE, + 'CONTINUE' => STANDARD, + 'CONTINUE!' => STANDARD, + 'QUEUE' => STANDARD, + 'QUEUE!' => STANDARD, + 'NFQUEUE' => STANDARD + NFQ, + 'NFQUEUE!' => STANDARD + NFQ, + 'dropBcast' => BUILTIN + ACTION, + 'allowBcast' => BUILTIN + ACTION, + 'dropNotSyn' => BUILTIN + ACTION, + 'rejNotSyn' => BUILTIN + ACTION, + 'dropInvalid' => BUILTIN + ACTION, + 'allowInvalid' => BUILTIN + ACTION, + 'allowinUPnP' => BUILTIN + ACTION, + 'forwardUPnP' => BUILTIN + ACTION, + 'Limit' => BUILTIN + ACTION, + ); + + for my $chain qw(OUTPUT PREROUTING) { + new_builtin_chain 'raw', $chain, 'ACCEPT'; + } + + for my $chain qw(INPUT OUTPUT FORWARD) { + new_builtin_chain 'filter', $chain, 'DROP'; + } + + for my $chain qw(PREROUTING POSTROUTING OUTPUT) { + new_builtin_chain 'nat', $chain, 'ACCEPT'; + } + + for my $chain qw(PREROUTING INPUT OUTPUT FORWARD POSTROUTING ) { new_builtin_chain 'mangle', $chain, 'ACCEPT'; } } } - # # Add ESTABLISHED,RELATED rules and synparam jumps to the passed chain # @@ -1914,7 +1964,16 @@ sub expand_rule( $$$$$$$$$$$ ) if ( $source ) { if ( $source eq '-' ) { $source = ''; - } elsif ( $source =~ /^([^:]+):([^:]+)$/ ) { + } elsif ( $family == F_IPV4 ) { + if ( $source =~ /^([^:]+):([^:]+)$/ ) { + $iiface = $1; + $inets = $2; + } elsif ( $source =~ /\+|~|\..*\./ ) { + $inets = $source; + } else { + $iiface = $source; + } + } elsif ( $source =~ /^([^;]+);([^;]+)$/ ) { $iiface = $1; $inets = $2; } elsif ( $source =~ /\+|~|\..*\./ ) { @@ -1986,7 +2045,16 @@ sub expand_rule( $$$$$$$$$$$ ) } $dest = ''; - } elsif ( $dest =~ /^([^:]+):([^:]+)$/ ) { + } elsif ( $family == F_IPV4 ) { + if ( $dest =~ /^([^:]+):([^:]+)$/ ) { + $diface = $1; + $dnets = $2; + } elsif ( $dest =~ /\+|~|\..*\./ ) { + $dnets = $dest; + } else { + $diface = $dest; + } + } elsif ( $dest =~ /^([^;]+);([^;]+)$/ ) { $diface = $1; $dnets = $2; } elsif ( $dest =~ /\+|~|\..*\./ ) { @@ -2363,10 +2431,14 @@ sub create_netfilter_load() { my @table_list; - push @table_list, 'raw' if $capabilities{RAW_TABLE}; - push @table_list, 'nat' if $capabilities{NAT_ENABLED}; - push @table_list, 'mangle' if $capabilities{MANGLE_ENABLED} && $config{MANGLE_ENABLED}; - push @table_list, 'filter'; + if ( $family == F_IPV4 ) { + push @table_list, 'raw' if $capabilities{RAW_TABLE}; + push @table_list, 'nat' if $capabilities{NAT_ENABLED}; + push @table_list, 'mangle' if $capabilities{MANGLE_ENABLED} && $config{MANGLE_ENABLED}; + push @table_list, 'filter'; + } else { + @table_list = qw( raw mangle filter ); + } $mode = NULL_MODE; @@ -2376,11 +2448,13 @@ sub create_netfilter_load() { push_indent; - save_progress_message "Preparing iptables-restore input..."; + my $utility = $family == F_IPV4 ? 'iptables-restore' : 'ip6tables-restore'; + + save_progress_message "Preparing $utility input..."; emit ''; - emit 'exec 3>${VARDIR}/.iptables-restore-input'; + emit "exec 3>\${VARDIR}/.${utility}-input"; enter_cat_mode; @@ -2425,7 +2499,7 @@ sub create_netfilter_load() { enter_cmd_mode; # - # Now generate the actual iptables-restore command + # Now generate the actual ip[6]tables-restore command # emit( 'exec 3>&-', '', @@ -2433,9 +2507,9 @@ sub create_netfilter_load() { '', 'progress_message2 "Running $command..."', '', - 'cat ${VARDIR}/.iptables-restore-input | $command # Use this nonsensical form to appease SELinux', + "cat \${VARDIR}/.${utility}-input | \$command # Use this nonsensical form to appease SELinux", 'if [ $? != 0 ]; then', - ' fatal_error "iptables-restore Failed. Input is in ${VARDIR}/.iptables-restore-input"', + qq( fatal_error "iptables-restore Failed. Input is in \${VARDIR}/.${utility}-input"), "fi\n" ); diff --git a/Shorewall-perl/Shorewall/Compiler.pm b/Shorewall-perl/Shorewall/Compiler.pm index 6183ef8c1..933c2fe10 100644 --- a/Shorewall-perl/Shorewall/Compiler.pm +++ b/Shorewall-perl/Shorewall/Compiler.pm @@ -37,6 +37,7 @@ use Shorewall::Accounting; use Shorewall::Rules; use Shorewall::Proc; use Shorewall::Proxyarp; +use Shorewall::IPAddrs; our @ISA = qw(Exporter); our @EXPORT = qw( compiler EXPORT TIMESTAMP DEBUG ); @@ -49,6 +50,8 @@ our $test; our $reused = 0; +our $family = F_IPV4; + use constant { EXPORT => 0x01 , TIMESTAMP => 0x02 , DEBUG => 0x04 }; @@ -57,8 +60,8 @@ use constant { EXPORT => 0x01 , # Reinitilize the package-globals in the other modules # sub reinitialize() { - Shorewall::Config::initialize; - Shorewall::Chains::initialize; + Shorewall::Config::initialize($family); + Shorewall::Chains::initialize ($family); Shorewall::Zones::initialize; Shorewall::Policy::initialize; Shorewall::Nat::initialize; @@ -733,8 +736,14 @@ sub compiler { defined($val) && ($val >= MIN_VERBOSITY) && ($val <= MAX_VERBOSITY); } + sub edit_family( $ ) { + my $val = numeric_value( shift ); + defined($val) && ($val == F_IPV4 || $val == F_IPV6); + } + my %parms = ( object => { store => \$objectfile }, directory => { store => \$directory }, + family => { store => \$family , edit => \&edit_family } , verbosity => { store => \$verbosity , edit => \&edit_verbosity } , timestamp => { store => \$timestamp, edit => \&edit_boolean } , debug => { store => \$debug, edit => \&edit_boolean } , @@ -755,7 +764,7 @@ sub compiler { ${$ref->{store}} = $val; } - reinitialize if $reused++; + reinitialize if ++$reused || $family == F_IPV6; if ( $directory ne '' ) { fatal_error "$directory is not an existing directory" unless -d $directory; diff --git a/Shorewall-perl/Shorewall/Config.pm b/Shorewall-perl/Shorewall/Config.pm index 1979bb459..073ac68ec 100644 --- a/Shorewall-perl/Shorewall/Config.pm +++ b/Shorewall-perl/Shorewall/Config.pm @@ -100,6 +100,8 @@ our %EXPORT_TAGS = ( internal => [ qw( create_temp_object run_user_exit2 generate_aux_config + $product + $Product $command $doing $done @@ -108,6 +110,9 @@ our %EXPORT_TAGS = ( internal => [ qw( create_temp_object %globals %capabilities + F_IPV4 + F_IPV6 + MIN_VERBOSITY MAX_VERBOSITY ) ] ); @@ -240,8 +245,17 @@ our $shorewall_dir; # Shorewall Directory our $debug; # If true, use Carp to report errors with stack trace. +our $family; +our $toolname; +our $toolNAME; +our $product; +our $Product; + use constant { MIN_VERBOSITY => -1, - MAX_VERBOSITY => 2 }; + MAX_VERBOSITY => 2 , + F_IPV4 => 1, + F_IPV6 => 2, + }; # # Initialize globals -- we take this novel approach to globals initialization to allow @@ -251,7 +265,15 @@ use constant { MIN_VERBOSITY => -1, # also called by Shorewall::Compiler::compiler at the beginning of # the second and subsequent calls to that function. # -sub initialize() { +sub initialize( $ ) { + $family = shift; + + if ( $family == F_IPV4 ) { + ( $product, $Product, $toolname, $toolNAME ) = qw( shorewall Shorewall iptables IPTABLES ); + } else { + ( $product, $Product, $toolname, $toolNAME ) = qw( shorewall6 Shorewall6 ip6tables IP6TABLES ); + } + ( $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) @@ -274,115 +296,203 @@ sub initialize() { LOGPARMS => '', TC_SCRIPT => '', EXPORT => 0, - VERSION => "4.2.3", + VERSION => "4.3.0", CAPVERSION => 40203 , ); # # From shorewall.conf file # - %config = - ( STARTUP_ENABLED => undef, - VERBOSITY => undef, - # - # Logging - # - LOGFILE => undef, - LOGFORMAT => undef, - LOGTAGONLY => undef, - LOGRATE => undef, - LOGBURST => undef, - LOGALLNEW => undef, - BLACKLIST_LOGLEVEL => undef, - MACLIST_LOG_LEVEL => undef, - TCP_FLAGS_LOG_LEVEL => undef, - RFC1918_LOG_LEVEL => undef, - SMURF_LOG_LEVEL => undef, - LOG_MARTIANS => undef, - LOG_VERBOSITY => undef, - STARTUP_LOG => undef, - # - # Location of Files - # - IPTABLES => undef, - # - #PATH is inherited - # - PATH => undef, - SHOREWALL_SHELL => undef, - SUBSYSLOCK => undef, - MODULESDIR => undef, - # - #CONFIG_PATH is inherited - # - CONFIG_PATH => undef, - RESTOREFILE => undef, - IPSECFILE => undef, - LOCKFILE => undef, - # - # Default Actions/Macros - # - DROP_DEFAULT => undef, - REJECT_DEFAULT => undef, - ACCEPT_DEFAULT => undef, - QUEUE_DEFAULT => undef, - NFQUEUE_DEFAULT => undef, - # - # RSH/RCP Commands - # - RSH_COMMAND => undef, - RCP_COMMAND => undef, - # - # Firewall Options - # - BRIDGING => undef, - IP_FORWARDING => undef, - ADD_IP_ALIASES => undef, - ADD_SNAT_ALIASES => undef, - RETAIN_ALIASES => undef, - TC_ENABLED => undef, - TC_EXPERT => undef, - CLEAR_TC => undef, - MARK_IN_FORWARD_CHAIN => undef, - CLAMPMSS => undef, - ROUTE_FILTER => undef, - DETECT_DNAT_IPADDRS => undef, - MUTEX_TIMEOUT => undef, - ADMINISABSENTMINDED => undef, - BLACKLISTNEWONLY => undef, - DELAYBLACKLISTLOAD => undef, - MODULE_SUFFIX => undef, - DISABLE_IPV6 => undef, - DYNAMIC_ZONES => undef, - PKTTYPE=> undef, - RFC1918_STRICT => undef, - MACLIST_TABLE => undef, - MACLIST_TTL => undef, - SAVE_IPSETS => undef, - MAPOLDACTIONS => undef, - FASTACCEPT => undef, - IMPLICIT_CONTINUE => undef, - HIGH_ROUTE_MARKS => undef, - USE_ACTIONS=> undef, - OPTIMIZE => undef, - EXPORTPARAMS => undef, - SHOREWALL_COMPILER => undef, - EXPAND_POLICIES => undef, - KEEP_RT_TABLES => undef, - DELETE_THEN_ADD => undef, - MULTICAST => undef, - DONT_LOAD => '', - AUTO_COMMENT => undef , - MANGLE_ENABLED => undef , - NULL_ROUTE_RFC1918 => undef , - USE_DEFAULT_RT => undef , - # - # Packet Disposition - # - MACLIST_DISPOSITION => undef, - TCP_FLAGS_DISPOSITION => undef, - BLACKLIST_DISPOSITION => undef, - ); - + if ( $family == F_IPV4 ) { + %config = + ( STARTUP_ENABLED => undef, + VERBOSITY => undef, + # + # Logging + # + LOGFILE => undef, + LOGFORMAT => undef, + LOGTAGONLY => undef, + LOGRATE => undef, + LOGBURST => undef, + LOGALLNEW => undef, + BLACKLIST_LOGLEVEL => undef, + MACLIST_LOG_LEVEL => undef, + TCP_FLAGS_LOG_LEVEL => undef, + RFC1918_LOG_LEVEL => undef, + SMURF_LOG_LEVEL => undef, + LOG_MARTIANS => undef, + LOG_VERBOSITY => undef, + STARTUP_LOG => undef, + # + # Location of Files + # + IPTABLES => undef, + # + #PATH is inherited + # + PATH => undef, + SHOREWALL_SHELL => undef, + SUBSYSLOCK => undef, + MODULESDIR => undef, + # + #CONFIG_PATH is inherited + # + CONFIG_PATH => undef, + RESTOREFILE => undef, + IPSECFILE => undef, + LOCKFILE => undef, + # + # Default Actions/Macros + # + DROP_DEFAULT => undef, + REJECT_DEFAULT => undef, + ACCEPT_DEFAULT => undef, + QUEUE_DEFAULT => undef, + NFQUEUE_DEFAULT => undef, + # + # RSH/RCP Commands + # + RSH_COMMAND => undef, + RCP_COMMAND => undef, + # + # Firewall Options + # + BRIDGING => undef, + IP_FORWARDING => undef, + ADD_IP_ALIASES => undef, + ADD_SNAT_ALIASES => undef, + RETAIN_ALIASES => undef, + TC_ENABLED => undef, + TC_EXPERT => undef, + CLEAR_TC => undef, + MARK_IN_FORWARD_CHAIN => undef, + CLAMPMSS => undef, + ROUTE_FILTER => undef, + DETECT_DNAT_IPADDRS => undef, + MUTEX_TIMEOUT => undef, + ADMINISABSENTMINDED => undef, + BLACKLISTNEWONLY => undef, + DELAYBLACKLISTLOAD => undef, + MODULE_SUFFIX => undef, + DISABLE_IPV6 => undef, + DYNAMIC_ZONES => undef, + PKTTYPE=> undef, + RFC1918_STRICT => undef, + MACLIST_TABLE => undef, + MACLIST_TTL => undef, + SAVE_IPSETS => undef, + MAPOLDACTIONS => undef, + FASTACCEPT => undef, + IMPLICIT_CONTINUE => undef, + HIGH_ROUTE_MARKS => undef, + USE_ACTIONS=> undef, + OPTIMIZE => undef, + EXPORTPARAMS => undef, + SHOREWALL_COMPILER => undef, + EXPAND_POLICIES => undef, + KEEP_RT_TABLES => undef, + DELETE_THEN_ADD => undef, + MULTICAST => undef, + DONT_LOAD => '', + AUTO_COMMENT => undef , + MANGLE_ENABLED => undef , + NULL_ROUTE_RFC1918 => undef , + USE_DEFAULT_RT => undef , + # + # Packet Disposition + # + MACLIST_DISPOSITION => undef, + TCP_FLAGS_DISPOSITION => undef, + BLACKLIST_DISPOSITION => undef, + ); + } else { + %config = + ( STARTUP_ENABLED => undef, + VERBOSITY => undef, + # + # Logging + # + LOGFILE => undef, + LOGFORMAT => undef, + LOGTAGONLY => undef, + LOGRATE => undef, + LOGBURST => undef, + LOGALLNEW => undef, + BLACKLIST_LOGLEVEL => undef, + MACLIST_LOG_LEVEL => undef, + TCP_FLAGS_LOG_LEVEL => undef, + SMURF_LOG_LEVEL => undef, + LOG_VERBOSITY => undef, + STARTUP_LOG => undef, + # + # Location of Files + # + IP6TABLES => undef, + # + #PATH is inherited + # + PATH => undef, + SHOREWALL_SHELL => undef, + SUBSYSLOCK => undef, + MODULESDIR => undef, + # + #CONFIG_PATH is inherited + # + CONFIG_PATH => undef, + RESTOREFILE => undef, + LOCKFILE => undef, + # + # Default Actions/Macros + # + DROP_DEFAULT => undef, + REJECT_DEFAULT => undef, + ACCEPT_DEFAULT => undef, + QUEUE_DEFAULT => undef, + NFQUEUE_DEFAULT => undef, + # + # RSH/RCP Commands + # + RSH_COMMAND => undef, + RCP_COMMAND => undef, + # + # Firewall Options + # + IP_FORWARDING => undef, + TC_ENABLED => undef, + TC_EXPERT => undef, + CLEAR_TC => undef, + MARK_IN_FORWARD_CHAIN => undef, + CLAMPMSS => undef, + MUTEX_TIMEOUT => undef, + ADMINISABSENTMINDED => undef, + BLACKLISTNEWONLY => undef, + MODULE_SUFFIX => undef, + MACLIST_TABLE => undef, + MACLIST_TTL => undef, + MAPOLDACTIONS => 'Yes', + FASTACCEPT => undef, + IMPLICIT_CONTINUE => undef, + HIGH_ROUTE_MARKS => undef, + OPTIMIZE => undef, + EXPORTPARAMS => undef, + SHOREWALL_COMPILER => undef, + EXPAND_POLICIES => undef, + KEEP_RT_TABLES => undef, + DELETE_THEN_ADD => undef, + MULTICAST => undef, + DONT_LOAD => '', + AUTO_COMMENT => undef, + MANGLE_ENABLED => undef , + NULL_ROUTE_RFC1918 => undef , + USE_DEFAULT_RT => undef , + # + # Packet Disposition + # + MACLIST_DISPOSITION => undef, + TCP_FLAGS_DISPOSITION => undef, + BLACKLIST_DISPOSITION => undef, + ); + } # # From parsing the capabilities file # @@ -452,7 +562,7 @@ sub initialize() { } INIT { - initialize; + initialize( F_IPV4 ); # # These variables appear within single quotes in shorewall.conf -- add them to ENV # so that read_a_line doesn't have to be smart enough to parse that usage. @@ -1340,6 +1450,12 @@ sub default_yes_no ( $$ ) { } } +sub default_yes_no_ipv4 ( $$ ) { + my ( $var, $val ) = @_; + default_yes_no( $var, $val ); + warning_message "$var=Yes is ignored for IPv6" if $family == F_IPV4 && $config{$var}; +} + my %validlevels = ( DEBUG => 7, INFO => 6, NOTICE => 5, @@ -1681,7 +1797,7 @@ sub ensure_config_path() { my $f = "$globals{SHAREDIR}/configpath"; - $globals{CONFDIR} = '/usr/share/shorewall/configfiles/' if $> != 0; + $globals{CONFDIR} = "/usr/share/$product/configfiles/"; unless ( $config{CONFIG_PATH} ) { fatal_error "$f does not exist" unless -f $f; @@ -1728,7 +1844,7 @@ sub set_shorewall_dir( $ ) { # Small functions called by get_configuration. We separate them so profiling is more useful # sub process_shorewall_conf() { - my $file = find_file 'shorewall.conf'; + my $file = find_file "$product.conf"; if ( -f $file ) { if ( -r _ ) { @@ -1774,9 +1890,9 @@ sub read_capabilities() { } if ( $capabilities{CAPVERSION} ) { - warning_message "Your capabilities file is out of date -- it does not contain all of the capabilities defined by Shorewall version $globals{VERSION}" unless $capabilities{CAPVERSION} >= $globals{CAPVERSION}; + warning_message "Your capabilities file is out of date -- it does not contain all of the capabilities defined by $Product version $globals{VERSION}" unless $capabilities{CAPVERSION} >= $globals{CAPVERSION}; } else { - warning_message "Your capabilities file may not contain all of the capabilities defined by Shorewall version $globals{VERSION}"; + warning_message "Your capabilities file may not contain all of the capabilities defined by $Product version $globals{VERSION}"; } } @@ -1787,12 +1903,12 @@ sub get_capabilities( $ ) { my $export = $_[0]; if ( ! $export && $> == 0 ) { # $> == $EUID - my $iptables = $config{IPTABLES}; + my $iptables = $config{$toolNAME}; if ( $iptables ) { - fatal_error "IPTABLES=$iptables does not exist or is not executable" unless -x $iptables; + fatal_error "$toolNAME=$iptables does not exist or is not executable" unless -x $iptables; } else { - fatal_error "Can't find iptables executable" unless $iptables = which 'iptables'; + fatal_error "Can't find $toolname executable" unless $iptables = which $toolname; } my $iptables_restore=$iptables . '-restore'; @@ -1877,8 +1993,8 @@ sub get_configuration( $ ) { } check_trivalue ( 'IP_FORWARDING', 'on' ); - check_trivalue ( 'ROUTE_FILTER', '' ); - check_trivalue ( 'LOG_MARTIANS', 'on' ); + check_trivalue ( 'ROUTE_FILTER', '' ); fatal_error "ROUTE_FILTER=On is not supported in IPv6" if $config{ROUTE_FILTER} eq 'on' && $family == F_IPV6; + check_trivalue ( 'LOG_MARTIANS', 'on' ); fatal_error "LOG_MARTIANS=On is not supported in IPv6" if $config{LOG_MARTIANS} eq 'on' && $family == F_IPV6; default 'STARTUP_LOG' , ''; @@ -1913,7 +2029,7 @@ sub get_configuration( $ ) { unless ( $config{ADD_IP_ALIASES} || $config{ADD_SNAT_ALIASES} ) { $config{RETAIN_ALIASES} = ''; } else { - default_yes_no 'RETAIN_ALIASES' , ''; + default_yes_no_ipv4 'RETAIN_ALIASES' , ''; } default_yes_no 'ADMINISABSENTMINDED' , ''; diff --git a/Shorewall-perl/Shorewall/IPAddrs.pm b/Shorewall-perl/Shorewall/IPAddrs.pm index 5e72637a6..d44b95ccb 100644 --- a/Shorewall-perl/Shorewall/IPAddrs.pm +++ b/Shorewall-perl/Shorewall/IPAddrs.pm @@ -26,15 +26,20 @@ # package Shorewall::IPAddrs; require Exporter; -use Shorewall::Config qw( :DEFAULT split_list require_capability in_hex8); +use Socket6; +use Shorewall::Config qw( :DEFAULT split_list require_capability in_hex8 F_IPV4 F_IPV6 ); use strict; our @ISA = qw(Exporter); our @EXPORT = qw( ALLIPv4 + ALLIPv6 + ALLIP + ALL TCP UDP ICMP + IPv6_ICMP SCTP validate_address @@ -45,33 +50,80 @@ our @EXPORT = qw( ALLIPv4 ip_range_explicit expand_port_range allipv4 + allipv6 + allip rfc1918_networks resolve_proto proto_name + use_ipv4_addrs + use_ipv6_addrs + using_ipv4_addrs + using_ipv6_addrs validate_port validate_portpair validate_port_list 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' ); +our $family; -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' , + 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" ); +sub use_ipv4_addrs() { + $family = F_IPV4; +} + +sub using_ipv4() { + $family == F_IPV4; +} + +sub use_ipv6_addrs() { + $family = F_IPV6; +} + +sub using_ipv6() { + $family == F_IPV6; +} + +# +# 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() { + use_ipv4_addrs; +} + +INIT { + initialize; +} + sub vlsm_to_mask( $ ) { my $vlsm = $_[0]; in_hex8 ( ( 0xFFFFFFFF << ( 32 - $vlsm ) ) && 0xFFFFFFFF ); } -sub valid_address( $ ) { +sub valid_4address( $ ) { my $address = $_[0]; my @address = split /\./, $address; @@ -83,20 +135,19 @@ sub valid_address( $ ) { 1; } -sub validate_address( $$ ) { +sub validate_4address( $$ ) { my ( $addr, $allow_name ) = @_; my @addrs = ( $addr ); - unless ( valid_address $addr ) { + unless ( valid_4address $addr ) { fatal_error "Invalid IP Address ($addr)" unless $allow_name; fatal_error "Unknown Host ($addr)" unless (@addrs = gethostbyname $addr); if ( defined wantarray ) { shift @addrs for (1..4); for ( @addrs ) { - my (@a) = unpack('C4',$_); - $_ = join('.', @a ); + $_ = inet_htoa $_; } } } @@ -130,7 +181,7 @@ sub encodeaddr( $ ) { $result; } -sub validate_net( $$ ) { +sub validate_4net( $$ ) { my ($net, $vlsm, $rest) = split( '/', $_[0], 3 ); my $allow_name = $_[1]; @@ -142,10 +193,10 @@ sub validate_net( $$ ) { if ( defined $vlsm ) { fatal_error "Invalid VLSM ($vlsm)" unless $vlsm =~ /^\d+$/ && $vlsm <= 32; fatal_error "Invalid Network address ($_[0])" if defined $rest; - fatal_error "Invalid IP address ($net)" unless valid_address $net; + fatal_error "Invalid IP address ($net)" unless valid_4address $net; } else { fatal_error "Invalid Network address ($_[0])" if $_[0] =~ '/' || ! defined $net; - validate_address $net, $_[1]; + validate_4address $net, $_[1]; $vlsm = 32; } @@ -159,11 +210,11 @@ sub validate_net( $$ ) { } } -sub validate_range( $$ ) { +sub validate_4range( $$ ) { my ( $low, $high ) = @_; - validate_address $low, 0; - validate_address $high, 0; + validate_4address $low, 0; + validate_4address $high, 0; my $first = decodeaddr $low; my $last = decodeaddr $high; @@ -171,6 +222,16 @@ sub validate_range( $$ ) { fatal_error "Invalid IP Range ($low-$high)" unless $first <= $last; } +sub validate_4host( $$ ) { + my ( $host, $allow_name ) = $_[0]; + + if ( $host =~ /^(\d+\.\d+\.\d+\.\d+)-(\d+\.\d+\.\d+\.\d+)$/ ) { + validate_4ange $1, $2; + } else { + validate_4net( $host, $allow_name ); + } +} + sub ip_range_explicit( $ ) { my $range = $_[0]; my @result; @@ -182,7 +243,7 @@ sub ip_range_explicit( $ ) { push @result, $low; if ( defined $high ) { - validate_address $high, 0; + validate_faddress $high, 0; my $first = decodeaddr $low; my $last = decodeaddr $high; @@ -209,20 +270,14 @@ sub decompose_net( $ ) { } -sub validate_host( $$ ) { - my ( $host, $allow_name ) = $_[0]; - - if ( $host =~ /^(\d+\.\d+\.\d+\.\d+)-(\d+\.\d+\.\d+\.\d+)$/ ) { - validate_range $1, $2; - } else { - validate_net( $host, $allow_name ); - } -} - sub allipv4() { @allipv4; } +sub allipv6() { + @allipv6; +} + sub rfc1918_networks() { @rfc1918_networks } @@ -231,7 +286,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' ); # @@ -345,6 +400,8 @@ my %icmp_types = ( any => 'any', 'address-mask-reply' => 18 ); sub validate_icmp( $ ) { + fatal_error "IPv4 ICMP not allowed in an IPv6 Rule" unless $family == F_IPV4; + my $type = $_[0]; my $value = $icmp_types{$type}; @@ -419,4 +476,159 @@ 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 ); + my $allow_name = $_[1]; + + 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, $allow_name; + } +} + +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)"; +} + +sub validate_6host( $$ ) { + my ( $host, $allow_name ) = $_[0]; + + if ( $host =~ /^(.*:.*)-(.*:.*)$/ ) { + validate_6range $1, $2; + } else { + validate_6net( $host, $allow_name ); + } +} + +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( $ ) { + fatal_error "IPv6 ICMP not allowed in an IPv4 Rule" unless $family == F_IPV6; + 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)" +} + +sub ALLIP() { + $family == F_IPV4 ? ALLIPv4 : ALLIPv6; +} + +sub allip() { + $family == F_IPV4 ? ALLIPv4 : ALLIPv6; +} + +sub valid_address ( $ ) { + $family == F_IPV4 ? valid_4address( $_[0] ) : valid_6address( $_[0] ); +} + +sub validate_address ( $$ ) { + $family == F_IPV4 ? validate_4address( $_[0], $_[1] ) : validate_6address( $_[0], $_[1] ); +} + +sub validate_net ( $$ ) { + $family == F_IPV4 ? validate_4net( $_[0], $_[1] ) : validate_6net( $_[0], $_[1] ); +} + +sub validate_range ($$ ) { + $family == F_IPV4 ? validate_4range( $_[0], $_[1] ) : validate_6range( $_[0], $_[1] ); +} + +sub validate_host ($$ ) { + $family == F_IPV4 ? validate_4host( $_[0], $_[1] ) : validate_6host( $_[0], $_[1] ); +} + 1; diff --git a/Shorewall-perl/compiler.pl b/Shorewall-perl/compiler.pl index 9a3c1826a..8c86fdf35 100755 --- a/Shorewall-perl/compiler.pl +++ b/Shorewall-perl/compiler.pl @@ -35,11 +35,13 @@ # --refresh= # Make the 'refresh' command refresh a comma-separated list of chains rather than 'blacklst'. # --log= # Log file # --log_verbosity= # Log Verbosity range -1 to 2 +# --family= # IP family; 1 = IPv4, 2 = IPv6 # use strict; use FindBin; use lib "$FindBin::Bin"; use Shorewall::Compiler; +use Shorewall::IPAddrs; use Getopt::Long; sub usage( $ ) { @@ -55,6 +57,7 @@ sub usage( $ ) { [ --log= ] [ --log-verbose={-1|0-2} ] [ --test ] + [ --family={1|2} ] '; exit shift @_; } @@ -72,6 +75,7 @@ my $log = ''; my $log_verbose = 0; my $help = 0; my $test = 0; +my $family = 1; # F_IPV4 Getopt::Long::Configure ('bundling'); @@ -92,6 +96,8 @@ my $result = GetOptions('h' => \$help, 'l=s' => \$log, 'log_verbosity=i' => \$log_verbose, 'test' => \$test, + 'f=i' => \$family, + 'family=i' => \$family, ); usage(1) unless $result && @ARGV < 2; @@ -106,4 +112,5 @@ compiler( object => defined $ARGV[0] ? $ARGV[0] : '', chains => $chains, log => $log, log_verbosity => $log_verbose, - test => $test ); + test => $test, + family => $family );