From 7546de58d97a3a4d36dc27ab4e8764f77dc4f887 Mon Sep 17 00:00:00 2001 From: Tony Finch Date: Tue, 13 Sep 2005 17:51:05 +0000 Subject: [PATCH] Add util/ratelimit.pl to assist with choosing ratelimit settings. --- doc/doc-txt/ChangeLog | 4 +- doc/doc-txt/NewStuff | 6 +- src/util/README | 9 ++- src/util/ratelimit.pl | 137 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 src/util/ratelimit.pl diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 5ac7397a8..2fc2eefa6 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.229 2005/09/13 15:40:07 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.230 2005/09/13 17:51:05 fanf2 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -188,6 +188,8 @@ PH/47 Added an interface to a fake DNS resolver for use by the new test suite, backwards compatible; if it can't find the fake resolver, it drops back. Thus, both old and new test suites can be run. +TF/02 Added util/ratelimit.pl + Exim version 4.52 ----------------- diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 3d3c1d8e1..82a239230 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/NewStuff,v 1.69 2005/09/13 11:13:27 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/NewStuff,v 1.70 2005/09/13 17:51:05 fanf2 Exp $ New Features in Exim -------------------- @@ -151,6 +151,10 @@ PH/12 There is a new variable called $smtp_command which contains the full SMTP possible to distinguish between HELO and EHLO, and also between things like "MAIL FROM:<>" and "MAIL FROM: <>". +TF/01 There's a new script in util/ratelimit.pl which extracts sending + rates from log files, to assist with choosing appropriate settings + when deploying the ratelimit ACL condition. + Exim version 4.52 ----------------- diff --git a/src/util/README b/src/util/README index 7fd04f2dc..655fef2fb 100644 --- a/src/util/README +++ b/src/util/README @@ -1,4 +1,4 @@ -$Cambridge: exim/src/util/README,v 1.1 2005/05/24 11:20:40 ph10 Exp $ +$Cambridge: exim/src/util/README,v 1.2 2005/09/13 17:51:06 fanf2 Exp $ The "util" directory in the Exim distribution --------------------------------------------- @@ -25,6 +25,13 @@ A Perl script for a converting flat file into a format that is suitable for processing by cdbmake into a cdb file. It has some advantages over the cdbmake-12 awk script. +ratelimit.pl +------------ + +A Perl script for computing peak sending rates from a log file. This is for +use with the ratelimit ACL condition, so that you can get some idea of what a +reasonable limit would be before deploying the feature. + unknownuser.sh -------------- diff --git a/src/util/ratelimit.pl b/src/util/ratelimit.pl new file mode 100644 index 000000000..a30cfb60a --- /dev/null +++ b/src/util/ratelimit.pl @@ -0,0 +1,137 @@ +#!/usr/bin/perl -wT +# +# $Cambridge: exim/src/util/ratelimit.pl,v 1.1 2005/09/13 17:51:06 fanf2 Exp $ + +use strict; + +sub usage () { + print < logfile + +The aim of this script is to compute clients' peak sending rates +from an Exim log file, using the same formula as Exim's ratelimit +ACL condition. This is so that you can get an idea of a reasonable +limit setting before you deploy the restrictions. + +This script isn't perfectly accurate, because the time stamps in +Exim's log files are only accurate to a seond whereas internally Exim +computes sender rates to the accuracy of your computer's clock +(typically 10ms). + +The log files to be processed can be specified on the command line +after the other arguments; if no filenames are specified the script +will read from stdin. + +The first command line argument is the smoothing period, as defined by +the documentation for the ratelimit ACL condition. The second argumetn +is a regular expression. + +Each line is matched against the regular expression. Lines that do not +match are ignored. The regex may contain 0, 1, or 2 () capturing +sub-expressions. + +If there are no () sub-expressions, then every line that matches is +used to compute a single rate. Its maximum value is reported when the +script finishes. + +If there is one () sub-expression, then the text matched by the +sub-expression is used to identify a rate lookup key, similar to the +lookup key used by the ratelimit ACL condition. For example, you might +write a regex to match the client IP address, or the authenticated +username. Separate rates are computed for each different client and +the maximum rate for each client is reported when the script finishes. + +If there are two () sub-expressions, then the text matched by the +first sub-expression is used to identify a rate lookup key as above, +and the second is used to match the message size recorded in the log +line, e.g. " S=(\\d+) ". In this case the byte rate is computed instead +of the message rate, similar to the per_byte option of the ratelimit +ACL condition. +END + exit 1; +} + +sub iso2unix (@) { + my ($y,$m,$d,$H,$M,$S,$zs,$zh,$zm) = @_; + use integer; + $y -= $m < 3; + $m += $m < 3 ? 10 : -2; + my $z = defined $zs ? "${zs}1" * ($zh * 60 + $zm) : 0; + my $t = $y/400 - $y/100 + $y/4 + $y*365 + + $m*367/12 + $d - 719499; + return $t * 86400 + + $H * 3600 + + $M * 60 + + $S + - $z; +} + +my $debug = 0; +my $progress = 0; +while (@ARGV && $ARGV[0] =~ /^-\w+$/) { + $debug = 1 if $ARGV[0] =~ s/(-\w*)d(\w*)/$1$2/; + $progress = 1 if $ARGV[0] =~ s/(-\w*)p(\w*)/$1$2/; + shift if $ARGV[0] eq "-"; +} + +usage if @ARGV < 2; + +my $progtime = ""; + +my $period = shift; + +my $re_txt = shift; +my $re = qr{$re_txt}o; + +my %time; +my %rate; +my %max; + +sub debug ($) { + my $key = shift; + printf "%s\t%12d %8s %5.2f %5.2f\n", + $_, $time{$key}, $key, $max{$key}, $rate{$key}; +} + +while (<>) { + next unless $_ =~ $re; + my $key = $1 || ""; + my $size = $2 || 1.0; + my $time = iso2unix + ($_ =~ m{^(\d{4})-(\d\d)-(\d\d)[ ] + (\d\d):(\d\d):(\d\d)[ ] + (?:([+-])(\d\d)(\d\d)[ ])? + }x); + if ($progress) { + my $prog_now = substr $_, 0, 14; + if ($progtime ne $prog_now) { + $progtime = $prog_now; + print "$progtime\n"; + } + } + if (not defined $time{$key}) { + $time{$key} = $time; + $rate{$key} = 0.0; + $max{$key} = 0.0; + debug $key if $debug; + next; + } + # see acl_ratelimit() for details of the following + my $interval = $time - $time{$key}; + my $i_over_p = $interval / $period; + my $a = exp(-$i_over_p); + $i_over_p = 1e-9 if $i_over_p <= 0.0; + $time{$key} = $time; + $rate{$key} = $size * (1.0 - $a) / $i_over_p + $a * $rate{$key}; + $max{$key} = $rate{$key} if $rate{$key} > $max{$key}; + debug $key if $debug; +} + +print map { + " " x (20 - length) . + "$_ : $max{$_}\n" +} sort { + $max{$a} <=> $max{$b} +} keys %max; + +# eof -- 2.30.2