diff --git a/Shorewall/Perl/Shorewall/Compiler.pm b/Shorewall/Perl/Shorewall/Compiler.pm index 30f5cc6ed..f64899f33 100644 --- a/Shorewall/Perl/Shorewall/Compiler.pm +++ b/Shorewall/Perl/Shorewall/Compiler.pm @@ -779,7 +779,7 @@ sub compiler { # # Setup Masquerade/SNAT # - setup_snat( $update ); + setup_snat; # # Setup Nat # diff --git a/Shorewall/Perl/Shorewall/Nat.pm b/Shorewall/Perl/Shorewall/Nat.pm index 73f2c07c9..a34ddb34e 100644 --- a/Shorewall/Perl/Shorewall/Nat.pm +++ b/Shorewall/Perl/Shorewall/Nat.pm @@ -22,8 +22,8 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, see . # -# This module contains code for dealing with the /etc/shorewall/masq, -# /etc/shorewall/nat and /etc/shorewall/netmap files. +# This module contains code for dealing with the /etc/shorewall/nat and +# /etc/shorewall/netmap files. # package Shorewall::Nat; require Exporter; @@ -37,7 +37,7 @@ use strict; our @ISA = qw(Exporter); our @EXPORT = qw( setup_nat setup_netmap add_addresses ); -our %EXPORT_TAGS = ( rules => [ qw ( handle_nat_rule handle_nonat_rule process_one_masq convert_masq @addresses_to_add %addresses_to_add ) ] ); +our %EXPORT_TAGS = ( rules => [ qw ( handle_nat_rule handle_nonat_rule convert_masq @addresses_to_add %addresses_to_add ) ] ); our @EXPORT_OK = (); Exporter::export_ok_tags('rules'); @@ -57,351 +57,6 @@ sub initialize($) { %addresses_to_add = (); } -# -# Process a single rule from the the masq file -# -sub process_one_masq1( $$$$$$$$$$$ ) -{ - my ( $interfacelist, $networks, $addresses, $proto, $ports, $ipsec, $mark, $user, $condition, $origdest, $probability ) = @_; - - my $pre_nat; - my $add_snat_aliases = $family == F_IPV4 && $config{ADD_SNAT_ALIASES}; - my $destnets = ''; - my $baserule = ''; - my $inlinematches = ''; - my $prerule = ''; - my $savelist; - # - # Leading '+' - # - $pre_nat = 1 if $interfacelist =~ s/^\+//; - - # - # Check for INLINE - # - if ( $interfacelist =~ /^INLINE\((.+)\)$/ ) { - $interfacelist = $1; - $inlinematches = get_inline_matches(0); - } else { - $inlinematches = get_inline_matches(0); - } - - $savelist = $interfacelist; - # - # Handle early matches - # - if ( $inlinematches =~ s/s*\+// ) { - $prerule = $inlinematches; - $inlinematches = ''; - } - # - # Parse the remaining part of the INTERFACE column - # - if ( $family == F_IPV4 ) { - if ( $interfacelist =~ /^([^:]+)::([^:]*)$/ ) { - $add_snat_aliases = 0; - $destnets = $2; - $interfacelist = $1; - } elsif ( $interfacelist =~ /^([^:]+:[^:]+):([^:]+)$/ ) { - $destnets = $2; - $interfacelist = $1; - } elsif ( $interfacelist =~ /^([^:]+):$/ ) { - $add_snat_aliases = 0; - $interfacelist = $1; - } elsif ( $interfacelist =~ /^([^:]+):([^:]*)$/ ) { - my ( $one, $two ) = ( $1, $2 ); - if ( $2 =~ /\./ || $2 =~ /^%/ ) { - $interfacelist = $one; - $destnets = $two; - } - } - } elsif ( $interfacelist =~ /^(.+?):(.+)$/ ) { - $interfacelist = $1; - $destnets = $2; - } - # - # If there is no source or destination then allow all addresses - # - $networks = ALLIP if $networks eq '-'; - $destnets = ALLIP if $destnets eq '-'; - - # - # Handle IPSEC options, if any - # - if ( $ipsec ne '-' ) { - fatal_error "Non-empty IPSEC column requires policy match support in your kernel and iptables" unless have_capability( 'POLICY_MATCH' ); - - if ( $ipsec =~ /^yes$/i ) { - $baserule .= do_ipsec_options 'out', 'ipsec', ''; - } elsif ( $ipsec =~ /^no$/i ) { - $baserule .= do_ipsec_options 'out', 'none', ''; - } else { - $baserule .= do_ipsec_options 'out', 'ipsec', $ipsec; - } - } elsif ( have_ipsec ) { - $baserule .= '-m policy --pol none --dir out '; - } - - # - # Handle Protocol, Ports and Condition - # - $baserule .= do_proto( $proto, $ports, '' ); - # - # Handle Mark - # - $baserule .= do_test( $mark, $globals{TC_MASK} ) if $mark ne '-'; - $baserule .= do_user( $user ) if $user ne '-'; - $baserule .= do_probability( $probability ) if $probability ne '-'; - - my $target; - - for my $fullinterface (split_list $interfacelist, 'interface' ) { - my $rule = ''; - - $target = 'MASQUERADE '; - # - # Isolate and verify the interface part - # - ( my $interface = $fullinterface ) =~ s/:.*//; - - if ( $interface =~ /(.*)[(](\w*)[)]$/ ) { - $interface = $1; - my $provider = $2; - - fatal_error "Missing Provider ($fullinterface)" unless supplied $provider; - - $fullinterface =~ s/[(]\w*[)]//; - my $realm = provider_realm( $provider ); - - fatal_error "$provider is not a shared-interface provider" unless $realm; - - $rule .= "-m realm --realm $realm "; - } - - fatal_error "Unknown interface ($interface)" unless my $interfaceref = known_interface( $interface ); - - if ( $interfaceref->{root} ) { - $interface = $interfaceref->{name} if $interface eq $interfaceref->{physical}; - } else { - $rule .= match_dest_dev( $interface ); - $interface = $interfaceref->{name}; - } - - my $chainref = ensure_chain('nat', $pre_nat ? snat_chain $interface : masq_chain $interface); - - $baserule .= do_condition( $condition , $chainref->{name} ); - - my $detectaddress = 0; - my $exceptionrule = ''; - my $randomize = ''; - my $persistent = ''; - my $conditional = 0; - # - # Parse the ADDRESSES column - # - if ( $addresses ne '-' ) { - my $saveaddresses = $addresses; - if ( $addresses eq 'random' ) { - require_capability( 'MASQUERADE_TGT', 'Masquerade rules', '') if $family == F_IPV6; - $randomize = '--random '; - } else { - $addresses =~ s/:persistent$// and $persistent = ' --persistent '; - $addresses =~ s/:random$// and $randomize = ' --random '; - - require_capability 'PERSISTENT_SNAT', ':persistent', 's' if $persistent; - - if ( $addresses =~ /^SAME/ ) { - fatal_error "The SAME target is no longer supported"; - } elsif ( $addresses eq 'detect' ) { - my $variable = get_interface_address $interface; - $target = "SNAT --to-source $variable"; - - if ( interface_is_optional $interface ) { - add_commands( $chainref, - '', - "if [ \"$variable\" != 0.0.0.0 ]; then" ); - incr_cmd_level( $chainref ); - $detectaddress = 1; - } - } elsif ( $addresses eq 'NONAT' ) { - fatal_error "'persistent' may not be specified with 'NONAT'" if $persistent; - fatal_error "'random' may not be specified with 'NONAT'" if $randomize; - $target = 'RETURN'; - $add_snat_aliases = 0; - } elsif ( $addresses ) { - my $addrlist = ''; - my @addrs = split_list $addresses, 'address'; - - fatal_error "Only one ADDRESS may be specified" if @addrs > 1; - - for my $addr ( @addrs ) { - if ( $addr =~ /^([&%])(.+)$/ ) { - my ( $type, $interface ) = ( $1, $2 ); - - my $ports = ''; - - if ( $interface =~ s/:(.+)$// ) { - validate_portpair1( $proto, $1 ); - $ports = ":$1"; - } - # - # Address Variable - # - $target = 'SNAT '; - - if ( $interface =~ /^{([a-zA-Z_]\w*)}$/ ) { - # - # User-defined address variable - # - $conditional = conditional_rule( $chainref, $addr ); - $addrlist .= '--to-source ' . "\$${1}${ports} "; - } else { - if ( $conditional = conditional_rule( $chainref, $addr ) ) { - # - # Optional Interface -- rule is conditional - # - $addr = get_interface_address $interface; - } else { - # - # Interface is not optional - # - $addr = record_runtime_address( $type, $interface ); - } - - if ( $ports ) { - $addr =~ s/ $//; - $addr = $family == F_IPV4 ? "${addr}${ports} " : "[$addr]$ports "; - } - - $addrlist .= '--to-source ' . $addr; - } - } elsif ( $family == F_IPV4 ) { - if ( $addr =~ /^.*\..*\..*\./ ) { - $target = 'SNAT '; - my ($ipaddr, $rest) = split ':', $addr, 2; - if ( $ipaddr =~ /^(.+)-(.+)$/ ) { - validate_range( $1, $2 ); - } else { - validate_address $ipaddr, 0; - } - - if ( supplied $rest ) { - validate_portpair1( $proto, $rest ); - $addrlist .= "--to-source $addr "; - } else { - $addrlist .= "--to-source $ipaddr"; - } - - $exceptionrule = do_proto( $proto, '', '' ) if $addr =~ /:/; - } else { - my $ports = $addr; - $ports =~ s/^://; - validate_portpair1( $proto, $ports ); - $addrlist .= "--to-ports $ports "; - $exceptionrule = do_proto( $proto, '', '' ); - } - } else { - $target = 'SNAT '; - - if ( $addr =~ /^\[/ ) { - # - # Can have ports specified - # - my $ports; - - if ( $addr =~ s/:([^]:]+)$// ) { - $ports = $1; - } - - fatal_error "Invalid IPv6 Address ($addr)" unless $addr =~ /^\[(.+)\]$/; - - $addr = $1; - - if ( $addr =~ /^(.+)-(.+)$/ ) { - fatal_error "Correct address range syntax is '[-]'" if $addr =~ /]-\[/; - validate_range( $1, $2 ); - } else { - validate_address $addr, 0; - } - - if ( supplied $ports ) { - validate_portpair1( $proto, $ports ); - $exceptionrule = do_proto( $proto, '', '' ); - $addr = "[$addr]:$ports"; - } - - $addrlist .= "--to-source $addr "; - } else { - if ( $addr =~ /^(.+)-(.+)$/ ) { - validate_range( $1, $2 ); - } else { - validate_address $addr, 0; - } - - $addrlist .= "--to-source $addr "; - } - } - } - - $target .= $addrlist; - } else { - fatal_error( "':persistent' is not allowed in a MASQUERADE rule" ) if $persistent; - require_capability( 'MASQUERADE_TGT', 'Masquerade rules', '' ) if $family == F_IPV6; - } - } - - $target .= $randomize; - $target .= $persistent; - $addresses = $saveaddresses; - } else { - require_capability( 'MASQUERADE_TGT', 'Masquerade rules', '' ) if $family == F_IPV6; - $add_snat_aliases = 0; - } - # - # And Generate the Rule(s) - # - expand_rule( $chainref , - POSTROUTE_RESTRICT , - $prerule , - $baserule . $inlinematches . $rule , - $networks , - $destnets , - $origdest , - $target , - '' , - '' , - $exceptionrule , - '' ) - unless unreachable_warning( 0, $chainref ); - - conditional_rule_end( $chainref ) if $detectaddress || $conditional; - - if ( $add_snat_aliases ) { - my ( $interface, $alias , $remainder ) = split( /:/, $fullinterface, 3 ); - fatal_error "Invalid alias ($alias:$remainder)" if defined $remainder; - for my $address ( split_list $addresses, 'address' ) { - my ( $addrs, $port ) = split /:/, $address; - next unless $addrs; - next if $addrs eq 'detect'; - for my $addr ( ip_range_explicit $addrs ) { - unless ( $addresses_to_add{$addr} ) { - $addresses_to_add{$addr} = 1; - if ( defined $alias ) { - push @addresses_to_add, $addr, "$interface:$alias"; - $alias++; - } else { - push @addresses_to_add, $addr, $interface; - } - } - } - } - } - } - - progress_message " Masq record \"$currentline\" $done"; - -} - sub convert_one_masq1( $$$$$$$$$$$$ ) { my ( $snat, $interfacelist, $networks, $addresses, $proto, $ports, $ipsec, $mark, $user, $condition, $origdest, $probability ) = @_; @@ -499,48 +154,9 @@ sub convert_one_masq1( $$$$$$$$$$$$ ) print $snat "$line\n"; } - progress_message " Masq record \"$rawcurrentline\" Converted"; } -sub process_one_masq( $ ) -{ - my ( $snat ) = @_; - - if ( $snat ) { - unless ( $rawcurrentline =~ /^\s*(?:#.*)?$/ ) { - # - # Line was not blank or all comment - # - my ($interfacelist, $networks, $addresses, $protos, $ports, $ipsec, $mark, $user, $condition, $origdest, $probability ) = - split_rawline2( 'masq file', - { interface => 0, source => 1, address => 2, proto => 3, port => 4, ipsec => 5, mark => 6, user => 7, switch => 8, origdest => 9, probability => 10 }, - {}, #Nopad - undef, #Columns - 1 ); #Allow inline matches - - if ( $interfacelist ne '-' ) { - for my $proto ( split_list $protos, 'Protocol' ) { - convert_one_masq1( $snat, $interfacelist, $networks, $addresses, $proto, $ports, $ipsec, $mark, $user, $condition, $origdest, $probability ); - } - } - } - } else { - my ($interfacelist, $networks, $addresses, $protos, $ports, $ipsec, $mark, $user, $condition, $origdest, $probability ) = - split_line2( 'masq file', - { interface => 0, source => 1, address => 2, proto => 3, port => 4, ipsec => 5, mark => 6, user => 7, switch => 8, origdest => 9, probability => 10 }, - {}, #Nopad - undef, #Columns - 1 ); #Allow inline matches - - fatal_error 'INTERFACE must be specified' if $interfacelist eq '-'; - - for my $proto ( split_list $protos, 'Protocol' ) { - process_one_masq1( $interfacelist, $networks, $addresses, $proto, $ports, $ipsec, $mark, $user, $condition, $origdest, $probability ); - } - } -} - sub open_snat_for_output( $ ) { my ($fn ) = @_; my ( $snat, $fn1 ); diff --git a/Shorewall/Perl/Shorewall/Rules.pm b/Shorewall/Perl/Shorewall/Rules.pm index 50beaa442..9ee14b25b 100644 --- a/Shorewall/Perl/Shorewall/Rules.pm +++ b/Shorewall/Perl/Shorewall/Rules.pm @@ -5851,28 +5851,17 @@ sub process_snat( ) } # -# Process the masq or snat file +# Process snat file - If a masq file exists, convert it before processing snat # -sub setup_snat( $ ) # Convert masq->snat if true +sub setup_snat() { my $fn; - my $have_masq; - if ( $_[0] ) { - convert_masq(); - } elsif ( $fn = open_file( 'masq', 1, 1 ) ) { - first_entry( sub { progress_message2 "$doing $fn..."; require_capability 'NAT_ENABLED' , "a non-empty masq file" , 's'; } ); - process_one_masq(0), $have_masq = 1 while read_a_line( NORMAL_READ ); - } + convert_masq(); - unless ( $have_masq ) { - # - # Masq file empty or didn't exist - # - if ( $fn = open_file( 'snat', 1, 1 ) ) { - first_entry( sub { progress_message2 "$doing $fn..."; require_capability 'NAT_ENABLED' , "a non-empty snat file" , 's'; } ); - process_snat while read_a_line( NORMAL_READ ); - } + if ( $fn = open_file( 'snat', 1, 1 ) ) { + first_entry( sub { progress_message2 "$doing $fn..."; require_capability 'NAT_ENABLED' , "a non-empty snat file" , 's'; } ); + process_snat while read_a_line( NORMAL_READ ); } }