Implement REJECT_ACTION

Signed-off-by: Tom Eastep <teastep@shorewall.net>
This commit is contained in:
Tom Eastep 2013-09-01 09:14:10 -07:00
parent 1540e50cce
commit 67603c5eb3
17 changed files with 303 additions and 120 deletions

View File

@ -2788,8 +2788,8 @@ sub initialize_chain_table($) {
'DROP!' => STANDARD, 'DROP!' => STANDARD,
'A_DROP' => STANDARD + AUDIT, 'A_DROP' => STANDARD + AUDIT,
'A_DROP!' => STANDARD + AUDIT, 'A_DROP!' => STANDARD + AUDIT,
'REJECT' => STANDARD, 'REJECT' => STANDARD + OPTIONS,
'REJECT!' => STANDARD, 'REJECT!' => STANDARD + OPTIONS,
'A_REJECT' => STANDARD + AUDIT, 'A_REJECT' => STANDARD + AUDIT,
'A_REJECT!' => STANDARD + AUDIT, 'A_REJECT!' => STANDARD + AUDIT,
'DNAT' => NATRULE + OPTIONS, 'DNAT' => NATRULE + OPTIONS,
@ -2852,8 +2852,8 @@ sub initialize_chain_table($) {
'DROP!' => STANDARD, 'DROP!' => STANDARD,
'A_DROP' => STANDARD + AUDIT, 'A_DROP' => STANDARD + AUDIT,
'A_DROP!' => STANDARD + AUDIT, 'A_DROP!' => STANDARD + AUDIT,
'REJECT' => STANDARD, 'REJECT' => STANDARD + OPTIONS,
'REJECT!' => STANDARD, 'REJECT!' => STANDARD + OPTIONS,
'A_REJECT' => STANDARD + AUDIT, 'A_REJECT' => STANDARD + AUDIT,
'A_REJECT!' => STANDARD + AUDIT, 'A_REJECT!' => STANDARD + AUDIT,
'DNAT' => NATRULE + OPTIONS, 'DNAT' => NATRULE + OPTIONS,

View File

@ -850,6 +850,10 @@ sub compiler {
# #
apply_policy_rules; apply_policy_rules;
# #
# Reject Action
#
process_reject_action if $config{REJECT_ACTION};
#
# Accounting. # Accounting.
# #
setup_accounting if $config{ACCOUNTING}; setup_accounting if $config{ACCOUNTING};

View File

@ -819,6 +819,7 @@ sub initialize( $;$$) {
USE_RT_NAMES => undef, USE_RT_NAMES => undef,
CHAIN_SCRIPTS => undef, CHAIN_SCRIPTS => undef,
TRACK_RULES => undef, TRACK_RULES => undef,
REJECT_ACTION => undef,
# #
# Packet Disposition # Packet Disposition
# #
@ -5392,6 +5393,12 @@ sub get_configuration( $$$$ ) {
default_yes_no 'CHAIN_SCRIPTS' , 'Yes'; default_yes_no 'CHAIN_SCRIPTS' , 'Yes';
default_yes_no 'TRACK_RULES' , ''; default_yes_no 'TRACK_RULES' , '';
if ( $val = $config{REJECT_ACTION} ) {
fatal_error "Invalid Reject Action Name ($val)" unless $val =~ /^[a-zA-Z][\w-]*$/;
} else {
$config{REJECT_ACTION} = '';
}
require_capability 'COMMENTS', 'TRACK_RULES=Yes', 's' if $config{TRACK_RULES}; require_capability 'COMMENTS', 'TRACK_RULES=Yes', 's' if $config{TRACK_RULES};
default_yes_no 'MANGLE_ENABLED' , have_capability( 'MANGLE_ENABLED' ) ? 'Yes' : ''; default_yes_no 'MANGLE_ENABLED' , have_capability( 'MANGLE_ENABLED' ) ? 'Yes' : '';

View File

@ -983,42 +983,44 @@ sub add_common_rules ( $ ) {
} }
} }
if ( have_capability( 'ADDRTYPE' ) ) { unless ( $config{REJECT_ACTION} ) {
add_ijump $rejectref , j => 'DROP' , addrtype => '--src-type BROADCAST'; if ( have_capability( 'ADDRTYPE' ) ) {
} else { add_ijump $rejectref , j => 'DROP' , addrtype => '--src-type BROADCAST';
if ( $family == F_IPV4 ) {
add_commands $rejectref, 'for address in $ALL_BCASTS; do';
} else { } else {
add_commands $rejectref, 'for address in $ALL_ACASTS; do'; if ( $family == F_IPV4 ) {
add_commands $rejectref, 'for address in $ALL_BCASTS; do';
} else {
add_commands $rejectref, 'for address in $ALL_ACASTS; do';
}
incr_cmd_level $rejectref;
add_ijump $rejectref, j => 'DROP', d => '$address';
decr_cmd_level $rejectref;
add_commands $rejectref, 'done';
} }
incr_cmd_level $rejectref;
add_ijump $rejectref, j => 'DROP', d => '$address';
decr_cmd_level $rejectref;
add_commands $rejectref, 'done';
}
if ( $family == F_IPV4 ) {
add_ijump $rejectref , j => 'DROP', s => '224.0.0.0/4';
} else {
add_ijump $rejectref , j => 'DROP', s => IPv6_MULTICAST;
}
add_ijump $rejectref , j => 'DROP', p => 2;
add_ijump $rejectref , j => 'REJECT', targetopts => '--reject-with tcp-reset', p => 6;
if ( have_capability( 'ENHANCED_REJECT' ) ) {
add_ijump $rejectref , j => 'REJECT', p => 17;
if ( $family == F_IPV4 ) { if ( $family == F_IPV4 ) {
add_ijump $rejectref, j => 'REJECT --reject-with icmp-host-unreachable', p => 1; add_ijump $rejectref , j => 'DROP', s => '224.0.0.0/4';
add_ijump $rejectref, j => 'REJECT --reject-with icmp-host-prohibited';
} else { } else {
add_ijump $rejectref, j => 'REJECT --reject-with icmp6-addr-unreachable', p => 58; add_ijump $rejectref , j => 'DROP', s => IPv6_MULTICAST;
add_ijump $rejectref, j => 'REJECT --reject-with icmp6-adm-prohibited'; }
add_ijump $rejectref , j => 'DROP', p => 2;
add_ijump $rejectref , j => 'REJECT', targetopts => '--reject-with tcp-reset', p => 6;
if ( have_capability( 'ENHANCED_REJECT' ) ) {
add_ijump $rejectref , j => 'REJECT', p => 17;
if ( $family == F_IPV4 ) {
add_ijump $rejectref, j => 'REJECT --reject-with icmp-host-unreachable', p => 1;
add_ijump $rejectref, j => 'REJECT --reject-with icmp-host-prohibited';
} else {
add_ijump $rejectref, j => 'REJECT --reject-with icmp6-addr-unreachable', p => 58;
add_ijump $rejectref, j => 'REJECT --reject-with icmp6-adm-prohibited';
}
} else {
add_ijump $rejectref , j => 'REJECT';
} }
} else {
add_ijump $rejectref , j => 'REJECT';
} }
$list = find_interfaces_by_option 'dhcp'; $list = find_interfaces_by_option 'dhcp';

View File

@ -54,6 +54,7 @@ our @EXPORT = qw(
perl_action_helper perl_action_helper
perl_action_tcp_helper perl_action_tcp_helper
check_state check_state
process_reject_action
); );
our @EXPORT_OK = qw( initialize process_rule ); our @EXPORT_OK = qw( initialize process_rule );
@ -1635,90 +1636,6 @@ my %builtinops = ( 'dropBcast' => \&dropBcast,
'Limit' => \&Limit, 'Limit' => \&Limit,
); );
#
# This function is called prior to processing of the policy file. It:
#
# - Adds the builtin actions to the target table
# - Reads actions.std and actions (in that order) and for each entry:
# o Adds the action to the target table
# o Verifies that the corresponding action file exists
#
sub process_actions() {
progress_message2 "Locating Action Files...";
#
# Add built-in actions to the target table and create those actions
#
$targets{$_} = new_action( $_ , ACTION + BUILTIN, 1, 0 ) for @builtins;
for my $file ( qw/actions.std actions/ ) {
open_file( $file, 2 );
while ( read_a_line( NORMAL_READ ) ) {
my ( $action, $options ) = split_line 'action file' , { action => 0, options => 1 };
my $type = ACTION;
my $noinline = 0;
my $nolog = 0;
my $builtin = 0;
if ( $action =~ /:/ ) {
warning_message 'Default Actions are now specified in /etc/shorewall/shorewall.conf';
$action =~ s/:.*$//;
}
fatal_error "Invalid Action Name ($action)" unless $action =~ /^[a-zA-Z][\w-]*$/;
if ( $options ne '-' ) {
for ( split_list( $options, 'option' ) ) {
if ( $_ eq 'inline' ) {
$type = INLINE;
} elsif ( $_ eq 'noinline' ) {
$noinline = 1;
} elsif ( $_ eq 'nolog' ) {
$nolog = 1;
} elsif ( $_ eq 'builtin' ) {
$builtin = 1;
} else {
fatal_error "Invalid option ($_)";
}
}
}
fatal_error "Conflicting OPTIONS ($options)" if $noinline && $type == INLINE;
if ( my $actiontype = $targets{$action} ) {
if ( ( $actiontype & ACTION ) && ( $type == INLINE ) ) {
if ( $actions{$action}->{noinline} ) {
warning_message "'inline' option ignored on action $action -- that action may not be in-lined";
next;
}
delete $actions{$action};
delete $targets{$action};
} else {
warning_message "Duplicate Action Name ($action) Ignored" unless $actiontype & ( ACTION | INLINE );
next;
}
}
if ( $builtin ) {
$targets{$action} = USERBUILTIN + OPTIONS;
$builtin_target{$action} = 1;
} else {
new_action $action, $type, $noinline, $nolog;
my $actionfile = find_file( "action.$action" );
fatal_error "Missing Action File ($actionfile)" unless -f $actionfile;
$inlines{$action} = { file => $actionfile, nolog => $nolog } if $type == INLINE;
}
}
}
}
sub process_rule ( $$$$$$$$$$$$$$$$$$$ ); sub process_rule ( $$$$$$$$$$$$$$$$$$$ );
# #
@ -1809,6 +1726,96 @@ sub process_action($$) {
pop_action_params( $oldparms ); pop_action_params( $oldparms );
} }
#
# This function is called prior to processing of the policy file. It:
#
# - Adds the builtin actions to the target table
# - Reads actions.std and actions (in that order) and for each entry:
# o Adds the action to the target table
# o Verifies that the corresponding action file exists
#
sub process_actions() {
progress_message2 "Locating Action Files...";
#
# Add built-in actions to the target table and create those actions
#
$targets{$_} = new_action( $_ , ACTION + BUILTIN, 1, 0 ) for @builtins;
for my $file ( qw/actions.std actions/ ) {
open_file( $file, 2 );
while ( read_a_line( NORMAL_READ ) ) {
my ( $action, $options ) = split_line 'action file' , { action => 0, options => 1 };
my $type = ACTION;
my $noinline = 0;
my $nolog = ( $action eq $config{REJECT_ACTION} ) || 0;
my $builtin = 0;
if ( $action =~ /:/ ) {
warning_message 'Default Actions are now specified in /etc/shorewall/shorewall.conf';
$action =~ s/:.*$//;
}
fatal_error "Invalid Action Name ($action)" unless $action =~ /^[a-zA-Z][\w-]*$/;
if ( $options ne '-' ) {
for ( split_list( $options, 'option' ) ) {
if ( $_ eq 'inline' ) {
$type = INLINE;
} elsif ( $_ eq 'noinline' ) {
$noinline = 1;
} elsif ( $_ eq 'nolog' ) {
$nolog = 1;
} elsif ( $_ eq 'builtin' ) {
$builtin = 1;
} else {
fatal_error "Invalid option ($_)";
}
}
}
fatal_error "Conflicting OPTIONS ($options)" if $noinline && $type == INLINE;
if ( my $actiontype = $targets{$action} ) {
if ( ( $actiontype & ACTION ) && ( $type == INLINE ) ) {
if ( $actions{$action}->{noinline} ) {
warning_message "'inline' option ignored on action $action -- that action may not be in-lined";
next;
}
delete $actions{$action};
delete $targets{$action};
} else {
warning_message "Duplicate Action Name ($action) Ignored" unless $actiontype & ( ACTION | INLINE );
next;
}
}
if ( $builtin ) {
$targets{$action} = USERBUILTIN + OPTIONS;
$builtin_target{$action} = 1;
} else {
new_action $action, $type, $noinline, $nolog;
my $actionfile = find_file( "action.$action" );
fatal_error "Missing Action File ($actionfile)" unless -f $actionfile;
$inlines{$action} = { file => $actionfile, nolog => $nolog } if $type == INLINE;
}
}
}
if ( my $action = $config{REJECT_ACTION} ) {
my $type = $targets{$action};
fatal_error "REJECT_ACTION ($action) was not defined" unless $type;
fatal_error "REJECT_ACTION ($action) is not an action" unless $type & (ACTION | INLINE);
}
}
# #
# Create a policy action if it doesn't already exist # Create a policy action if it doesn't already exist
# #
@ -1823,6 +1830,41 @@ sub use_policy_action( $$ ) {
$ref; $ref;
} }
#
# Process the REJECT_ACTION
#
sub process_reject_action() {
my $rejectref = $filter_table->{reject};
my $action = $config{REJECT_ACTION};
if ( ( $targets{$action} || 0 ) == ACTION ) {
add_ijump $rejectref, j => use_policy_action( $action, $rejectref->{name} );
} else {
process_inline( $action, #Inline
$rejectref, #Chain
'', #Matches
'', #Log Level and Tag
$action, #Target
'', #Param
'-', #Source
'-', #Dest
'-', #Proto
'-', #Ports
'-', #Sports
'-', #Original Dest
'-', #Rate
'-', #User
'-', #Mark
'-', #ConnLimit
'-', #Time
'-', #Headers
'-', #Condition
'-', #Helper
0, #Wildcard
);
}
}
################################################################################ ################################################################################
# End of functions moved from the Actions module in 4.4.16 # End of functions moved from the Actions module in 4.4.16
################################################################################ ################################################################################
@ -2007,7 +2049,7 @@ sub process_inline ($$$$$$$$$$$$$$$$$$$$$) {
my $actiontype = $targets{$action} || find_macro( $action ); my $actiontype = $targets{$action} || find_macro( $action );
fatal_error( "Invalid Action ($mtarget) in inline action" ) unless $actiontype & ( ACTION + STANDARD + NATRULE + MACRO + CHAIN + INLINE ); fatal_error( "Invalid Action ($mtarget) in inline action" ) unless $actiontype & ( ACTION + STANDARD + NATRULE + MACRO + CHAIN + INLINE + INLINERULE );
if ( $msource ) { if ( $msource ) {
if ( $msource eq '-' ) { if ( $msource eq '-' ) {

View File

@ -194,6 +194,8 @@ OPTIMIZE=All
OPTIMIZE_ACCOUNTING=No OPTIMIZE_ACCOUNTING=No
REJECT_ACTION=
REQUIRE_INTERFACE=Yes REQUIRE_INTERFACE=Yes
RESTORE_DEFAULT_ROUTE=Yes RESTORE_DEFAULT_ROUTE=Yes

View File

@ -205,6 +205,8 @@ OPTIMIZE=All
OPTIMIZE_ACCOUNTING=No OPTIMIZE_ACCOUNTING=No
REJECT_ACTION=
REQUIRE_INTERFACE=No REQUIRE_INTERFACE=No
RESTORE_DEFAULT_ROUTE=Yes RESTORE_DEFAULT_ROUTE=Yes

View File

@ -203,6 +203,8 @@ OPTIMIZE=All
OPTIMIZE_ACCOUNTING=No OPTIMIZE_ACCOUNTING=No
REJECT_ACTION=
REQUIRE_INTERFACE=No REQUIRE_INTERFACE=No
RESTORE_DEFAULT_ROUTE=Yes RESTORE_DEFAULT_ROUTE=Yes

View File

@ -206,6 +206,8 @@ OPTIMIZE=All
OPTIMIZE_ACCOUNTING=No OPTIMIZE_ACCOUNTING=No
REJECT_ACTION=
REQUIRE_INTERFACE=No REQUIRE_INTERFACE=No
RESTORE_DEFAULT_ROUTE=Yes RESTORE_DEFAULT_ROUTE=Yes

View File

@ -194,6 +194,8 @@ OPTIMIZE=0
OPTIMIZE_ACCOUNTING=No OPTIMIZE_ACCOUNTING=No
REJECT_ACTION=
REQUIRE_INTERFACE=No REQUIRE_INTERFACE=No
RESTORE_DEFAULT_ROUTE=Yes RESTORE_DEFAULT_ROUTE=Yes

View File

@ -2000,7 +2000,7 @@ LOG:info:,bar net fw</programlisting>
<varlistentry> <varlistentry>
<term><emphasis <term><emphasis
role="bold">PROVIDER_OFFSET</emphasis>=[<replaceable>number</replaceable>]</term> role="bold">PROVIDER_OFFSET</emphasis>=[<replaceable>number</replaceable>]If</term>
<listitem> <listitem>
<para>Added in Shorewall 4.4.26. The offset from the right <para>Added in Shorewall 4.4.26. The offset from the right
@ -2095,6 +2095,49 @@ LOG:info:,bar net fw</programlisting>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><emphasis
role="bold">REJECT_ACTION=</emphasis><emphasis>action</emphasis></term>
<listitem>
<para>Added in Shorewall 4.5.21. When a REJECT target is specified,
Shorewall normally handles the response as follows:</para>
<itemizedlist>
<listitem>
<para>If the destination address of the packet is a broadcast or
multicast address, the packet is dropped.</para>
</listitem>
<listitem>
<para>if the protocol is ICMP (2) then the packet is
dropped.</para>
</listitem>
<listitem>
<para>if the protocol is TCP (6) then the packet is rejected
with an RST.</para>
</listitem>
<listitem>
<para>if the protocol is ICMP (1) then the packet is rejected
with a 'host-unreachable' ICMP.</para>
</listitem>
<listitem>
<para>otherwise, the packet is rejected with a 'host-prohibited'
ICMP.</para>
</listitem>
</itemizedlist>
<para>You can modify this behavior by implementing your own
<replaceable>action</replaceable> that handles REJECT and specifying
it's name in this option. The <emphasis role="bold">nolog</emphasis>
option will automatically be assumed for the specified
<replaceable>action</replaceable>.</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><emphasis role="bold">REQUIRE_INTERFACE=</emphasis>[<emphasis <term><emphasis role="bold">REQUIRE_INTERFACE=</emphasis>[<emphasis
role="bold">Yes</emphasis>|<emphasis role="bold">No</emphasis>]</term> role="bold">Yes</emphasis>|<emphasis role="bold">No</emphasis>]</term>

View File

@ -177,6 +177,8 @@ OPTIMIZE=All
OPTIMIZE_ACCOUNTING=No OPTIMIZE_ACCOUNTING=No
REJECT_ACTION=
REQUIRE_INTERFACE=Yes REQUIRE_INTERFACE=Yes
RESTORE_ROUTEMARKS=Yes RESTORE_ROUTEMARKS=Yes

View File

@ -177,6 +177,8 @@ OPTIMIZE=All
OPTIMIZE_ACCOUNTING=No OPTIMIZE_ACCOUNTING=No
REJECT_ACTION=
REQUIRE_INTERFACE=No REQUIRE_INTERFACE=No
RESTORE_ROUTEMARKS=Yes RESTORE_ROUTEMARKS=Yes

View File

@ -177,6 +177,8 @@ OPTIMIZE=All
OPTIMIZE_ACCOUNTING=No OPTIMIZE_ACCOUNTING=No
REJECT_ACTION=
REQUIRE_INTERFACE=No REQUIRE_INTERFACE=No
RESTORE_ROUTEMARKS=Yes RESTORE_ROUTEMARKS=Yes

View File

@ -177,6 +177,8 @@ OPTIMIZE=All
OPTIMIZE_ACCOUNTING=No OPTIMIZE_ACCOUNTING=No
REJECT_ACTION=
REQUIRE_INTERFACE=No REQUIRE_INTERFACE=No
RESTORE_ROUTEMARKS=Yes RESTORE_ROUTEMARKS=Yes

View File

@ -177,6 +177,8 @@ OPTIMIZE=1
OPTIMIZE_ACCOUNTING=No OPTIMIZE_ACCOUNTING=No
REJECT_ACTION=
REQUIRE_INTERFACE=No REQUIRE_INTERFACE=No
RESTORE_ROUTEMARKS=Yes RESTORE_ROUTEMARKS=Yes

View File

@ -1816,6 +1816,8 @@ LOG:info:,bar net fw</programlisting>
on the remote system that the files are to be copied on the remote system that the files are to be copied
into.</member> into.</member>
</simplelist></para> </simplelist></para>
<programlisting></programlisting>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -1849,6 +1851,69 @@ LOG:info:,bar net fw</programlisting>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><emphasis
role="bold">REJECT_ACTION=</emphasis><emphasis>action</emphasis></term>
<listitem>
<para>Added in Shorewall 4.5.21. When a REJECT target is specified,
Shorewall normally handles the response as follows:</para>
<itemizedlist>
<listitem>
<para>If the destination address of the packet is a broadcast or
multicast address, the packet is dropped.</para>
</listitem>
<listitem>
<para>if the protocol is ICMP (58) then the packet is
dropped.</para>
</listitem>
<listitem>
<para>if the protocol is TCP (6) then the packet is rejected
with an RST.</para>
</listitem>
<listitem>
<para>if the protocol is ICMP (1) then the packet is rejected
with a 'addr-unreachable' ICMP.</para>
</listitem>
<listitem>
<para>otherwise, the packet is rejected with a 'adm-prohibited'
ICMP.</para>
</listitem>
</itemizedlist>
<para>You can modify this behavior by implementing your own
<replaceable>action</replaceable> that handles REJECT and specifying
it's name in this option. The <emphasis role="bold">nolog</emphasis>
option will automatically be assumed for the specified
<replaceable>action</replaceable>.</para>
<para>The following action implements the standard behavior:</para>
<programlisting>?format 2
#TARGET SOURCE DEST PROTO
Broadcast(DROP) - - -
DROP - - 2
INLINE - - 6 ; -j REJECT --reject-with tcp-reset
?if __ENHANCED_REJECT
INLINE - - 17 ; -j REJECT
?if __IPV4
INLINE - - 1 ; -j REJECT --reject-with icmp-host-unreachable
INLINE - - - ; -j REJECT --reject-with icmp-host-prohibited
?else
INLINE - - 58 ; -j REJECT --reject-with icmp6-addr-unreachable
INLINE - - - ; -j REJECT --reject-with icmp6-adm-prohibited
?endif
?else
INLINE - - - ; -j REJECT
?endif</programlisting>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><emphasis role="bold">REQUIRE_INTERFACE=</emphasis>[<emphasis <term><emphasis role="bold">REQUIRE_INTERFACE=</emphasis>[<emphasis
role="bold">Yes</emphasis>|<emphasis role="bold">No</emphasis>]</term> role="bold">Yes</emphasis>|<emphasis role="bold">No</emphasis>]</term>