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. # loaded after this one and replaces some of the functions declared here.
# #
SHOREWALL_CAPVERSION=50106 SHOREWALL_CAPVERSION=50112
if [ -z "$g_basedir" ]; then 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 qt $g_tool -t nat -A $chain -j NETMAP --to 2001:470:B:227::/64 && NETMAP_TARGET=Yes
fi fi
qt $g_tool -t nat -A $chain -j MASQUERADE && MASQUERADE_TGT=Yes 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 -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 -F $chain
qt $g_tool -t nat -X $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 "NFQUEUE CPU Fanout (CPU_FANOUT)" $CPU_FANOUT
report_capability "NETMAP Target (NETMAP_TARGET)" $NETMAP_TARGET report_capability "NETMAP Target (NETMAP_TARGET)" $NETMAP_TARGET
report_capability "--nflog-size support (NFLOG_SIZE)" $NFLOG_SIZE 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 " Kernel Version (KERNELVERSION): $KERNELVERSION"
echo " Capabilities Version (CAPVERSION): $CAPVERSION" echo " Capabilities Version (CAPVERSION): $CAPVERSION"
@ -3439,6 +3441,7 @@ report_capabilities_unsorted1() {
report_capability1 NETMAP_TARGET report_capability1 NETMAP_TARGET
report_capability1 NFLOG_SIZE report_capability1 NFLOG_SIZE
report_capability1 RESTORE_WAIT_OPTION report_capability1 RESTORE_WAIT_OPTION
report_capability1 NAT_INPUT_CHAIN
report_capability1 AMANDA_HELPER report_capability1 AMANDA_HELPER
report_capability1 FTP_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', $chain, 'ACCEPT';
} }
new_builtin_chain 'nat', 'INPUT', 'ACCEPT' if have_capability('NAT_INPUT_CHAIN');
for my $chain ( qw(PREROUTING INPUT OUTPUT ) ) { for my $chain ( qw(PREROUTING INPUT OUTPUT ) ) {
new_builtin_chain 'mangle', $chain, 'ACCEPT'; new_builtin_chain 'mangle', $chain, 'ACCEPT';
} }
@ -3244,6 +3246,8 @@ sub initialize_chain_table($) {
new_builtin_chain 'nat', $chain, 'ACCEPT'; 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 ) ) { for my $chain ( qw(PREROUTING INPUT OUTPUT FORWARD POSTROUTING ) ) {
new_builtin_chain 'mangle', $chain, 'ACCEPT'; new_builtin_chain 'mangle', $chain, 'ACCEPT';
} }

View File

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

View File

@ -5501,22 +5501,6 @@ sub process_snat1( $$$$$$$$$$$$ ) {
$interfaces = $dest; $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 # Handle Protocol, Ports and Condition
# #
$baserule .= do_proto( $proto, $ports, '' ); $baserule .= do_proto( $proto, $ports, '' );
@ -5527,7 +5511,9 @@ sub process_snat1( $$$$$$$$$$$$ ) {
$baserule .= do_user( $user ) if $user ne '-'; $baserule .= do_user( $user ) if $user ne '-';
$baserule .= do_probability( $probability ) if $probability 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 $rule = '';
my $saveaddresses = $addresses; my $saveaddresses = $addresses;
@ -5535,9 +5521,21 @@ sub process_snat1( $$$$$$$$$$$$ ) {
my $savebaserule = $baserule; my $savebaserule = $baserule;
my $interface = $fullinterface; my $interface = $fullinterface;
$interface =~ s/:.*//; #interface name may include 'alias' 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 {
$interface =~ s/:.*// if $family == F_IPV4; #interface name may include 'alias'
unless ( $inaction ) {
if ( $interface =~ /(.*)[(](\w*)[)]$/ ) { if ( $interface =~ /(.*)[(](\w*)[)]$/ ) {
$interface = $1; $interface = $1;
my $provider = $2; my $provider = $2;
@ -5560,11 +5558,34 @@ sub process_snat1( $$$$$$$$$$$$ ) {
$rule .= match_dest_dev( $interface ); $rule .= match_dest_dev( $interface );
$interface = $interfaceref->{name}; $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} ); $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 $detectaddress = 0;
my $exceptionrule = ''; my $exceptionrule = '';
@ -5572,6 +5593,7 @@ sub process_snat1( $$$$$$$$$$$$ ) {
if ( $action eq 'SNAT' ) { if ( $action eq 'SNAT' ) {
if ( $addresses eq 'detect' ) { if ( $addresses eq 'detect' ) {
fatal_error q('detect' not allowed when the destination is $FW) unless $interface;
my $variable = get_interface_address $interface; my $variable = get_interface_address $interface;
$target .= " --to-source $variable"; $target .= " --to-source $variable";
@ -5698,6 +5720,7 @@ sub process_snat1( $$$$$$$$$$$$ ) {
$target .= $addrlist; $target .= $addrlist;
} }
} elsif ( $action eq 'MASQUERADE' ) { } elsif ( $action eq 'MASQUERADE' ) {
fatal_error q('MASQUERADE' not allowed when the destination is $FW') unless $interface;
if ( supplied $addresses ) { if ( supplied $addresses ) {
validate_portpair1($proto, $addresses ); validate_portpair1($proto, $addresses );
$target .= " --to-ports $addresses"; $target .= " --to-ports $addresses";
@ -5715,7 +5738,7 @@ sub process_snat1( $$$$$$$$$$$$ ) {
$params, $params,
$loglevel, $loglevel,
$source, $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, $proto,
$ports, $ports,
$ipsec, $ipsec,
@ -5780,7 +5803,7 @@ sub process_snat1( $$$$$$$$$$$$ ) {
$destnets = ALLIP unless supplied $destnets && $destnets ne '-'; $destnets = ALLIP unless supplied $destnets && $destnets ne '-';
expand_rule( $chainref , expand_rule( $chainref ,
POSTROUTE_RESTRICT , $interface ? POSTROUTE_RESTRICT : INPUT_RESTRICT ,
$prerule , $prerule ,
$baserule . $inlinematches . $rule , $baserule . $inlinematches . $rule ,
$source , $source ,
@ -5795,7 +5818,7 @@ sub process_snat1( $$$$$$$$$$$$ ) {
conditional_rule_end( $chainref ) if $detectaddress || $conditional; 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 ); my ( $interface, $alias , $remainder ) = split( /:/, $fullinterface, 3 );
fatal_error "Invalid alias ($alias:$remainder)" if defined $remainder; fatal_error "Invalid alias ($alias:$remainder)" if defined $remainder;
for my $address ( split_list $addresses, 'address' ) { for my $address ( split_list $addresses, 'address' ) {

View File

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