#!/usr/bin/perl

use strict;
use Socket;
use IPC::Open3;
use vars qw( @local_nets %lists $prefix );

my $MySelf = $0;			# program name to refer from generated documents
my $QueryString = ( ( exists $ENV{QUERY_STRING} && $ENV{QUERY_STRING} ) ? $ENV{QUERY_STRING} : <> );
					# input parameters
my $LightColor = 'WHITE';
my $DarkColor = 'ORANGE';
my $BGColor = '#50a0a0';
my $FGColor = 'YELLOW';
my $AcctLog = '/usr/local/sbin/AcctLog';


############################################################################
# Arguments error page
############################################################################
sub error
{
	print <<END;
Content-type: text/html

<html>
<body bgcolor="$BGColor" text="$FGColor">
<H3>$lang::error_bad_params</H3>
</body>
</html>
END
}


############################################################################
# Client address error page
############################################################################
sub error_address
{
	print <<END;
Content-type: text/html

<html>
<body bgcolor="$BGColor" text="$FGColor">
<CENTER><H3>$lang::error_client_address</H3></CENTER>
<P>
$lang::error_client_address_advise
</body>
</html>
END
}


############################################################################
# Obtain a CGI parameter
############################################################################
sub get_param
{
	my $name = shift;

	if( $QueryString && $QueryString =~ /^(.+\&)?$name=([^&]+)/ ){
		return decode_url( $2 );
	}else{
		return undef;
	}
}


############################################################################
# Decode url-encoded text
############################################################################
sub decode_url
{
	my $value = shift;
	$value =~ tr/+/ /;
	$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
	return $value;
}


############################################################################
# Resolve ip address to name
############################################################################
sub resolve
{
	my $address = shift;
	my $name = '';
	my $bin_net;
	my $bin_mask;
	my $bin_addr = inet_aton( $address );
	my $belongs = 0;

	foreach ( @local_nets ) {
		if( /^(\d+\.\d+\.\d+\.\d+)\/(\d+)$/ ){
			$bin_net = inet_aton( $1 );
			$bin_mask = pack( "N", ~( 0xffffffff >> $2 ) );
			if( ( $bin_addr & $bin_mask ) eq $bin_net ){
				$belongs = 1;
				last;
			}
		}
	}
	return $address unless $belongs;
	$name = gethostbyaddr( $bin_addr, AF_INET );
	return $name ? $name : $address;
}


### main () ###

push @INC, '/usr/local/etc/tas';
require 'AcctLog.conf';
require 'tas.conf';
require 'cgi.conf';

my $time_period = get_param( 'TIME_PERIOD' );
my $traffic_type = get_param( 'TRAFFIC_TYPE' );
my $table_caption = get_param( 'TABLE_CAPTION' );
my $column_caption = get_param( 'COLUMN_CAPTION' );
my $hostaddr = $ENV{HTTP_X_FORWARDED_FOR} ? $ENV{HTTP_X_FORWARDED_FOR} : $ENV{REMOTE_ADDR};
my $hostname = resolve( $hostaddr );
my $sort = get_param( 'SORT_COLUMN' );
my $do_resolve = get_param( 'RESOLVE_FLAG' );
my $column_catexp = get_param( 'COLUMN_CATEGORY_EXPRESSION' );
my $dir = get_param( 'TRAFFIC_DIRECTION' );
my $units = get_param( 'MEASUREMENT_UNITS' );
my $agent_host = get_param( 'AGENT_HOST_LIST' );
my $proto = get_param( 'PROTOCOL_LIST' );
my $status = get_param( 'STATUS_LIST' );
my $rounding = get_param( 'ROUNDING_OPTION' );
my @proxies = split /\:/, get_param( 'PROXIES' );
my $conffile = '/tmp/$MySelf.$$.' . time();
my $dbprefix = "$prefix/$traffic_type.$time_period";
my $pi;		# progress indicator
my $host;

unless( $traffic_type
&& $time_period
&& $table_caption
&& $column_caption
&& $hostaddr
&& $sort
&& $do_resolve
&& $column_catexp
&& $dir
&& $units
&& $agent_host
&& $proto
&& $status
&& $rounding ){
	error();
	exit;
}

foreach ( @proxies ){
	if( inet_aton( $hostaddr ) eq inet_aton( $_ ) ){
		error_address();
		exit;
	}
} 

$host = ( $traffic_type eq 'ip' || !$hostname ) ? $hostaddr : $hostname;

# strip the directory path:
$MySelf =~ s#.*\/##;

$SIG{'PIPE'} = $SIG{'TERM'} = sub { unlink $conffile; exit 1; };

open( CONF, ">$conffile" ) || die "Can't open $conffile: $!";

print CONF <<END;
\@local_nets = (
END
foreach ( @local_nets ){
	print CONF <<END;
	"$_",
END
}
print CONF <<END;
);

\%tables = (
	"$traffic_type" => [
		[
			"$table_caption",
			"$host",
			$sort,
			"$do_resolve",
			[
				[ "$column_caption", "$column_catexp", "$dir", "$units", "$agent_host", "$proto", "$status" ],
			],
			"$rounding",
		]
	]
);
END
close CONF;

open3( \*WRTRFH, \*RDRFH, \*RDRFH, $AcctLog, '-h', '-f', $conffile, '-d', $dbprefix, $traffic_type );
close WRTRFH;

$| = 1;

print <<END;
Content-type: text/html

<html>
<head>
<title>$lang::report_title</title>
</head>
<body bgcolor="$BGColor" text="$FGColor">
END
while( $_ = <RDRFH> ){
	print;
}

print <<END;
</body>
</html>
END
unlink $conffile;

### end of main() ###


