Allow two limits in the RATE LIMIT columns

Signed-off-by: Tom Eastep <teastep@shorewall.net>
This commit is contained in:
Tom Eastep 2014-10-22 11:21:43 -07:00
parent 54461a9a90
commit f5bdc9e7f4
3 changed files with 158 additions and 75 deletions

View File

@ -4876,62 +4876,79 @@ my %norate = ( DROP => 1, REJECT => 1 );
# Create a "-m limit" match for the passed LIMIT/BURST # Create a "-m limit" match for the passed LIMIT/BURST
# #
sub do_ratelimit( $$ ) { sub do_ratelimit( $$ ) {
my ( $rate, $action ) = @_; my ( $rates, $action ) = @_;
return '' unless $rate and $rate ne '-'; return '' unless $rates and $rates ne '-';
fatal_error "Rate Limiting not available with $action" if $norate{$action}; fatal_error "Rate Limiting not available with $action" if $norate{$action};
#
# "-m hashlimit" match for the passed LIMIT/BURST
#
if ( $rate =~ /^[sd]:{1,2}/ ) {
require_capability 'HASHLIMIT_MATCH', 'Per-ip rate limiting' , 's';
my $limit = "-m hashlimit "; my @rates = split_list $rates, 'rate';
my $match = have_capability( 'OLD_HL_MATCH' ) ? 'hashlimit' : 'hashlimit-upto';
my $units;
if ( $rate =~ /^[sd]:((\w*):)?((\d+)(\/(sec|min|hour|day))?):(\d+)$/ ) { if ( @rates == 2 ) {
fatal_error "Invalid Rate ($3)" unless $4; $rates[0] = 's:' . $rates[0];
fatal_error "Invalid Burst ($7)" unless $7; $rates[1] = 'd:' . $rates[1];
$limit .= "--$match $3 --hashlimit-burst $7 --hashlimit-name "; } elsif ( @rates > 2 ) {
$limit .= $2 ? $2 : 'shorewall' . $hashlimitset++; fatal error "Only two rates may be specified";
$limit .= ' --hashlimit-mode '; }
$units = $6;
} elsif ( $rate =~ /^[sd]:((\w*):)?((\d+)(\/(sec|min|hour|day))?)$/ ) {
fatal_error "Invalid Rate ($3)" unless $4;
$limit .= "--$match $3 --hashlimit-name ";
$limit .= $2 ? $2 : 'shorewall' . $hashlimitset++;
$limit .= ' --hashlimit-mode ';
$units = $6;
} else {
fatal_error "Invalid rate ($rate)";
}
$limit .= $rate =~ /^s:/ ? 'srcip ' : 'dstip '; my $limit = '';
if ( $units && $units ne 'sec' ) { for my $rate ( @rates ) {
my $expire = 60000; # 1 minute in milliseconds #
# "-m hashlimit" match for the passed LIMIT/BURST
#
if ( $rate =~ /^([sd]):{1,2}/ ) {
require_capability 'HASHLIMIT_MATCH', 'Per-ip rate limiting' , 's';
if ( $units ne 'min' ) { my $match = have_capability( 'OLD_HL_MATCH' ) ? 'hashlimit' : 'hashlimit-upto';
$expire *= 60; #At least an hour my $units;
$expire *= 24 if $units eq 'day';
$limit .= "-m hashlimit ";
if ( $rate =~ /^[sd]:((\w*):)?((\d+)(\/(sec|min|hour|day))?):(\d+)$/ ) {
fatal_error "Invalid Rate ($3)" unless $4;
fatal_error "Invalid Burst ($7)" unless $7;
$limit .= "--$match $3 --hashlimit-burst $7 --hashlimit-name ";
$limit .= $2 ? $2 : 'shorewall' . $hashlimitset++;
$limit .= ' --hashlimit-mode ';
$units = $6;
} elsif ( $rate =~ /^[sd]:((\w*):)?((\d+)(\/(sec|min|hour|day))?)$/ ) {
fatal_error "Invalid Rate ($3)" unless $4;
$limit .= "--$match $3 --hashlimit-name ";
$limit .= $2 ? $2 : 'shorewall' . $hashlimitset++;
$limit .= ' --hashlimit-mode ';
$units = $6;
} else {
fatal_error "Invalid rate ($rate)";
} }
$limit .= "--hashlimit-htable-expire $expire "; $limit .= $rate =~ /^s:/ ? 'srcip ' : 'dstip ';
}
$limit; if ( $units && $units ne 'sec' ) {
} elsif ( $rate =~ /^((\d+)(\/(sec|min|hour|day))?):(\d+)$/ ) { my $expire = 60000; # 1 minute in milliseconds
fatal_error "Invalid Rate ($1)" unless $2;
fatal_error "Invalid Burst ($5)" unless $5; if ( $units ne 'min' ) {
"-m limit --limit $1 --limit-burst $5 "; $expire *= 60; #At least an hour
} elsif ( $rate =~ /^(\d+)(\/(sec|min|hour|day))?$/ ) { $expire *= 24 if $units eq 'day';
fatal_error "Invalid Rate (${1}${2})" unless $1; }
"-m limit --limit $rate ";
} else { $limit .= "--hashlimit-htable-expire $expire ";
fatal_error "Invalid rate ($rate)"; }
} else {
if ( $rate =~ /^((\d+)(\/(sec|min|hour|day))?):(\d+)$/ ) {
fatal_error "Invalid Rate ($1)" unless $2;
fatal_error "Invalid Burst ($5)" unless $5;
$limit = "-m limit --limit $1 --limit-burst $5 ";
} elsif ( $rate =~ /^(\d+)(\/(sec|min|hour|day))?$/ ) {
fatal_error "Invalid Rate (${1}${2})" unless $1;
$limit = "-m limit --limit $rate ";
} else {
fatal_error "Invalid rate ($rate)";
}
}
} }
$limit;
} }
# #

View File

@ -1226,22 +1226,41 @@
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><emphasis role="bold">RATE LIMIT</emphasis> (rate) - [<emphasis <term><emphasis role="bold">RATE LIMIT</emphasis> (rate) -
role="bold">-</emphasis>|[{<emphasis>s</emphasis>|<emphasis <replaceable>limit</replaceable></term>
role="bold">d</emphasis>}:[[<replaceable>name</replaceable>]:]]]<emphasis>rate</emphasis><emphasis
role="bold">/</emphasis>{<emphasis
role="bold">sec</emphasis>|<emphasis
role="bold">min</emphasis>|<emphasis
role="bold">hour</emphasis>|<emphasis
role="bold">day</emphasis>}[:<emphasis>burst</emphasis>]</term>
<listitem> <listitem>
<para>where <replaceable>limit</replaceable> is one of:</para>
<simplelist>
<member>[<emphasis
role="bold">-</emphasis>|[{<emphasis>s</emphasis>|<emphasis
role="bold">d</emphasis>}:[[<replaceable>name</replaceable>]:]]]<emphasis>rate</emphasis><emphasis
role="bold">/</emphasis>{<emphasis
role="bold">sec</emphasis>|<emphasis
role="bold">min</emphasis>|<emphasis
role="bold">hour</emphasis>|<emphasis
role="bold">day</emphasis>}[:<emphasis>burst</emphasis>]</member>
<member>[<replaceable>name</replaceable>1]:<emphasis>rate1</emphasis><emphasis
role="bold">/</emphasis>{<emphasis
role="bold">sec</emphasis>|<emphasis
role="bold">min</emphasis>|<emphasis
role="bold">hour</emphasis>|<emphasis
role="bold">day</emphasis>}[:<emphasis>burst1</emphasis>],[<replaceable>name</replaceable>2]:<emphasis>rate2</emphasis><emphasis
role="bold">/</emphasis>{<emphasis
role="bold">sec</emphasis>|<emphasis
role="bold">min</emphasis>|<emphasis
role="bold">hour</emphasis>|<emphasis
role="bold">day</emphasis>}[:<emphasis>burst2</emphasis>]</member>
</simplelist>
<para>You may optionally rate-limit the rule by placing a value in <para>You may optionally rate-limit the rule by placing a value in
this column:</para> this column:</para>
<para><emphasis>rate</emphasis> is the number of connections per <para><emphasis>rate*</emphasis> is the number of connections per
interval (<emphasis role="bold">sec</emphasis> or <emphasis interval (<emphasis role="bold">sec</emphasis> or <emphasis
role="bold">min</emphasis>) and <emphasis>burst</emphasis> is the role="bold">min</emphasis>) and <emphasis>burst</emphasis>* is the
largest burst permitted. If no <emphasis>burst</emphasis> is given, largest burst permitted. If no <emphasis>burst</emphasis> is given,
a value of 5 is assumed. There may be no no white-space embedded in a value of 5 is assumed. There may be no no white-space embedded in
the specification.</para> the specification.</para>
@ -1250,15 +1269,28 @@
<para>When <option>s:</option> or <option>d:</option> is specified, <para>When <option>s:</option> or <option>d:</option> is specified,
the rate applies per source IP address or per destination IP address the rate applies per source IP address or per destination IP address
respectively. The <replaceable>name</replaceable> may be chosen by respectively. The <replaceable>name</replaceable>s may be chosen by
the user and specifies a hash table to be used to count matching the user and specifiy a hash table to be used to count matching
connections. If not given, the name <emphasis connections. If not given, the name <emphasis
role="bold">shorewallN</emphasis> (where N is a unique integer) is role="bold">shorewallN</emphasis> (where N is a unique integer) is
assumed. Where more than one rule specifies the same name, the assumed. Where more than one rule or POLICY specifies the same name,
connections counts for the rules are aggregated and the individual the connections counts for the rules are aggregated and the
rates apply to the aggregated count.</para> individual rates apply to the aggregated count.</para>
<para>Example: <emphasis role="bold">s:ssh:3/min:5</emphasis></para> <para>Beginning with Shorewall 4.6.5, two<replaceable>
limit</replaceable>s may be specified, separated by a comma. In this
case, the first limit (<replaceable>name1</replaceable>,
<replaceable>rate1</replaceable>, burst1) specifies the per-source
IP limit and the second limit specifies the per-destination IP
limit.</para>
<para>Example: <emphasis
role="bold">client:10/sec:20,:60/sec:100</emphasis></para>
<para>In this example, the 'client' hash table will be used to
enforce the per-source limit and the compiler will pick a unique
name for the hash table that tracks the per-destination
limit.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -1127,22 +1127,41 @@
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><emphasis role="bold">RATE LIMIT</emphasis> (rate) - [<emphasis <term><emphasis role="bold">RATE LIMIT</emphasis> (rate) -
role="bold">-</emphasis>|[{<emphasis>s</emphasis>|<emphasis <replaceable>limit</replaceable></term>
role="bold">d</emphasis>}:[[<replaceable>name</replaceable>]:]]]<emphasis>rate</emphasis><emphasis
role="bold">/</emphasis>{<emphasis
role="bold">sec</emphasis>|<emphasis
role="bold">min</emphasis>|<emphasis
role="bold">hour</emphasis>|<emphasis
role="bold">day</emphasis>}[:<emphasis>burst</emphasis>]</term>
<listitem> <listitem>
<para>where <replaceable>limit</replaceable> is one of:</para>
<simplelist>
<member>[<emphasis
role="bold">-</emphasis>|[{<emphasis>s</emphasis>|<emphasis
role="bold">d</emphasis>}:[[<replaceable>name</replaceable>]:]]]<emphasis>rate</emphasis><emphasis
role="bold">/</emphasis>{<emphasis
role="bold">sec</emphasis>|<emphasis
role="bold">min</emphasis>|<emphasis
role="bold">hour</emphasis>|<emphasis
role="bold">day</emphasis>}[:<emphasis>burst</emphasis>]</member>
<member>[<replaceable>name</replaceable>1]:<emphasis>rate1</emphasis><emphasis
role="bold">/</emphasis>{<emphasis
role="bold">sec</emphasis>|<emphasis
role="bold">min</emphasis>|<emphasis
role="bold">hour</emphasis>|<emphasis
role="bold">day</emphasis>}[:<emphasis>burst1</emphasis>],[<replaceable>name</replaceable>2]:<emphasis>rate2</emphasis><emphasis
role="bold">/</emphasis>{<emphasis
role="bold">sec</emphasis>|<emphasis
role="bold">min</emphasis>|<emphasis
role="bold">hour</emphasis>|<emphasis
role="bold">day</emphasis>}[:<emphasis>burst2</emphasis>]</member>
</simplelist>
<para>You may optionally rate-limit the rule by placing a value in <para>You may optionally rate-limit the rule by placing a value in
this column:</para> this column:</para>
<para><emphasis>rate</emphasis> is the number of connections per <para><emphasis>rate*</emphasis> is the number of connections per
interval (<emphasis role="bold">sec</emphasis> or <emphasis interval (<emphasis role="bold">sec</emphasis> or <emphasis
role="bold">min</emphasis>) and <emphasis>burst</emphasis> is the role="bold">min</emphasis>) and <emphasis>burst</emphasis>* is the
largest burst permitted. If no <emphasis>burst</emphasis> is given, largest burst permitted. If no <emphasis>burst</emphasis> is given,
a value of 5 is assumed. There may be no no white-space embedded in a value of 5 is assumed. There may be no no white-space embedded in
the specification.</para> the specification.</para>
@ -1151,13 +1170,28 @@
<para>When <option>s:</option> or <option>d:</option> is specified, <para>When <option>s:</option> or <option>d:</option> is specified,
the rate applies per source IP address or per destination IP address the rate applies per source IP address or per destination IP address
respectively. The <replaceable>name</replaceable> may be chosen by respectively. The <replaceable>name</replaceable>s may be chosen by
the user and specifies a hash table to be used to count matching the user and specifiy a hash table to be used to count matching
connections. If not given, the name <emphasis connections. If not given, the name <emphasis
role="bold">shorewallN</emphasis> (where N is a unique integer) is role="bold">shorewallN</emphasis> (where N is a unique integer) is
assumed. Where more than one POLICY specifies the same name, the assumed. Where more than one rule or POLICY specifies the same name,
connections counts for the rules are aggregated and the individual the connections counts for the rules are aggregated and the
rates apply to the aggregated count.</para> individual rates apply to the aggregated count.</para>
<para>Beginning with Shorewall 4.6.5, two<replaceable>
limit</replaceable>s may be specified, separated by a comma. In this
case, the first limit (<replaceable>name1</replaceable>,
<replaceable>rate1</replaceable>, burst1) specifies the per-source
IP limit and the second limit specifies the per-destination IP
limit.</para>
<para>Example: <emphasis
role="bold">client:10/sec:20,:60/sec:100</emphasis></para>
<para>In this example, the 'client' hash table will be used to
enforce the per-source limit and the compiler will pick a unique
name for the hash table that tracks the per-destination
limit.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>