Implement INPUT SNAT

Signed-off-by: Tom Eastep <teastep@shorewall.net>
This commit is contained in:
Tom Eastep 2018-01-22 14:38:25 -08:00
parent 3bf5066f82
commit a9a379c5a5
No known key found for this signature in database
GPG Key ID: 96E6B3F2423A4D10
5 changed files with 96 additions and 52 deletions

View File

@ -25,7 +25,7 @@
# loaded after this one and replaces some of the functions declared here.
#
SHOREWALL_CAPVERSION=50106
SHOREWALL_CAPVERSION=50112
if [ -z "$g_basedir" ]; then
#
@ -2863,6 +2863,7 @@ determine_capabilities() {
qt $g_tool -t nat -A $chain -j NETMAP --to 2001:470:B:227::/64 && NETMAP_TARGET=Yes
fi
qt $g_tool -t nat -A $chain -j MASQUERADE && MASQUERADE_TGT=Yes
qt $g_tool -t nat -L INPUT -n && NAT_INPUT_CHAIN=Yes
qt $g_tool -t nat -A $chain -p udplite -m multiport --dport 33 -j REDIRECT --to-port 22 && UDPREDIRECT=Yes
qt $g_tool -t nat -F $chain
qt $g_tool -t nat -X $chain
@ -3331,6 +3332,7 @@ report_capabilities_unsorted() {
report_capability "NFQUEUE CPU Fanout (CPU_FANOUT)" $CPU_FANOUT
report_capability "NETMAP Target (NETMAP_TARGET)" $NETMAP_TARGET
report_capability "--nflog-size support (NFLOG_SIZE)" $NFLOG_SIZE
report_capability "INPUT chain in nat table (NAT_INPUT_CHAIN)" $NAT_INPUT_CHAIN
echo " Kernel Version (KERNELVERSION): $KERNELVERSION"
echo " Capabilities Version (CAPVERSION): $CAPVERSION"
@ -3439,6 +3441,7 @@ report_capabilities_unsorted1() {
report_capability1 NETMAP_TARGET
report_capability1 NFLOG_SIZE
report_capability1 RESTORE_WAIT_OPTION
report_capability1 NAT_INPUT_CHAIN
report_capability1 AMANDA_HELPER
report_capability1 FTP_HELPER

View File

@ -3182,6 +3182,8 @@ sub initialize_chain_table($) {
new_builtin_chain 'nat', $chain, 'ACCEPT';
}
new_builtin_chain 'nat', 'INPUT', 'ACCEPT' if have_capability('NAT_INPUT_CHAIN');
for my $chain ( qw(PREROUTING INPUT OUTPUT ) ) {
new_builtin_chain 'mangle', $chain, 'ACCEPT';
}
@ -3244,6 +3246,8 @@ sub initialize_chain_table($) {
new_builtin_chain 'nat', $chain, 'ACCEPT';
}
new_builtin_chain 'nat', 'INPUT', 'ACCEPT' if have_capability('NAT_INPUT_CHAIN');
for my $chain ( qw(PREROUTING INPUT OUTPUT FORWARD POSTROUTING ) ) {
new_builtin_chain 'mangle', $chain, 'ACCEPT';
}

View File

@ -496,6 +496,7 @@ our %capdesc = ( NAT_ENABLED => 'NAT',
NFLOG_SIZE => '--nflog-size support',
RESTORE_WAIT_OPTION
=> 'iptables-restore --wait option',
NAT_INPUT_CHAIN => 'INPUT chain in NAT table',
AMANDA_HELPER => 'Amanda Helper',
FTP_HELPER => 'FTP Helper',
FTP0_HELPER => 'FTP-0 Helper',
@ -835,7 +836,7 @@ sub initialize( $;$$$) {
EXPORT => 0,
KLUDGEFREE => '',
VERSION => "5.1.8-Beta1",
CAPVERSION => 50106 ,
CAPVERSION => 50112 ,
BLACKLIST_LOG_TAG => '',
RELATED_LOG_TAG => '',
MACLIST_LOG_TAG => '',
@ -1129,6 +1130,7 @@ sub initialize( $;$$$) {
NETMAP_TARGET => undef,
NFLOG_SIZE => undef,
RESTORE_WAIT_OPTION => undef,
NAT_INPUT_CHAIN => undef,
AMANDA_HELPER => undef,
FTP_HELPER => undef,
@ -4446,6 +4448,12 @@ sub Nat_Enabled() {
qt1( "$iptables $iptablesw -t nat -L -n" );
}
sub Nat_Input_Chain {
have_capability( 'NAT_ENABLED' ) || return '';
qt1( "$iptables $iptablesw -t nat -L INPUT -n" );
}
sub Persistent_Snat() {
have_capability( 'NAT_ENABLED' ) || return '';
@ -5091,6 +5099,7 @@ our %detect_capability =
MASQUERADE_TGT => \&Masquerade_Tgt,
MULTIPORT => \&Multiport,
NAT_ENABLED => \&Nat_Enabled,
NAT_INPUT_CHAIN => \&Nat_Input_Chain,
NETBIOS_NS_HELPER => \&Netbios_ns_Helper,
NETMAP_TARGET => \&Netmap_Target,
NEW_CONNTRACK_MATCH => \&New_Conntrack_Match,
@ -5190,6 +5199,7 @@ sub determine_capabilities() {
#
$capabilities{NAT_ENABLED} = detect_capability( 'NAT_ENABLED' );
$capabilities{PERSISTENT_SNAT} = detect_capability( 'PERSISTENT_SNAT' );
$capabilities{NAT_INPUT_CHAIN} = detect_capability( 'NAT_INPUT_CHAIN' );
$capabilities{MANGLE_ENABLED} = detect_capability( 'MANGLE_ENABLED' );
if ( $capabilities{CONNTRACK_MATCH} = detect_capability( 'CONNTRACK_MATCH' ) ) {

View File

@ -5501,22 +5501,6 @@ sub process_snat1( $$$$$$$$$$$$ ) {
$interfaces = $dest;
}
#
# 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, '' );
@ -5527,7 +5511,9 @@ sub process_snat1( $$$$$$$$$$$$ ) {
$baserule .= do_user( $user ) if $user ne '-';
$baserule .= do_probability( $probability ) if $probability ne '-';
for my $fullinterface ( split_list( $interfaces, 'interface' ) ) {
my @interfaces = split_list( $interfaces, 'interface' );
for my $fullinterface ( @interfaces ) {
my $rule = '';
my $saveaddresses = $addresses;
@ -5535,36 +5521,71 @@ sub process_snat1( $$$$$$$$$$$$ ) {
my $savebaserule = $baserule;
my $interface = $fullinterface;
$interface =~ s/:.*//; #interface name may include 'alias'
unless ( $inaction ) {
if ( $interface =~ /(.*)[(](\w*)[)]$/ ) {
$interface = $1;
my $provider = $2;
fatal_error "Missing Provider ($dest)" unless supplied $provider;
$dest =~ 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};
if ( $inaction ) {
$interface =~ s/:.*// if $family == F_IPV4; #interface name may include 'alias'
} else {
if ( $interface eq firewall_zone ) {
if ( @interfaces == 1 ) {
fatal_error q('+' not valid when the DEST is $FW) if $pre_nat;
fatal_error q('MASQUERADE' not allowed when DEST is $FW) if $action eq 'MASQUERADE';
require_capability 'NAT_INPUT_CHAIN', '$FW in the DEST column', 's';
$interface = '';
} else {
fatal_error q($FW may not appear in a list of interfaces);
}
} else {
$rule .= match_dest_dev( $interface );
$interface = $interfaceref->{name};
$interface =~ s/:.*// if $family == F_IPV4; #interface name may include 'alias'
if ( $interface =~ /(.*)[(](\w*)[)]$/ ) {
$interface = $1;
my $provider = $2;
fatal_error "Missing Provider ($dest)" unless supplied $provider;
$dest =~ 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};
}
}
$chainref = ensure_chain('nat', $pre_nat ? snat_chain $interface : masq_chain $interface);
$chainref = $interface ? ensure_chain('nat', $pre_nat ? snat_chain $interface : masq_chain $interface) : $nat_table->{INPUT};
}
$baserule .= do_condition( $condition , $chainref->{name} );
#
# 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' );
my $dir = $interface ? 'out' : 'in';
if ( $ipsec =~ /^yes$/i ) {
$baserule .= do_ipsec_options $dir, 'ipsec', '';
} elsif ( $ipsec =~ /^no$/i ) {
$baserule .= do_ipsec_options $dir, 'none', '';
} else {
$baserule .= do_ipsec_options $dir, 'ipsec', $ipsec;
}
} elsif ( have_ipsec ) {
if ( $interface ) {
$baserule .= '-m policy --pol none --dir out ';
} else {
$baserule .= '-m policy --pol none --dir in ';
}
}
my $detectaddress = 0;
my $exceptionrule = '';
@ -5572,6 +5593,7 @@ sub process_snat1( $$$$$$$$$$$$ ) {
if ( $action eq 'SNAT' ) {
if ( $addresses eq 'detect' ) {
fatal_error q('detect' not allowed when the destination is $FW) unless $interface;
my $variable = get_interface_address $interface;
$target .= " --to-source $variable";
@ -5698,6 +5720,7 @@ sub process_snat1( $$$$$$$$$$$$ ) {
$target .= $addrlist;
}
} elsif ( $action eq 'MASQUERADE' ) {
fatal_error q('MASQUERADE' not allowed when the destination is $FW') unless $interface;
if ( supplied $addresses ) {
validate_portpair1($proto, $addresses );
$target .= " --to-ports $addresses";
@ -5715,7 +5738,7 @@ sub process_snat1( $$$$$$$$$$$$ ) {
$params,
$loglevel,
$source,
supplied( $destnets ) && $destnets ne '-' ? $inaction ? $destnets : join( ':', $interface, $destnets ) : $inaction ? '-' : $interface,
supplied( $destnets ) && $destnets ne '-' ? $inaction || $interface ? join( ':', $interface, $destnets ) : $destnets : $inaction ? '-' : $interface,
$proto,
$ports,
$ipsec,
@ -5780,7 +5803,7 @@ sub process_snat1( $$$$$$$$$$$$ ) {
$destnets = ALLIP unless supplied $destnets && $destnets ne '-';
expand_rule( $chainref ,
POSTROUTE_RESTRICT ,
$interface ? POSTROUTE_RESTRICT : INPUT_RESTRICT ,
$prerule ,
$baserule . $inlinematches . $rule ,
$source ,
@ -5795,7 +5818,7 @@ sub process_snat1( $$$$$$$$$$$$ ) {
conditional_rule_end( $chainref ) if $detectaddress || $conditional;
if ( $add_snat_aliases && $addresses ) {
if ( $interface && $add_snat_aliases && $addresses ) {
my ( $interface, $alias , $remainder ) = split( /:/, $fullinterface, 3 );
fatal_error "Invalid alias ($alias:$remainder)" if defined $remainder;
for my $address ( split_list $addresses, 'address' ) {

View File

@ -253,10 +253,10 @@
<listitem>
<para>Set of hosts that you wish to masquerade. You can specify this
as an <emphasis>address</emphasis> (net or host) or as an
<emphasis>interface</emphasis> (use of an
<emphasis>interface</emphasis> is deprecated). If you give the name
of an interface, the interface must be up before you start the
firewall and the Shorewall rules compiler will warn you of that
<emphasis>interface</emphasis>. Unless you want to perform SNAT in
the INPUT chain (see DEST below), if you give the name of an
interface (deprecated), the interface must be up before you start
the firewall and the Shorewall rules compiler will warn you of that
fact. (Shorewall will use your main routing table to determine the
appropriate addresses to masquerade).</para>
@ -268,9 +268,9 @@
<varlistentry>
<term><emphasis role="bold">DEST</emphasis> -
<emphasis>interface</emphasis>[<emphasis
{<emphasis>interface</emphasis>[<emphasis
role="bold">:</emphasis><emphasis>digit][,</emphasis><emphasis>interface</emphasis>[<emphasis
role="bold">:</emphasis><emphasis>digit</emphasis>]]...[<emphasis
role="bold">:</emphasis><emphasis>digit</emphasis>]]...|$FW}[<emphasis
role="bold">:</emphasis>[<emphasis>dest-address</emphasis>[<emphasis
role="bold">,</emphasis><emphasis>dest-address</emphasis>]...[<emphasis>exclusion</emphasis>]]</term>
@ -286,6 +286,10 @@
is the only use for the alias name; it may not appear in any other
place in your Shorewall configuration.</emphasis></para>
<para>Beginning with Shorewall 5.1.12, SNAT may be performed in the
nat table's INPUT chain by specifying $FW rather than one or more
interfaces. </para>
<para>Each interface must match an entry in <ulink
url="/manpages/shorewall-interfaces.html">shorewall-interfaces</ulink>(5).
Shorewall allows loose matches to wildcard entries in <ulink