#!/usr/bin/perl
#
#ALEXSANDRO [email protected]
#Raptor 1.0 Beta
#
#path dir
$homedir="/etc/raptor";
$cachedir="/cache/raptor";
$lockdir="/cache/raptor/locks";
#files
$logfile="/var/log/proxy.log";
$logerro="/var/log/proxy.err";
$begin=time;
open FILE, "$homedir/plugins.lst";
chomp( @plugins = <FILE> );
close FILE;
# Wait time in seconds for a lock to die.
$deadlink=120; # two minutes
### Code!
$ourver="1.0 beta - filtering/caching";
$d=$hard=$help=$log=$v=0; #debug
foreach $j (@ARGV)
{
$d++ if($j eq "-d");
$v++ if($j eq "-v");
$hard++ if($j eq "-a");
$help++ if($j eq "-h");
$log++ if($j eq "-l");
$rand++ if($j eq "-f");
$limit++ if($j eq "-r");
$cflush++ if($j eq "-c");
}
if($help)
{
print STDERR <<EOF;
$0 options:
-d debug
-v verbose
-a hard fail on banned URLs
-l log interaction
-f futz around with pulling images a bit
-r try to rate limit (not implemented)
-c Flush the TempCache and exit.
EOF
exit 1;
}
# Requirements
use Socket;
$|=1;
$log=1;
# Error subroutine. If we run into trouble, we do it here.
sub err {
my ($e,$r)=@_;
# Quickly suck in some junk just in case...
# BUG: It just delays netscape somehow.
# while(<>) {;}
print STDERR "$$: $e -- $r\n" if($v);
print "HTTP/1.0 $e\r\n";
print "Content-Type: text/html\r\n";
print "Connection: close\r\n\r\n";
print "<html><head><title>$e</title></head><body>\r\n";
print "<h1>$e</h1><BR><P>";
print "Raptor cannot fulfill your request -- $r<P>$req<P>\n";
print "<hr><br><i>Raptor version $ourver<br></I>\r\n";
exit 0;
}
sub nothing {
print STDERR "$$: Sending nothing\n" if($v);
print "HTTP/1.0 200 OK\r\n";
print "Content-Type: text/html\r\n";
print "Connection: close\r\n\r\n";
print "// Nothing. \r\n";
print "\r\n";
exit 0;
}
sub blank {
print STDERR "$$: Sending blank\n" if($v);
print "HTTP/1.0 200 OK\nConnection: close\n";
print "Content-type: image/gif\n\n", pack "H*", "47494638396101000100800000ffffff"."00000021f90401000000002c00000000"."010001000002024401003b";
exit 0;
}
# Generic file send routine.
sub sendthis {
my ($file)=@_;
while( -e "$lock" )
{
unlink "$lock" if(-M "$lock" > $deadlink);
sleep 3;
}
$file_size = -s $file;
open(IN,"<$file") || &err("500 Internal Server Error","Cannot open cached file ($!)");
while(<IN>)
{
print;
}
$begin=time - $begin;
$xfor="127.0.0.1" if (!$xfor);
print LOG time.".000 $begin $xfor TCP_HIT/$codi $file_size $type http://$url - NONE/- $xtype\n" if($log);
exit;
}
# Open up a logfile.
if($log)
{
$log='' unless(open(LOG,">>$logfile"));
$lerr='' unless(open(ERRO,">>$logerro"));
}
# Read the first line of the request and pharze it.
$_=$req=<STDIN>; tr/\n\r//d;
exit if(/^$/);
#print ERRO "$$: line: $_\n" if($log);
m#^(GET|POST|HEAD) http://([^/]+)(/.*) (HTTP\S+)$#i;
$type=$1; $site=$2; $page=$3; $ver=$4;
$url=$site.$page;
$line=$_;
#search cached
$cachethis=0;
$domain=0;
foreach $j (@plugins)
{
if($site =~ /$j/)
{
$domain = $j;
}
}
if($site =~ /^([^:]+):(\d+)$/)
{
$remote=$1; $port=$2;
} else {
$remote=$site; $port=80;
}
$iaddr = inet_aton($remote) ;
# Call out and strangle someone
&err("400 Bad Request","Site $remote can't be resolved ($!).") unless($iaddr);
$paddr = sockaddr_in($port, $iaddr);
$proto = getprotobyname('tcp');
socket(SOCK, PF_INET, SOCK_STREAM, $proto) || &err("500 Internal Server Error","Something went wrong trying to connect to $remote ($!).");
connect(SOCK, $paddr) || &err("500 Internal Server Error","Cannot connect to $remote ($!)");
$old=select(SOCK); $|=1; select($old);
print SOCK "$type $page $ver\r\n"; # Xmission's webserver is funky
$lo=0;
while(<STDIN>)
{
$ok=1;
$l=$_;
tr/\r\n//d;
$lo=2 if(/^$/);
$cont=$1 if(/^Content-[lL]ength: (\d+)$/);
$nocache++ if(/^Pragma: no-cache/);
$ok=0 if(/^Proxy-Connection:/);
$ok=0 if(/^Range: bytes/);
$xfor=$1 if(/X-Forwarded-For:\s(.*)/);
print SOCK "Connection: close$l" if($lo);
print SOCK "$l" if($ok);
print STDERR "$$ >>> $l" if($ok && $d);
last if($lo);
}
if($cont)
{
while($cont)
{
$in=read STDIN, $buf, ($cont < 512 ? $cont : 512 );
$cont -= $in;
print SOCK $buf;
}
}
$conn=0; $lc=0;
while(<SOCK>)
{
$l=$_; $lc++;
tr/\r\n//d;
last if(/^$/);
$http=$1 if(/(^HTTP.*)\s([0-9])/);
$codi=$1 if(/^HTTP.*\s([0-9]{3})\s/);
$xtype=$1 if(/^Content-Type.*\s(.*)/);
$conn++ if(/^Connection:/);
$cont=$1 if(/^Content-[lL]ength: (\d+)$/);
print $l unless($conn);
}
$rsize=$cont;
print "Connection: close\r\n" if($codi =~ /304/);
print $l if ($codi =~ /304/);;
close SOCK if ($codi =~ /304/);
exit 0 if ($codi =~ /304/);
&err("500 Internal Server Error","Blank document returned. ($!)") unless($lc);
unless($url =~ /\?/ && !$domain)
{
$file=0;
if($domain)
{
#carrega plugin para tratar a $url
$plugin = "$homedir/plugins/$domain.pl";
if(-e $plugin)
{
print ERRO "$$: LOADING $domain.pl.\n" unless($xfor); #if($log);
do "$homedir/plugins/$domain.pl";
} else {
print ERRO "$$: plugin $domain.pl not found.\n" if($log);
}
}
if($file)
{
$file="$cachedir/$file";
$lock=$1 if ($file =~ /^.*\/(.*$)/);
$lock="$lockdir/$lock.LOCK";
if(-e $file)
{
if( -e $lock )
{
unlink "$lock" if(-M "$lock" > $deadlink);
}
unless( -e $lock )
{
$size = -s $file;
if($rsize > $size)
{
unlink "$file";
print ERRO "FILE ERROR: LSIZE: $size - RSIZE: $rsize arquivo corrompido ou incompleto $file.\n" if($log);
}
}
}
unless(-e $lock)
{
print "X-Cache: HIT from Raptor\r\n" if (-e $file && -s $file);
print "Connection: close\r\n";
print $l;
&sendthis($file) if (-e $file && -s $file);
$cachethis=$file;
}
else
{
print "Connection: close\r\n";
print $l;
}
} else {
}
} else {
print "Connection: close\r\n";
print $l;
}
if($cachethis)
{
$file=$cachethis;
$file=~m#^(.*/)[^/]+$#; $dir=$1;
$lsize=$cont;
if(! -e $dir)
{
system "mkdir -p $dir";
}
while(-e $lock)
{
# Hmmm... already being pulled.
unlink "$lock" if(-M "$lock" > $deadlink);
sleep 3;
}
if(open(OUT,">$lock"))
{
print OUT "$$\n";
print OUT "$url\n";
print OUT "$file\n";
close(OUT);
$cachethis=0 unless( open(OUT,">$file") );
unlink "$lock" unless($cachethis);
}
$xaddr=inet_ntoa($iaddr);
$begin=time - $begin;
$xfor="127.0.0.1" if (!$xfor);
$lsize=0 if(!$lsize);
print LOG time.".000 $begin $xfor TCP_MISS/$codi $lsize $type http://$url - DIRECT/$xaddr $xtype\n" if($log);
}
if($cont)
{
while($cont)
{
$in=read SOCK, $buf, ($cont < 512 ? $cont : 512 );
$cont -= $in;
print $buf;
print OUT $buf if($cachethis);
last if($count < 0);
}
} else {
$loop=0;
while(<SOCK>)
{
print;
print OUT if($cachethis);
$loop++ if (/^$/);
last if($loop == 100);
}
}
close(SOCK);
unlink "$lock" if($cachethis);
close(OUT);
exit;