2009-02-22 22:15:05 +01:00
|
|
|
#
|
2009-06-13 16:07:55 +02:00
|
|
|
# Shorewall 4.4 -- /usr/share/shorewall/Shorewall/Raw.pm
|
2009-02-22 22:15:05 +01:00
|
|
|
#
|
|
|
|
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
|
|
#
|
2011-05-23 19:06:56 +02:00
|
|
|
# (c) 2009,2010,2011 - Tom Eastep (teastep@shorewall.net)
|
2009-02-22 22:15:05 +01:00
|
|
|
#
|
|
|
|
# Complete documentation is available at http://shorewall.net
|
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of Version 2 of the GNU General Public License
|
|
|
|
# as published by the Free Software Foundation.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program; if not, write to the Free Software
|
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
#
|
2012-08-03 19:53:20 +02:00
|
|
|
# This module contains the code that handles the /etc/shorewall/conntrack file.
|
2009-02-22 22:15:05 +01:00
|
|
|
#
|
|
|
|
package Shorewall::Raw;
|
|
|
|
require Exporter;
|
|
|
|
use Shorewall::Config qw(:DEFAULT :internal);
|
|
|
|
use Shorewall::IPAddrs;
|
|
|
|
use Shorewall::Zones;
|
|
|
|
use Shorewall::Chains qw(:DEFAULT :internal);
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
|
|
|
|
our @ISA = qw(Exporter);
|
2012-08-08 16:23:20 +02:00
|
|
|
our @EXPORT = qw( setup_conntrack );
|
2012-08-11 16:48:03 +02:00
|
|
|
our @EXPORT_OK = qw( handle_helper_rule );
|
2011-07-11 00:10:27 +02:00
|
|
|
our $VERSION = 'MODULEVERSION';
|
2009-02-22 22:15:05 +01:00
|
|
|
|
2011-12-05 02:15:58 +01:00
|
|
|
my %valid_ctevent = ( new => 1, related => 1, destroy => 1, reply => 1, assured => 1, protoinfo => 1, helper => 1, mark => 1, natseqinfo => 1, secmark => 1 );
|
|
|
|
|
2009-02-22 22:15:05 +01:00
|
|
|
#
|
|
|
|
# Notrack
|
|
|
|
#
|
2012-11-21 23:20:56 +01:00
|
|
|
sub process_conntrack_rule( $$$$$$$$$$ ) {
|
2009-02-22 22:15:05 +01:00
|
|
|
|
2012-11-21 23:20:56 +01:00
|
|
|
my ($chainref, $zoneref, $action, $source, $dest, $proto, $ports, $sports, $user, $switch ) = @_;
|
2012-08-11 16:48:03 +02:00
|
|
|
|
|
|
|
require_capability 'RAW_TABLE', 'conntrack rules', '';
|
2009-02-22 22:15:05 +01:00
|
|
|
|
|
|
|
$proto = '' if $proto eq 'any';
|
|
|
|
$ports = '' if $ports eq 'any' || $ports eq 'all';
|
|
|
|
$sports = '' if $sports eq 'any' || $sports eq 'all';
|
|
|
|
|
2012-08-11 16:48:03 +02:00
|
|
|
my $zone;
|
|
|
|
my $restriction = PREROUTE_RESTRICT;
|
2009-02-22 22:15:05 +01:00
|
|
|
|
2012-11-21 22:07:01 +01:00
|
|
|
if ( $chainref ) {
|
2012-11-26 03:37:23 +01:00
|
|
|
$restriction = OUTPUT_RESTRICT if $chainref->{name} eq 'OUTPUT';
|
2012-11-21 22:07:01 +01:00
|
|
|
} else {
|
2012-08-11 16:48:03 +02:00
|
|
|
#
|
|
|
|
# Entry in the conntrack file
|
|
|
|
#
|
|
|
|
if ( $zoneref ) {
|
|
|
|
$zone = $zoneref->{name};
|
|
|
|
} else {
|
|
|
|
($zone, $source) = split /:/, $source, 2;
|
|
|
|
$zoneref = find_zone ( $zone );
|
|
|
|
}
|
|
|
|
|
|
|
|
$chainref = ensure_raw_chain( notrack_chain $zone );
|
2012-11-26 03:37:23 +01:00
|
|
|
$restriction = OUTPUT_RESTRICT if $zoneref->{type} & (FIREWALL | VSERVER );
|
2012-08-11 16:48:03 +02:00
|
|
|
fatal_error 'USER/GROUP is not allowed unless the SOURCE zone is $FW or a Vserver zone' if $user ne '-' && $restriction != OUTPUT_RESTRICT;
|
|
|
|
}
|
2009-02-22 22:15:05 +01:00
|
|
|
|
2011-12-05 02:15:58 +01:00
|
|
|
my $target = $action;
|
2011-12-18 16:21:32 +01:00
|
|
|
my $exception_rule = '';
|
2012-11-21 23:20:56 +01:00
|
|
|
my $rule = do_proto( $proto, $ports, $sports ) . do_user ( $user ) . do_condition( $switch );
|
2011-12-05 02:15:58 +01:00
|
|
|
|
2012-08-26 17:08:57 +02:00
|
|
|
if ( $action eq 'NOTRACK' ) {
|
|
|
|
#
|
|
|
|
# A patch that deimplements the NOTRACK target has been posted on the
|
|
|
|
# Netfilter development list
|
|
|
|
#
|
2012-08-26 18:17:57 +02:00
|
|
|
$action = 'CT --notrack' if have_capability 'CT_TARGET';
|
2012-11-18 20:35:40 +01:00
|
|
|
} elsif ( $action ne 'DROP' ) {
|
2011-12-05 02:15:58 +01:00
|
|
|
( $target, my ( $option, $args, $junk ) ) = split ':', $action, 4;
|
|
|
|
|
|
|
|
fatal_error "Invalid notrack ACTION ( $action )" if $junk || $target ne 'CT';
|
|
|
|
|
2012-08-03 19:53:20 +02:00
|
|
|
require_capability 'CT_TARGET', 'CT entries in the conntrack file', '';
|
2011-12-05 02:15:58 +01:00
|
|
|
|
|
|
|
if ( $option eq 'notrack' ) {
|
2012-08-03 19:53:20 +02:00
|
|
|
fatal_error "Invalid conntrack ACTION ( $action )" if supplied $args;
|
2011-12-05 02:15:58 +01:00
|
|
|
$action = 'CT --notrack';
|
|
|
|
} else {
|
|
|
|
fatal_error "Invalid or missing CT option and arguments" unless supplied $option && supplied $args;
|
|
|
|
|
2011-12-17 17:59:27 +01:00
|
|
|
if ( $option eq 'helper' ) {
|
2012-08-02 20:10:08 +02:00
|
|
|
my $modifiers = '';
|
|
|
|
|
2012-08-02 22:25:44 +02:00
|
|
|
if ( $args =~ /^([-\w.]+)\((.+)\)$/ ) {
|
2012-08-02 20:10:08 +02:00
|
|
|
$args = $1;
|
|
|
|
$modifiers = $2;
|
|
|
|
}
|
|
|
|
|
2011-12-17 17:59:27 +01:00
|
|
|
fatal_error "Invalid helper' ($args)" if $args =~ /,/;
|
2011-12-24 18:24:01 +01:00
|
|
|
validate_helper( $args, $proto );
|
2012-08-07 00:54:45 +02:00
|
|
|
$action = "CT --helper $helpers_aliases{$args}";
|
2011-12-18 16:21:32 +01:00
|
|
|
$exception_rule = do_proto( $proto, '-', '-' );
|
2011-12-05 02:15:58 +01:00
|
|
|
|
2012-08-05 17:09:17 +02:00
|
|
|
for my $mod ( split_list1( $modifiers, 'ctevents' ) ) {
|
2012-08-02 20:10:08 +02:00
|
|
|
fatal_error "Invalid helper option ($mod)" unless $mod =~ /^(\w+)=(.+)$/;
|
2012-08-05 17:09:17 +02:00
|
|
|
$mod = $1;
|
|
|
|
my $val = $2;
|
2012-08-02 20:10:08 +02:00
|
|
|
|
|
|
|
if ( $mod eq 'ctevents' ) {
|
2012-08-05 17:09:17 +02:00
|
|
|
for ( split_list( $val, 'ctevents' ) ) {
|
2012-08-02 20:10:08 +02:00
|
|
|
fatal_error "Invalid 'ctevents' event ($_)" unless $valid_ctevent{$_};
|
|
|
|
}
|
|
|
|
|
2012-08-05 17:09:17 +02:00
|
|
|
$action .= " --ctevents $val";
|
2012-08-02 20:10:08 +02:00
|
|
|
} elsif ( $mod eq 'expevents' ) {
|
2012-08-05 17:09:17 +02:00
|
|
|
fatal_error "Invalid expevent argument ($val)" unless $val eq 'new';
|
2012-08-02 20:10:08 +02:00
|
|
|
$action .= ' --expevents new';
|
|
|
|
} else {
|
|
|
|
fatal_error "Invalid helper option ($mod)";
|
|
|
|
}
|
|
|
|
}
|
2012-08-05 17:09:17 +02:00
|
|
|
} else {
|
|
|
|
fatal_error "Invalid CT option ($option)";
|
2011-12-05 02:15:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-19 00:01:13 +01:00
|
|
|
expand_rule( $chainref ,
|
|
|
|
$restriction ,
|
2011-12-24 02:55:13 +01:00
|
|
|
$rule,
|
2011-12-19 00:01:13 +01:00
|
|
|
$source ,
|
|
|
|
$dest ,
|
|
|
|
'' ,
|
|
|
|
$action ,
|
|
|
|
'' ,
|
|
|
|
$target ,
|
|
|
|
$exception_rule );
|
2012-04-24 23:52:57 +02:00
|
|
|
|
2012-08-08 16:23:20 +02:00
|
|
|
progress_message " Conntrack rule \"$currentline\" $done";
|
2009-02-22 22:15:05 +01:00
|
|
|
}
|
|
|
|
|
2012-08-11 16:48:03 +02:00
|
|
|
sub handle_helper_rule( $$$$$$$$$$$ ) {
|
|
|
|
my ( $helper, $source, $dest, $proto, $ports, $sports, $sourceref, $action_target, $actionchain, $user, $rule ) = @_;
|
|
|
|
|
|
|
|
if ( $helper ne '-' ) {
|
|
|
|
fatal_error "A HELPER is not allowed with this ACTION" if $action_target;
|
|
|
|
#
|
|
|
|
# This means that an ACCEPT or NAT rule with a helper is being processed
|
|
|
|
#
|
|
|
|
process_conntrack_rule( $actionchain ? ensure_raw_chain( $actionchain ) : undef ,
|
|
|
|
$sourceref ,
|
|
|
|
"CT:helper:$helper",
|
|
|
|
$source ,
|
|
|
|
$dest ,
|
|
|
|
$proto ,
|
|
|
|
$ports ,
|
|
|
|
$sports ,
|
2012-11-21 23:20:56 +01:00
|
|
|
$user,
|
|
|
|
'-',
|
|
|
|
);
|
2012-08-11 16:48:03 +02:00
|
|
|
} else {
|
|
|
|
assert( $action_target );
|
|
|
|
#
|
|
|
|
# The target is an action
|
|
|
|
#
|
|
|
|
if ( $actionchain ) {
|
|
|
|
#
|
|
|
|
# And the source is another action chain
|
|
|
|
#
|
|
|
|
expand_rule( ensure_raw_chain( $actionchain ) ,
|
|
|
|
PREROUTE_RESTRICT ,
|
|
|
|
$rule ,
|
|
|
|
$source ,
|
|
|
|
$dest ,
|
|
|
|
'' ,
|
|
|
|
$action_target ,
|
|
|
|
'',
|
|
|
|
'CT' ,
|
|
|
|
'' );
|
|
|
|
} else {
|
|
|
|
expand_rule( ensure_raw_chain( notrack_chain( $sourceref->{name} ) ) ,
|
|
|
|
( $sourceref->{type} == FIREWALL || $sourceref->{type} == VSERVER ?
|
|
|
|
OUTPUT_RESTRICT :
|
|
|
|
PREROUTE_RESTRICT ) ,
|
|
|
|
$rule ,
|
|
|
|
$source ,
|
|
|
|
$dest ,
|
|
|
|
'' ,
|
|
|
|
$action_target ,
|
|
|
|
'' ,
|
|
|
|
'CT' ,
|
|
|
|
'' );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-05 02:15:58 +01:00
|
|
|
sub process_format( $ ) {
|
|
|
|
my $format = shift;
|
|
|
|
|
2012-11-23 05:56:56 +01:00
|
|
|
fatal_error q(FORMAT must be '1', '2' or '3') unless $format =~ /^[123]$/;
|
2011-12-05 02:15:58 +01:00
|
|
|
|
|
|
|
$format;
|
|
|
|
}
|
|
|
|
|
2012-08-08 16:23:20 +02:00
|
|
|
sub setup_conntrack() {
|
2009-02-22 22:15:05 +01:00
|
|
|
|
2012-08-13 16:28:07 +02:00
|
|
|
for my $name ( qw/notrack conntrack/ ) {
|
2012-08-02 20:02:17 +02:00
|
|
|
|
2012-08-13 16:28:07 +02:00
|
|
|
my $fn = open_file( $name );
|
2012-08-02 20:02:17 +02:00
|
|
|
|
2012-08-13 16:28:07 +02:00
|
|
|
if ( $fn ) {
|
2009-02-22 22:15:05 +01:00
|
|
|
|
2012-08-16 23:46:48 +02:00
|
|
|
my $format = 1;
|
|
|
|
|
|
|
|
my $action = 'NOTRACK';
|
|
|
|
|
2012-08-13 16:28:07 +02:00
|
|
|
my $empty = 1;
|
2009-02-22 22:15:05 +01:00
|
|
|
|
2012-08-16 19:49:59 +02:00
|
|
|
first_entry( "$doing $fn..." );
|
2009-02-22 22:15:05 +01:00
|
|
|
|
2012-08-13 16:28:07 +02:00
|
|
|
while ( read_a_line( NORMAL_READ ) ) {
|
2012-11-21 23:20:56 +01:00
|
|
|
my ( $source, $dest, $proto, $ports, $sports, $user, $switch );
|
2011-12-05 02:15:58 +01:00
|
|
|
|
2012-08-13 16:28:07 +02:00
|
|
|
if ( $format == 1 ) {
|
2012-11-21 23:20:56 +01:00
|
|
|
( $source, $dest, $proto, $ports, $sports, $user, $switch ) = split_line1 'Conntrack File', { source => 0, dest => 1, proto => 2, dport => 3, sport => 4, user => 5, switch => 6 };
|
2012-04-24 23:52:57 +02:00
|
|
|
|
2012-08-13 16:28:07 +02:00
|
|
|
if ( $source eq 'FORMAT' ) {
|
|
|
|
$format = process_format( $dest );
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
} else {
|
2012-11-21 23:20:56 +01:00
|
|
|
( $action, $source, $dest, $proto, $ports, $sports, $user, $switch ) = split_line1 'Conntrack File', { action => 0, source => 1, dest => 2, proto => 3, dport => 4, sport => 5, user => 6, switch => 7 }, { COMMENT => 0, FORMAT => 2 };
|
2012-04-24 23:52:57 +02:00
|
|
|
|
2012-08-13 16:28:07 +02:00
|
|
|
if ( $action eq 'FORMAT' ) {
|
|
|
|
$format = process_format( $source );
|
|
|
|
$action = 'NOTRACK';
|
|
|
|
next;
|
|
|
|
}
|
2012-08-16 23:46:48 +02:00
|
|
|
}
|
2012-08-13 16:28:07 +02:00
|
|
|
|
2012-08-16 23:46:48 +02:00
|
|
|
if ( $action eq 'COMMENT' ) {
|
|
|
|
process_comment;
|
|
|
|
next;
|
2011-12-05 02:15:58 +01:00
|
|
|
}
|
2012-04-24 23:52:57 +02:00
|
|
|
|
2012-08-16 19:49:59 +02:00
|
|
|
$empty = 0;
|
|
|
|
|
2012-11-23 05:56:56 +01:00
|
|
|
if ( $format < 3 ) {
|
|
|
|
if ( $source =~ /^all(-)?(:(.+))?$/ ) {
|
|
|
|
fatal_error 'USER/GROUP is not allowed unless the SOURCE zone is $FW or a Vserver zone' if $user ne '-';
|
2012-11-26 01:31:05 +01:00
|
|
|
for my $zone ( $1 ? off_firewall_zones : all_zones ) {
|
|
|
|
process_conntrack_rule( undef ,
|
|
|
|
undef,
|
|
|
|
$action,
|
|
|
|
$zone . ( $2 || ''),
|
|
|
|
$dest,
|
|
|
|
$proto,
|
|
|
|
$ports,
|
|
|
|
$sports,
|
|
|
|
$user ,
|
|
|
|
$switch );
|
|
|
|
}
|
2012-11-23 05:56:56 +01:00
|
|
|
} else {
|
|
|
|
process_conntrack_rule( undef, undef, $action, $source, $dest, $proto, $ports, $sports, $user, $switch );
|
|
|
|
}
|
2012-11-25 17:52:33 +01:00
|
|
|
} elsif ( $action =~ s/:O$// ) {
|
2012-11-23 05:56:56 +01:00
|
|
|
process_conntrack_rule( $raw_table->{OUTPUT}, undef, $action, $source, $dest, $proto, $ports, $sports, $user, $switch );
|
|
|
|
} elsif ( $action =~ s/:OP// || $action =~ s/:PO// ) {
|
|
|
|
process_conntrack_rule( $raw_table->{PREROUTING}, undef, $action, $source, $dest, $proto, $ports, $sports, $user, $switch );
|
|
|
|
process_conntrack_rule( $raw_table->{OUTPUT}, undef, $action, $source, $dest, $proto, $ports, $sports, $user, $switch );
|
2012-08-13 16:28:07 +02:00
|
|
|
} else {
|
2012-11-23 05:56:56 +01:00
|
|
|
$action =~ s/:P//;
|
|
|
|
process_conntrack_rule( $raw_table->{PREROUTING}, undef, $action, $source, $dest, $proto, $ports, $sports, $user, $switch );
|
|
|
|
}
|
2010-09-28 19:48:44 +02:00
|
|
|
}
|
2012-04-24 23:52:57 +02:00
|
|
|
|
2012-08-13 16:28:07 +02:00
|
|
|
clear_comment;
|
|
|
|
|
2012-08-16 23:46:48 +02:00
|
|
|
if ( $name eq 'notrack') {
|
|
|
|
if ( $empty ) {
|
|
|
|
if ( unlink( $fn ) ) {
|
|
|
|
warning_message "Empty notrack file ($fn) removed";
|
|
|
|
} else {
|
|
|
|
warning_message "Unable to remove empty notrack file ($fn): $!";
|
|
|
|
}
|
2012-08-13 16:28:07 +02:00
|
|
|
} else {
|
2012-08-16 23:46:48 +02:00
|
|
|
warning_message "Non-empty notrack file ($fn); please move its contents to the conntrack file";
|
2012-08-02 20:10:08 +02:00
|
|
|
}
|
|
|
|
}
|
2009-02-22 22:15:05 +01:00
|
|
|
}
|
2010-09-28 19:48:44 +02:00
|
|
|
}
|
2009-02-22 22:15:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
1;
|