From 67603c5eb3f7dac85f1777fd2c1ac74d9606c280 Mon Sep 17 00:00:00 2001 From: Tom Eastep Date: Sun, 1 Sep 2013 09:14:10 -0700 Subject: [PATCH] Implement REJECT_ACTION Signed-off-by: Tom Eastep --- Shorewall/Perl/Shorewall/Chains.pm | 8 +- Shorewall/Perl/Shorewall/Compiler.pm | 4 + Shorewall/Perl/Shorewall/Config.pm | 7 + Shorewall/Perl/Shorewall/Misc.pm | 62 ++--- Shorewall/Perl/Shorewall/Rules.pm | 212 +++++++++++------- Shorewall/Samples/Universal/shorewall.conf | 2 + .../Samples/one-interface/shorewall.conf | 2 + .../Samples/three-interfaces/shorewall.conf | 2 + .../Samples/two-interfaces/shorewall.conf | 2 + Shorewall/configfiles/shorewall.conf | 2 + Shorewall/manpages/shorewall.conf.xml | 45 +++- Shorewall6/Samples6/Universal/shorewall6.conf | 2 + .../Samples6/one-interface/shorewall6.conf | 2 + .../Samples6/three-interfaces/shorewall6.conf | 2 + .../Samples6/two-interfaces/shorewall6.conf | 2 + Shorewall6/configfiles/shorewall6.conf | 2 + Shorewall6/manpages/shorewall6.conf.xml | 65 ++++++ 17 files changed, 303 insertions(+), 120 deletions(-) diff --git a/Shorewall/Perl/Shorewall/Chains.pm b/Shorewall/Perl/Shorewall/Chains.pm index 1949a3d25..1d4a9fdbf 100644 --- a/Shorewall/Perl/Shorewall/Chains.pm +++ b/Shorewall/Perl/Shorewall/Chains.pm @@ -2788,8 +2788,8 @@ sub initialize_chain_table($) { 'DROP!' => STANDARD, 'A_DROP' => STANDARD + AUDIT, 'A_DROP!' => STANDARD + AUDIT, - 'REJECT' => STANDARD, - 'REJECT!' => STANDARD, + 'REJECT' => STANDARD + OPTIONS, + 'REJECT!' => STANDARD + OPTIONS, 'A_REJECT' => STANDARD + AUDIT, 'A_REJECT!' => STANDARD + AUDIT, 'DNAT' => NATRULE + OPTIONS, @@ -2852,8 +2852,8 @@ sub initialize_chain_table($) { 'DROP!' => STANDARD, 'A_DROP' => STANDARD + AUDIT, 'A_DROP!' => STANDARD + AUDIT, - 'REJECT' => STANDARD, - 'REJECT!' => STANDARD, + 'REJECT' => STANDARD + OPTIONS, + 'REJECT!' => STANDARD + OPTIONS, 'A_REJECT' => STANDARD + AUDIT, 'A_REJECT!' => STANDARD + AUDIT, 'DNAT' => NATRULE + OPTIONS, diff --git a/Shorewall/Perl/Shorewall/Compiler.pm b/Shorewall/Perl/Shorewall/Compiler.pm index 7d8b38a10..a6ff12195 100644 --- a/Shorewall/Perl/Shorewall/Compiler.pm +++ b/Shorewall/Perl/Shorewall/Compiler.pm @@ -850,6 +850,10 @@ sub compiler { # apply_policy_rules; # + # Reject Action + # + process_reject_action if $config{REJECT_ACTION}; + # # Accounting. # setup_accounting if $config{ACCOUNTING}; diff --git a/Shorewall/Perl/Shorewall/Config.pm b/Shorewall/Perl/Shorewall/Config.pm index ff66adf68..5f524414f 100644 --- a/Shorewall/Perl/Shorewall/Config.pm +++ b/Shorewall/Perl/Shorewall/Config.pm @@ -819,6 +819,7 @@ sub initialize( $;$$) { USE_RT_NAMES => undef, CHAIN_SCRIPTS => undef, TRACK_RULES => undef, + REJECT_ACTION => undef, # # Packet Disposition # @@ -5392,6 +5393,12 @@ sub get_configuration( $$$$ ) { default_yes_no 'CHAIN_SCRIPTS' , 'Yes'; 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}; default_yes_no 'MANGLE_ENABLED' , have_capability( 'MANGLE_ENABLED' ) ? 'Yes' : ''; diff --git a/Shorewall/Perl/Shorewall/Misc.pm b/Shorewall/Perl/Shorewall/Misc.pm index 120310aec..c64369b1d 100644 --- a/Shorewall/Perl/Shorewall/Misc.pm +++ b/Shorewall/Perl/Shorewall/Misc.pm @@ -983,42 +983,44 @@ sub add_common_rules ( $ ) { } } - if ( have_capability( 'ADDRTYPE' ) ) { - add_ijump $rejectref , j => 'DROP' , addrtype => '--src-type BROADCAST'; - } else { - if ( $family == F_IPV4 ) { - add_commands $rejectref, 'for address in $ALL_BCASTS; do'; + unless ( $config{REJECT_ACTION} ) { + if ( have_capability( 'ADDRTYPE' ) ) { + add_ijump $rejectref , j => 'DROP' , addrtype => '--src-type BROADCAST'; } 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 ) { - add_ijump $rejectref, j => 'REJECT --reject-with icmp-host-unreachable', p => 1; - add_ijump $rejectref, j => 'REJECT --reject-with icmp-host-prohibited'; + add_ijump $rejectref , j => 'DROP', s => '224.0.0.0/4'; } else { - add_ijump $rejectref, j => 'REJECT --reject-with icmp6-addr-unreachable', p => 58; - add_ijump $rejectref, j => 'REJECT --reject-with icmp6-adm-prohibited'; + 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 ) { + 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'; diff --git a/Shorewall/Perl/Shorewall/Rules.pm b/Shorewall/Perl/Shorewall/Rules.pm index 9855e1ece..7d8c82900 100644 --- a/Shorewall/Perl/Shorewall/Rules.pm +++ b/Shorewall/Perl/Shorewall/Rules.pm @@ -54,6 +54,7 @@ our @EXPORT = qw( perl_action_helper perl_action_tcp_helper check_state + process_reject_action ); our @EXPORT_OK = qw( initialize process_rule ); @@ -1635,90 +1636,6 @@ my %builtinops = ( 'dropBcast' => \&dropBcast, '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 ( $$$$$$$$$$$$$$$$$$$ ); # @@ -1809,6 +1726,96 @@ sub process_action($$) { 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 # @@ -1823,6 +1830,41 @@ sub use_policy_action( $$ ) { $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 ################################################################################ @@ -2007,7 +2049,7 @@ sub process_inline ($$$$$$$$$$$$$$$$$$$$$) { 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 eq '-' ) { diff --git a/Shorewall/Samples/Universal/shorewall.conf b/Shorewall/Samples/Universal/shorewall.conf index afb3ae13b..9f8870129 100644 --- a/Shorewall/Samples/Universal/shorewall.conf +++ b/Shorewall/Samples/Universal/shorewall.conf @@ -194,6 +194,8 @@ OPTIMIZE=All OPTIMIZE_ACCOUNTING=No +REJECT_ACTION= + REQUIRE_INTERFACE=Yes RESTORE_DEFAULT_ROUTE=Yes diff --git a/Shorewall/Samples/one-interface/shorewall.conf b/Shorewall/Samples/one-interface/shorewall.conf index 3c56f3e98..655dbf444 100644 --- a/Shorewall/Samples/one-interface/shorewall.conf +++ b/Shorewall/Samples/one-interface/shorewall.conf @@ -205,6 +205,8 @@ OPTIMIZE=All OPTIMIZE_ACCOUNTING=No +REJECT_ACTION= + REQUIRE_INTERFACE=No RESTORE_DEFAULT_ROUTE=Yes diff --git a/Shorewall/Samples/three-interfaces/shorewall.conf b/Shorewall/Samples/three-interfaces/shorewall.conf index 06ab0f54e..e0fcc9cd6 100644 --- a/Shorewall/Samples/three-interfaces/shorewall.conf +++ b/Shorewall/Samples/three-interfaces/shorewall.conf @@ -203,6 +203,8 @@ OPTIMIZE=All OPTIMIZE_ACCOUNTING=No +REJECT_ACTION= + REQUIRE_INTERFACE=No RESTORE_DEFAULT_ROUTE=Yes diff --git a/Shorewall/Samples/two-interfaces/shorewall.conf b/Shorewall/Samples/two-interfaces/shorewall.conf index b0fdb02cf..36722e902 100644 --- a/Shorewall/Samples/two-interfaces/shorewall.conf +++ b/Shorewall/Samples/two-interfaces/shorewall.conf @@ -206,6 +206,8 @@ OPTIMIZE=All OPTIMIZE_ACCOUNTING=No +REJECT_ACTION= + REQUIRE_INTERFACE=No RESTORE_DEFAULT_ROUTE=Yes diff --git a/Shorewall/configfiles/shorewall.conf b/Shorewall/configfiles/shorewall.conf index 4a7343363..452124046 100644 --- a/Shorewall/configfiles/shorewall.conf +++ b/Shorewall/configfiles/shorewall.conf @@ -194,6 +194,8 @@ OPTIMIZE=0 OPTIMIZE_ACCOUNTING=No +REJECT_ACTION= + REQUIRE_INTERFACE=No RESTORE_DEFAULT_ROUTE=Yes diff --git a/Shorewall/manpages/shorewall.conf.xml b/Shorewall/manpages/shorewall.conf.xml index 584fe8fd9..b7fd8ff11 100644 --- a/Shorewall/manpages/shorewall.conf.xml +++ b/Shorewall/manpages/shorewall.conf.xml @@ -2000,7 +2000,7 @@ LOG:info:,bar net fw PROVIDER_OFFSET=[number] + role="bold">PROVIDER_OFFSET=[number]If Added in Shorewall 4.4.26. The offset from the right @@ -2095,6 +2095,49 @@ LOG:info:,bar net fw + + REJECT_ACTION=action + + + Added in Shorewall 4.5.21. When a REJECT target is specified, + Shorewall normally handles the response as follows: + + + + If the destination address of the packet is a broadcast or + multicast address, the packet is dropped. + + + + if the protocol is ICMP (2) then the packet is + dropped. + + + + if the protocol is TCP (6) then the packet is rejected + with an RST. + + + + if the protocol is ICMP (1) then the packet is rejected + with a 'host-unreachable' ICMP. + + + + otherwise, the packet is rejected with a 'host-prohibited' + ICMP. + + + + You can modify this behavior by implementing your own + action that handles REJECT and specifying + it's name in this option. The nolog + option will automatically be assumed for the specified + action. + + + REQUIRE_INTERFACE=[Yes|No] diff --git a/Shorewall6/Samples6/Universal/shorewall6.conf b/Shorewall6/Samples6/Universal/shorewall6.conf index 767f08f30..8b9be48d0 100644 --- a/Shorewall6/Samples6/Universal/shorewall6.conf +++ b/Shorewall6/Samples6/Universal/shorewall6.conf @@ -177,6 +177,8 @@ OPTIMIZE=All OPTIMIZE_ACCOUNTING=No +REJECT_ACTION= + REQUIRE_INTERFACE=Yes RESTORE_ROUTEMARKS=Yes diff --git a/Shorewall6/Samples6/one-interface/shorewall6.conf b/Shorewall6/Samples6/one-interface/shorewall6.conf index 6ca292c39..f2b6781d4 100644 --- a/Shorewall6/Samples6/one-interface/shorewall6.conf +++ b/Shorewall6/Samples6/one-interface/shorewall6.conf @@ -177,6 +177,8 @@ OPTIMIZE=All OPTIMIZE_ACCOUNTING=No +REJECT_ACTION= + REQUIRE_INTERFACE=No RESTORE_ROUTEMARKS=Yes diff --git a/Shorewall6/Samples6/three-interfaces/shorewall6.conf b/Shorewall6/Samples6/three-interfaces/shorewall6.conf index 935796ab8..83a1a5e1a 100644 --- a/Shorewall6/Samples6/three-interfaces/shorewall6.conf +++ b/Shorewall6/Samples6/three-interfaces/shorewall6.conf @@ -177,6 +177,8 @@ OPTIMIZE=All OPTIMIZE_ACCOUNTING=No +REJECT_ACTION= + REQUIRE_INTERFACE=No RESTORE_ROUTEMARKS=Yes diff --git a/Shorewall6/Samples6/two-interfaces/shorewall6.conf b/Shorewall6/Samples6/two-interfaces/shorewall6.conf index c7e7a3f4d..ecf5de65d 100644 --- a/Shorewall6/Samples6/two-interfaces/shorewall6.conf +++ b/Shorewall6/Samples6/two-interfaces/shorewall6.conf @@ -177,6 +177,8 @@ OPTIMIZE=All OPTIMIZE_ACCOUNTING=No +REJECT_ACTION= + REQUIRE_INTERFACE=No RESTORE_ROUTEMARKS=Yes diff --git a/Shorewall6/configfiles/shorewall6.conf b/Shorewall6/configfiles/shorewall6.conf index 86e2be387..935af8328 100644 --- a/Shorewall6/configfiles/shorewall6.conf +++ b/Shorewall6/configfiles/shorewall6.conf @@ -177,6 +177,8 @@ OPTIMIZE=1 OPTIMIZE_ACCOUNTING=No +REJECT_ACTION= + REQUIRE_INTERFACE=No RESTORE_ROUTEMARKS=Yes diff --git a/Shorewall6/manpages/shorewall6.conf.xml b/Shorewall6/manpages/shorewall6.conf.xml index 0d08d7524..e4869a5ec 100644 --- a/Shorewall6/manpages/shorewall6.conf.xml +++ b/Shorewall6/manpages/shorewall6.conf.xml @@ -1816,6 +1816,8 @@ LOG:info:,bar net fw on the remote system that the files are to be copied into. + + @@ -1849,6 +1851,69 @@ LOG:info:,bar net fw + + REJECT_ACTION=action + + + Added in Shorewall 4.5.21. When a REJECT target is specified, + Shorewall normally handles the response as follows: + + + + If the destination address of the packet is a broadcast or + multicast address, the packet is dropped. + + + + if the protocol is ICMP (58) then the packet is + dropped. + + + + if the protocol is TCP (6) then the packet is rejected + with an RST. + + + + if the protocol is ICMP (1) then the packet is rejected + with a 'addr-unreachable' ICMP. + + + + otherwise, the packet is rejected with a 'adm-prohibited' + ICMP. + + + + You can modify this behavior by implementing your own + action that handles REJECT and specifying + it's name in this option. The nolog + option will automatically be assumed for the specified + action. + + The following action implements the standard behavior: + + ?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 + + + REQUIRE_INTERFACE=[Yes|No]