package cool_env;

$inet_iface;
$inet_band;
$lan_iface;
$lan_gate_ip;
$lan_band;
$lan_ip_range;
$iptables;
$tc;
$temp_path;
$init_path;
$wassup_path;
$ugly_hlan_iface;
$ugly_hinet_iface;
$ugly_ipt_bytes_pos;
$ugly_arp_hwaddr_pos;
$hfile;
$wassup;

@prot=("TCP","UDP","ICMP","REST");
@dir=("IN","OUT");

sub create
{
    ($class_name,
    $inet_iface,$inet_band,$ugly_hinet_iface,
    $lan_iface,$lan_band,$ugly_hlan_iface,$lan_gate_ip,$lan_ip_range,
    $iptables,$tc,$temp_path,$init_path,$wassup_path)=@_;
    my ($self)={};
    bless($self,$class_name);
    $ugly_ipt_bytes_pos=1;
    $ugly_arp_hwaddr_pos=2;
    open $hfile,'>>',$temp_path;

open $wassup,'>>',$wassup_path;

    return $self;
}

sub finish
{
    close $hfile;
    close $wassup;
#    system("$iptables -Z");
    system("$iptables -Z FWD");
for my $pr (@prot){for my $dr (@dir) {system("iptables -Z $pr\_$dr\_FWD");}}
    system("chmod 755 $temp_path");
    system("mv $temp_path $init_path");
    system("mv $wassup_path $wassup_path.txt");

undef $inet_iface;
undef $inet_band;
undef $lan_iface;
undef $lan_gate_ip;
undef $lan_band;
undef $lan_ip_range;
undef $iptables;
undef $tc;
undef $temp_path;
undef $init_path;
undef $ugly_hlan_iface;
undef $ugly_hinet_iface;
undef $ugly_ipt_bytes_pos;
undef $ugly_arp_hwaddr_pos;
undef $hfile;
undef $wassup;
undef $self;
}

sub print_var
{
    print "$inet_iface,$inet_band,$ugly_hinet_iface,
$lan_iface,$lan_band,$ugly_hlan_iface,$lan_gate_ip,$lan_ip_range,
$iptables,$tc,$temp_path,$init_path, $wassup_path\n";
}

sub print_head
    {
#head rules
print $hfile "#!/bin/sh
#/media/log mount
umount /media/log
#mount -t ramfs -omaxsize=5M none /media/log
mount -t ramfs -o size=5m ramfs /media/log
#FORWARD
$iptables -N TCP_IN_FWD
$iptables -N TCP_OUT_FWD
$iptables -N ICMP_IN_FWD
$iptables -N ICMP_OUT_FWD
$iptables -N UDP_IN_FWD
$iptables -N UDP_OUT_FWD
$iptables -N REST_IN_FWD
$iptables -N REST_OUT_FWD
$iptables -N FWD
$iptables -A FORWARD -i $inet_iface -o $lan_iface -d $lan_ip_range -j FWD
$iptables -A FORWARD -s $lan_ip_range -o $inet_iface -i $lan_iface -j FWD
$iptables -A FWD -p tcp -o $lan_iface -j TCP_IN_FWD
$iptables -A FWD -p tcp -o $inet_iface -j TCP_OUT_FWD
$iptables -A FWD -p udp -o $lan_iface -j UDP_IN_FWD
$iptables -A FWD -p udp -o $inet_iface -j UDP_OUT_FWD
$iptables -A FWD -p icmp -o $lan_iface -j ICMP_IN_FWD
$iptables -A FWD -p icmp -o $inet_iface -j ICMP_OUT_FWD
$iptables -A FWD -o $lan_iface -j REST_IN_FWD
$iptables -A FWD -o $inet_iface -j REST_OUT_FWD
#LOG FORWARDED PACKETS
$iptables -I TCP_IN_FWD -p tcp --tcp-flags SYN,ACK SYN,ACK -j LOG --log-level 4
$iptables -I TCP_OUT_FWD -m state --state NEW -j LOG --log-level 4
$iptables -I UDP_IN_FWD -m limit --limit 10/s -j LOG --log-level 4
$iptables -I UDP_OUT_FWD -m limit --limit 10/s -j LOG --log-level 4
$iptables -I ICMP_IN_FWD -j LOG --log-level 4
$iptables -I ICMP_OUT_FWD -j LOG --log-level 4
#TC header
$tc qdisc del dev $lan_iface root
$tc qdisc del dev $inet_iface root
$tc qdisc add dev $lan_iface root handle $ugly_hlan_iface: cbq bandwidth $lan_band avpkt 1000 mpu 64
$tc qdisc add dev $inet_iface root handle $ugly_hinet_iface: cbq bandwidth $inet_band avpkt 1000 mpu 64";
    }

sub chain
{
    my ($self,$action,$chain,$ip)=@_;
#print"chain($action,$chain,$ip);\n";
    my %rule_opt=(IN=>"-d $ip",OUT=>"-s $ip");

    $chain=~/(.*)\_(.*)\_(.*)/;
    if($action eq "destr")
    {
	if(system("iptables -F $1\_$2\_$3")==0)
	  {system("iptables -D $1\_$2\_FWD $rule_opt{$2} -j $1\_$2\_$3");
	   system("iptables -X $1\_$2\_$3");}
    }
    if($action eq "block")
    {
	if(system("$iptables -F $1\_$2\_$3")==0)
	  {system("$iptables -I $1\_$2\_$3 -j DROP");
	   system("$iptables -A $1\_$2\_$3 -j ACCEPT");}
    }
    if($action eq "unblock") {system("iptables -D $1\_$2\_$3 -j DROP");}
    if($action eq "build")
    {
	if(system("$iptables -N $1\_$2\_$3")==0)
	  {system("$iptables -A $1\_$2\_FWD $rule_opt{$2} -j $1\_$2\_$3");
	   system("$iptables -A $1\_$2\_$3 -j ACCEPT");}
    }
    if($action eq "print")
    {
	print $hfile "\n#$3\[$ip]($1\_$2)
$iptables -N $1\_$2\_$3
$iptables -A $1\_$2\_FWD $rule_opt{$2} -j $1\_$2\_$3
$iptables -A $1\_$2\_$3 -j ACCEPT";
    }
}

sub nip
{
    my ($self,$action,$nip,$ip)=@_;
#print"nip($action,$nip,$ip);\n";
    if($action eq "learn")
    {
	my %delta=();
	for my $pr (@prot){for my $dr (@dir)
        {
	my $ipt_std_out;
	my @fields=();
	open($ipt_std_out,"iptables -L -Z $pr\_$dr\_$nip -v -x -n|grep ACCEPT|") or return 0;
	while(<$ipt_std_out>) {@fields = split;}
	close($ipt_std_out);
#system("iptables -Z $pr\_$dr\_$nip");
	$delta{"$pr\_$dr"}=0;
	$delta{"$pr\_$dr"}=$fields[$ugly_ipt_bytes_pos] if defined $fields[$ugly_ipt_bytes_pos];
	}
    }
    return %delta;
    }
    else {for my $pr (@prot){for my $dr (@dir) {$self->chain($action,"$pr\_$dr\_$nip",$ip);}}}
}

sub tc_pipe
    {
    my ($self,$action,$dr,$id,$ip,$RATE,$WEIGHT)=@_;
#    print"tc_pipe($action,$dr,$id,$ip,$RATE,$WEIGHT);\n";
    my %tc_class_opt=(
    IN=>"dev $lan_iface parent $ugly_hlan_iface:0 classid $ugly_hlan_iface:$id",
    OUT=>"dev $inet_iface parent $ugly_hinet_iface:0 classid $ugly_hinet_iface:$id");
    my %tc_filter_opt=(
    IN=>"dev $lan_iface parent $ugly_hlan_iface:0 protocol ip pref 1 handle $ugly_hlan_iface$id fw classid $ugly_hlan_iface:$id",
    OUT=>"dev $inet_iface parent $ugly_hinet_iface:0 protocol ip pref 1 handle $ugly_hinet_iface$id fw classid $ugly_hinet_iface:$id");
    my %tc_rule_opt=(
    IN=>"POSTROUTING -s! $lan_gate_ip -d $ip -o $lan_iface -j MARK --set-mark $ugly_hlan_iface$id",
    OUT=>"FORWARD -s $ip -i $inet_iface -j MARK --set-mark $ugly_hinet_iface$id");

if ($action eq "destr")
    {system("tc filter del $tc_filter_opt{$dr}");
     system("tc class del $tc_class_opt{$dr}");
     system("iptables -t mangle -D $tc_rule_opt{$dr}");}
if ($action eq "build")
    {system("tc class replace $tc_class_opt{$dr} cbq rate $RATE weight $WEIGHT allot 1514 prio 1 avpkt 1000 bounded");
     system("tc filter replace $tc_filter_opt{$dr}");
     system("iptables -t mangle -A $tc_rule_opt{$dr}");}
if ($action eq "print")
    {print $hfile "\n#$ip(pipe\_$dr)
$tc class replace $tc_class_opt{$dr} cbq rate $RATE weight $WEIGHT allot 1514 prio 1 avpkt 1000 bounded
$tc filter replace $tc_filter_opt{$dr}
$iptables -t mangle -A $tc_rule_opt{$dr}";}
    }

sub tc_root_check
    {
    my ($self,$td)=@_;
    my @tc_fields=();
    if($td eq "out"){$int=$inet_iface;$hint=$ugly_hinet_iface;$intb=$inet_band;}
    elsif ($td eq "in"){$int=$lan_iface;$hint=$ugly_hlan_iface;$intb=$lan_band;}
    open(my $tc_std_out,"tc qdisc show dev $int|") or return 0;
    while(<$tc_std_out>) {@tc_fields = split;}close($tc_std_out);
    if($tc_fields[1] ne "cbq"){system("$tc qdisc add dev $int root handle $hint: cbq bandwidth $intb avpkt 1000 mpu 64;");return 0;}
    else {return 1;}
    }

sub ntoa
    {
    my ($self,$nip)=@_;
    return sprintf("%d.%d.%d.%d",((($nip&0xFF000000)>>24),(($nip&0xFF0000)>>16),(($nip&0xFF00)>>8),($nip&0xFF)))
    }

sub hwaddr
    {
    my ($self,$ip)=@_;
    my @arp_fields=();
    open(my $arp_std_out,"arp -n|grep $ip\\ ;|") or return 0;
    while(<$arp_std_out>) {@arp_fields = split;}close($arp_std_out);
    if((defined $arp_fields[$ugly_arp_hwaddr_pos])and($arp_fields[$ugly_arp_hwaddr_pos-1] ne "(incomplete)"))
    {return join('',split(/:/,$arp_fields[$ugly_arp_hwaddr_pos]));}
    else {return 0;}
    }

sub ipt_log_manage
    {
    my ($self,$syslog_pid_path,$ipt_log_path)=@_;
    my $pid=();
    system("savelog $ipt_log_path");
    system("rm $ipt_log_path.*.gz");
    system("touch $ipt_log_path");
    system("chown syslog:adm $ipt_log_path");
    system("chmod 755 $ipt_log_path");
    my $hfile;
    open $hfile,'<',$syslog_pid_path;while(<$hfile>) {$pid=$_;}close($hfile);
    if(defined $pid) {
#    print"kill -HUP $pid\n";
    system("kill -HUP $pid");}
    }

sub wassup
    {
    print $wassup "##############\n";
    print $wassup "#   uptime   #\n";
    print $wassup "##############\n\n";
    open(my $uptime_std_out,"uptime|") or return 0;
    while(<$uptime_std_out>) {print $wassup "$_";}
    close($uptime_std_out);
    print $wassup "\n##############\n";
    print $wassup "#   arp -n   #\n";
    print $wassup "##############\n\n";
    open(my $arp_std_out,"arp -n|") or return 0;
    while(<$arp_std_out>) {print $wassup "$_";}
    close($arp_std_out);
    print $wassup "\n###################\n";
    print $wassup "#  tc_$lan_iface show   #\n";
    print $wassup "###################\n\n";
    open(my $tc_std_out,"tc qdisc show dev $lan_iface|") or return 0;while(<$tc_std_out>) {print $wassup "$_";}close($tc_std_out);
    open(my $tc_std_out,"tc class show dev $lan_iface|") or return 0;while(<$tc_std_out>) {print $wassup "$_";}close($tc_std_out);
    open(my $tc_std_out,"tc filter show dev $lan_iface|") or return 0;while(<$tc_std_out>) {print $wassup "$_";}close($tc_std_out);
    print $wassup "\n###################\n";
    print $wassup "#  tc_$inet_iface show   #\n";
    print $wassup "###################\n\n";
    open(my $tc_std_out,"tc qdisc show dev $inet_iface|") or return 0;while(<$tc_std_out>) {print $wassup "$_";}close($tc_std_out);
    open(my $tc_std_out,"tc class show dev $inet_iface|") or return 0;while(<$tc_std_out>) {print $wassup "$_";}close($tc_std_out);
    open(my $tc_std_out,"tc filter show dev $inet_iface|") or return 0;while(<$tc_std_out>) {print $wassup "$_";}close($tc_std_out);
    print $wassup "\n##################################\n";
    print $wassup "#  iptables -t mangle -L -v -n   #\n";
    print $wassup "##################################\n\n";
    open(my $ipt_std_out,"iptables -t mangle -L -v -n|") or return 0;
    while(<$ipt_std_out>) {print $wassup "$_";}
    close($ipt_std_out);
    print $wassup "\n########################\n";
    print $wassup "#  iptables -L -v -n   #\n";
    print $wassup "########################\n\n";
    open(my $ipt_std_out,"iptables -L -v -n|") or return 0;
    while(<$ipt_std_out>) {print $wassup "$_";}
    close($ipt_std_out);
    }

1;