#!/usr/bin/perl
#
# This code is distributed under the terms of the GPL
#
# (c) 2006 marco.s
#
# $Id: updxlrator,v 1.0 2006/10/03 00:00:00 marco.s Exp $
#

use strict;

use IO::Socket;

$|=1;

my $swroot="/var/ipfire";
my $updcachedir="/srv/web/ipfire/html/updatecache";
my %netsettings=();
my %xlratorsettings=();
my $http_port="81";
my $logfile="/var/log/updatexlrator/cache.log";
my $logging=0;
my $passive_mode=0;
my $maxusage=0;
my $nice='';
my @tmp=();
my $now='';
my $request='';
my $from_local_cache=0;
my $dsturl='';
my $hostaddr='';
my $username='';
my $method='';
my @metadata=();

my $sfNoSource = "0";
my $sfOk       = "1";
my $sfOutdated = "2";

unless (-d "$updcachedir/metadata")
{
	unless (-d "$updcachedir") { mkdir "$updcachedir"; }
	mkdir "$updcachedir/metadata";
	system("chown nobody.squid $updcachedir");
	system("chmod 775 $updcachedir");
	system("chown nobody.squid $updcachedir/metadata");
	system("chmod 775 $updcachedir/metadata");
}

readhash("${swroot}/ethernet/settings", \%netsettings);

if (-e "$swroot/updatexlrator/settings")
{
	&readhash("$swroot/updatexlrator/settings", \%xlratorsettings);
	if ($xlratorsettings{'ENABLE_LOG'} eq 'on') { $logging=1; };
	if ($xlratorsettings{'PASSIVE_MODE'} eq 'on') { $passive_mode=1; };
	$maxusage=$xlratorsettings{'MAX_DISK_USAGE'};
	if ($xlratorsettings{'LOW_DOWNLOAD_PRIORITY'} eq 'on') { $nice='/bin/nice --adjustment=15 '; };
}
if (!$maxusage) { $maxusage=75; };


while (<>) {

	$request=$_;
	$from_local_cache=0;

	@tmp=split(/ /,$request);
	chomp(@tmp);

	$dsturl  =$tmp[0];
	$hostaddr=$tmp[1]; while ($hostaddr =~ /.*\/$/) { chop $hostaddr; }
	$username=$tmp[2]; if ($username eq '') { $username='-'; };
	$method  =$tmp[3];

	if (($method eq 'GET') || ($method eq 'HEAD')) 
	{

	# -----------------------------------------------------------
	#  Section: Windows Update / Windows Downloads
	# -----------------------------------------------------------

	if (
	    (($dsturl =~ m@^http://[^/]*\.microsoft\.com/.*\.(exe|psf|msi)$@i) ||
	     ($dsturl =~ m@^http://[^/]*\.windowsupdate\.com/.*\.(exe|psf|cab)$@i))
	&&   ($dsturl !~ m@^http://[^/]*\.microsoft\.com/.*(/autoupd|selfupdate/).*\.cab@i)
	&&   ($dsturl !~ m@\&@)
	   )
	{
		$from_local_cache = &cache_access($dsturl,$hostaddr,$username,"Microsoft");
	}

	# -----------------------------------------------------------
	#  Section: Adobe Downloads
	# -----------------------------------------------------------

	if ($dsturl =~ m@^http://(ar)?download\.adobe\.com/.*\.(exe|bin|dmg|idx|gz)$@i)
	{
		$from_local_cache = &cache_access($dsturl,$hostaddr,$username,"Adobe");
	}

	# -----------------------------------------------------------
	#  Section: Symantec Downloads
	# -----------------------------------------------------------

	if ($dsturl =~ m@^[f|h]t?tp://[^/]*\.symantec(liveupdate)?\.com/.*\.(exe|zip|xdb)$@i)
	{
		$from_local_cache = &cache_access($dsturl,$hostaddr,$username,"Symantec");
	}
	
	# -----------------------------------------------------------
	# Section: Avira Downloads
	# -----------------------------------------------------------
	
	if ($dsturl =~ m@^http://dl[0-9]\.avgate\.net/.*\.(htm|html|gz)$@i)
	{
	$from_local_cache = &cache_access($dsturl,$hostaddr,$username,"Avira");
	}
	
	# ----------------------------------------------------------- 
	# Section: Avast Downloads 
	# -----------------------------------------------------------  
	
	if ($dsturl =~ m@^http://download[0-99]\.avast\.com/.*\.(exe|zip|vps|stamp|vpu)$@i) 
	{ 
	$from_local_cache = &cache_access($dsturl,$hostaddr,$username,"Avast"); 
	}  
	
	# ----------------------------------------------------------- 
	# Section: IPFire Downloads 
	# -----------------------------------------------------------  
	
	if ($dsturl =~ m@^[f|h]t?tp://.*\.(ipfire)$@i) 
	{ 
	$from_local_cache = &cache_access($dsturl,$hostaddr,$username,"IPFire"); 
	} 
	
	# ----------------------------------------------------------- 
	# Section: Linux Downloads 
	# -----------------------------------------------------------  
	
	if ($dsturl =~ m@^[f|h]t?tp://.*\.(deb|rpm)$@i) 
	{ 
	$from_local_cache = &cache_access($dsturl,$hostaddr,$username,"Linux"); 
	}
	
	# ----------------------------------------------------------- 
	
	# ----------------------------------------------------------- 
	# Section: Apple Downloads 
	# -----------------------------------------------------------  
	
	if ($dsturl =~ m@^[f|h]t?tp://swcdn\.apple.*\.(pkm|tar)$@i) 
	{ 
	$from_local_cache = &cache_access($dsturl,$hostaddr,$username,"Apple"); 
	}
	
	# ----------------------------------------------------------- 
	# Section: Kaspersky Downloads
  # not working properly 
	# -----------------------------------------------------------  
	
	#if ($dsturl =~ m@^http://dnl-.*\.kaspersky-labs\.com\/(diffs|bases|AutoPatches).*$@i) 
	#{ 
	#$from_local_cache = &cache_access($dsturl,$hostaddr,$username,"Kaspersky"); 
	#}

	# ----------------------------------------------------------- 

	}

	if ($from_local_cache) { $request="http://$netsettings{'GREEN_ADDRESS'}:$http_port/updatecache/".substr($dsturl,rindex($dsturl,"/")+1)." $hostaddr $username $method\n"; }

	print $request;
}

# -------------------------------------------------------------------

sub readhash
{
	my $filename = $_[0];
	my $hash = $_[1];
	my ($var, $val);

	if (-e $filename)
	{
		open(FILE, $filename) or die "Unable to read file $filename";
		while (<FILE>)
		{
			chop;
			($var, $val) = split /=/, $_, 2;
			if ($var)
			{
				$val =~ s/^\'//g;
				$val =~ s/\'$//g;

				# Untaint variables read from hash
				$var =~ /([A-Za-z0-9_-]*)/; $var = $1;
				$val =~ /([\w\W]*)/; $val = $1;
				$hash->{$var} = $val;
			}
		}
		close FILE;
	}
}

# -------------------------------------------------------------------

sub writelog
{
	open(LOGFILE,">>$logfile");
	print LOGFILE time." $_[0] $_[1] $_[2] $_[3] $_[4]\n";
	close(LOGFILE);
}

# -------------------------------------------------------------------

sub diskfree
{
	open(DF,"/bin/df --block-size=1 $_[0]|");
	while(<DF>)
	{
		unless ($_ =~ m/^Filesystem/ )
		{
			my ($device,$size,$used,$free,$percent,$mount) = split;
			if ($free =~ m/^(\d+)$/)
			{
				close DF;
				return $free;
			}
		}
	}
	close DF;
}

# -------------------------------------------------------------------

sub diskusage
{
	open(DF,"/bin/df $_[0]|");
	while(<DF>)
	{
		unless ($_ =~ m/^Filesystem/ )
		{
			my ($device,$size,$used,$free,$percent,$mount) = split;
			if ($percent =~ m/^(\d+)%$/)
			{
				close DF;
				$percent =~ s/%$//;
				return $percent;
			}
		}
	}
	close DF;
}

# -------------------------------------------------------------------

sub getdownloadsize
{
	my $remote=0;
	my @response=();
	my $contentlength=0;

	my $url = $_[0];

	$url =~ s@^(.*)://([^/]*)@@;

	my $proto = $1;
	my $fqhn  = $2;

	if ((-e "$swroot/red/active") && ($proto eq 'http'))
	{
		$remote = IO::Socket::INET->new(
			PeerHost => $fqhn,
			PeerPort => 'http(80)',
			Timeout  => 1
		);
	}

	if ($remote)
	{
		print $remote "HEAD $url HTTP/1.0\n";
		print $remote "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\n";
		print $remote "Host: $fqhn\n";
		print $remote "Accept: */*\n\n";
		while (<$remote>) { push(@response,$_); }
		close $remote;
		if ($response[0] =~ /^HTTP\/\d+\.\d+\s\d+\sOK\s*$/)
		{
			foreach (@response)
			{
				if (/^Content-Length: /i)
				{
					s/^Content-Length: //i;
					$contentlength=$_;
				}
			}
		}
	}
	return $contentlength;
}

# -------------------------------------------------------------------

sub cache_access 
{
	my $updsource="UPDCACHE";
	my $updfile='';
	my $do_redirect=0;

	$_[0] =~ s@\%2f@/@ig;
	$updfile = substr($_[0],rindex($_[0],"/")+1);

	if (!-e "$updcachedir/metadata/$updfile")
	{
		open(FILE,">$updcachedir/metadata/$updfile");
		print FILE "$_[0]\n$_[3]\n$sfOutdated\n0\n";
		close(FILE);
	}

	if (-e "$updcachedir/$updfile")
	{
		open(FILE,">>$updcachedir/metadata/$updfile");
		print FILE time."\n";
		close(FILE);
		$do_redirect=1;
	}
		else
	{
		$updsource="DLSOURCE";
		if ((!$passive_mode) && (&diskusage($updcachedir) <= $maxusage) && (&getdownloadsize <= &diskfree($updcachedir)) && (!-e "$updcachedir/download/$updfile"))
		{
			system("$nice/var/ipfire/updatexlrator/bin/download $_[0] &");
		}
	}

	if ($logging) { &writelog($_[1],$_[2],$_[3],$updsource,$_[0]); }

	return $do_redirect;
}

# -------------------------------------------------------------------
