Add CONNLIMIT support

git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@8757 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
This commit is contained in:
teastep 2008-10-07 23:23:07 +00:00
parent 3e47ff2468
commit 28cc9eec76
10 changed files with 160 additions and 41 deletions

View File

@ -4,4 +4,6 @@ Changes in Shorewall 4.2.1
2) Fixed minor CONNBYTES editing issue.
3) Add CONNLIMIT to policy and rules.
Initial release of Shorewall 4.2.0.

View File

@ -7,6 +7,6 @@
# http://www.shorewall.net/manpages/shorewall-policy.html
#
###############################################################################
#SOURCE DEST POLICY LOG LIMIT:BURST
# LEVEL
#SOURCE DEST POLICY LOG LIMIT: CONNLIMIT:
# LEVEL BURST MASK
#LAST LINE -- DO NOT REMOVE

View File

@ -88,6 +88,43 @@ Problems corrected in Shorewall 4.2.1
non-zero. A value of zero for <max> was equivalent to omitting
<max>.
Other changes in Shorewall 4.2.1
1) With the recent renewed interest in DOS attacks, it seems
appropriate to have connection limiting support in Shorewall. To
that end, a CONNLIMIT column has been added to both the policy and
rules files.
The content of these columns is of the format
[!] <limit>[:<mask>]
where
<limit> is the limit on simultaneous TCP connections.
<mask> specifies the size of the network to which
the limit applies and is specified as a
CIDR mask length. The default value for
<mask> is 32 which means that each remote
IP address can have <limit> TCP connections
active at once.
! Not allowed in the policy file. In the rules file, it
causes connections to match when the number of
current connections exceeds <limit>.
When specified in the policy file, the limit is envorced on all
connections that are subject to the given policy (just like
LIMIT:BURST). The limit is checked on new connections before the
connection is passed through the rules in the NEW section of the
rules file.
It is important to note that while the limit is only checked for
those destinations specified in the DEST column, the number of
current connections is calculated over all destinations and not
just the destination specified in the DEST column.
New Features in Shorewall 4.2.
1) Shorewall 4.2 contains support for multiple Internet providers

View File

@ -6,8 +6,8 @@
# The manpage is also online at
# http://www.shorewall.net/manpages/shorewall-rules.html
#
############################################################################################################################
#ACTION SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE USER/ MARK
######################################################################################################################################
#ACTION SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE USER/ MARK CONNLIMIT
# PORT PORT(S) DEST LIMIT GROUP
#SECTION ESTABLISHED
#SECTION RELATED

View File

@ -120,6 +120,7 @@ our %EXPORT_TAGS = (
validate_mark
do_test
do_ratelimit
do_connlimit
do_user
do_tos
do_connbytes
@ -169,7 +170,7 @@ our $VERSION = 4.1.5;
# policychain => <name of policy chain> -- self-reference if this is a policy chain
# policypair => [ <policy source>, <policy dest> ] -- Used for reporting duplicated policies
# loglevel => <level>
# synparams => <burst/limit>
# synparams => <burst/limit + connlimit>
# synchain => <name of synparam chain>
# default => <default action>
# cmdlevel => <number of open loops or blocks in runtime commands>
@ -1269,6 +1270,26 @@ sub do_ratelimit( $$ ) {
}
}
#
# Create a "-m connlimit" match for the passed CONNLIMIT
#
sub do_connlimit( $ ) {
my ( $limit ) = @_;
return '' unless $limit and $limit ne '-';
my $invert = $limit =~ s/^!// ? '' : '! '; # Note Carefully -- we actually do 'connlimit-at-or-below'
if ( $limit =~ /^(\d+):(\d+)$/ ) {
fatal_error "Invalid Mask ($2)" unless $2 > 0 || $2 < 31;
"-m connlimit ${invert}--connlimit-above $1 --connmask $2";
} elsif ( $limit =~ /^(\d+)$/ ) {
"-m connlimit ${invert}--connlimit-above $limit ";
} else {
fatal_error "Invalid connlimit ($limit)";
}
}
#
# Create a "-m owner" match for the passed USER/GROUP
#

View File

@ -212,10 +212,11 @@ sub validate_policy()
while ( read_a_line ) {
my ( $client, $server, $originalpolicy, $loglevel, $synparams ) = split_line 3, 5, 'policy file';
my ( $client, $server, $originalpolicy, $loglevel, $synparams, $connlimit ) = split_line 3, 6, 'policy file';
$loglevel = '' if $loglevel eq '-';
$synparams = '' if $synparams eq '-';
$connlimit = '' if $connlimit eq '-';
my $clientwild = ( "\L$client" eq 'all' );
@ -300,8 +301,12 @@ sub validate_policy()
$chainref->{loglevel} = validate_level( $loglevel ) if defined $loglevel && $loglevel ne '';
if ( $synparams ne '' ) {
$chainref->{synparams} = do_ratelimit $synparams, 'ACCEPT';
if ( $synparams ne '' || $connlimit ne '' ) {
my $value = '';
fatal_error "Invalid CONNLIMIT ($connlimit)" if $connlimit =~ /^!/;
$value = do_ratelimit $synparams, 'ACCEPT' if $synparams ne '';
$value = do_connlimit $connlimit if $connlimit ne '';
$chainref->{synparams} = $value;
$chainref->{synchain} = $chain
}

View File

@ -811,13 +811,13 @@ sub setup_mac_lists( $ ) {
}
}
sub process_rule1 ( $$$$$$$$$$$ );
sub process_rule1 ( $$$$$$$$$$$$ );
#
# Expand a macro rule from the rules file
#
sub process_macro ( $$$$$$$$$$$$$ ) {
my ($macro, $target, $param, $source, $dest, $proto, $ports, $sports, $origdest, $rate, $user, $mark, $wildcard ) = @_;
sub process_macro ( $$$$$$$$$$$$$$ ) {
my ($macro, $target, $param, $source, $dest, $proto, $ports, $sports, $origdest, $rate, $user, $mark, $connlimit, $wildcard ) = @_;
my $nocomment = no_comment;
@ -906,6 +906,7 @@ sub process_macro ( $$$$$$$$$$$$$ ) {
merge_macro_column( $mrate, $rate ) ,
merge_macro_column( $muser, $user ) ,
$mark,
$connlimit,
$wildcard
);
@ -923,8 +924,8 @@ sub process_macro ( $$$$$$$$$$$$$ ) {
# Once a rule has been expanded via wildcards (source and/or dest zone == 'all'), it is processed by this function. If
# the target is a macro, the macro is expanded and this function is called recursively for each rule in the expansion.
#
sub process_rule1 ( $$$$$$$$$$$ ) {
my ( $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $wildcard ) = @_;
sub process_rule1 ( $$$$$$$$$$$$ ) {
my ( $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $connlimit, $wildcard ) = @_;
my ( $action, $loglevel) = split_action $target;
my ( $basictarget, $param ) = get_target_param $action;
my $rule = '';
@ -967,6 +968,7 @@ sub process_rule1 ( $$$$$$$$$$$ ) {
$ratelimit,
$user,
$mark,
$connlimit,
$wildcard );
$macro_nest_level--;
@ -1106,7 +1108,7 @@ sub process_rule1 ( $$$$$$$$$$$ ) {
#
# Generate Fixed part of the rule
#
$rule = join( '', do_proto($proto, $ports, $sports), do_ratelimit( $ratelimit, $basictarget ) , do_user( $user ) , do_test( $mark , 0xFF ) );
$rule = join( '', do_proto($proto, $ports, $sports), do_ratelimit( $ratelimit, $basictarget ) , do_user( $user ) , do_test( $mark , 0xFF ) , do_connlimit( $connlimit ) );
unless ( $section eq 'NEW' ) {
fatal_error "Entries in the $section SECTION of the rules file not permitted with FASTACCEPT=Yes" if $config{FASTACCEPT};
@ -1171,7 +1173,7 @@ sub process_rule1 ( $$$$$$$$$$$ ) {
my $interfacesref = $sourceref->{interfaces};
my @interfaces = keys %$interfacesref;
$origdest = @interfaces ? "detect:@interfaces" : ALLIPv4;
} else {
} else {
$origdest = ALLIPv4;
}
}
@ -1265,6 +1267,7 @@ sub process_rule1 ( $$$$$$$$$$$ ) {
$action ,
'' );
}
#
# Add filter table rule, unless this is a NATONLY rule type
#
@ -1281,7 +1284,7 @@ sub process_rule1 ( $$$$$$$$$$$ ) {
$origdest = '';
}
expand_rule( ensure_chain ('filter', $chain ) ,
expand_rule( ensure_chain( 'filter', $chain ) ,
$restriction ,
$rule ,
$source ,
@ -1299,8 +1302,8 @@ sub process_rule1 ( $$$$$$$$$$$ ) {
#
# Deals with the ugliness of wildcard zones ('all' in SOURCE and/or DEST column).
#
sub process_rule ( $$$$$$$$$$ ) {
my ( $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark ) = @_;
sub process_rule ( $$$$$$$$$$$ ) {
my ( $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $connlimit ) = @_;
my $intrazone = 0;
my $includesrcfw = 1;
my $includedstfw = 1;
@ -1362,7 +1365,7 @@ sub process_rule ( $$$$$$$$$$ ) {
for my $zone1 ( all_zones ) {
if ( $includedstfw || ( zone_type( $zone1 ) ne 'firewall' ) ) {
if ( $intrazone || ( $zone ne $zone1 ) ) {
process_rule1 $target, $zone, $zone1 , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, 1;
process_rule1 $target, $zone, $zone1 , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $connlimit, 1;
}
}
}
@ -1370,7 +1373,7 @@ sub process_rule ( $$$$$$$$$$ ) {
my $destzone = (split( /:/, $dest, 2 ) )[0];
$destzone = firewall_zone unless defined_zone( $destzone ); # We do this to allow 'REDIRECT all ...'; process_rule1 will catch the case where the dest zone is invalid
if ( $intrazone || ( $zone ne $destzone ) ) {
process_rule1 $target, $zone, $dest , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, 1;
process_rule1 $target, $zone, $dest , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $connlimit, 1;
}
}
}
@ -1379,11 +1382,11 @@ sub process_rule ( $$$$$$$$$$ ) {
for my $zone ( all_zones ) {
my $sourcezone = ( split( /:/, $source, 2 ) )[0];
if ( ( $includedstfw || ( zone_type( $zone ) ne 'firewall') ) && ( ( $sourcezone ne $zone ) || $intrazone) ) {
process_rule1 $target, $source, $zone , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, 1;
process_rule1 $target, $source, $zone , $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $connlimit, 1;
}
}
} else {
process_rule1 $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, 0;
process_rule1 $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $connlimit, 0;
}
progress_message " Rule \"$thisline\" $done";
@ -1400,7 +1403,7 @@ sub process_rules() {
while ( read_a_line ) {
my ( $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark ) = split_line1 1, 10, 'rules file', \%rules_commands;
my ( $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $connlimit ) = split_line1 1, 11, 'rules file', \%rules_commands;
if ( $target eq 'COMMENT' ) {
process_comment;
@ -1426,7 +1429,7 @@ sub process_rules() {
if ( "\L$source" =~ /^none(:.*)?$/ || "\L$dest" =~ /^none(:.*)?$/ ) {
progress_message "Rule \"$currentline\" ignored."
} else {
process_rule $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark;
process_rule $target, $source, $dest, $proto, $ports, $sports, $origdest, $ratelimit, $user, $mark, $connlimit;
}
}
}

View File

@ -357,13 +357,14 @@ State:Stopped (Thu Mar 30 14:08:11 PDT 2006)</programlisting>
</listitem>
<listitem>
<para>Please give details about what doesn't work. Reports that say
<quote>I followed the directions and it didn't work</quote> may elicit
sympathy but probably little in the way of help. Again -- if ping from
A to B fails, say so (and see below for information about reporting
<quote>ping</quote> problems). If Computer B doesn't show up in
<quote>Network Neighborhood</quote> then say so. If access by IP
address works but by DNS names it doesn't then say so.</para>
<para>Please <emphasis role="bold">give details about what doesn't
work</emphasis>. Reports that say <quote>I followed the directions and
it didn't work</quote> may elicit sympathy but probably little in the
way of help. Again -- if ping from A to B fails, say so (and see below
for information about reporting <quote>ping</quote> problems). If
Computer B doesn't show up in <quote>Network Neighborhood</quote> then
say so. If access by IP address works but by DNS names it doesn't then
say so.</para>
</listitem>
<listitem>
@ -373,10 +374,10 @@ State:Stopped (Thu Mar 30 14:08:11 PDT 2006)</programlisting>
</listitem>
<listitem>
<para>Please do NOT include the output of <command>iptables
-L</command> — the output of <emphasis role="bold">shorewall
show</emphasis> or <command>shorewall dump</command> is much more
useful to us.</para>
<para>Please <emphasis role="bold">do NOT include the output
of</emphasis> <command>iptables -L</command> — the output of <emphasis
role="bold">shorewall show</emphasis> or <command>shorewall
dump</command> is much more useful to us.</para>
</listitem>
<listitem>
@ -387,10 +388,10 @@ State:Stopped (Thu Mar 30 14:08:11 PDT 2006)</programlisting>
</listitem>
<listitem>
<para>Please do not include Shorewall configuration files unless you
have been specifically asked to do so. The output of
<command>shorewall dump</command> collected as described above is much
more useful.</para>
<para>Please <emphasis role="bold">do not include Shorewall
configuration files</emphasis> unless you have been specifically asked
to do so. The output of <command>shorewall dump</command> collected as
described above is much more useful.</para>
</listitem>
<listitem>

View File

@ -1,4 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<refentry>
<refmeta>
<refentrytitle>shorewall-policy</refentrytitle>
@ -235,6 +237,29 @@
not limited.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><emphasis role="bold">CONNLIMIT</emphasis> - [<emphasis
role="bold">!</emphasis>]<emphasis>limit</emphasis>[:<emphasis>mask</emphasis>]</term>
<listitem>
<para>Added in Shorewall-perl 4.2.1. May be used to limit the number
of simultaneous connections from each individual host to
<replaceable>limit</replaceable> connections. While the limit is
only checked on connections to which this policy could apply, the
number of current connections is calculated over all current
connections from the SOURCE host. By default, the limit is applied
to each host individually but can be made to apply to networks of
hosts by specifying a <replaceable>mask</replaceable>. The
<replaceable>mask</replaceable> specifies the width of a VLSM mask
to be applied to the source address; the number of current
connections is then taken over all hosts in the subnet
<replaceable>source-address</replaceable>/<replaceable>mask</replaceable>.
When<option> !</option> is specified, the rule matches when the
number of connection exceeds the
<replaceable>limit</replaceable>.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
@ -287,4 +312,4 @@
shorewall-tcrules(5), shorewall-tos(5), shorewall-tunnels(5),
shorewall-zones(5)</para>
</refsect1>
</refentry>
</refentry>

View File

@ -1,4 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<refentry>
<refmeta>
<refentrytitle>shorewall-rules</refentrytitle>
@ -1071,6 +1073,29 @@
</variablelist>
</listitem>
</varlistentry>
<varlistentry>
<term><emphasis role="bold">CONNLIMIT</emphasis> - [<emphasis
role="bold">!</emphasis>]<emphasis>limit</emphasis>[:<emphasis>mask</emphasis>]</term>
<listitem>
<para>Added in Shorewall-perl 4.2.1. May be used to limit the number
of simultaneous connections from each individual host to
<replaceable>limit</replaceable> connections. While the limit is
only checked on rules specifying CONNLIMIT, the number of current
connections is calculated over all current connections from the
SOURCE host. By default, the limit is applied to each host but can
be made to apply to networks of hosts by specifying a
<replaceable>mask</replaceable>. The <replaceable>mask</replaceable>
specifies the width of a VLSM mask to be applied to the source
address; the number of current connections is then taken over all
hosts in the subnet
<replaceable>source-address</replaceable>/<replaceable>mask</replaceable>.
When<option> !</option> is specified, the rule matches when the
number of connection exceeds the
<replaceable>limit</replaceable>.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
@ -1267,4 +1292,4 @@
shorewall-tcclasses(5), shorewall-tcdevices(5), shorewall-tcrules(5),
shorewall-tos(5), shorewall-tunnels(5), shorewall-zones(5)</para>
</refsect1>
</refentry>
</refentry>