# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: kinkie@squid-cache.org-20140511191235-6863g5qc3nop8urp # target_branch: ../trunk # testament_sha1: 84962f755d8cf286a97a0513e7091b006ae80d74 # timestamp: 2014-05-11 21:13:09 +0200 # base_revision_id: squid3@treenet.co.nz-20140509173225-\ # 3s1x3sr5j4mc1l8h # # Begin patch === modified file 'configure.ac' --- configure.ac 2014-04-25 15:14:14 +0000 +++ configure.ac 2014-05-11 19:12:35 +0000 @@ -3504,6 +3504,7 @@ helpers/negotiate_auth/wrapper/Makefile helpers/external_acl/Makefile helpers/external_acl/AD_group/Makefile + helpers/external_acl/delayer/Makefile helpers/external_acl/eDirectory_userip/Makefile helpers/external_acl/file_userip/Makefile helpers/external_acl/kerberos_ldap_group/Makefile === modified file 'helpers/external_acl/Makefile.am' --- helpers/external_acl/Makefile.am 2012-06-12 08:50:53 +0000 +++ helpers/external_acl/Makefile.am 2014-05-11 19:12:35 +0000 @@ -1,5 +1,6 @@ DIST_SUBDIRS= \ AD_group \ + delayer \ eDirectory_userip \ file_userip \ kerberos_ldap_group \ === added directory 'helpers/external_acl/delayer' === added file 'helpers/external_acl/delayer/Makefile.am' --- helpers/external_acl/delayer/Makefile.am 1970-01-01 00:00:00 +0000 +++ helpers/external_acl/delayer/Makefile.am 2014-05-11 19:12:35 +0000 @@ -0,0 +1,12 @@ +include $(top_srcdir)/src/Common.am + +libexec_SCRIPTS = delayer +CLEANFILES += delayer delayer.8 +man_MANS = delayer.8 +EXTRA_DIST = delayer.pl.in delayer.8 required.m4 + +delayer.8: delayer + pod2man delayer delayer.8 + +delayer: delayer.pl.in + $(subst_perlshell) === added file 'helpers/external_acl/delayer/delayer.pl.in' --- helpers/external_acl/delayer/delayer.pl.in 1970-01-01 00:00:00 +0000 +++ helpers/external_acl/delayer/delayer.pl.in 2014-05-11 19:12:35 +0000 @@ -0,0 +1,257 @@ +#!@PERL@ +=pod + +=head1 NAME + +delayer - Squid external acl helper adding artificial delay to requests + +=head1 SYNOPSIS + +delayer [--help] [--debug] [--log file] [--wait msec] + +=head1 OPTIONS + +=over 8 + +=item B<--help> or B<-h> + +Print help message to stdout + +=item B<--debug> or B<-d> + +Emit debugging output to STDERR and ultimately cache.log + +=item B<--log /path/to/file> or B<-l /path/to/file> + +Emit debugging output to specified file instead of STDERR. Also turns on debugging + +=item B<--wait msec> or B<-w msec> + +Delay each request by the specified amount of msec. +Unless this option is specified, by default each submitted request +will be delayed by half a second (500 msec). + +=back + +=head1 DESCRIPTION + +Squid external acl helper; causes squid to delay responding to HTTP requests. + +By carefully crafting the ACLs of a Squid setup it is possible to +selectively delay requests received by a proxy. After the configured amount +of time, it will always return "true". + +=head1 CONFIGURATION + +To engage it, this snippet of configuration template can be used in squid.conf: + + external_acl_type delayer concurrency=100000 children-max=2 children-startup=1 children-idle=1 cache=10 %URI /path/to/delayer -w 200 + acl delay external delayer + http_access allow acl1 acl2 acl3 delay !all + +It is important that the acl referencing the delayer be the penultimate clause in the +http_access line. It will cause delay to all requests that match all the +preceding acls in the line. The !all clause at the end of the line will make it +so that no traffic is authorized by this ACL, only the delay to evaluate +the delay clause will be inserted before evaluating following http_access lines. +It is also important to place the http_access line carefully in the sequence +of all http_access_lines; it should be near the beginning, but be careful +not to insert unwanted slow acls (especially proxy_auth). + +It is possible to customize how delay is calculated for each request by +modifying the "calc_delay" PERL function in the script, documentation on this +is embedded in the source code comments. + +=head1 AUTHOR + +This software is written by Francesco Chemolli + +=head1 COPYRIGHT + +(C) 2014 Francesco Chemolli + +This program is free software. You may redistribute copies of it under the +terms of the GNU General Public License version 2, or (at your opinion) any +later version. + +=head1 QUESTIONS + +Questions on this code are best addressed on the Squid-users mailing list + + +=head1 REPORTING BUGS + +Bug reports need to be made in English. +See http://wiki.squid-cache.org/SquidFaq/BugReporting for details of what you +need to include with your bug report. +Report bugs or bug fixes using http://bugs.squid-cache.org/ + +=head1 SEE ALSO + +B(8), B(7), B http://wiki.squid-cache.org/ , +B http://www.squid-cache.org/Doc/config/ + +=cut + +use strict; +use warnings; +use Getopt::Long qw(:config auto_version auto_help); +use Data::Dumper; +use Time::HiRes qw(gettimeofday tv_interval); + +# options handling +my %opts = (); #for getopt +my $debug = 0; #debug +my $logfile = *STDERR; #filehandle to logfile +my $logfilename; +my $delay = 500; #in milliseconds. Configurable with the -w option. +#for custom delay algorithms, you can customize the dispatch_request function + +#calculate the delay for the request. +# Gets as input the verbatim full line received from squid +# (channel number and all, as configured in squid.conf) and returns +# a floating point number >= 0 which is the delay to be applied to the request +# in seconds. +# Notice that in order to have efficient data structures, the delay is +# assumed to be monotonously growing. In other words, a long-delay +# item will stall the queue until completed. Supporting generic delays +# requires transforming @queue from a FIFO to a priority queue. +sub calc_delay { + return $delay; +} + +GetOptions("debug|d" => \$debug, + "wait|w=i" => \$delay, + "log|l=s" => \$logfilename) +or die("Error in parsing command line arguments"); +if (defined $opts{h}) { + HELP_MESSAGE(); + exit 0; +} +$delay /= 1000.0; # transform msec into sec +if ($logfilename) { + open ($logfile,">>", "$opts{l}"); + $debug=1; +} + +my @p=split(/[\\\/]/,$0); +my $prg_basename=pop @p; +$prg_basename .= "[$$]"; +undef @p; +my $reqid=0; #sequence number for requests + +# variables initialization for select +my $rvec = ''; +vec($rvec,0,1) = 1; #stdin +my ($nfound, $rd, $nread, $req); + +#requests queue +my @queue = (); # array of references to hashes, with keys chan, when, req, reqid + +# signal handlers +$SIG{HUP} = \&dump_state; + +#disable IO buffering +$| = 1; +my $fh=select($logfile); $|=1; select($fh); undef($fh); + +# takes a result from a gettimeofday call and turns it into a +# floating-point number suitable for approximate time calculations and select +sub fract_time { + return $_[0]+$_[1]/1000000; +} + +sub dispatch_request { + my $r = $_[0]; + chomp $r; + &debug("got request: '$r'"); + my %evt = (); + my @fields; + @fields = split (/\s+/, $r); + $evt{when} = &calc_delay($r)+fract_time(gettimeofday()); + $evt{reqid}=$reqid++; + $evt{req} = $r; + $evt{chan} = $fields[0]; + &debug("Dispatching: reqid $evt{reqid}, chan $evt{chan}, when $evt{when}, raw {$evt{req}}"); + push @queue,\%evt; +} + +sub next_event { + my $now = fract_time(gettimeofday()); + if (@queue) { + my $when = $queue[0]->{when} - $now; + &debug("Next event is in $when seconds"); + return $when; + } + &debug("No events in queue"); + return undef; +} + +sub handle_events { + my $now = fract_time(gettimeofday()); + while ( @queue ) { + &debug("Queue length is $#queue"); + last if ($queue[0]->{when} > $now); + my %evt = %{shift @queue}; + &debug("Event: reqid $evt{reqid}, chan $evt{chan}, when $evt{when}, raw {$evt{req}}"); + print $evt{chan} , " OK\n"; + } +} + +# main loop +while(1) { + &debug("selecting"); + $nfound = select($rd = $rvec,undef,undef,&next_event()); + &debug("found $nfound bits set"); + if ($nfound == -1 ) { + next if ($!{ERESTART} || $!{EAGAIN} || $!{EINTR}); + &debug("error in select: $!"); + exit 1; + } + if (vec($rd,0,1)==1) { #got stuff from stdin + my $d; #data + $nread = sysread(STDIN,$d,40960); # read 40kb + # clear the signal-bit, stdin is special + vec($rd,0,1) = 0; + if ($nread==0) { + &debug("nothing read from stdin, exiting"); + exit 0; + } + my $i; + while ($i = index($d,"\n")) { #BUG: assumption of no spill-over + last if ($i == -1); + &dispatch_request(substr($d,0,$i)); + $d=substr($d,$i+1); + } + } + &handle_events(); +} + +my $doc = <<_EOF; +delay-adding external acl helper +authorizes all requests, adding a delay before doing so. +supports multiplexed helper protocol. +Options: + -h, --help: this help message + -d, --debug: enable debug output + -l , --log : log output to named file instead of stderr (implies debug) + -w , --wait delay each request by this number milliseconds + +AUTHOR: Francesco Chemolli +Licensed under the terms of the GNU GPL v2 or later (see source for details) +_EOF +our $VERSION = "1.0"; + +sub HELP_MESSAGE { + print STDERR $doc; +} + +sub dump_state { + $SIG{HUP} = \&dump_state; + print STDERR "Queue:\n",Dumper(\@queue),"\n"; +} + +sub debug { + return unless ($debug); + print $logfile $prg_basename , ": ", @_, "\n"; +} === added file 'helpers/external_acl/delayer/required.m4' --- helpers/external_acl/delayer/required.m4 1970-01-01 00:00:00 +0000 +++ helpers/external_acl/delayer/required.m4 2014-05-11 19:12:35 +0000 @@ -0,0 +1,3 @@ +if test "x$PERL" != "x" -a "x$POD2MAN" != "x"; then + BUILD_HELPER="delayer" +fi === modified file 'helpers/external_acl/modules.m4' --- helpers/external_acl/modules.m4 2013-05-04 06:34:24 +0000 +++ helpers/external_acl/modules.m4 2014-05-11 19:12:35 +0000 @@ -27,6 +27,9 @@ elif test "x$helper" = "xLM_group" ; then m4_include([helpers/external_acl/LM_group/required.m4]) + elif test "x$helper" = "xdelayer" ; then + m4_include([helpers/external_acl/delayer/required.m4]) + elif test "x$helper" = "xSQL_session" ; then m4_include([helpers/external_acl/SQL_session/required.m4]) # Begin bundle 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 P9F3JFOFCQwQboaQ