diff --git a/Shorewall6/Shorewall/Chains.pm b/Shorewall6/Shorewall/Chains.pm deleted file mode 100644 index cd669e9e6..000000000 --- a/Shorewall6/Shorewall/Chains.pm +++ /dev/null @@ -1,2083 +0,0 @@ -# -# Shorewall-perl 4.0 -- /usr/share/shorewall-perl/Shorewall/Chains.pm -# -# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt] -# -# (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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# This is the low-level ip6tables module. It provides the basic services -# of chain and rule creation. It is used by the higher level modules such -# as Rules to create ip6tables-restore input. -# -package Shorewall::Chains; -require Exporter; - -use Shorewall::Config; -use Shorewall::Ports; -use Shorewall::Zones; -use Shorewall::IPAddrs; - -use strict; - -our @ISA = qw(Exporter); -our @EXPORT = qw( STANDARD - NATRULE - BUILTIN - NONAT - NATONLY - REDIRECT - ACTION - MACRO - LOGRULE - NFQ - NO_RESTRICT - PREROUTE_RESTRICT - INPUT_RESTRICT - OUTPUT_RESTRICT - POSTROUTE_RESTRICT - ALL_RESTRICT - - process_comment - clear_comment - incr_cmd_level - decr_cmd_level - add_command - add_commands - mark_referenced - add_file - add_rule - insert_rule - chain_base - forward_chain - input_chain - output_chain - masq_chain - syn_flood_chain - mac_chain - macrecent_target - dynamic_fwd - dynamic_in - dynamic_out - dynamic_chains - dnat_chain - snat_chain - ecn_chain - first_chains - new_chain - ensure_chain - ensure_filter_chain - ensure_mangle_chain - new_standard_chain - new_builtin_chain - initialize_chain_table - finish_section - setup_zone_mss - newexclusionchain - clearrule - do_proto - mac_match - verify_mark - verify_small_mark - validate_mark - do_test - do_ratelimit - do_user - do_tos - match_source_dev - match_dest_dev - iprange_match - match_source_net - match_dest_net - match_orig_dest - match_ipsec_in - match_ipsec_out - log_rule_limit - log_rule - expand_rule - addnatjump - insertnatjump - get_interface_address - get_interface_addresses - get_interface_bcasts - set_global_variables - create_netfilter_load - create_chainlist_reload - - %chain_table - $mangle_table - $filter_table - $section - %sections - %targets - ); -our @EXPORT_OK = qw( initialize ); -our $VERSION = '4.04'; - -# -# Chain Table -# -# %chain_table { => { => { name => -# table =>
-# is_policy => 0|1 -# is_optional => 0|1 -# referenced => 0|1 -# log => -# policy => -# policychain => -- self-reference if this is a policy chain -# policypair => [ , ] -- Used for reporting duplicated policies -# loglevel => -# synparams => -# synchain => -# default => -# cmdlevel => -# rules => [ -# -# ... -# ] -# } , -# => ... -# } -# } -# -# 'is_optional' only applies to policy chains; when true, indicates that this is a provisional policy chain which might be -# replaced. Policy chains created under the IMPLICIT_CONTINUE=Yes option are optional. -# -# Only 'referenced' chains get written to the ip6tables-restore input. -# -# 'loglevel', 'synparams', 'synchain' and 'default' only apply to policy chains. -# -our %chain_table; -our $mangle_table; -our $filter_table; -# -# It is a layer violation to keep information about the rules file sections in this module but in Shorewall, the rules file -# and the filter table are very closely tied. By keeping the information here, we avoid making several other modules dependent -# on Shorewall::Rules. -# -our %sections; -our $section; - -our $comment; - -use constant { STANDARD => 1, #defined by Netfilter - NATRULE => 2, #Involves NAT - BUILTIN => 4, #A built-in action - NONAT => 8, #'NONAT' or 'ACCEPT+' - NATONLY => 16, #'DNAT-' or 'REDIRECT-' - REDIRECT => 32, #'REDIRECT' - ACTION => 64, #An action (may be built-in) - MACRO => 128, #A Macro - LOGRULE => 256, #'LOG' - NFQ => 512, #'NFQUEUE' - }; - -our %targets; -# -# expand_rule() restrictions -# -use constant { NO_RESTRICT => 0, # FORWARD chain rule - Both -i and -o may be used in the rule - PREROUTE_RESTRICT => 1, # PREROUTING chain rule - -o converted to -d
using main routing table - INPUT_RESTRICT => 4, # INPUT chain rule - -o not allowed - OUTPUT_RESTRICT => 8, # OUTPUT chain rule - -i not allowed - POSTROUTE_RESTRICT => 16, # POSTROUTING chain rule - -i converted to -s
using main routing table - ALL_RESTRICT => 12 # fw->fw rule - neither -i nor -o allowed - }; -our $exclseq; -our $iprangematch; -our $chainseq; - -our %interfaceaddr; -our %interfaceaddrs; -our %interfacenets; -our %interfacebcasts; - -our @builtins = qw(PREROUTING INPUT FORWARD OUTPUT POSTROUTING); - -# -# Mode of the generator. -# -use constant { NULL_MODE => 0 , # Generating neither shell commands nor ip6tables-restore input - CAT_MODE => 1 , # Generating ip6tables-restore input - CMD_MODE => 2 }; # Generating shell commands. - -our $mode; - -# -# 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() { - %chain_table = ( raw => {} , - mangle => {}, - filter => {} ); - - $mangle_table = $chain_table{mangle}; - $filter_table = $chain_table{filter}; - - # - # These get set to 1 as sections are encountered. - # - %sections = ( ESTABLISHED => 0, - RELATED => 0, - NEW => 0 - ); - # - # Current rules file section. - # - $section = 'ESTABLISHED'; - # - # Contents of last COMMENT line. - # - $comment = ''; - # - # As new targets (Actions and Macros) 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; - # - # Used to suppress duplicate match specifications. - # - $iprangematch = 0; - # - # Sequence for naming temporary chains - # - $chainseq = undef; - # - # Keep track of which interfaces have active 'address', 'addresses' and 'networks' variables - # - %interfaceaddr = (); - %interfaceaddrs = (); - %interfacenets = (); - %interfacebcasts = (); -} - -INIT { - initialize; -} - -# -# Add a run-time command to a chain. Arguments are: -# -# Chain reference , Command -# - -# -# Process a COMMENT line (in $currentline) -# -sub process_comment() { - if ( $capabilities{COMMENTS} ) { - ( $comment = $currentline ) =~ s/^\s*COMMENT\s*//; - $comment =~ s/\s*$//; - } else { - warning_message "COMMENT ignored -- requires comment support in ip6tables/Netfilter"; - } -} - -# -# Clear the $comment variable -# -sub clear_comment() { - $comment = ''; -} - -# -# Functions to manipulate cmdlevel -# -sub incr_cmd_level( $ ) { - $_[0]->{cmdlevel}++; -} - -sub decr_cmd_level( $ ) { - fatal_error "Internal error in decr_cmd_level()" if --$_[0]->{cmdlevel} < 0; -} - -sub add_command($$) -{ - my ($chainref, $command) = @_; - - push @{$chainref->{rules}}, join ('', ' ' x $chainref->{cmdlevel} , $command ); - - $chainref->{referenced} = 1; -} - -sub add_commands { - my $chainref = shift @_; - - for my $command ( @_ ) { - push @{$chainref->{rules}}, join ('', ' ' x $chainref->{cmdlevel} , $command ); - } - - $chainref->{referenced} = 1; -} - -sub mark_referenced( $ ) { - $_[0]->{referenced} = 1; -} - -# -# Copy a file into a chain's rules as a set of run-time commands -# - -sub add_file( $$ ) { - my $chainref = $_[0]; - my $file = find_file $_[1]; - - if ( -f $file ) { - open EF , '<', $file or fatal_error "Unable to open $file: $!"; - - add_commands( $chainref, - qq(progress_message "Processing $file..."), - '' ); - - while ( my $line = ) { - chomp $line; - add_command $chainref, $line; - } - - add_command $chainref, ''; - - close EF; - } -} - -# -# Add a rule to a chain. Arguments are: -# -# Chain reference , Rule -# -sub add_rule($$) -{ - my ($chainref, $rule) = @_; - - $iprangematch = 0; - - $rule .= qq( -m comment --comment "$comment") if $comment; - - if ( $chainref->{cmdlevel} ) { - $rule =~ s/"/\\"/g; #Must preserve quotes in the rule - add_command $chainref , qq(echo "-A $chainref->{name} $rule" >&3); - } else { - push @{$chainref->{rules}}, join( ' ', '-A' , $chainref->{name}, $rule ); - $chainref->{referenced} = 1; - } -} - -# -# Insert a rule into a chain. Arguments are: -# -# Chain reference , Rule Number, Rule -# -sub insert_rule($$$) -{ - my ($chainref, $number, $rule) = @_; - - fatal_error 'Internal Error in insert_rule()' if $chainref->{cmdlevel}; - - $rule .= "-m comment --comment \"$comment\"" if $comment; - - splice( @{$chainref->{rules}}, $number - 1, 0, join( ' ', '-A', $chainref->{name}, $rule ) ); - - $iprangematch = 0; - - $chainref->{referenced} = 1; - -} - -# -# Form the name of a chain. -# -sub chain_base($) { - my $chain = $_[0]; - - $chain =~ s/^@/at_/; - $chain =~ tr/[.\-%@]/_/; - $chain =~ s/\+$//; - $chain; -} - -sub chain_base_cond($) { - $config{DYNAMIC_ZONES} ? chain_base($_[0]) : $_[0]; -} - -# -# Forward Chain for an interface -# -sub forward_chain($) -{ - chain_base_cond($_[0]) . '_fwd'; -} - -# -# Input Chain for an interface -# -sub input_chain($) -{ - chain_base_cond($_[0]) . '_in'; -} - -# -# Output Chain for an interface -# -sub output_chain($) -{ - chain_base_cond($_[0]) . '_out'; -} - -# -# Masquerade Chain for an interface -# -sub masq_chain($) -{ - chain_base_cond($_[0]) . '_masq'; -} - -# -# Syn_flood_chain -- differs from the other _chain functions in that the argument is a chain table reference -# -sub syn_flood_chain ( $ ) { - '@' . $_[0]->{synchain}; -} - -# -# MAC Verification Chain for an interface -# -sub mac_chain( $ ) -{ - chain_base_cond($_[0]) . '_mac'; -} - -sub macrecent_target($) -{ - $config{MACLIST_TTL} ? chain_base_cond($_[0]) . '_rec' : 'RETURN'; -} - -# -# Functions for creating dynamic zone rules -# -sub dynamic_fwd( $ ) -{ - chain_base_cond($_[0]) . '_dynf'; -} - -sub dynamic_in( $ ) -{ - chain_base_cond($_[0]) . '_dyni'; -} - -sub dynamic_out( $ ) # $1 = interface -{ - chain_base_cond($_[0]) . '_dyno'; -} - -sub dynamic_chains( $ ) #$1 = interface -{ - my $c = chain_base_cond($_[0]); - - [ $c . '_dyni' , $c . '_dynf' , $c . '_dyno' ]; -} - -# -# DNAT Chain from a zone -# -sub dnat_chain( $ ) -{ - chain_base_cond($_[0]) . '_dnat'; -} - -# -# SNAT Chain to an interface -# -sub snat_chain( $ ) -{ - chain_base_cond($_[0]) . '_snat'; -} - -# -# ECN Chain to an interface -# -sub ecn_chain( $ ) -{ - chain_base_cond($_[0]) . '_ecn'; -} - -# -# First chains for an interface -# -sub first_chains( $ ) #$1 = interface -{ - my $c = chain_base_cond($_[0]); - - [ $c . '_fwd', $c . '_in' ]; -} - -# -# Create a new chain and return a reference to it. -# -sub new_chain($$) -{ - my ($table, $chain) = @_; - - warning_message "Internal error in new_chain()" if $chain_table{$table}{$chain}; - - $chain_table{$table}{$chain} = { name => $chain, - rules => [], - table => $table, - loglevel => '', - log => 1, - cmdlevel => 0 }; -} - -# -# Create an anonymous chain -# -sub new_anon_chain( $ ) { - my $chainref = $_[0]; - my $seq = $chainseq++; - new_chain( $chainref->{table}, 'chain' . "$seq" ); -} - -# -# -# Create a chain if it doesn't exist already -# -sub ensure_chain($$) -{ - my ($table, $chain) = @_; - - my $ref = $chain_table{$table}{$chain}; - - return $ref if $ref; - - new_chain $table, $chain; -} - -sub finish_chain_section( $$ ); - -# -# Create a filter chain if necessary. Optionally populate it with the appropriate ESTABLISHED,RELATED rule(s) and perform SYN rate limiting. -# -sub ensure_filter_chain( $$ ) -{ - my ($chain, $populate) = @_; - - my $chainref = $filter_table->{$chain}; - - $chainref = new_chain 'filter' , $chain unless $chainref; - - if ( $populate and ! $chainref->{referenced} ) { - if ( $section eq 'NEW' or $section eq 'DONE' ) { - finish_chain_section $chainref , 'ESTABLISHED,RELATED'; - } elsif ( $section eq 'RELATED' ) { - finish_chain_section $chainref , 'ESTABLISHED'; - } - } - - $chainref->{referenced} = 1; - - $chainref; -} - -sub ensure_mangle_chain($) { - my $chain = $_[0]; - - my $chainref = ensure_chain 'mangle', $chain; - - $chainref->{referenced} = 1; - - $chainref; -} - -# -# Add a builtin chain -# -sub new_builtin_chain($$$) -{ - my ( $table, $chain, $policy ) = @_; - - my $chainref = new_chain $table, $chain; - $chainref->{referenced} = 1; - $chainref->{policy} = $policy; - $chainref->{builtin} = 1; -} - -sub new_standard_chain($) { - my $chainref = new_chain 'filter' ,$_[0]; - $chainref->{referenced} = 1; - $chainref; -} - -# -# Add all builtin chains to the chain table -# -# -sub initialize_chain_table() -{ - 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 INPUT OUTPUT FORWARD POSTROUTING) { - new_builtin_chain 'mangle', $chain, 'ACCEPT'; - } -} - -# -# Add ESTABLISHED,RELATED rules and synparam jumps to the passed chain -# -sub finish_chain_section ($$) { - my ($chainref, $state ) = @_; - my $chain = $chainref->{name}; - - add_rule $chainref, "-m state --state $state -j ACCEPT" unless $config{FASTACCEPT}; - - if ($sections{RELATED} ) { - if ( $chainref->{is_policy} ) { - if ( $chainref->{synparams} ) { - my $synchainref = ensure_chain 'filter', syn_flood_chain $chainref; - if ( $section eq 'DONE' ) { - if ( $chainref->{policy} =~ /^(ACCEPT|CONTINUE|QUEUE|NFQUEUE)/ ) { - add_rule $chainref, "-p tcp --syn -j $synchainref->{name}"; - } - } else { - add_rule $chainref, "-p tcp --syn -j $synchainref->{name}"; - } - } - } else { - my $policychainref = $filter_table->{$chainref->{policychain}}; - if ( $policychainref->{synparams} ) { - my $synchainref = ensure_chain 'filter', syn_flood_chain $policychainref; - add_rule $chainref, "-p tcp --syn -j $synchainref->{name}"; - } - } - } -} - -# -# Do section-end processing -# -sub finish_section ( $ ) { - my $sections = $_[0]; - - for my $section ( split /,/, $sections ) { - $sections{$section} = 1; - } - - for my $zone ( all_zones ) { - for my $zone1 ( all_zones ) { - my $chainref = $chain_table{'filter'}{"${zone}2${zone1}"}; - if ( $chainref->{referenced} ) { - finish_chain_section $chainref, $sections; - } - } - } -} - -# -# Helper for set_mss -# -sub set_mss1( $$ ) { - my ( $chain, $mss ) = @_; - my $chainref = ensure_chain 'filter', $chain; - - if ( $chainref->{policy} ne 'NONE' ) { - my $match = $capabilities{TCPMSS_MATCH} ? "-m tcpmss --mss $mss: " : ''; - insert_rule $chainref, 1, "-p tcp --tcp-flags SYN,RST SYN ${match}-j TCPMSS --set-mss $mss" - } -} - -# -# Set up rules to set MSS to and/or from zone "$zone" -# -sub set_mss( $$$ ) { - my ( $zone, $mss, $direction) = @_; - - for my $z ( all_zones ) { - if ( $direction eq '_in' ) { - set_mss1 "${zone}2${z}" , $mss; - } elsif ( $direction eq '_out' ) { - set_mss1 "${z}2${zone}", $mss; - } else { - set_mss1 "${z}2${zone}", $mss; - set_mss1 "${zone}2${z}", $mss; - } - } -} - -# -# Interate over non-firewall zones and interfaces with 'mss=' setting adding TCPMSS rules as appropriate. -# -sub setup_zone_mss() { - for my $zone ( all_zones ) { - my $zoneref = find_zone( $zone ); - - set_mss( $zone, $zoneref->{options}{in_out}{mss}, '' ) if $zoneref->{options}{in_out}{mss}; - set_mss( $zone, $zoneref->{options}{in}{mss}, '_in' ) if $zoneref->{options}{in}{mss}; - set_mss( $zone, $zoneref->{options}{out}{mss}, '_out' ) if $zoneref->{options}{out}{mss}; - } -} - -sub newexclusionchain() { - my $seq = $exclseq++; - "excl${seq}"; -} - -sub clearrule() { - $iprangematch = 0; -} - -sub validate_proto( $ ) { - my $proto = $_[0]; - my $value = $protocols{$proto}; - return $value if defined $value; - return $proto if $proto =~ /^(\d+)$/ && $proto <= 65535; - return $proto if $proto eq 'all'; - fatal_error "Invalid/Unknown protocol ($proto)"; -} - -sub validate_portpair( $ ) { - my $portpair = $_[0]; - - fatal_error "Invalid port range ($portpair)" if $portpair =~ tr/:/:/ > 1; - - $portpair = "0$portpair" if substr( $portpair, 0, 1 ) eq ':'; - $portpair = "${portpair}65535" if substr( $portpair, -1, 1 ) eq ':'; - - my @ports = split/:/, $portpair, 2; - - for my $port ( @ports ) { - my $value = $services{$port}; - - unless ( defined $value ) { - $value = $port if $port =~ /^(\d+)$/ && $port <= 65535; - } - - fatal_error "Invalid/Unknown port/service ($port)" unless defined $value; - - $port = $value; - } - - if ( @ports == 2 ) { - fatal_error "Invalid port range ($portpair)" unless $ports[0] < $ports[1]; - } - - join ':', @ports; - -} - -sub validate_port_list( $ ) { - my $result = ''; - my $list = $_[0]; - my @list = split/,/, $list; - - if ( @list > 1 && $list =~ /:/ ) { - require_capability( 'XMULTIPORT' , 'Port ranges in a port list', '' ); - } - - for ( @list ) { - my $value = validate_portpair( $_ ); - $result = $result ? join ',', $result, $value : $value; - } - - $result; -} - -my %icmp_types = ( any => 'any', - 'echo-reply' => 0, - 'destination-unreachable' => 3, - 'network-unreachable' => '3/0', - 'host-unreachable' => '3/1', - 'protocol-unreachable' => '3/2', - 'port-unreachable' => '3/3', - 'fragmentation-needed' => '3/4', - 'source-route-failed' => '3/5', - 'network-unknown' => '3/6', - 'host-unknown' => '3/7', - 'network-prohibited' => '3/9', - 'host-prohibited' => '3/10', - 'TOS-network-unreachable' => '3/11', - 'TOS-host-unreachable' => '3/12', - 'communication-prohibited' => '3/13', - 'host-precedence-violation' => '3/14', - 'precedence-cutoff' => '3/15', - 'source-quench' => 4, - 'redirect' => 5, - 'network-redirect' => '5/0', - 'host-redirect' => '5/1', - 'TOS-network-redirect' => '5/2', - 'TOS-host-redirect' => '5/3', - 'echo-request' => '8', - 'router-advertisement' => 9, - 'router-solicitation' => 10, - 'time-exceeded' => 11, - 'ttl-zero-during-transit' => '11/0', - 'ttl-zero-during-reassembly' => '11/1', - 'parameter-problem' => 12, - 'ip-header-bad' => '12/0', - 'required-option-missing' => '12/1', - 'timestamp-request' => 13, - 'timestamp-reply' => 14, - 'address-mask-request' => 17, - 'address-mask-reply' => 18 ); - -sub validate_icmp( $ ) { - my $type = $_[0]; - - my $value = $icmp_types{$type}; - - return $value if defined $value; - - if ( $type =~ /^(\d+)(\/(\d+))?$/ ) { - return $type if $1 < 256 && ( ! $2 || $3 < 256 ); - } - - fatal_error "Invalid ICMP Type ($type)" -} - -# -# Handle parsing of PROTO, DEST PORT(S) , SOURCE PORTS(S). Returns the appropriate match string. -# -sub do_proto( $$$ ) -{ - my ($proto, $ports, $sports ) = @_; - # - # Return the number of ports represented by the passed list - # - sub port_count( $ ) { - ( $_[0] =~ tr/,:/,:/ ) + 1; - } - - my $output = ''; - - $proto = '' if $proto eq '-'; - $ports = '' if $ports eq '-'; - $sports = '' if $sports eq '-'; - - if ( $proto ) { - if ( $proto =~ /^(((tcp|6)((:syn)?))|(udp|17))$/ ) { - - if ( $4 ) { - $output = '-p 6 --syn '; - } else { - $proto = $protocols{$proto} if defined $protocols{$proto}; - $output = "-p $proto "; - } - - my $multiport = 0; - - if ( $ports ne '' ) { - if ( $ports =~ tr/,/,/ > 0 || $sports =~ tr/,/,/ > 0 ) { - fatal_error "Port list requires Multiport support in your kernel/ip6tables ($ports)" unless $capabilities{MULTIPORT}; - fatal_error "Too many entries in port list ($ports)" if port_count( $ports ) > 15; - $ports = validate_port_list $ports; - $output .= "-m multiport --dports $ports "; - $multiport = 1; - } else { - $ports = validate_portpair $ports; - $output .= "--dport $ports "; - } - } else { - $multiport = ( ( $sports =~ tr/,/,/ ) > 0 ); - } - - if ( $sports ne '' ) { - if ( $multiport ) { - fatal_error "Too many entries in port list ($sports)" if port_count( $sports ) > 15; - $sports = validate_port_list $sports; - $output .= "-m multiport --sports $sports "; - } else { - $sports = validate_portpair $sports; - $output .= "--sport $sports "; - } - } - } elsif ( $proto =~ /^(icmp|1)$/i ) { - fatal_error 'Multiple ICMP types are not permitted' if $ports =~ /,/; - $output .= "-p icmp "; - - if ( $ports ne '' ) { - $ports = validate_icmp $ports; - $output .= "--icmp-type $ports "; - } - - fatal_error 'SOURCE PORT(S) not permitted with ICMP' if $sports ne ''; - } elsif ( $proto =~ /^(ipp2p(:(tcp|udp|all))?)$/i ) { - require_capability( 'IPP2P_MATCH' , 'PROTO = ipp2p' , 's' ); - $proto = $2 ? $3 : 'tcp'; - $ports = 'ipp2p' unless $ports; - $output .= "-p $proto -m ipp2p --$ports "; - } else { - fatal_error "SOURCE/DEST PORT(S) not allowed with PROTO $proto" if $ports ne '' || $sports ne ''; - $proto = validate_proto $proto; - $output .= "-p $proto "; - } - } elsif ( $ports ne '' || $sports ne '' ) { - fatal_error "SOURCE/DEST PORT(S) not allowed without PROTO" - } - - $output; -} - -sub mac_match( $ ) { - my $mac = $_[0]; - - $mac =~ s/^(!?)~//; - $mac =~ s/^!// if my $invert = ( $1 ? '! ' : ''); - $mac =~ tr/-/:/; - - "--match mac --mac-source ${invert}$mac "; -} - -# -# Mark validatation functions -# -sub verify_mark( $ ) { - my $mark = $_[0]; - my $limit = $config{HIGH_ROUTE_MARKS} ? 0xFFFF : 0xFF; - - fatal_error "Invalid Mark or Mask value ($mark)" - unless numeric_value( $mark ) <= $limit; -} - -sub verify_small_mark( $ ) { - verify_mark ( (my $mark) = $_[0] ); - fatal_error "Mark value ($mark) too large" if numeric_value( $mark ) > 0xFF; -} - -sub validate_mark( $ ) { - for ( split '/', $_[0] ) { - verify_mark $_; - } -} - -# -# Generate an appropriate -m [conn]mark match string for the contents of a MARK column -# - -sub do_test ( $$ ) -{ - my ($testval, $mask) = @_; - - return '' unless $testval and $testval ne '-'; - - my $invert = $testval =~ s/^!// ? '! ' : ''; - my $match = $testval =~ s/:C$// ? "-m connmark ${invert}--mark" : "-m mark ${invert}--mark"; - - validate_mark $testval; - - $testval .= '/0xFF' unless ( $testval =~ '/' ); - - "$match $testval "; -} - -my %norate = ( DROP => 1, REJECT => 1 ); - -# -# Create a "-m limit" match for the passed LIMIT/BURST -# -sub do_ratelimit( $$ ) { - my ( $rate, $action ) = @_; - - return '' unless $rate and $rate ne '-'; - - fatal_error "Rate Limiting not available with $action" if $norate{$action}; - - if ( $rate =~ /^(\d+(\/(sec|min|hour|day))?):(\d+)$/ ) { - "-m limit --limit $1 --limit-burst $4 "; - } elsif ( $rate =~ /^(\d+)(\/(sec|min|hour|day))?$/ ) { - "-m limit --limit $rate "; - } else { - fatal_error "Invalid rate ($rate)"; - } -} - -# -# Create a "-m owner" match for the passed USER/GROUP -# -sub do_user( $ ) { - my $user = $_[0]; - my $rule = '-m owner '; - - return '' unless defined $user and $user ne '-'; - - if ( $user =~ /^(!)?(.*)\+(.*)$/ ) { - $rule .= "! --cmd-owner $2 " if defined $2 && $2 ne ''; - $user = "!$1"; - } elsif ( $user =~ /^(.*)\+(.*)$/ ) { - $rule .= "--cmd-owner $2 " if defined $2 && $2 ne ''; - $user = $1; - } - - if ( $user =~ /^!(.*):(.*)$/ ) { - $rule .= "! --uid-owner $1 " if defined $1 && $1 ne ''; - $rule .= "! --gid-owner $2 " if defined $2 && $2 ne ''; - } elsif ( $user =~ /^(.*):(.*)$/ ) { - $rule .= "--uid-owner $1 " if defined $1 && $1 ne ''; - $rule .= "--gid-owner $2 " if defined $2 && $2 ne ''; - } elsif ( $user =~ /^!/ ) { - $rule .= "! --uid-owner $user "; - } else { - $rule .= "--uid-owner $user "; - } - - $rule; -} - -# -# Create a "-m tos" match for the passed TOS -# -sub do_tos( $ ) { - my $tos = $_[0]; - - $tos ne '-' ? "-m tos --tos $tos " : ''; -} - -# -# Match Source Interface -# -sub match_source_dev( $ ) { - my $interface = shift; - my $interfaceref = find_interface( $interface ); - if ( $interfaceref && $interfaceref->{options}{port} ) { - "-i $interfaceref->{bridge} -m physdev --physdev-in $interface "; - } else { - "-i $interface "; - } -} - -# -# Match Dest device -# -sub match_dest_dev( $ ) { - my $interface = shift; - my $interfaceref = find_interface( $interface ); - if ( $interfaceref && $interfaceref->{options}{port} ) { - "-o $interfaceref->{bridge} -m physdev --physdev-out $interface "; - } else { - "-o $interface "; - } -} - -# -# Avoid generating a second '-m iprange' in a single rule. -# -sub iprange_match() { - my $match = ''; - - require_capability( 'IPRANGE_MATCH' , 'Address Ranges' , '' ); - unless ( $iprangematch ) { - $match = '-m iprange '; - $iprangematch = 1 unless $capabilities{KLUDGEFREE}; - } - - $match; -} - -# -# Get set flags (ipsets). -# -sub get_set_flags( $$ ) { - my ( $setname, $option ) = @_; - my $options = $option; - - if ( $setname =~ /^(.*)\[([1-6])\]$/ ) { - $setname = $1; - my $count = $2; - $options .= ",$option" while --$count > 0; - } elsif ( $setname =~ /^(.*)\[(.*)\]$/ ) { - $setname = $1; - $options = $2; - } - - $setname =~ s/^\+//; - - fatal_error "Invalid ipset name ($setname)" unless $setname =~ /^[a-zA-Z]\w*/; - - "--set $setname $options " -} - -# -# Match a Source. Currently only handles IP addresses and ranges -# -sub match_source_net( $ ) { - my $net = $_[0]; - - if ( $net =~ /^(!?)(\d+\.\d+\.\d+\.\d+)-(\d+\.\d+\.\d+\.\d+)$/ ) { - my ($addr1, $addr2) = ( $2, $3 ); - $net =~ s/!// if my $invert = $1 ? '! ' : ''; - validate_range $addr1, $addr2; - iprange_match . "${invert}--src-range $net "; - } elsif ( $net =~ /^(!?)~(.*)$/ ) { - ( $net = $2 ) =~ tr/-/:/; - my $invert = $1 ? '! ' : ''; - "-m mac --mac-source ${invert}$net "; - } elsif ( $net =~ /^(!?)\+/ ) { - require_capability( 'IPSET_MATCH' , 'ipset names in Shorewall configuration files' , '' ); - join( '', '-m set ', $1 ? '! ' : '', get_set_flags( $net, 'src' ) ); - } elsif ( $net =~ /^!/ ) { - $net =~ s/!//; - validate_net $net; - "-s ! $net "; - } else { - validate_net $net; - $net eq ALLIPv4 ? '' : "-s $net "; - } -} - -# -# Match a Source. Currently only handles IP addresses and ranges -# -sub match_dest_net( $ ) { - my $net = $_[0]; - - if ( $net =~ /^(!?)(\d+\.\d+\.\d+\.\d+)-(\d+\.\d+\.\d+\.\d+)$/ ) { - my ($addr1, $addr2) = ( $2, $3 ); - $net =~ s/!// if my $invert = $1 ? '! ' : ''; - validate_range $addr1, $addr2; - iprange_match . "${invert}--dst-range $net "; - } elsif ( $net =~ /^(!?)\+/ ) { - require_capability( 'IPSET_MATCH' , 'ipset names in Shorewall configuration files' , ''); - join( '', '-m set ', $1 ? '! ' : '', get_set_flags( $net, 'dst' ) ); - } elsif ( $net =~ /^!/ ) { - $net =~ s/!//; - validate_net $net; - "-d ! $net "; - } else { - validate_net $net; - $net eq ALLIPv4 ? '' : "-d $net "; - } -} - -# -# Match original destination -# -sub match_orig_dest ( $ ) { - my $net = $_[0]; - - return '' if $net eq ALLIPv4; - return '' unless $capabilities{CONNTRACK_MATCH}; - - if ( $net =~ /^!/ ) { - $net =~ s/!//; - validate_net $net; - "-m conntrack --ctorigdst ! $net "; - } else { - validate_net $net; - $net eq ALLIPv4 ? '' : "-m conntrack --ctorigdst $net "; - } -} - -# -# Match Source IPSEC -# -sub match_ipsec_in( $$ ) { - my ( $zone , $hostref ) = @_; - my $match = '-m policy --dir in --pol '; - my $zoneref = find_zone( $zone ); - my $optionsref = $zoneref->{options}; - - if ( $zoneref->{type} eq 'ipsec4' ) { - $match .= "ipsec $optionsref->{in_out}{ipsec}$optionsref->{in}{ipsec}"; - } elsif ( $capabilities{POLICY_MATCH} ) { - $match .= "$hostref->{ipsec} $optionsref->{in_out}{ipsec}$optionsref->{in}{ipsec}"; - } else { - ''; - } -} - -# -# Match Dest IPSEC -# -sub match_ipsec_out( $$ ) { - my ( $zone , $hostref ) = @_; - my $match = '-m policy --dir out --pol '; - my $zoneref = find_zone( $zone ); - my $optionsref = $zoneref->{options}; - - if ( $zoneref->{type} eq 'ipsec4' ) { - $match .= "ipsec $optionsref->{in_out}{ipsec}$optionsref->{out}{ipsec}"; - } elsif ( $capabilities{POLICY_MATCH} ) { - $match .= "$hostref->{ipsec} $optionsref->{in_out}{ipsec}$optionsref->{out}{ipsec}" - } else { - ''; - } -} - -# -# Generate a log message -# -sub log_rule_limit( $$$$$$$$ ) { - my ($level, $chainref, $chain, $disposition, $limit, $tag, $command, $predicates ) = @_; - - my $prefix; - - $level = validate_level $level; # Do this here again because this function can be called directly from user exits. - - return 1 if $level eq ''; - - unless ( $predicates =~ /-m limit / ) { - $limit = $globals{LOGLIMIT} unless $limit && $limit ne '-'; - $predicates .= $limit if $limit; - } - - if ( $tag ) { - if ( $config{LOGTAGONLY} ) { - $chain = $tag; - $tag = ''; - } else { - $tag .= ' '; - } - } else { - $tag = '' unless defined $tag; - } - - if ( $globals{LOGRULENUMBERS} ) { - $prefix = (sprintf $config{LOGFORMAT} , $chain , $chainref->{log}++, $disposition ) . $tag; - } else { - $prefix = (sprintf $config{LOGFORMAT} , $chain , $disposition) . $tag; - } - - if ( length $prefix > 29 ) { - $prefix = substr( $prefix, 0, 28 ) . ' '; - warning_message "Log Prefix shortened to \"$prefix\""; - } - - if ( $level eq 'ULOG' ) { - $prefix = "-j ULOG $globals{LOGPARMS}--ulog-prefix \"$prefix\" "; - } else { - $prefix = "-j LOG $globals{LOGPARMS}--log-level $level --log-prefix \"$prefix\" "; - } - - $predicates .= ' ' if $predicates && substr( $predicates, -1, 1 ) ne ' '; - - if ( $command eq 'add' ) { - add_rule ( $chainref, $predicates . $prefix ); - } else { - insert_rule ( $chainref , 1 , $predicates . $prefix ); - } -} - -sub log_rule( $$$$ ) { - my ( $level, $chainref, $disposition, $predicates ) = @_; - - log_rule_limit $level, $chainref, $chainref->{name} , $disposition, $globals{LOGLIMIT}, '', 'add', $predicates; -} - -# -# Split a comma-separated source or destination host list but keep [...] together. -# -sub mysplit( $ ) { - my @input = split /,/, $_[0]; - - return @input unless $_[0] =~ /\[/; - - my @result; - - while ( @input ) { - my $element = shift @input; - - if ( $element =~ /\[/ ) { - while ( substr( $element, -1, 1 ) ne ']' ) { - last unless @input; - $element .= ( ',' . shift @input ); - } - - fatal_error "Invalid Host List ($_[0])" unless substr( $element, -1, 1 ) eq ']'; - } - - push @result, $element; - } - - @result; -} - -# -# Returns the name of the shell variable holding the first address of the passed interface -# -sub interface_address( $ ) { - my $variable = chain_base( $_[0] ) . '_address'; - "\U$variable"; -} - -# -# Record that the ruleset requires the first IP address on the passed interface -# -sub get_interface_address ( $ ) { - my ( $interface ) = $_[0]; - - my $variable = interface_address( $interface ); - my $function = interface_is_optional( $interface ) ? 'find_first_interface_address_if_any' : 'find_first_interface_address'; - - $interfaceaddr{$interface} = "$variable=\$($function $interface)"; - - "\$$variable"; -} - -# -# Returns the name of the shell variable holding the broadcast addresses of the passed interface -# -sub interface_bcasts( $ ) { - my $variable = chain_base( $_[0] ) . '_bcasts'; - "\U$variable"; -} - -# -# Record that the ruleset requires the broadcast addresses on the passed interface -# -sub get_interface_bcasts ( $ ) { - my ( $interface ) = $_[0]; - - my $variable = interface_bcasts( $interface ); - - $interfacebcasts{$interface} = qq($variable="\$(get_interface_bcasts $interface) 255.255.255.255"); - - "\$$variable"; -} - -# -# Returns the name of the shell variable holding the addresses of the passed interface -# -sub interface_addresses( $ ) { - my $variable = chain_base( $_[0] ) . '_addresses'; - "\U$variable"; -} - -# -# Record that the ruleset requires the IP addresses on the passed interface -# -sub get_interface_addresses ( $ ) { - my ( $interface ) = $_[0]; - - my $variable = interface_addresses( $interface ); - - if ( interface_is_optional $interface ) { - $interfaceaddrs{$interface} = qq($variable=\$(find_interface_addresses $interface)\n); - } else { - $interfaceaddrs{$interface} = qq($variable=\$(find_interface_addresses $interface) -[ -n "\$$variable" ] || fatal_error "Unable to determine the IP address(es) of $interface" -); - } - - "\$$variable"; -} - -# -# Returns the name of the shell variable holding the networks routed out of the passed interface -# -sub interface_nets( $ ) { - my $variable = chain_base( $_[0] ) . '_networks'; - "\U$variable"; -} - -# -# Record that the ruleset requires the first IP address on the passed interface -# -sub get_interface_nets ( $ ) { - my ( $interface ) = $_[0]; - - my $variable = interface_nets( $interface ); - - if ( interface_is_optional $interface ) { - $interfacenets{$interface} = qq($variable=\$(get_routed_networks $interface)\n); - } else { - $interfacenets{$interface} = qq($variable=\$(get_routed_networks $interface) -[ -n "\$$variable" ] || fatal_error "Unable to determine the routes through interface \\"$interface\\"" -); - } - - "\$$variable"; - -} - -# -# This function provides a uniform way to generate rules (something the original Shorewall sorely needed). -# -# Returns the destination interface specified in the rule, if any. -# -sub expand_rule( $$$$$$$$$$ ) -{ - my ($chainref , # Chain - $restriction, # Determines what to do with interface names in the SOURCE or DEST - $rule, # Caller's matches that don't depend on the SOURCE, DEST and ORIGINAL DEST - $source, # SOURCE - $dest, # DEST - $origdest, # ORIGINAL DEST - $target, # Target ('-j' part of the rule) - $loglevel , # Log level (and tag) - $disposition, # Primative part of the target (RETURN, ACCEPT, ...) - $exceptionrule # Caller's matches used in exclusion case - ) = @_; - - my ($iiface, $diface, $inets, $dnets, $iexcl, $dexcl, $onets , $oexcl ); - my $chain = $chainref->{name}; - my $initialcmdlevel = $chainref->{cmdlevel}; - - # - # Handle Log Level - # - my $logtag; - - if ( $loglevel ne '' ) { - ( $loglevel, $logtag, my $remainder ) = split( /:/, $loglevel, 3 ); - - fatal_error "Invalid log tag" if defined $remainder; - - if ( $loglevel =~ /^none!?$/i ) { - return if $disposition eq 'LOG'; - $loglevel = $logtag = ''; - } else { - $loglevel = validate_level( $loglevel ); - $logtag = '' unless defined $logtag; - } - } elsif ( $disposition eq 'LOG' ) { - fatal_error "LOG requires a level"; - } - # - # Isolate Source Interface, if any - # - if ( $source ) { - if ( $source eq '-' ) { - $source = ''; - } elsif ( $source =~ /^([^:]+):([^:]+)$/ ) { - $iiface = $1; - $inets = $2; - } elsif ( $source =~ /\+|~|\..*\./ ) { - $inets = $source; - } else { - $iiface = $source; - } - } else { - $source = ''; - } - - # - # Verify Interface, if any - # - if ( $iiface ) { - fatal_error "Unknown Interface ($iiface)" unless known_interface $iiface; - - if ( $restriction & POSTROUTE_RESTRICT ) { - # - # An interface in the SOURCE column of a masq file - # - fatal_error "Bridge ports may not appear in the SOURCE column of this file" if port_to_bridge( $iiface ); - - my $networks = get_interface_nets ( $iiface ); - - add_command( $chainref , join( '', 'for source in ', $networks, '; do' ) ); - - $rule .= '-s $source '; - - incr_cmd_level $chainref; - } else { - fatal_error "Source Interface ($iiface) not allowed when the source zone is the firewall zone" if $restriction & OUTPUT_RESTRICT; - $rule .= match_source_dev( $iiface ); - } - } - - # - # Isolate Destination Interface, if any - # - if ( $dest ) { - if ( $dest eq '-' ) { - $dest = ''; - } elsif ( ( $restriction & PREROUTE_RESTRICT ) && $dest =~ /^detect:(.*)$/ ) { - # - # DETECT_DNAT_IPADDRS=Yes and we're generating the nat rule - # - my @interfaces = split /\s+/, $1; - - if ( @interfaces > 1 ) { - my $list = ""; - - for my $interface ( @interfaces ) { - $list = join( ' ', $list , get_interface_address( $interface ) ); - } - - add_command( $chainref , "for address in $list; do" ); - - $rule .= '-d $address '; - incr_cmd_level $chainref; - } else { - $rule .= join ( '', '-d ', get_interface_address( $interfaces[0] ), ' ' ); - } - - $dest = ''; - } elsif ( $dest =~ /^([^:]+):([^:]+)$/ ) { - $diface = $1; - $dnets = $2; - } elsif ( $dest =~ /\+|~|\..*\./ ) { - $dnets = $dest; - } else { - $diface = $dest; - } - } else { - $dest = ''; - } - - # - # Verify Destination Interface, if any - # - if ( $diface ) { - fatal_error "Unknown Interface ($diface)" unless known_interface $diface; - - if ( $restriction & PREROUTE_RESTRICT ) { - # - # ADDRESS 'detect' in the masq file. - # - fatal_error "Bridge port ($diface) not allowed" if port_to_bridge( $diface ); - add_command( $chainref , 'for dest in ' . get_interface_addresses( $diface) . '; do' ); - $rule .= '-d $dest '; - incr_cmd_level $chainref; - } else { - fatal_error "Bridge Port ($diface) not allowed in OUTPUT or POSTROUTING rules" if ( $restriction & ( POSTROUTE_RESTRICT + OUTPUT_RESTRICT ) ) && port_to_bridge( $diface ); - fatal_error "Destination Interface ($diface) not allowed when the destination zone is the firewall zone" if $restriction & INPUT_RESTRICT; - - if ( $iiface ) { - my $bridge = port_to_bridge( $diface ); - fatal_error "Source interface ($iiface) is not a port on the same bridge as the destination interface ( $diface )" if $bridge && $bridge ne source_port_to_bridge( $iiface ); - } - - $rule .= match_dest_dev( $diface ); - } - } else { - $diface = ''; - } - - if ( $origdest ) { - if ( $origdest eq '-' || ! $capabilities{CONNTRACK_MATCH} ) { - $origdest = ''; - } elsif ( $origdest =~ /^detect:(.*)$/ ) { - # - # Either the filter part of a DNAT rule or 'detect' was given in the ORIG DEST column - # - my @interfaces = split /\s+/, $1; - - if ( @interfaces > 1 ) { - my $list = ""; - - for my $interface ( @interfaces ) { - $list = join( ' ', $list , get_interface_address( $interface ) ); - } - - add_command( $chainref , "for address in $list; do" ); - $rule .= '-m conntrack --ctorigdst $address '; - incr_cmd_level $chainref; - } else { - get_interface_address $interfaces[0]; - $rule .= join( '', '-m conntrack --ctorigdst $', interface_address ( $interfaces[0] ), ' ' ); - } - - $origdest = ''; - } else { - fatal_error "Invalid ORIGINAL DEST" if $origdest =~ /^([^!]+)?,!([^!]+)$/ || $origdest =~ /.*!.*!/; - - if ( $origdest =~ /^([^!]+)?!([^!]+)$/ ) { - # - # Exclusion - # - $onets = $1; - $oexcl = $2; - } else { - $oexcl = ''; - $onets = $origdest; - } - - unless ( $onets ) { - my @oexcl = mysplit $oexcl; - if ( @oexcl == 1 ) { - $rule .= match_orig_dest( "!$oexcl" ); - $oexcl = ''; - } - } - } - } else { - $oexcl = ''; - } - - # - # Determine if there is Source Exclusion - # - if ( $inets ) { - fatal_error "Invalid SOURCE" if $inets =~ /^([^!]+)?,!([^!]+)$/ || $inets =~ /.*!.*!/; - - if ( $inets =~ /^([^!]+)?!([^!]+)$/ ) { - $inets = $1; - $iexcl = $2; - } else { - $iexcl = ''; - } - - unless ( $inets || ( $iiface && $restriction & POSTROUTE_RESTRICT ) ) { - my @iexcl = mysplit $iexcl; - if ( @iexcl == 1 ) { - $rule .= match_source_net "!$iexcl"; - $iexcl = ''; - } - - } - } else { - $iexcl = ''; - } - - # - # Determine if there is Destination Exclusion - # - if ( $dnets ) { - fatal_error "Invalid DEST" if $dnets =~ /^([^!]+)?,!([^!]+)$/ || $dnets =~ /.*!.*!/; - - if ( $dnets =~ /^([^!]+)?!([^!]+)$/ ) { - $dnets = $1; - $dexcl = $2; - } else { - $dexcl = ''; - } - - unless ( $dnets ) { - my @dexcl = mysplit $dexcl; - if ( @dexcl == 1 ) { - $rule .= match_dest_net "!$dexcl"; - $dexcl = ''; - } - } - } else { - $dexcl = ''; - } - - $inets = ALLIPv4 unless $inets; - $dnets = ALLIPv4 unless $dnets; - $onets = ALLIPv4 unless $onets; - - if ( $iexcl || $dexcl || $oexcl ) { - # - # We have non-trivial exclusion -- need to create an exclusion chain - # - fatal_error "Exclusion is not possible in ACCEPT+/CONTINUE/NONAT rules" if $disposition eq 'RETURN'; - - my $echain = newexclusionchain; - - # - # Use the current rule and sent all possible matches to the exclusion chain - # - for my $onet ( mysplit $onets ) { - $onet = match_orig_dest $onet; - for my $inet ( mysplit $inets ) { - for my $dnet ( mysplit $dnets ) { - # - # We evaluate the source net match in the inner loop to accomodate systems without $capabilities{KLUDGEFREE} - # - add_rule $chainref, join( '', $rule, match_source_net( $inet), match_dest_net( $dnet ), $onet, "-j $echain" ); - } - } - } - - # - # Create the Exclusion Chain - # - my $echainref = new_chain $chainref->{table}, $echain; - - # - # Generate RETURNs for each exclusion - # - add_rule $echainref, ( match_source_net $_ ) . '-j RETURN' for ( mysplit $iexcl ); - add_rule $echainref, ( match_dest_net $_ ) . '-j RETURN' for ( mysplit $dexcl ); - add_rule $echainref, ( match_orig_dest $_ ) . '-j RETURN' for ( mysplit $oexcl ); - # - # Log rule - # - log_rule_limit $loglevel , $echainref , $chain, $disposition , '', $logtag , 'add' , '' if $loglevel; - # - # Generate Final Rule - # - add_rule( $echainref, $exceptionrule . $target ) unless $disposition eq 'LOG'; - } else { - # - # No exclusions - # - for my $onet ( mysplit $onets ) { - $onet = match_orig_dest $onet; - for my $inet ( mysplit $inets ) { - # - # We defer evaluating the source net match to accomodate system without $capabilities{KLUDGEFREE} - # - for my $dnet ( mysplit $dnets ) { - if ( $loglevel ne '' ) { - log_rule_limit - $loglevel , - $chainref , - $chain, - $disposition , - '' , - $logtag , - 'add' , - join( '', $rule, match_source_net( $inet) , match_dest_net( $dnet ), $onet ); - } - - unless ( $disposition eq 'LOG' ) { - add_rule - $chainref, - join( '', $rule, match_source_net ($inet), match_dest_net( $dnet ), $onet, $target ); - } - } - } - } - } - - while ( $chainref->{cmdlevel} > $initialcmdlevel ) { - decr_cmd_level $chainref; - add_command $chainref, 'done'; - } - - $diface; -} - -sub emit_comment() { - emit ( '#', - '# Establish the values of shell variables used in the following function calls', - '#' ); - our $emitted_comment = 1; -} - -sub emit_test() { - emit ( 'if [ "$COMMAND" != restore ]; then' , - '' ); - push_indent; - our $emitted_test = 1; -} - -# -# Generate setting of global variables -# -sub set_global_variables() { - - our ( $emitted_comment, $emitted_test ) = (0, 0); - - for ( values %interfaceaddr ) { - emit_comment unless $emitted_comment; - emit $_; - } - - for ( values %interfaceaddrs ) { - emit_comment unless $emitted_comment; - emit_test unless $emitted_test; - emit $_; - } - - for ( values %interfacenets ) { - emit_comment unless $emitted_comment; - emit_test unless $emitted_test; - emit $_; - } - - unless ( $capabilities{ADDRTYPE} ) { - emit_comment unless $emitted_comment; - emit_test unless $emitted_test; - emit 'ALL_BCASTS="$(get_all_bcasts) 255.255.255.255"'; - - for ( values %interfacebcasts ) { - emit $_; - } - } - - pop_indent, emit "fi\n" if $emitted_test; - -} - -# -# What follows is the code that generates the input to ip6tables-restore -# -# We always write the ip6tables-restore input into a file then pass the -# file to ip6tables-restore. That way, if things go wrong, the user (and Shorewall support) -# has (have) something to look at to determine the error -# -# We may have to generate part of the input at run-time. The rules array in each chain -# table entry may contain rules (begin with '-A') or shell source. We alternate between -# writing the rules ('-A') into the temporary file to be bassed to ip6tables-restore -# (CAT_MODE) and and writing shell source into the generated script (CMD_MODE). -# -# The following two functions are responsible for the mode transitions. -# -sub enter_cat_mode() { - emit ''; - emit 'cat >&3 << __EOF__'; - $mode = CAT_MODE; -} - -sub enter_cmd_mode() { - emit_unindented "__EOF__\n" if $mode == CAT_MODE; - $mode = CMD_MODE; -} - -# -# Emits the passed rule (input to ip6tables-restore) or command -# -sub emitr( $ ) { - my $rule = $_[0]; - - if ( $rule && substr( $rule, 0, 2 ) eq '-A' ) { - # - # A rule - # - enter_cat_mode unless $mode == CAT_MODE; - emit_unindented $rule; - } else { - # - # A command - # - enter_cmd_mode unless $mode == CMD_MODE; - emit $rule; - } -} - -# -# Generate the netfilter input -# -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}; - push @table_list, 'filter'; - - $mode = NULL_MODE; - - emit ( 'setup_netfilter()', - '{' - ); - - push_indent; - - save_progress_message "Preparing ip6tables-restore input..."; - - emit ''; - - emit 'exec 3>${VARDIR}/.ip6tables-restore-input'; - - enter_cat_mode; - - for my $table ( @table_list ) { - emit_unindented "*$table"; - - my @chains; - # - # ip6tables-restore seems to be quite picky about the order of the builtin chains - # - for my $chain ( @builtins ) { - my $chainref = $chain_table{$table}{$chain}; - if ( $chainref ) { - fatal_error "Internal error in create_netfilter_load()" if $chainref->{cmdlevel}; - emit_unindented ":$chain $chainref->{policy} [0:0]"; - push @chains, $chainref; - } - } - # - # First create the chains in the current table - # - for my $chain ( grep $chain_table{$table}{$_}->{referenced} , ( sort keys %{$chain_table{$table}} ) ) { - my $chainref = $chain_table{$table}{$chain}; - unless ( $chainref->{builtin} ) { - fatal_error "Internal error in create_netfilter_load()" if $chainref->{cmdlevel}; - emit_unindented ":$chainref->{name} - [0:0]"; - push @chains, $chainref; - } - } - # - # Then emit the rules - # - for my $chainref ( @chains ) { - emitr $_ for ( @{$chainref->{rules}} ); - } - # - # Commit the changes to the table - # - enter_cat_mode unless $mode == CAT_MODE; - emit_unindented 'COMMIT'; - } - - enter_cmd_mode; - # - # Now generate the actual ip6tables-restore command - # - emit( 'exec 3>&-', - '', - 'progress_message2 "Running ip6tables-restore..."', - '', - 'cat ${VARDIR}/.ip6tables-restore-input | $IP6TABLES_RESTORE # Use this nonsensical form to appease SELinux', - 'if [ $? != 0 ]; then', - ' fatal_error "ip6tables-restore Failed. Input is in ${VARDIR}/.ip6tables-restore-input"', - "fi\n" - ); - - pop_indent; - - emit "}\n"; -} - -# -# Generate the netfilter input for refreshing a list of chains -# -sub create_chainlist_reload($) { - - my $chains = $_[0]; - - my @chains = split ',', $chains; - - unless ( @chains ) { - @chains = qw( blacklst ) if $filter_table->{blacklst}; - } - - $mode = NULL_MODE; - - emit( 'chainlist_reload()', - '{' - ); - - push_indent; - - if ( @chains ) { - if ( @chains == 1 ) { - progress_message2 "Compiling ip6tables-restore input for chain @chains..."; - save_progress_message "Preparing ip6tables-restore input for chain @chains..."; - } else { - progress_message2 "Compiling ip6tables-restore input for chain $chains..."; - save_progress_message "Preparing ip6tables-restore input for chains $chains..."; - } - - emit ''; - - emit 'exec 3>${VARDIR}/.ip6tables-restore-input'; - - enter_cat_mode; - - my $table = 'filter'; - - my %chains; - - for my $chain ( @chains ) { - ( $table , $chain ) = split ':', $chain if $chain =~ /:/; - - fatal_error "Invalid table ( $table )" unless $table =~ /^(nat|mangle|filter)$/; - fatal_error "No $table chain found with name $chain" unless $chain_table{$table}{$chain}; - - $chains{$table} = [] unless $chains{$table}; - - push @{$chains{$table}}, $chain; - } - - for $table qw(nat mangle filter) { - next unless $chains{$table}; - - emit_unindented "*$table"; - - my $tableref=$chain_table{$table}; - - @chains = sort @{$chains{$table}}; - - for my $chain ( @chains ) { - my $chainref = $tableref->{$chain}; - emit_unindented ":$chainref->{name} $chainref->{policy} [0:0]" if $chainref->{builtin}; - } - - for my $chain ( @chains ) { - my $chainref = $tableref->{$chain}; - emit_unindented ":$chainref->{name} - [0:0]" unless $chainref->{builtin}; - } - - for my $chain ( @chains ) { - my $chainref = $tableref->{$chain}; - my @rules = @{$chainref->{rules}}; - - @rules = () unless @rules; - # - # Emit the chain rules - # - emitr $_ for ( @rules ); - } - # - # Commit the changes to the table - # - enter_cat_mode unless $mode == CAT_MODE; - - emit_unindented 'COMMIT'; - } - - enter_cmd_mode; - # - # Now generate the actual ip6tables-restore command - # - emit( 'exec 3>&-', - '', - 'progress_message2 "Running ip6tables-restore..."', - '', - 'cat ${VARDIR}/.ip6tables-restore-input | $IP6TABLES_RESTORE -n # Use this nonsensical form to appease SELinux', - 'if [ $? != 0 ]; then', - ' fatal_error "ip6tables-restore Failed. Input is in ${VARDIR}/.ip6tables-restore-input"', - "fi\n" - ); - } else { - emit('true'); - } - - pop_indent; - - emit "}\n"; -} - -1; diff --git a/Shorewall6/Shorewall/Compiler.pm b/Shorewall6/Shorewall/Compiler.pm deleted file mode 100644 index 06718e911..000000000 --- a/Shorewall6/Shorewall/Compiler.pm +++ /dev/null @@ -1,761 +0,0 @@ -#! /usr/bin/perl -w -# -# The Shoreline Firewall4 (Shorewall-perl) Packet Filtering Firewall Compiler - V4.0 -# -# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt] -# -# (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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# - -package Shorewall::Compiler; -require Exporter; -use Shorewall::Config; -use Shorewall::Chains; -use Shorewall::Zones; -use Shorewall::Policy; -use Shorewall::Tc; -use Shorewall::Tunnels; -use Shorewall::Actions; -use Shorewall::Accounting; -use Shorewall::Rules; -use Shorewall::Proc; - -our @ISA = qw(Exporter); -our @EXPORT = qw( compiler EXPORT TIMESTAMP DEBUG ); -our @EXPORT_OK = qw( $export ); -our $VERSION = '4.04'; - -our $export; - -our $reused = 0; - -use constant { EXPORT => 0x01 , - TIMESTAMP => 0x02 , - DEBUG => 0x04 }; - -# -# Reinitilize the package-globals in the other modules -# -sub reinitialize() { - Shorewall::Config::initialize; - Shorewall::Chains::initialize; - Shorewall::Zones::initialize; - Shorewall::Policy::initialize; - Shorewall::Tc::initialize; - Shorewall::Actions::initialize; - Shorewall::Accounting::initialize; - Shorewall::Rules::initialize; -} - -# -# First stage of script generation. -# -# Copy the prog.header to the generated script. -# Generate the various user-exit jacket functions. -# Generate the 'initialize()' function. -# -# Note: This function is not called when $command eq 'check'. So it must have no side effects other -# than those related to writing to the object file. - -sub generate_script_1() { - - my $date = localtime; - - emit "#!/bin/sh\n#\n# Compiled firewall script generated by Shorewall-perl $globals{VERSION} - $date\n#"; - - copy $globals{SHAREDIRPL} . 'prog.header'; - - for my $exit qw/init isusable start tcclear started stop stopped clear refresh refreshed/ { - emit "\nrun_${exit}_exit() {"; - push_indent; - append_file $exit or emit 'true'; - pop_indent; - emit '}'; - } - - emit ( '', - '#', - '# This function initializes the global variables used by the program', - '#', - 'initialize()', - '{', - ' #', - ' # These variables are required by the library functions called in this script', - ' #' - ); - - push_indent; - - if ( $export ) { - emit ( 'SHAREDIR=/usr/share/shorewall-lite', - 'CONFDIR=/etc/shorewall-lite', - 'PRODUCT="Shorewall Lite"' - ); - } else { - emit ( 'SHAREDIR=/usr/share/shorewall', - 'CONFDIR=/etc/shorewall', - 'PRODUCT=\'Shorewall\'', - ); - } - - emit( '[ -f ${CONFDIR}/vardir ] && . ${CONFDIR}/vardir' ); - - if ( $export ) { - emit ( 'CONFIG_PATH="/etc/shorewall-lite:/usr/share/shorewall-lite"' , - '[ -n "${VARDIR:=/var/lib/shorewall-lite}" ]' ); - } else { - emit ( qq(CONFIG_PATH="$config{CONFIG_PATH}") , - '[ -n "${VARDIR:=/var/lib/shorewall}" ]' ); - } - - emit 'TEMPFILE='; - - propagateconfig; - - emit ( '[ -n "${COMMAND:=restart}" ]', - '[ -n "${VERBOSE:=0}" ]', - qq([ -n "\${RESTOREFILE:=$config{RESTOREFILE}}" ]), - '[ -n "$LOGFORMAT" ] || LOGFORMAT="Shorewall:%s:%s:"', - qq(VERSION="$globals{VERSION}") , - qq(PATH="$config{PATH}") , - 'TERMINATOR=fatal_error' , - '' - ); - - if ( $config{IP6TABLES} ) { - emit( qq(IP6TABLES="$config{IP6TABLES}"), - '[ -x "$IP6TABLES" ] || startup_error "IP6TABLES=$IP6TABLES does not exist or is not executable"', - ); - } else { - emit( '[ -z "$IP6TABLES" ] && IP6TABLES=$(mywhich ip6tables) # /sbin/shorewall6 exports IP6TABLES', - '[ -n "$IP6TABLES" -a -x "$IP6TABLES" ] || startup_error "Can\'t find ip6tables executable"' - ); - } - - emit( 'IP6TABLES_RESTORE=${IP6TABLES}-restore', - '[ -x "$IP6TABLES_RESTORE" ] || startup_error "$IP6TABLES_RESTORE does not exist or is not executable"' ); - - append_file 'params' if $config{EXPORTPARAMS}; - - emit ( '', - "STOPPING=", - '', - '#', - '# The library requires that ${VARDIR} exist', - '#', - '[ -d ${VARDIR} ] || mkdir -p ${VARDIR}' - ); - - emit ( '', - '#', - '# Recent kernels are difficult to configure -- we see state match omitted a lot so we check for it here', - '#', - 'qt $IP6TABLES -N foox1234', - 'qt $IP6TABLES -A foox1234 -m state --state ESTABLISHED,RELATED -j ACCEPT', - 'result=$?', - 'qt $IP6TABLES -F foox1234', - 'qt $IP6TABLES -X foox1234', - '[ $result = 0 ] || startup_error "Your kernel/ip6tables do not include state match support. No version of Shorewall6 will run on this system"', - '' ); - - pop_indent; - - emit "}\n"; # End of initialize() - -} - -sub compile_stop_firewall() { - - emit <<'EOF'; -# -# Stop/restore the firewall after an error or because of a 'stop' or 'clear' command -# -stop_firewall() { - - deletechain() { - qt $IP6TABLES -L $1 -n && qt $IP6TABLES -F $1 && qt $IP6TABLES -X $1 - } - - deleteallchains() { - $IP6TABLES -F - $IP6TABLES -X - } - - setcontinue() { - $IP6TABLES -A $1 -m state --state ESTABLISHED,RELATED -j ACCEPT - } - - case $COMMAND in - stop|clear|restore) - ;; - *) - set +x - - case $COMMAND in - start) - logger -p kern.err "ERROR:$PRODUCT start failed" - ;; - restart) - logger -p kern.err "ERROR:$PRODUCT restart failed" - ;; - restore) - logger -p kern.err "ERROR:$PRODUCT restore failed" - ;; - esac - - if [ "$RESTOREFILE" = NONE ]; then - COMMAND=clear - clear_firewall - echo "$PRODUCT Cleared" - - kill $$ - exit 2 - else - RESTOREPATH=${VARDIR}/$RESTOREFILE - - if [ -x $RESTOREPATH ]; then - echo Restoring ${PRODUCT:=Shorewall6}... - - if $RESTOREPATH restore; then - echo "$PRODUCT restored from $RESTOREPATH" - set_state "Started" - else - set_state "Unknown" - fi - - kill $$ - exit 2 - fi - fi - ;; - esac - - set_state "Stopping" - - STOPPING="Yes" - - TERMINATOR= - - deletechain shorewall - - run_stop_exit; - -EOF - - if ( $capabilities{MANGLE_ENABLED} ) { - emit <<'EOF'; - run_iptables -t mangle -F - run_iptables -t mangle -X - for chain in PREROUTING INPUT FORWARD POSTROUTING; do - qt $IP6TABLES -t mangle -P $chain ACCEPT - done - -EOF - } - - if ( $capabilities{RAW_TABLE} ) { - emit <<'EOF'; - run_ip6tables -t raw -F - run_ip6tables -t raw -X - for chain in PREROUTING OUTPUT; do - qt $IP6TABLES -t raw -P $chain ACCEPT - done - -EOF - } - - push_indent; - - emit 'delete_tc1' if $config{CLEAR_TC}; - - my $criticalhosts = process_criticalhosts; - - if ( @$criticalhosts ) { - if ( $config{ADMINISABSENTMINDED} ) { - emit ( 'for chain in INPUT OUTPUT; do', - ' setpolicy $chain ACCEPT', - 'done', - '', - 'setpolicy FORWARD DROP', - '', - 'deleteallchains', - '' - ); - - for my $hosts ( @$criticalhosts ) { - my ( $interface, $host ) = ( split /:/, $hosts ); - my $source = match_source_net $host; - my $dest = match_dest_net $host; - - emit( "\$IP6TABLES -A INPUT -i $interface $source -j ACCEPT", - "\$IP6TABLES -A OUTPUT -o $interface $dest -j ACCEPT" - ); - } - - emit( '', - 'for chain in INPUT OUTPUT; do', - ' setpolicy $chain DROP', - "done\n" - ); - } else { - emit( '', - 'for chain in INPUT OUTPUT; do', - ' setpolicy \$chain ACCEPT', - 'done', - '', - 'setpolicy FORWARD DROP', - '', - "deleteallchains\n" - ); - - for my $hosts ( @$criticalhosts ) { - my ( $interface, $host ) = ( split /:/, $hosts ); - my $source = match_source_net $host; - my $dest = match_dest_net $host; - - emit( "\$IP6TABLES -A INPUT -i $interface $source -j ACCEPT", - "\$IP6TABLES -A OUTPUT -o $interface $dest -j ACCEPT" - ); - } - - emit( "\nsetpolicy INPUT DROP", - '', - 'for chain in INPUT FORWARD; do', - ' setcontinue $chain', - "done\n" - ); - } - } elsif ( $config{ADMINISABSENTMINDED} ) { - emit( 'for chain in INPUT FORWARD; do', - ' setpolicy $chain DROP', - 'done', - '', - 'setpolicy OUTPUT ACCEPT', - '', - 'deleteallchains', - '', - 'for chain in INPUT FORWARD; do', - ' setcontinue $chain', - "done\n", - ); - } else { - emit( 'for chain in INPUT OUTPUT FORWARD; do', - ' setpolicy $chain DROP', - 'done', - '', - "deleteallchains\n" - ); - } - - process_routestopped; - - emit( '$IP6TABLES -A INPUT -i lo -j ACCEPT', - '$IP6TABLES -A OUTPUT -o lo -j ACCEPT' - ); - - emit '$IP6TABLES -A OUTPUT -o lo -j ACCEPT' unless $config{ADMINISABSENTMINDED}; - - my $interfaces = find_interfaces_by_option 'dhcp'; - - for my $interface ( @$interfaces ) { - emit "\$IP6TABLES -A INPUT -p udp -i $interface --dport 67:68 -j ACCEPT"; - emit "\$IP6TABLES -A OUTPUT -p udp -o $interface --dport 67:68 -j ACCEPT" unless $config{ADMINISABSENTMINDED}; - # - # This might be a bridge - # - emit "\$IP6TABLES -A FORWARD -p udp -i $interface -o $interface --dport 67:68 -j ACCEPT"; - } - - emit ''; - - if ( $config{IP_FORWARDING} eq 'on' ) { - emit( 'echo 1 > /proc/sys/net/ipv4/ip_forward', - 'progress_message2 IP Forwarding Enabled' ); - } elsif ( $config{IP_FORWARDING} eq 'off' ) { - emit( 'echo 0 > /proc/sys/net/ipv4/ip_forward', - 'progress_message2 IP Forwarding Disabled!' - ); - } - - emit 'run_stopped_exit'; - - pop_indent; - - emit ' - set_state "Stopped" - - logger -p kern.info "$PRODUCT Stopped" - - case $COMMAND in - stop|clear) - ;; - *) - # - # The firewall is being stopped when we were trying to do something - # else. Kill the shell in case we\'re running in a subshell - # - kill $$ - ;; - esac -} -'; - -} - -# -# Second Phase of Script Generation -# -# copies the 'prog.functions' file into the script, generates -# clear_routing_and_traffic_shaping() and the first part of -# 'setup_routing_and_traffic_shaping()' -# -# The bulk of that function is produced by the various config file -# parsing routines that are called directly out of 'compiler()'. -# -# We create two separate functions rather than one so that the -# define_firewall() shell can set global IP configuration variables -# after the old config has been cleared and before we start instantiating -# the new config. That way, the variables reflect the way that the -# distribution's tools have configured IP without any Shorewall -# modifications. -# -# Note: This function is not called when $command eq 'check'. So it must have no side effects other -# than those related to writing to the object file. -# -sub generate_script_2 () { - - copy $globals{SHAREDIRPL} . 'prog.functions'; - - emit( '', - '#', - '# Clear Routing and Traffic Shaping', - '#', - 'clear_routing_and_traffic_shaping() {' - ); - - push_indent; - - save_progress_message 'Initializing...'; - - if ( $export ) { - my $fn = find_file 'modules'; - - if ( $fn ne "$globals{SHAREDIR}/modules" && -f $fn ) { - emit 'echo MODULESDIR="$MODULESDIR" > ${VARDIR}/.modulesdir'; - emit 'cat > ${VARDIR}/.modules << EOF'; - open_file $fn; - while ( read_a_line ) { - emit_unindented $currentline; - } - emit_unindented 'EOF'; - emit 'reload_kernel_modules < ${VARDIR}/.modules'; - } else { - emit 'load_kernel_modules Yes'; - } - } else { - emit 'load_kernel_modules Yes'; - } - - emit ''; - - emit ( '[ "$COMMAND" = refresh ] && run_refresh_exit || run_init_exit', - '', - ); - - emit "delete_tc1\n" if $config{CLEAR_TC}; - - pop_indent; - - emit "}\n"; - - emit( '#', - '# Setup Routing and Traffic Shaping', - '#', - 'setup_routing_and_traffic_shaping() {' - ); - - push_indent; - -} - -# -# Third (final) stage of script generation. -# -# Generate the end of 'setup_routing_and_traffic_shaping()': -# Generate code for loading the various files in /var/lib/shorewall6[-lite] -# -# Generate the 'setup_netfilter()' function that runs ip6tables-restore. -# Generate the 'define_firewall()' function. -# -# Note: This function is not called when $command eq 'check'. So it must have no side effects other -# than those related to writing to the object file. -# -sub generate_script_3($) { - - emit( '', - 'if [ "$COMMAND" != refresh ]; then' ); - - push_indent; - - emit 'cat > ${VARDIR}/chains << __EOF__'; - dump_rule_chains; - emit_unindented '__EOF__'; - - emit 'cat > ${VARDIR}/zones << __EOF__'; - dump_zone_contents; - emit_unindented '__EOF__'; - - pop_indent; - - emit "fi\n"; - - add_addresses; - - pop_indent; - - emit "}\n"; - - progress_message2 "Creating ip6tables-restore input..."; - create_netfilter_load; - create_chainlist_reload( $_[0] ); - - emit "#\n# Start/Restart the Firewall\n#"; - emit 'define_firewall() {'; - push_indent; - - emit "\nclear_routing_and_traffic_shaping"; - - set_global_variables; - - emit ''; - - emit<<'EOF'; -setup_routing_and_traffic_shaping - -if [ $COMMAND = restore ]; then - ip6tables_save_file=${VARDIR}/$(basename $0)-ip6tables - if [ -f $ip6tables_save_file ]; then - cat $ip6tables_save_file | $IP6TABLES_RESTORE # Use this nonsensical form to appease SELinux - else - fatal_error "$ip6tables_save_file does not exist" - fi - set_state "Started" -else - if [ $COMMAND = refresh ]; then - chainlist_reload - run_refreshed_exit - $IP6TABLES -N shorewall - set_state "Started" - else - setup_netfilter - restore_dynamic_rules - run_start_exit - $IP6TABLES -N shorewall - set_state "Started" - run_started_exit - fi - - cp -f $(my_pathname) ${VARDIR}/.restore -fi - -date > ${VARDIR}/restarted - -case $COMMAND in - start) - logger -p kern.info "$PRODUCT started" - ;; - restart) - logger -p kern.info "$PRODUCT restarted" - ;; - refresh) - logger -p kern.info "$PRODUCT refreshed" - ;; - restore) - logger -p kern.info "$PRODUCT restored" - ;; -esac -EOF - - pop_indent; - - emit "}\n"; - - copy $globals{SHAREDIRPL} . 'prog.footer'; -} - -# -# The Compiler. -# -# If the first argument is non-null, it names the script file to generate. -# Otherwise, this is a 'check' command and no script is produced. -# -sub compiler( $$$$$ ) { - - my ( $objectfile, $directory, $verbosity, $options , $chains ) = @_; - - $export = 0; - - reinitialize if $reused++; - - if ( $directory ne '' ) { - fatal_error "$directory is not an existing directory" unless -d $directory; - set_shorewall_dir( $directory ); - } - - set_verbose( $verbosity ) unless $verbosity eq ''; - $export = 1 if $options & EXPORT; - set_timestamp( 1 ) if $options & TIMESTAMP; - set_debug( 1 ) if $options & DEBUG; - # - # Get shorewall.conf and capabilities. - # - get_configuration( $export ); - - report_capabilities; - - require_capability( 'MULTIPORT' , "Shorewall6 $globals{VERSION}" , 's' ); - require_capability( 'RECENT_MATCH' , 'MACLIST_TTL' , 's' ) if $config{MACLIST_TTL}; - require_capability( 'XCONNMARK' , 'HIGH_ROUTE_MARKS=Yes' , 's' ) if $config{HIGH_ROUTE_MARKS}; - require_capability( 'MANGLE_ENABLED' , 'Traffic Shaping' , 's' ) if $config{TC_ENABLED}; - - set_command( 'check', 'Checking', 'Checked' ) unless $objectfile; - - initialize_chain_table; - - unless ( $command eq 'check' ) { - create_temp_object( $objectfile ); - generate_script_1; - } - - # - # Process the zones file. - # - determine_zones; - # - # Process the interfaces file. - # - validate_interfaces_file ( $export ); - # - # Process the hosts file. - # - validate_hosts_file; - # - # Report zone contents - # - zone_report; - # - # Do action pre-processing. - # - process_actions1; - # - # Process the Policy File. - # - validate_policy; - # - # Compile the 'stop_firewall()' function - # - compile_stop_firewall; - # - # Start Second Part of script - # - generate_script_2 unless $command eq 'check'; - # - # Set up MSS rules - # - setup_mss; - # - # Do all of the zone-independent stuff - # - add_common_rules; - # - # /proc stuff - # - setup_arp_filtering; - setup_route_filtering; - setup_martian_logging; - setup_source_routing; - setup_forwarding; - # - # Handle MSS setings in the zones file - # - setup_zone_mss; - # - # TOS - # - process_tos; - # - # ECN - # - setup_ecn; - # - # MACLIST Filtration - # - setup_mac_lists 1; - # - # Process the rules file. - # - process_rules; - # - # Add Tunnel rules. - # - setup_tunnels; - # - # Post-rules action processing. - # - process_actions2; - process_actions3; - # - # MACLIST Filtration again - # - setup_mac_lists 2; - # - # Apply Policies - # - apply_policy_rules; - # - # TCRules and Traffic Shaping - # - setup_tc; - # - # Accounting. - # - setup_accounting; - # - # We generate the matrix even though we don't write out the rules. That way, we insure that - # a compile of the script won't blow up during that step. - # - generate_matrix; - - if ( $command eq 'check' ) { - progress_message3 "Shorewall configuration verified"; - } else { - # - # Finish the script. - # - generate_script_3( $chains ); - finalize_object ( $export ); - # - # And generate the auxilary config file - # - generate_aux_config if $export; - } - - 1; -} - -1; diff --git a/Shorewall6/Shorewall/FallbackPorts.pm b/Shorewall6/Shorewall/FallbackPorts.pm deleted file mode 100644 index d647a0825..000000000 --- a/Shorewall6/Shorewall/FallbackPorts.pm +++ /dev/null @@ -1,518 +0,0 @@ -# -# Shorewall-perl 4.0 -- /usr/share/shorewall-perl/Shorewall/Ports.pm -# -# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt] -# -# (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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# This module exports the %protocols and %services hashes built from -# /etc/protocols and /etc/services respectively. -# -# Module generated using buildports.pl 4.0.0-Beta7 - Fri Jun 29 14:10:45 2007 -# -package Shorewall::Ports; - -use strict; -use warnings; - -our @ISA = qw(Exporter); -our @EXPORT = qw( %protocols %services ); -our @EXPORT_OK = qw(); -our $VERSION = '4.00'; - -our %protocols = ( - ip => 0, - IP => 0, - icmp => 1, - ICMP => 1, - igmp => 2, - IGMP => 2, - ggp => 3, - GGP => 3, - ipencap => 4, - 'IP-ENCAP' => 4, - st => 5, - ST => 5, - tcp => 6, - TCP => 6, - egp => 8, - EGP => 8, - igp => 9, - IGP => 9, - pup => 12, - PUP => 12, - udp => 17, - UDP => 17, - hmp => 20, - HMP => 20, - 'xns-idp' => 22, - 'XNS-IDP' => 22, - rdp => 27, - RDP => 27, - 'iso-tp4' => 29, - 'ISO-TP4' => 29, - xtp => 36, - XTP => 36, - ddp => 37, - DDP => 37, - 'idpr-cmtp' => 38, - 'IDPR-CMTP' => 38, - ipv6 => 41, - IPv6 => 41, - 'ipv6-route' => 43, - 'IPv6-Route' => 43, - 'ipv6-frag' => 44, - 'IPv6-Frag' => 44, - idrp => 45, - IDRP => 45, - rsvp => 46, - RSVP => 46, - gre => 47, - GRE => 47, - esp => 50, - 'IPSEC-ESP' => 50, - ah => 51, - 'IPSEC-AH' => 51, - skip => 57, - SKIP => 57, - 'ipv6-icmp' => 58, - 'IPv6-ICMP' => 58, - 'ipv6-nonxt' => 59, - 'IPv6-NoNxt' => 59, - 'ipv6-opts' => 60, - 'IPv6-Opts' => 60, - rspf => 73, - RSPF => 73, - CPHB => 73, - vmtp => 81, - VMTP => 81, - eigrp => 88, - EIGRP => 88, - ospf => 89, - OSPFIGP => 89, - 'ax.25' => 93, - 'AX.25' => 93, - ipip => 94, - IPIP => 94, - etherip => 97, - ETHERIP => 97, - encap => 98, - ENCAP => 98, - pim => 103, - PIM => 103, - ipcomp => 108, - IPCOMP => 108, - vrrp => 112, - VRRP => 112, - l2tp => 115, - L2TP => 115, - isis => 124, - ISIS => 124, - sctp => 132, - SCTP => 132, - fc => 133, - FC => 133, - ); - -our %services = ( - tcpmux => 1, - echo => 7, - discard => 9, - sink => 9, - null => 9, - systat => 11, - users => 11, - daytime => 13, - netstat => 15, - qotd => 17, - quote => 17, - msp => 18, - chargen => 19, - ttytst => 19, - source => 19, - 'ftp-data' => 20, - ftp => 21, - fsp => 21, - fspd => 21, - ssh => 22, - telnet => 23, - smtp => 25, - mail => 25, - time => 37, - timserver => 37, - rlp => 39, - resource => 39, - nameserver => 42, - name => 42, - whois => 43, - nicname => 43, - tacacs => 49, - 're-mail-ck' => 50, - domain => 53, - mtp => 57, - 'tacacs-ds' => 65, - bootps => 67, - bootpc => 68, - tftp => 69, - gopher => 70, - rje => 77, - netrjs => 77, - finger => 79, - www => 80, - http => 80, - link => 87, - ttylink => 87, - kerberos => 88, - kerberos5 => 88, - krb5 => 88, - 'kerberos-sec' => 88, - supdup => 95, - hostnames => 101, - hostname => 101, - 'iso-tsap' => 102, - tsap => 102, - 'acr-nema' => 104, - dicom => 104, - 'csnet-ns' => 105, - 'cso-ns' => 105, - rtelnet => 107, - pop2 => 109, - postoffice => 109, - 'pop-2' => 109, - pop3 => 110, - 'pop-3' => 110, - sunrpc => 111, - portmapper => 111, - auth => 113, - authentication => 113, - tap => 113, - ident => 113, - sftp => 115, - 'uucp-path' => 117, - nntp => 119, - readnews => 119, - untp => 119, - ntp => 123, - pwdgen => 129, - 'loc-srv' => 135, - epmap => 135, - 'netbios-ns' => 137, - 'netbios-dgm' => 138, - 'netbios-ssn' => 139, - imap2 => 143, - imap => 143, - snmp => 161, - 'snmp-trap' => 162, - snmptrap => 162, - 'cmip-man' => 163, - 'cmip-agent' => 164, - mailq => 174, - xdmcp => 177, - nextstep => 178, - NeXTStep => 178, - NextStep => 178, - bgp => 179, - prospero => 191, - irc => 194, - smux => 199, - 'at-rtmp' => 201, - 'at-nbp' => 202, - 'at-echo' => 204, - 'at-zis' => 206, - qmtp => 209, - z3950 => 210, - wais => 210, - ipx => 213, - imap3 => 220, - pawserv => 345, - zserv => 346, - fatserv => 347, - rpc2portmap => 369, - codaauth2 => 370, - clearcase => 371, - Clearcase => 371, - ulistserv => 372, - ldap => 389, - imsp => 406, - https => 443, - snpp => 444, - 'microsoft-ds' => 445, - kpasswd => 464, - saft => 487, - isakmp => 500, - rtsp => 554, - nqs => 607, - 'npmp-local' => 610, - dqs313_qmaster => 610, - 'npmp-gui' => 611, - dqs313_execd => 611, - 'hmmp-ind' => 612, - dqs313_intercell => 612, - ipp => 631, - exec => 512, - biff => 512, - comsat => 512, - login => 513, - who => 513, - whod => 513, - shell => 514, - cmd => 514, - syslog => 514, - printer => 515, - spooler => 515, - talk => 517, - ntalk => 518, - route => 520, - router => 520, - routed => 520, - timed => 525, - timeserver => 525, - tempo => 526, - newdate => 526, - courier => 530, - rpc => 530, - conference => 531, - chat => 531, - netnews => 532, - netwall => 533, - gdomap => 538, - uucp => 540, - uucpd => 540, - klogin => 543, - kshell => 544, - krcmd => 544, - afpovertcp => 548, - remotefs => 556, - rfs_server => 556, - rfs => 556, - nntps => 563, - snntp => 563, - submission => 587, - ldaps => 636, - tinc => 655, - silc => 706, - 'kerberos-adm' => 749, - webster => 765, - rsync => 873, - 'ftps-data' => 989, - ftps => 990, - telnets => 992, - imaps => 993, - ircs => 994, - pop3s => 995, - socks => 1080, - proofd => 1093, - rootd => 1094, - openvpn => 1194, - rmiregistry => 1099, - kazaa => 1214, - nessus => 1241, - lotusnote => 1352, - lotusnotes => 1352, - 'ms-sql-s' => 1433, - 'ms-sql-m' => 1434, - ingreslock => 1524, - 'prospero-np' => 1525, - datametrics => 1645, - 'old-radius' => 1645, - 'sa-msg-port' => 1646, - 'old-radacct' => 1646, - kermit => 1649, - l2f => 1701, - l2tp => 1701, - radius => 1812, - 'radius-acct' => 1813, - radacct => 1813, - msnp => 1863, - 'unix-status' => 1957, - 'log-server' => 1958, - remoteping => 1959, - nfs => 2049, - 'rtcm-sc104' => 2101, - cvspserver => 2401, - venus => 2430, - 'venus-se' => 2431, - codasrv => 2432, - 'codasrv-se' => 2433, - mon => 2583, - dict => 2628, - gpsd => 2947, - gds_db => 3050, - icpv2 => 3130, - icp => 3130, - mysql => 3306, - nut => 3493, - distcc => 3632, - daap => 3689, - svn => 3690, - subversion => 3690, - iax => 4569, - 'radmin-port' => 4899, - rfe => 5002, - mmcc => 5050, - sip => 5060, - 'sip-tls' => 5061, - aol => 5190, - 'xmpp-client' => 5222, - 'jabber-client' => 5222, - 'xmpp-server' => 5269, - 'jabber-server' => 5269, - cfengine => 5308, - postgresql => 5432, - postgres => 5432, - x11 => 6000, - 'x11-0' => 6000, - 'x11-1' => 6001, - 'x11-2' => 6002, - 'x11-3' => 6003, - 'x11-4' => 6004, - 'x11-5' => 6005, - 'x11-6' => 6006, - 'x11-7' => 6007, - 'gnutella-svc' => 6346, - 'gnutella-rtr' => 6347, - 'afs3-fileserver' => 7000, - bbs => 7000, - 'afs3-callback' => 7001, - 'afs3-prserver' => 7002, - 'afs3-vlserver' => 7003, - 'afs3-kaserver' => 7004, - 'afs3-volser' => 7005, - 'afs3-errors' => 7006, - 'afs3-bos' => 7007, - 'afs3-update' => 7008, - 'afs3-rmtsys' => 7009, - 'font-service' => 7100, - xfs => 7100, - 'bacula-dir' => 9101, - 'bacula-fd' => 9102, - 'bacula-sd' => 9103, - amanda => 10080, - hkp => 11371, - bprd => 13720, - bpdbm => 13721, - 'bpjava-msvc' => 13722, - vnetd => 13724, - bpcd => 13782, - vopied => 13783, - wnn6 => 22273, - kerberos4 => 750, - 'kerberos-iv' => 750, - kdc => 750, - kerberos_master => 751, - passwd_server => 752, - krb_prop => 754, - krb5_prop => 754, - hprop => 754, - krbupdate => 760, - kreg => 760, - swat => 901, - kpop => 1109, - knetd => 2053, - 'zephyr-srv' => 2102, - 'zephyr-clt' => 2103, - 'zephyr-hm' => 2104, - eklogin => 2105, - kx => 2111, - iprop => 2121, - supfilesrv => 871, - supfiledbg => 1127, - linuxconf => 98, - poppassd => 106, - ssmtp => 465, - smtps => 465, - moira_db => 775, - moira_update => 777, - moira_ureg => 779, - spamd => 783, - omirr => 808, - omirrd => 808, - customs => 1001, - skkserv => 1178, - predict => 1210, - rmtcfg => 1236, - wipld => 1300, - xtel => 1313, - xtelw => 1314, - support => 1529, - sieve => 2000, - cfinger => 2003, - ndtp => 2010, - frox => 2121, - ninstall => 2150, - zebrasrv => 2600, - zebra => 2601, - ripd => 2602, - ripngd => 2603, - ospfd => 2604, - bgpd => 2605, - ospf6d => 2606, - ospfapi => 2607, - isisd => 2608, - afbackup => 2988, - afmbackup => 2989, - xtell => 4224, - fax => 4557, - hylafax => 4559, - distmp3 => 4600, - munin => 4949, - lrrd => 4949, - 'enbd-cstatd' => 5051, - 'enbd-sstatd' => 5052, - pcrd => 5151, - noclog => 5354, - hostmon => 5355, - rplay => 5555, - rptp => 5556, - nsca => 5667, - mrtd => 5674, - bgpsim => 5675, - canna => 5680, - 'sane-port' => 6566, - sane => 6566, - saned => 6566, - ircd => 6667, - 'zope-ftp' => 8021, - webcache => 8080, - tproxy => 8081, - omniorb => 8088, - 'clc-build-daemon' => 8990, - xinetd => 9098, - mandelspawn => 9359, - mandelbrot => 9359, - zope => 9673, - kamanda => 10081, - amandaidx => 10082, - amidxtape => 10083, - smsqp => 11201, - xpilot => 15345, - 'sgi-cmsd' => 17001, - 'sgi-crsd' => 17002, - 'sgi-gcd' => 17003, - 'sgi-cad' => 17004, - isdnlog => 20011, - vboxd => 20012, - binkp => 24554, - asp => 27374, - csync2 => 30865, - dircproxy => 57000, - tfido => 60177, - fido => 60179, - ); - -1; diff --git a/Shorewall6/Shorewall/IPAddrs.pm b/Shorewall6/Shorewall/IPAddrs.pm deleted file mode 100644 index fd8121b55..000000000 --- a/Shorewall6/Shorewall/IPAddrs.pm +++ /dev/null @@ -1,102 +0,0 @@ -# -# Shorewall-6 4.1 -- /usr/share/shorewall6/Shorewall6/IPAddrs.pm -# -# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt] -# -# (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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# This module provides interfaces for dealing with IPv6 addresses. -# -package Shorewall::IPAddrs; -require Exporter; -use Shorewall::Config; - -use strict; - -our @ISA = qw(Exporter); -our @EXPORT = qw( ALLIPv6 - - validate_address - validate_net - validate_host - validate_range - ip_range_explicit - allipv6 - ); -our @EXPORT_OK = qw( ); -our $VERSION = '4.03'; - -# -# Some IPv6 useful stuff -# -our @allipv6 = ( '::/0' ); - -sub allipv6() { - @allipv6 -} - -use constant { ALLIPv6 => '::/0' }; - -sub valid_address( $ ) { - 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_address( $ ) { - my $addr = $_[0]; - - unless ( valid_address $addr ) { - fatal_error "Unknown Host ($addr)" unless defined gethostbyname $addr; - } -} - -sub validate_net( $ ) { - my ($net, $vlsm, $rest) = split( '/', $_[0], 3 ); - - fatal_error "An ipset name ($net) is not allowed in this context" if substr( $net, 0, 1 ) eq '+'; - - if ( defined $vlsm ) { - fatal_error "Invalid VLSM ($vlsm)" unless $vlsm =~ /^\d+$/ && $vlsm <= 64; - fatal_error "Invalid Network address ($_[0])" if defined $rest; - fatal_error "Invalid IPv6 address ($net)" unless valid_address $net; - } else { - fatal_error "Invalid Network address ($_[0])" if $_[0] =~ '/' || ! defined $net; - validate_address $net; - } -} - -1; diff --git a/Shorewall6/Shorewall/Zones.pm b/Shorewall6/Shorewall/Zones.pm deleted file mode 100644 index de0100351..000000000 --- a/Shorewall6/Shorewall/Zones.pm +++ /dev/null @@ -1,1026 +0,0 @@ -# -# Shorewall-perl 4.0 -- /usr/share/shorewall-perl/Shorewall/Zones.pm -# -# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt] -# -# (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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# This module contains the code which deals with /etc/shorewall/zones, -# /etc/shorewall/interfaces and /etc/shorewall/hosts. -# -package Shorewall::Zones; -require Exporter; -use Shorewall::Config; -use Shorewall::IPAddrs; - -use strict; - -our @ISA = qw(Exporter); -our @EXPORT = qw( NOTHING - NUMERIC - NETWORK - IPSECPROTO - IPSECMODE - - numeric_value - determine_zones - zone_report - dump_zone_contents - find_zone - firewall_zone - defined_zone - zone_type - all_zones - complex_zones - non_firewall_zones - single_interface - validate_interfaces_file - all_interfaces - find_interface - known_interface - have_bridges - port_to_bridge - source_port_to_bridge - interface_is_optional - find_interfaces_by_option - get_interface_option - validate_hosts_file - find_hosts_by_option - ); - -our @EXPORT_OK = qw( initialize ); -our $VERSION = '4.03'; - -# -# IPSEC Option types -# -use constant { NOTHING => 'NOTHING', - NUMERIC => '0x[\da-fA-F]+|\d+', - NETWORK => '\d+.\d+.\d+.\d+(\/\d+)?', - IPSECPROTO => 'ah|esp|ipcomp', - IPSECMODE => 'tunnel|transport' - }; - -# -# Zone Table. -# -# @zones contains the ordered list of zones with sub-zones appearing before their parents. -# -# %zones{ => {type = > 'firewall', 'ipv4', 'ipsec4', 'bport4'; -# options => { complex => 0|1 -# in_out => < policy match string > -# in => < policy match string > -# out => < policy match string > -# } -# parents => [ ] Parents, Children and interfaces are listed by name -# children => [ ] -# interfaces => [ ] -# bridge => -# hosts { } => [ { => { ipsec => 'ipsec'|'none' -# options => { => -# ... -# } -# hosts => [ , , ... ] -# } -# => ... -# } -# ] -# } -# => ... -# } -# -# $firewall_zone names the firewall zone. -# -our @zones; -our %zones; -our $firewall_zone; - -our %reservedName = ( all => 1, - none => 1, - SOURCE => 1, - DEST => 1 ); - -# -# Interface Table. -# -# @interfaces lists the interface names in the order that they appear in the interfaces file. -# -# %interfaces { => { root => -# options => { = , -# ... -# } -# zone => -# bridge => -# broadcasts => 'none', 'detect' or [ , , ... ] -# } -# } -# -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() { - @zones = (); - %zones = (); - $firewall_zone = ''; - - @interfaces = (); - %interfaces = (); - @bridges = (); -} - -INIT { - initialize; -} - -# -# Convert value to decimal number -# -sub numeric_value ( $ ) { - my $mark = $_[0]; - fatal_error "Invalid Numeric Value ($mark)" unless "\L$mark" =~ /^(0x[a-f0-9]+|0[0-7]*|[1-9]\d*)$/; - $mark =~ /^0/ ? oct $mark : $mark; -} - -# -# Parse the passed option list and return a reference to a hash as follows: -# -# => mss = -# => ipsec = <-m policy arguments to match options> -# -sub parse_zone_option_list($$) -{ - my %validoptions = ( mss => NUMERIC, - strict => NOTHING, - next => NOTHING, - reqid => NUMERIC, - spi => NUMERIC, - proto => IPSECPROTO, - mode => IPSECMODE, - "tunnel-src" => NETWORK, - "tunnel-dst" => NETWORK, - ); - - # - # Hash of options that have their own key in the returned hash. - # - my %key = ( mss => "mss" ); - - my ( $list, $zonetype ) = @_; - my %h; - my $options = ''; - my $fmt; - - if ( $list ne '-' ) { - for my $e ( split ',' , $list ) { - my $val = undef; - my $invert = ''; - - if ( $e =~ /([\w-]+)!=(.+)/ ) { - $val = $2; - $e = $1; - $invert = '! '; - } elsif ( $e =~ /([\w-]+)=(.+)/ ) { - $val = $2; - $e = $1; - } - - $fmt = $validoptions{$e}; - - fatal_error "Invalid Option ($e)" unless $fmt; - - if ( $fmt eq NOTHING ) { - fatal_error "Option \"$e\" does not take a value" if defined $val; - } else { - fatal_error "Missing value for option \"$e\"" unless defined $val; - fatal_error "Invalid value ($val) for option \"$e\"" unless $val =~ /^($fmt)$/; - } - - if ( $key{$e} ) { - $h{$e} = $val; - } else { - fatal_error "The \"$e\" option may only be specified for ipsec zones" unless $zonetype eq 'ipsec4'; - $options .= $invert; - $options .= "--$e "; - $options .= "$val "if defined $val; - } - } - } - - $h{ipsec} = $options ? "$options " : ''; - - \%h; -} - -# -# Parse the zones file. -# -sub determine_zones() -{ - my @z; - - my $fn = open_file 'zones'; - - my $first_entry = 1; - - while ( read_a_line ) { - - if ( $first_entry ) { - progress_message2 "$doing $fn..."; - $first_entry = 0; - } - - my @parents; - - my ($zone, $type, $options, $in_options, $out_options ) = split_line 1, 5, 'zones file'; - - if ( $zone =~ /(\w+):([\w,]+)/ ) { - $zone = $1; - @parents = split ',', $2; - - for my $p ( @parents ) { - fatal_error "Invalid Parent List ($2)" unless $p; - fatal_error "Unknown parent zone ($p)" unless $zones{$p}; - fatal_error 'Subzones of firewall zone not allowed' if $zones{$p}{type} eq 'firewall'; - push @{$zones{$p}{children}}, $zone; - } - } - - fatal_error "Invalid zone name ($zone)" unless "\L$zone" =~ /^[a-z]\w*$/ && length $zone <= $globals{MAXZONENAMELENGTH}; - fatal_error "Invalid zone name ($zone)" if $reservedName{$zone} || $zone =~ /^all2|2all$/; - fatal_error( "Duplicate zone name ($zone)" ) if $zones{$zone}; - - $type = "ipv4" unless $type; - - if ( $type =~ /ipv4/i ) { - $type = 'ipv4'; - } elsif ( $type =~ /^ipsec4?$/i ) { - $type = 'ipsec4'; - } elsif ( $type =~ /^bport4?$/i ) { - warning_message "Bridge Port zones should have a parent zone" unless @parents; - $type = 'bport4'; - } elsif ( $type eq 'firewall' ) { - fatal_error 'Firewall zone may not be nested' if @parents; - fatal_error "Only one firewall zone may be defined ($zone)" if $firewall_zone; - $firewall_zone = $zone; - $ENV{FW} = $zone; - $type = "firewall"; - } elsif ( $type eq '-' ) { - $type = 'ipv4'; - } else { - fatal_error "Invalid zone type ($type)" ; - } - - for ( $options, $in_options, $out_options ) { - $_ = '' if $_ eq '-'; - } - - $zones{$zone} = { type => $type, - parents => \@parents, - exclusions => [], - bridge => '', - options => { in_out => parse_zone_option_list( $options || '', $type ) , - in => parse_zone_option_list( $in_options || '', $type ) , - out => parse_zone_option_list( $out_options || '', $type ) , - complex => ($type eq 'ipsec4' || $options || $in_options || $out_options ? 1 : 0) } , - interfaces => {} , - children => [] , - hosts => {} - }; - push @z, $zone; - } - - fatal_error "No firewall zone defined" unless $firewall_zone; - - my %ordered; - - PUSHED: - { - ZONE: - for my $zone ( @z ) { - unless ( $ordered{$zone} ) { - for ( @{$zones{$zone}{children}} ) { - next ZONE unless $ordered{$_}; - } - $ordered{$zone} = 1; - push @zones, $zone; - redo PUSHED; - } - } - } - - fatal_error "Internal error in determine_zones()" unless scalar @zones == scalar @z; -} - -# -# Return true of we have any ipsec zones -# -sub haveipseczones() { - for my $zoneref ( values %zones ) { - return 1 if $zoneref->{type} eq 'ipsec4'; - } - - 0; -} - -# -# Report about zones. -# -sub zone_report() -{ - progress_message2 "Determining Hosts in Zones..."; - - for my $zone ( @zones ) - { - my $zoneref = $zones{$zone}; - my $hostref = $zoneref->{hosts}; - my $type = $zoneref->{type}; - my $optionref = $zoneref->{options}; - - progress_message " $zone ($type)"; - - my $printed = 0; - - if ( $hostref ) { - for my $type ( sort keys %$hostref ) { - my $interfaceref = $hostref->{$type}; - - for my $interface ( sort keys %$interfaceref ) { - my $arrayref = $interfaceref->{$interface}; - for my $groupref ( @$arrayref ) { - my $hosts = $groupref->{hosts}; - if ( $hosts ) { - my $grouplist = join ',', ( @$hosts ); - progress_message " $interface:$grouplist"; - $printed = 1; - } - } - - } - } - } - - unless ( $printed ) { - fatal_error "No bridge has been associated with zone $zone" if $type eq 'bport4' && ! $zoneref->{bridge}; - warning_message "*** $zone is an EMPTY ZONE ***" unless $type eq 'firewall'; - } - - } -} - -sub dump_zone_contents() -{ - for my $zone ( @zones ) - { - my $zoneref = $zones{$zone}; - my $hostref = $zoneref->{hosts}; - my $type = $zoneref->{type}; - my $optionref = $zoneref->{options}; - my $exclusions = $zoneref->{exclusions}; - my $entry = "$zone $type"; - - $entry .= ":$zoneref->{bridge}" if $type eq 'bport4'; - - if ( $hostref ) { - for my $type ( sort keys %$hostref ) { - my $interfaceref = $hostref->{$type}; - - for my $interface ( sort keys %$interfaceref ) { - my $arrayref = $interfaceref->{$interface}; - for my $groupref ( @$arrayref ) { - my $hosts = $groupref->{hosts}; - if ( $hosts ) { - my $grouplist = join ',', ( @$hosts ); - $entry .= " $interface:$grouplist"; - } - } - } - } - } - - if ( @$exclusions ) { - $entry .= ' exclude'; - - for my $host ( @$exclusions ) { - $entry .= " $host"; - } - } - - emit_unindented $entry; - } -} - -# -# If the passed zone is associated with a single interface, the name of the interface is returned. Otherwise, the funtion returns ''; -# -sub single_interface( $ ) { - my $zone = $_[0]; - my $zoneref = $zones{$zone}; - - fatal_error "Internal Error in single_zone()" unless $zoneref; - - my @keys = keys( %{$zoneref->{interfaces}} ); - - @keys == 1 ? $keys[0] : ''; -} - -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' }; -} - -# -# Verify that the passed zone name represents a declared zone. Return a -# reference to its zone table entry. -# -sub find_zone( $ ) { - my $zone = $_[0]; - - my $zoneref = $zones{$zone}; - - fatal_error "Unknown zone" unless $zoneref; - - $zoneref; -} - -sub zone_type( $ ) { - find_zone( $_[0] )->{type}; -} - -sub defined_zone( $ ) { - $zones{$_[0]}; -} - -sub all_zones() { - @zones; -} - -sub non_firewall_zones() { - grep ( $zones{$_}{type} ne 'firewall' , @zones ); -} - -sub complex_zones() { - grep( $zones{$_}{options}{complex} , @zones ); -} - -sub firewall_zone() { - $firewall_zone; -} - -# -# 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 = ) { - $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, - NUMERIC_IF_OPTION => 4, - MASK_IF_OPTION => 7, - - IF_OPTION_ZONEONLY => 8 }; - - my %validoptions = (blacklist => SIMPLE_IF_OPTION, - bridge => SIMPLE_IF_OPTION, - dhcp => SIMPLE_IF_OPTION, - maclist => SIMPLE_IF_OPTION, - optional => SIMPLE_IF_OPTION, - routeback => SIMPLE_IF_OPTION + IF_OPTION_ZONEONLY, - tcpflags => SIMPLE_IF_OPTION, - upnp => SIMPLE_IF_OPTION, - forward => SIMPLE_IF_OPTION, - mss => NUMERIC_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' ) { - my @broadcasts = split /,/, $networks; - - for my $address ( @broadcasts ) { - fatal_error 'Invalid BROADCAST address' unless $address =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/; - } - - if ( $capabilities{ADDRTYPE} ) { - warning_message 'Shorewall no longer uses broadcast addresses in rule generation when Address Type Match is available'; - } else { - $interfaces{$interface}{broadcasts} = \@broadcasts; - } - } - - 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"; - } - } elsif ( $type == NUMERIC_IF_OPTION ) { - fatal_error "The $option option requires a value" unless defined $value; - $options{$option} = numeric_value $value; - } - } - - $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 interfaces list -# -sub all_interfaces() { - @interfaces; -} - -# -# Return a reference to the interfaces table entry for an interface -# -sub find_interface( $ ) { - my $interface = $_[0]; - my $interfaceref = $interfaces{ $interface }; - - fatal_error "Unknown Interface ($interface)" unless $interfaceref; - - $interfaceref; -} - -# -# Returns true if there are bridges defined in the config -# -sub have_bridges() { - @bridges > 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 = 'ipsec4'; - $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; diff --git a/Shorewall6/shorewall6 b/Shorewall6/shorewall6 deleted file mode 100755 index 936dea604..000000000 --- a/Shorewall6/shorewall6 +++ /dev/null @@ -1,1638 +0,0 @@ -#!/bin/sh -# -# Shorewall Packet Filtering Firewall Control Program - V4.0 -# -# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt] -# -# (c) 1999,2000,2001,2002,2003,2004,2005,2006,2007 - Tom Eastep (teastep@shorewall.net) -# -# This file should be placed in /sbin/shorewall6. -# -# Shorewall documentation is available at http://www.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# If an error occurs while starting or restarting the firewall, the -# firewall is automatically stopped. -# -# The firewall uses configuration files in /etc/shorewall6/ - skeleton -# files are included with the firewall. -# -# Commands are: -# -# shorewall6 dump Dumps all Shorewall-related information -# for problem analysis -# shorewall6 start Starts the firewall -# shorewall6 restart Restarts the firewall -# shorewall6 stop Stops the firewall -# shorewall6 status Displays firewall status -# shorewall6 reset Resets ip6tables packet and -# byte counts -# shorewall6 clear Open the floodgates by -# removing all ip6tables rules -# and setting the three permanent -# chain policies to ACCEPT -# shorewall6 refresh Rebuild the common chain to -# compensate for a change of -# broadcast address on any "detect" -# interface. -# shorewall6 [re]load [ ] -# Compile a script and install it on a -# remote Shorewall6 Lite system. -# shorewall6 show [ ... ] Display the rules in each listed -# shorewall6 show actions Displays the available actions -# shorewall6 show log Print the last 20 log messages -# shorewall6 show connections Show the kernel's connection -# tracking table -# shorewall6 show nat Display the rules in the nat table -# shorewall6 show {mangle|tos} Display the rules in the mangle table -# shorewall6 show tc Display traffic control info -# shorewall6 show classifiers Display classifiers -# shorewall6 show capabilities Display ip6tables/kernel capabilities -# shorewall6 version Display the installed version id -# shorewall6 check [ -e ] [ ] Dry-run compilation. -# shorewall6 try [ ] Try a new configuration and if -# it doesn't work, revert to the -# standard one. If a timeout is supplied -# the command reverts back to the -# standard configuration after that many -# seconds have elapsed after successfully -# starting the new configuration. -# shorewall6 logwatch [ refresh-interval ] Monitor the local log for Shorewall -# messages. -# shorewall6 drop
... Temporarily drop all packets from the -# listed address(es) -# shorewall6 reject
... Temporarily reject all packets from the -# listed address(es) -# shorewall6 allow
... Reenable address(es) previously -# disabled with "drop" or "reject" -# shorewall6 save [ ] Save the list of "rejected" and -# "dropped" addresses so that it will -# be automatically reinstated the -# next time that Shorewall6 starts. -# Save the current state so that 'shorewall -# restore' can be used. -# -# shorewall6 forget [ ] Discard the data saved by 'shorewall6 save' -# -# shorewall6 restore [ ] Restore the state of the firewall from -# previously saved information. -# -# shorewall6 ipaddr {
/ |
} -# -# Displays information about the network -# defined by the argument[s] -# -# shorewall6 iprange
-
Decomposes a range of IP addresses into -# a list of network/host addresses. -# -# shorewall6 ipdecimal {
| } -# -# Displays the decimal equivalent of an IP -# address and vice versa. -# -# shorewall6 safe-start [ ] Starts the firewall and promtp for a c -# confirmation to accept or reject the new -# configuration -# -# shorewall6 safe-restart [ ] Restarts the firewall and prompt for a -# confirmation to accept or reject the new -# configuration -# -# shorewall6 compile [ -e ] [ ] -# Compile a firewall program file. - -# -# Set the configuration variables from shorewall.conf -# -get_config() { - - ensure_config_path - - if [ "$1" = Yes ]; then - params=$(find_file params) - - if [ -f $params ]; then - . $params - fi - fi - - config=$(find_file shorewall.conf) - - if [ -f $config ]; then - if [ -r $config ]; then - . $config - else - echo "Cannot read $config! (Hint: Are you root?)" >&2 - exit 1 - fi - else - echo "$config does not exist!" >&2 - exit 2 - fi - - ensure_config_path - - if [ -z "$EXPORT" -a "$(id -u)" = 0 ]; then - # - # This block is avoided for compile for export and when the user isn't root - # - export CONFIG_PATH - - if [ "$3" = Yes ]; then - [ -z "$LOGFILE" ] && LOGFILE=/var/log/messages - - if [ -n "$(syslog_circular_buffer)" ]; then - LOGREAD="logread | tac" - elif [ -f $LOGFILE ]; then - LOGREAD="tac $LOGFILE" - else - echo "LOGFILE ($LOGFILE) does not exist!" >&2 - exit 2 - fi - fi - - if [ -n "$IP6TABLES" ]; then - if [ ! -x "$IPTTABLES" ]; then - echo " ERROR: The program specified in IPTTABLES does not exist or is not executable" >&2 - exit 2 - fi - else - IP6TABLES=$(mywhich ip6tables 2> /dev/null) - if [ -z "$IP6TABLES" ] ; then - echo " ERROR: Can't find ip6tables executable" >&2 - exit 2 - fi - fi - - export IP6TABLES - - # - # Compile by non-root needs no restore file - # - [ -n "$RESTOREFILE" ] || RESTOREFILE=restore - - validate_restorefile RESTOREFILE - - export RESTOREFILE - - if [ "$2" = Yes ]; then - case $STARTUP_ENABLED in - No|no|NO) - echo " ERROR: Shorewall6 startup is disabled. To enable startup, set STARTUP_ENABLED=Yes in ${CONFDIR}/shorewall6.conf" >&2 - exit 2 - ;; - Yes|yes|YES) - ;; - *) - if [ -n "$STARTUP_ENABLED" ]; then - echo " ERROR: Invalid Value for STARTUP_ENABLE: $STARTUP_ENABLED" >&2 - exit 2 - fi - ;; - esac - fi - - case ${TC_ENABLED:=Internal} in - No|NO|no) - TC_ENABLED= - ;; - esac - - [ -n "LOGFORMAT" ] && LOGFORMAT="${LOGFORMAT%%%*}" - - [ -n "$LOGFORMAT" ] || LOGFORMAT="Shorewall:" - - export LOGFORMAT - - fi - - if [ -n "$SHOREWALL_SHELL" ]; then - if [ ! -x "$SHOREWALL_SHELL" ]; then - echo " ERROR: The program specified in SHOREWALL_SHELL does not exist or is not executable" >&2 - exit 2 - fi - fi - - [ -n "${VERBOSITY:=2}" ] - - VERBOSE=$(($VERBOSE_OFFSET + $VERBOSITY)) - - export VERBOSE - - [ -n "${HOSTNAME:=$(hostname)}" ] - - [ -n "$RSH_COMMAND" ] || RSH_COMMAND='ssh ${root}@${system} ${command}' - [ -n "$RCP_COMMAND" ] || RCP_COMMAND='scp ${files} ${root}@${system}:${destination}' - -} - -# -# Run the appropriate compiler -# -compiler() { - startup_error() { - echo " ERROR: $@" >&2 - exit 1 - } - - local command - command=$1 - - shift - - if [ $(id -u) -ne 0 ]; then - if [ -z "$SHOREWALL_DIR" -o "$SHOREWALL_DIR" = /etc/shorewall6 ]; then - startup_error "Ordinary users may not compile the /etc/shorewall6 configuration" - fi - fi - # - # We've now set SHOREWALL_DIR so recalculate CONFIG_PATH - # - ensure_config_path - - [ $command = exec ] || command= - - debugflags="-w" - [ -n "$DEBUG" ] && debugflags='-wd' - [ -n "$PROFILE" ] && debugflags='-wd:DProf' - - # Perl compiler only takes the output file as a argument - - [ "$1" = debug ] && shift; - [ "$1" = nolock ] && shift; - shift - - options="--verbose $VERBOSE "; - [ -n "$EXPORT" ] && options="$options --export " - [ -n "$SHOREWALL_DIR" ] && options="$options --directory $SHOREWALL_DIR " - [ -n "$TIMESTAMP" ] && options="$options --timestamp " - [ -n "$debugging" ] && options="$options --debug " - [ -n "$REFRESHCHAINS" ] && options="$options --refresh $REFRESHCHAINS" - # - # Run the appropriate params file - # - set -a; - run_user_exit params - set +a - - $command perl $debugflags ${SHAREDIR}/compiler.pl $options $@ -} - -# -# Start Command Executor -# -start_command() { - local finished - finished=0 - - do_it() { - local rc - rc=0 - - progress_message3 "Compiling..." - - if compiler run $debugging $nolock compile ${VARDIR}/.start; then - [ -n "$nolock" ] || mutex_on - ${VARDIR}/.start $debugging start - rc=$? - [ -n "$nolock" ] || mutex_off - else - rc=$? - logger -p kern.err "ERROR:Shorewall6 start failed" - fi - - exit $rc - } - - if shorewall_is_started; then - error_message "Shorewall6 is already running" - exit 0 - fi - - [ -n "$STARTUP_ENABLED" ] || fatal_error "Startup is disabled" - - while [ $finished -eq 0 -a $# -gt 0 ]; do - option=$1 - case $option in - -*) - option=${option#-} - - while [ -n "$option" ]; do - case $option in - -) - finished=1 - option= - ;; - f*) - FAST=Yes - option=${option#f} - ;; - *) - usage 1 - ;; - esac - done - shift - ;; - *) - finished=1 - ;; - esac - done - - case $# in - 0) - ;; - 1) - [ -n "$SHOREWALL_DIR" -o -n "$FAST" ] && usage 2 - - if [ ! -d $1 ]; then - if [ -e $1 ]; then - echo "$1 is not a directory" >&2 && exit 2 - else - echo "Directory $1 does not exist" >&2 && exit 2 - fi - fi - - SHOREWALL_DIR=$(resolve_file $1) - export SHOREWALL_DIR - ;; - *) - usage 1 - ;; - esac - - export NOROUTES - - if [ -n "$FAST" ]; then - if qt mywhich make; then - # - # RESTOREFILE is exported by get_config() - # - make -qf ${CONFDIR}/Makefile || FAST= - fi - - if [ -n "$FAST" ]; then - - RESTOREPATH=${VARDIR}/$RESTOREFILE - - if [ -x $RESTOREPATH ]; then - echo Restoring Shorewall6... - $SHOREWALL_SHELL $RESTOREPATH restore - date > ${VARDIR}/restarted - progress_message3 Shorewall6 restored from $RESTOREPATH - else - do_it - fi - else - do_it - fi - else - do_it - fi -} - -# -# Compile Command Executor -# -compile_command() { - local finished - finished=0 - - while [ $finished -eq 0 ]; do - [ $# -eq 0 ] && usage 1 - option=$1 - case $option in - -*) - shift - option=${option#-} - - [ -z "$option" ] && usage 1 - - while [ -n "$option" ]; do - case $option in - e*) - EXPORT=Yes - option=${option#e} - ;; - p*) - PROFILE=Yes - option=${option#p} - ;; - d*) - DEBUG=Yes; - option=${option#d} - ;; - -) - finished=1 - option= - ;; - *) - usage 1 - ;; - esac - done - ;; - *) - finished=1 - ;; - esac - done - - file= - - case $# in - 1) - file=$1 - [ -d $file ] && echo " ERROR: $file is a directory" >&2 && exit 2; - ;; - 2) - [ -n "$SHOREWALL_DIR" ] && usage 2 - - if [ ! -d $1 ]; then - if [ -e $1 ]; then - echo "$1 is not a directory" >&2 && exit 2 - else - echo "Directory $1 does not exist" >&2 && exit 2 - fi - fi - - SHOREWALL_DIR=$(resolve_file $1) - export SHOREWALL_DIR - file=$2 - ;; - *) - usage 1 - ;; - esac - - export EXPORT - - progress_message3 "Compiling..." - - compiler exec $debugging compile $file -} - -# -# Check Command Executor -# -check_command() { - local finished - finished=0 - - while [ $finished -eq 0 -a $# -gt 0 ]; do - option=$1 - case $option in - -*) - option=${option#-} - - while [ -n "$option" ]; do - case $option in - -) - finished=1 - option= - ;; - e*) - EXPORT=Yes - option=${option#e} - ;; - p*) - PROFILE=Yes - option=${option#p} - ;; - d*) - DEBUG=Yes; - option=${option#d} - ;; - *) - usage 1 - ;; - esac - done - shift - ;; - *) - finished=1 - ;; - esac - done - - case $# in - 0) - ;; - 1) - [ -n "$SHOREWALL_DIR" ] && usage 2 - - if [ ! -d $1 ]; then - if [ -e $1 ]; then - echo "$1 is not a directory" >&2 && exit 2 - else - echo "Directory $1 does not exist" >&2 && exit 2 - fi - fi - - SHOREWALL_DIR=$(resolve_file $1) - export SHOREWALL_DIR - ;; - *) - usage 1 - ;; - esac - - export EXPORT - - progress_message3 "Checking..." - - compiler exec $debugging $nolock check -} - -# -# Restart Command Executor -# -restart_command() { - local finished - finished=0 - local rc - rc=0 - - while [ $finished -eq 0 -a $# -gt 0 ]; do - option=$1 - case $option in - -*) - option=${option#-} - - while [ -n "$option" ]; do - case $option in - -) - finished=1 - option= - ;; - n*) - NOROUTES=Yes - option=${option#n} - ;; - *) - usage 1 - ;; - esac - done - shift - ;; - *) - finished=1 - ;; - esac - done - - case $# in - 0) - ;; - 1) - [ -n "$SHOREWALL_DIR" ] && usage 2 - - if [ ! -d $1 ]; then - if [ -e $1 ]; then - echo "$1 is not a directory" >&2 && exit 2 - else - echo "Directory $1 does not exist" >&2 && exit 2 - fi - fi - - SHOREWALL_DIR=$(resolve_file $1) - export SHOREWALL_DIR - ;; - *) - usage 1 - ;; - esac - - [ -n "$STARTUP_ENABLED" ] || fatal_error "Startup is disabled" - - export NOROUTES - - progress_message3 "Compiling..." - - if compiler run $debugging $nolock compile ${VARDIR}/.restart; then - [ -n "$nolock" ] || mutex_on - $SHOREWALL_SHELL ${VARDIR}/.restart $debugging restart - rc=$? - [ -n "$nolock" ] || mutex_off - else - rc=$? - logger -p kern.err "ERROR:Shorewall6 restart failed" - fi - - - return $rc -} - -# -# Refresh Command Executor -# -refresh_command() { - local finished - finished=0 - - while [ $finished -eq 0 -a $# -gt 0 ]; do - option=$1 - case $option in - -*) - option=${option#-} - - while [ -n "$option" ]; do - case $option in - -) - finished=1 - option= - ;; - *) - usage 1 - ;; - esac - done - shift - ;; - *) - finished=1 - ;; - esac - done - - if [ $# -gt 0 ]; then - REFRESHCHAINS=$1 - shift - - while [ $# -gt 0 ]; do - REFRESHCHAINS="$REFRESHCHAINS,$1" - shift - done - fi - - shorewall_is_started || fatal_error "Shorewall6 is not running" - - [ -n "$STARTUP_ENABLED" ] || fatal_error "Startup is disabled" - - export NOROUTES - - progress_message3 "Compiling..." - - if compiler run $debugging $nolock compile ${VARDIR}/.refresh; then - [ -n "$nolock" ] || mutex_on - $SHOREWALL_SHELL ${VARDIR}/.refresh $debugging refresh - rc=$? - [ -n "$nolock" ] || mutex_off - else - rc=$? - fi - - return $rc -} - -# -# Safe-start/safe-restart Command Executor -# -safe_commands() { - local finished - finished=0 - - # test is the shell supports timed read - read -t 0 junk 2> /dev/null - if [ $? -eq 2 -a ! -x /bin/bash ];then - echo "Your shell does not support a feature required to execute this command". - exit 2 - fi - - while [ $finished -eq 0 -a $# -gt 0 ]; do - option=$1 - case $option in - -*) - option=${option#-} - - while [ -n "$option" ]; do - case $option in - -) - finished=1 - option= - ;; - n*) - NOROUTES=Yes - option=${option#n} - ;; - *) - usage 1 - ;; - esac - done - shift - ;; - *) - finished=1 - ;; - esac - done - - case $# in - 0) - ;; - 1) - [ -n "$SHOREWALL_DIR" ] && usage 2 - - if [ ! -d $1 ]; then - if [ -e $1 ]; then - echo "$1 is not a directory" >&2 && exit 2 - else - echo "Directory $1 does not exist" >&2 && exit 2 - fi - fi - - SHOREWALL_DIR=$(resolve_file $1) - export SHOREWALL_DIR - ;; - *) - usage 1 - ;; - esac - - [ -n "$STARTUP_ENABLED" ] || fatal_error "Startup is disabled" - - if shorewall_is_started; then - running=Yes - else - running= - fi - - if [ "$COMMAND" = "safe-start" -a -n "$running" ]; then - # the command is safe-start but the firewall is already running - error_message "Shorewall6 is already started" - exit 0 - fi - - if [ "$COMMAND" = "safe-start" -o -z "$running" ]; then - # the command is safe-start or shorewall6 is not started yet - command="start" - else - # the command is safe-restart and the firewall is already running - command="restart" - fi - - progress_message3 "Compiling..." - - if ! compiler run $debugging nolock compile ${VARDIR}/.$command; then - status=$? - exit $status - fi - - case $command in - start) - export RESTOREFILE=NONE - progress_message3 "Starting..." - ;; - restart) - export RESTOREFILE=.safe - RESTOREPATH=${VARDIR}/.safe - save_config - progress_message3 "Restarting..." - ;; - esac - - [ -n "$nolock" ] || mutex_on - - if ${VARDIR}/.$command $command; then - - echo -n "Do you want to accept the new firewall configuration? [y/n] " - - if read_yesno_with_timeout; then - echo "New configuration has been accepted" - else - if [ "$command" = "restart" ]; then - ${VARDIR}/.safe restore - else - ${VARDIR}/.$command clear - fi - - [ -n "$nolock" ] || mutex_off - - echo "New configuration has been rejected and the old one restored" - exit 2 - fi - - fi - - [ -n "$nolock" ] || mutex_off -} - -# -# 'try' Command Executor -# -try_command() { - local finished - finished=0 - local timeout - timeout= - - handle_directory() { - [ -n "$SHOREWALL_DIR" ] && usage 2 - - if [ ! -d $1 ]; then - if [ -e $1 ]; then - echo "$1 is not a directory" >&2 && exit 2 - else - echo "Directory $1 does not exist" >&2 && exit 2 - fi - fi - - SHOREWALL_DIR=$(resolve_file $1) - export SHOREWALL_DIR - } - - while [ $finished -eq 0 -a $# -gt 0 ]; do - option=$1 - case $option in - -*) - option=${option#-} - - while [ -n "$option" ]; do - case $option in - -) - finished=1 - option= - ;; - n*) - NOROUTES=Yes - option=${option#n} - ;; - *) - usage 1 - ;; - esac - done - shift - ;; - *) - finished=1 - ;; - esac - done - - case $# in - 0) - usage 1 - ;; - 1) - handle_directory $1 - ;; - 2) - handle_directory $1 - timeout=$2 - case $timeout in - *[!0-9]*) - echo " ERROR: Invalid timeout ($timeout)" >&2; - exit 1 - ;; - esac - ;; - *) - usage 1 - ;; - esac - - [ -n "$STARTUP_ENABLED" ] || fatal_error "Startup is disabled" - - if shorewall_is_started; then - running=Yes - else - running= - fi - - if [ -z "$running" ]; then - # shorewall6 is not started yet - command="start" - else - # the firewall is already running - command="restart" - fi - - progress_message3 "Compiling..." - - if ! compiler run $debugging $nolock compile ${VARDIR}/.$command; then - status=$? - exit $status - fi - - case $command in - start) - export RESTOREFILE=NONE - progress_message3 "Starting..." - ;; - restart) - export RESTOREFILE=.try - RESTOREPATH=${VARDIR}/.try - save_config - progress_message3 "Restarting..." - ;; - esac - - [ -n "$nolock" ] || mutex_on - - if ${VARDIR}/.$command $command && [ -n "$timeout" ]; then - sleep $timeout - - if [ "$command" = "restart" ]; then - ${VARDIR}/.try restore - else - ${VARDIR}/.$command clear - fi - fi - - [ -n "$nolock" ] || mutex_off - - return 0 -} - -rsh_command() { - command="$*" - - eval $RSH_COMMAND -} - -rcp_command() { - files="$1" - destination=$2 - - eval $RCP_COMMAND -} - -# -# [Re]load command executor -# -reload_command() # $* = original arguments less the command. -{ - local verbose - verbose=$(make_verbose) - local file - file= - local capabilities - capabilities= - local finished - finished=0 - local saveit - saveit= - local result - local directory - local system - local getcaps - getcaps= - local root - root=root - local compiler - compiler= - - LITEDIR=/var/lib/shorewall-lite - - while [ $finished -eq 0 -a $# -gt 0 ]; do - option=$1 - case $option in - -*) - option=${option#-} - - while [ -n "$option" ]; do - case $option in - -) - finished=1 - option= - ;; - s*) - saveit=Yes - option=${option#s} - ;; - c*) - getcaps=Yes - option=${option#c} - ;; - r) - [ $# -gt 1 ] || fatal_error "Missing Root User name" - root=$2 - option= - shift - ;; - *) - usage 1 - ;; - esac - done - shift - ;; - *) - finished=1 - ;; - esac - done - - case $# in - 1) - directory="." - system=$1 - ;; - 2) - directory=$1 - system=$2 - ;; - *) - usage 1 - ;; - esac - - litedir=$(rsh_command /sbin/shorewall6-lite show config 2> /dev/null | grep ^LITEDIR | sed 's/LITEDIR is //') - - [ -n "$litedir" ] && LITEDIR=$litedir - - if [ -z "$getcaps" ]; then - SHOREWALL_DIR=$(resolve_file $directory) - ensure_config_path - capabilities=$(find_file capabilities) - [ -f $capabilities ] || getcaps=Yes - fi - - if [ -n "$getcaps" ]; then - if [ -f $directory/shorewall6.conf ]; then - . $directory/shorewall6.conf - ensure_config_path - fi - - progress_message "Getting Capabilities on system $system..." - if ! rsh_command "MODULESDIR=$MODULESDIR MODULE_SUFFIX=\"$MODULE_SUFFIX\" IP6TABLES=$IP6TABLES /usr/share/shorewall6-lite/shorecap" > $directory/capabilities; then - fatal_error "ERROR: Capturing capabilities on system $system failed" - fi - fi - - file=$(resolve_file $directory/firewall) - - if shorewall6 $debugging $verbose compile -e $directory $directory/firewall && \ - progress_message "Copying $file and ${file}.conf to ${system}:${LITEDIR}..." && \ - rcp_command "$directory/firewall $directory/firewall.conf" ${LITEDIR} - then - echo "Copy complete" - if [ $COMMAND = reload ]; then - rsh_command "/sbin/shorewall6-lite $debugging $verbose restart" && \ - progress_message3 "System $system reloaded" || saveit= - else - rsh_command "/sbin/shorewall6-lite $debugging $verbose start" && \ - progress_message3 "System $system loaded" || saveit= - fi - - if [ -n "$saveit" ]; then - rsh_command "/sbin/shorewall6-lite $debugging $verbose save" && \ - progress_message3 "Configuration on system $system saved" - fi - fi -} - -# -# Export command executor -# -export_command() # $* = original arguments less the command. -{ - local verbose - verbose=$(make_verbose) file= finished=0 directory target compiler= - - while [ $finished -eq 0 -a $# -gt 0 ]; do - option=$1 - case $option in - -*) - option=${option#-} - - while [ -n "$option" ]; do - case $option in - -) - finished=1 - option= - ;; - *) - fatal_error "Unrecognized option \"$option\"" - ;; - esac - done - shift - ;; - *) - finished=1 - ;; - esac - done - - case $# in - 1) - directory="." - target=$1 - ;; - 2) - directory=$1 - target=$2 - ;; - *) - fatal_error "ERROR: Invalid command syntax (\"man shorewall6\" for help)" - ;; - esac - - case $target in - *:*) - ;; - *) - target=$target: - ;; - esac - - file=$(resolve_file $directory/firewall) - - if shorewall6 $debugging $verbose compile -e $directory $directory/firewall && \ - echo "Copying $file and ${file}.conf to ${target#*@}..." && \ - scp $directory/firewall $directory/firewall.conf $target - then - progress_message3 "Copy complete" - fi -} - -# -# Give Usage Information -# -usage() # $1 = exit status -{ - echo "Usage: $(basename $0) [debug|trace] [nolock] [ -q ] [ -v ] [ -t ] " - echo "where is one of:" - echo " allow
..." - echo " check [ -e ] [ ]" - echo " clear [ -f ]" - echo " compile [ -e ] [ ] " - echo " drop
..." - echo " dump [ -x ]" - echo " export [ -C {shell|perl} ] [ ] [@][:]" - echo " forget [ ]" - echo " help" - echo " load [ -s ] [ -c ] [ -r ] [ -C {shell|perl} ] [ ] " - echo " logdrop
..." - echo " logreject
..." - echo " logwatch []" - echo " refresh [ ... ]" - echo " reject
..." - echo " reload [ -s ] [ -c ] [ -r ] [ ] " - echo " reset" - echo " restart [ -n ] [ -C {shell|perl} ] [ ]" - echo " restore [ -n ] [ ]" - echo " save [ ]" - echo " show [ -x ] [ -m ] [-f] [ -t {filter|mangle|nat} ] [ {chain [ [ ... ]|actions|capabilities|classifiers|config|connections|ip|log|macros|mangle|routing|tc|zones} ]" - echo " start [ -f ] [ -n ] [ ]" - echo " stop [ -f ]" - echo " status" - echo " try [ ]" - echo " version [ -a ]" - echo " safe-start [ ]" - echo " safe-restart [ ]" - echo - exit $1 -} - -# -# Execution begins here -# -debugging= - -if [ $# -gt 0 ] && [ "x$1" = "xdebug" -o "x$1" = "xtrace" ]; then - debugging=debug - shift -fi - -nolock= - -if [ $# -gt 0 ] && [ "$1" = "nolock" ]; then - nolock=nolock - shift -fi - -SHOREWALL_DIR= -IPT_OPTIONS="-nv" -FAST= -VERBOSE_OFFSET=0 -NOROUTES= -EXPORT= -export TIMESTAMP= -noroutes= - -finished=0 - -while [ $finished -eq 0 ]; do - [ $# -eq 0 ] && usage 1 - option=$1 - case $option in - -) - finished=1 - ;; - -*) - option=${option#-} - - while [ -n "$option" ]; do - case $option in - c) - [ $# -eq 1 ] && usage 1 - - if [ ! -d $2 ]; then - if [ -e $2 ]; then - echo "$2 is not a directory" >&2 && exit 2 - else - echo "Directory $2 does not exist" >&2 && exit 2 - fi - fi - - SHOREWALL_DIR=$(resolve_file $2) - option= - shift - ;; - e*) - EXPORT=Yes - option=${option#e} - ;; - x*) - IPT_OPTIONS="-xnv" - option=${option#x} - ;; - q*) - VERBOSE_OFFSET=$(($VERBOSE_OFFSET - 1 )) - option=${option#q} - ;; - f*) - FAST=Yes - option=${option#f} - ;; - v*) - VERBOSE_OFFSET=$(($VERBOSE_OFFSET + 1 )) - option=${option#v} - ;; - n*) - NOROUTES=Yes - option=${option#n} - ;; - t*) - TIMESTAMP=Yes - option=${option#t} - ;; - -) - finished=1 - option= - ;; - *) - usage 1 - ;; - esac - done - shift - ;; - *) - finished=1 - ;; - esac -done - -version_command() { - local finished - finished=0 - local all - all= - - while [ $finished -eq 0 -a $# -gt 0 ]; do - option=$1 - case $option in - -*) - option=${option#-} - - while [ -n "$option" ]; do - case $option in - -) - finished=1 - option= - ;; - a*) - all=Yes - option=${option#a} - ;; - *) - usage 1 - ;; - esac - done - shift - ;; - *) - finished=1 - ;; - esac - done - - [ $# -gt 0 ] && usage 1 - - echo $version -} - -if [ $# -eq 0 ]; then - usage 1 -fi - -[ -n "$SHOREWALL_DIR" ] && export SHOREWALL_DIR -PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin -MUTEX_TIMEOUT= - -SHAREDIR=/usr/share/shorewall6 -CONFDIR=/etc/shorewall6 -export PRODUCT="Shorewall6" - -[ -f ${CONFDIR}/vardir ] && . ${CONFDIR}/vardir - -[ -n "${VARDIR:=/var/lib/shorewall6}" ] - -FIREWALL=$SHAREDIR/firewall -LIBRARIES="$SHAREDIR/lib.base $SHAREDIR/lib.cli" -VERSION_FILE=$SHAREDIR/version -REFRESHCHAINS= - -for library in $LIBRARIES; do - if [ -f $library ]; then - . $library - else - echo "$library does not exist!" >&2 - exit 2 - fi -done - -if [ ! -f $FIREWALL ]; then - echo " ERROR: Shorewall6 is not properly installed" >&2 - if [ -L $FIREWALL ]; then - echo " $FIREWALL is a symbolic link to a" >&2 - echo " non-existant file" >&2 - else - echo " The file $FIREWALL does not exist" >&2 - fi - - exit 2 -fi - -if [ -f $VERSION_FILE ]; then - version=$(cat $VERSION_FILE) -else - echo " ERROR: Shorewall6 is not properly installed" >&2 - echo " The file $VERSION_FILE does not exist" >&2 - exit 1 -fi - -banner="Shorewall6-$version Status at $HOSTNAME -" - -case $(echo -e) in - -e*) - RING_BELL="echo \a" - ;; - *) - RING_BELL="echo -e \a" - ;; -esac - -case $(echo -n "Testing") in - -n*) - ECHO_N= - ;; - *) - ECHO_N=-n - ;; -esac - -COMMAND=$1 - -case "$COMMAND" in - start) - get_config Yes Yes - shift - start_command $@ - ;; - stop|clear) - if [ "x$2" = x-f ]; then - [ -x ${VARDIR}/.restore ] && FIREWALL=${VARDIR}/.restore - shift; - fi - - [ $# -ne 1 ] && usage 1 - get_config - export NOROUTES - mutex_on - $SHOREWALL_SHELL $FIREWALL $debugging $nolock $COMMAND - mutex_off - ;; - reset) - [ $# -ne 1 ] && usage 1 - get_config - export NOROUTES - mutex_on - $SHOREWALL_SHELL $FIREWALL $debugging $nolock reset - mutex_off - ;; - compile) - get_config Yes - shift - compile_command $@ - ;; - restart) - get_config Yes Yes - shift - restart_command $@ - ;; - refresh) - get_config Yes Yes - shift - refresh_command $@ - ;; - check) - get_config Yes - shift - check_command $@ - ;; - show|list) - get_config Yes No Yes - shift - show_command $@ - ;; - load|reload) - get_config Yes - shift - reload_command $@ - ;; - export) - get_config Yes - shift - export_command $@ - ;; - status) - [ $# -eq 1 ] || usage 1 - get_config - echo "Shorewall6-$version Status at $HOSTNAME - $(date)" - echo - if shorewall_is_started ; then - echo "Shorewall6 is running" - status=0 - else - echo "Shorewall6 is stopped" - status=4 - fi - - if [ -f ${VARDIR}/state ]; then - state="$(cat ${VARDIR}/state)" - case $state in - Stopped*|Clear*) - status=3 - ;; - esac - else - state=Unknown - fi - echo "State:$state" - echo - exit $status - ;; - dump) - get_config Yes No Yes - shift - dump_command $@ - ;; - version) - shift - version_command $@ - ;; - try) - get_config Yes - shift - try_command $@ - ;; - logwatch) - get_config Yes Yes Yes - banner="Shorewall6-$version Logwatch at $HOSTNAME -" - logwatch_command $@ - ;; - drop) - get_config - [ -n "$debugging" ] && set -x - [ $# -eq 1 ] && usage 1 - if shorewall_is_started ; then - [ -n "$nolock" ] || mutex_on - block DROP Dropped $* - [ -n "$nolock" ] || mutex_off - else - fatal_error "Shorewall6 is not started" - fi - ;; - logdrop) - get_config - [ -n "$debugging" ] && set -x - [ $# -eq 1 ] && usage 1 - if shorewall_is_started ; then - [ -n "$nolock" ] || mutex_on - block logdrop Dropped $* - [ -n "$nolock" ] || mutex_off - else - fatal_error "Shorewall6 is not started" - fi - ;; - reject|logreject) - get_config - [ -n "$debugging" ] && set -x - [ $# -eq 1 ] && usage 1 - if shorewall_is_started ; then - [ -n "$nolock" ] || mutex_on - block $COMMAND Rejected $* - [ -n "$nolock" ] || mutex_off - else - fatal_error "Shorewall6 is not started" - fi - ;; - allow) - get_config - allow_command $@ - ;; - save) - get_config - [ -n "$debugging" ] && set -x - - case $# in - 1) - ;; - 2) - RESTOREFILE="$2" - validate_restorefile '' - ;; - *) - usage 1 - ;; - esac - - RESTOREPATH=${VARDIR}/$RESTOREFILE - - [ -n "$nolock" ] || mutex_on - - save_config - - result=$? - - [ -n "$nolock" ] || mutex_off - - exit $result - ;; - forget) - get_config - case $# in - 1) - ;; - 2) - RESTOREFILE="$2" - validate_restorefile '' - ;; - *) - usage 1 - ;; - esac - - - RESTOREPATH=${VARDIR}/$RESTOREFILE - - if [ -x $RESTOREPATH ]; then - rm -f $RESTOREPATH - rm -f ${RESTOREPATH}-ip6tables - echo " $RESTOREPATH removed" - elif [ -f $RESTOREPATH ]; then - echo " $RESTOREPATH exists and is not a saved Shorewall6 configuration" - fi - rm -f ${VARDIR}/save - ;; - restore) - get_config - shift - restore_command $@ - ;; - help) - shift - usage - ;; - safe-restart|safe-start) - get_config Yes - shift - safe_commands $@ - ;; - *) - usage 1 - ;; - -esac