#!/usr/local/bin/perl -w
# PUSH traffic to sql
#
#
use vars qw(%RAD %conf $db %AUTH $DATE $TIME $var_dir %log_levels);
use strict;

if ($#ARGV < 1) {
  print "ABillS Ic collector
  traffic2sql [NAS_IDS] [Options]
   NAS_IDS    - Ids of NAS servers 1,2,3 or 1-100
 Options:
   log        - Log file for trafd
   INTERFACE  - Interface for trafd
   flowdir    - Folder where stored flow-capture result files
   FLOWTOOLS_IP_AGGREGATION - Aggregate Netflow files to ip.
   FLOWTOOLS_FT_BACKUP=dir - Backup old flow-tools ft* file. For debug only
   debug      - Set debug mode (1,2)
   DETAIL_ONLY- Make IP detalisation only
   UNKNOWN_IP_LOG - Enable unknown ip login
   PREPAID_STORE - Use alternative prepaid store for prepaid traffic colection.
   TCOLLECTOR - Total Collector mode. Collect all data to SQL without analysation
   AMON_ALIVE - Second for Amon Alive Alive interval (default value 120).
   VIRUS_ALERT=1000 - Count of small PKG
   LOG_FILE   - Debug log file for traffic2sql
   TRAFFIC_CLASS - Add all traffic as TRAFFIC_CLASS
   
   -d         - Deamon mode
   -fg        - foreground mode

   FLOW_CAT   - Flow tools flow-cat location
   FLOW_PRINT - Flow tools flow-print location\n";
  exit;
}

# Get nas servers is
my $NAS_IDS = $ARGV[0];
my $debug   = 0;

use FindBin '$Bin';
require $Bin . '/config.pl';
unshift(@INC, $Bin . '/../', $Bin . "/../Abills/$conf{dbtype}");
require Abills::Base;
Abills::Base->import();
my $begin_time = check_time();

my $ARGV     = parse_arguments(\@ARGV);
my $flow_dir = ($ARGV->{flowdir}) ? $ARGV->{flowdir} : $var_dir . "log/ipn/";
my $log_file = "$flow_dir/traffic2sql.log";

if (defined($ARGV->{debug})) {
  print "Debug mode on\n";
  $debug = $ARGV->{debug};
}
elsif (defined($ARGV->{help})) {
  print "Help:\n";
}

#Demonize section
if (defined($ARGV->{'-d'}) && !defined($ARGV->{'-fg'})) {
  print "Start... debug: $debug\n";
  mk_log('LOG_INFO', "traffci2sql Daemonize...");
  daemonize();
}
else {
  if (make_pid($flow_dir . "/traffic2sql.pid") == 1) {
    print "Already running PID: !\n";
    exit;
  }
}

if ($conf{IPN_DB}) {
  ($conf{dbtype}, $conf{dbhost}, $conf{dbname}, $conf{dbuser}, $conf{dbpasswd}) = split(/:/, $conf{IPN_DB}, 5);
}

require Abills::SQL;
my $sql = Abills::SQL->connect($conf{dbtype}, $conf{dbhost}, $conf{dbname}, $conf{dbuser}, $conf{dbpasswd});
my $db = $sql->{db};

# Get options ==============================================
my $IF_NAME = ($ARGV->{INTERFACE}) ? $ARGV->{INTERFACE} : '';

$conf{UNKNOWN_IP_LOG} = $ARGV->{UNKNOWN_IP_LOG};

if ($ARGV->{DETAIL_ONLY}) {
  $conf{IPN_DETAIL} = 1;
  print "DETAIL_ONLY=$conf{IPN_DETAIL}\n" if ($debug > 0);
}
if ($ARGV->{TCOLLECTOR}) {
  $conf{IPN_TCOLLECTOR} = 1;
  print "TCOLLECTOR=$conf{IPN_TCOLLECTOR}\n" if ($debug > 0);
}
if ($ARGV->{AMON_ALIVE}) {
  $conf{IPN_AMON_ALIVE} = $ARGV->{AMON_ALIVE};
  print "AMON_ALIVE=$conf{IPN_AMON_ALIVE}\n" if ($debug > 0);
}

#==========================================================

require Ipn_Collector;
Ipn_Collector->import();
my $Ipn = Ipn_Collector->new($db, \%conf);
use POSIX qw(strftime mktime ctime);

require Acct;
Acct->import();
my $Acct   = Acct->new($db, \%conf);
my $NAS_ID = 0;
my $log    = $var_dir . "log/ipn/trafd_" . $NAS_ID . "_" . $IF_NAME;

if ($NAS_IDS eq '') {
  print "You don't specify NAS ID\n";
  exit;
}

$log = $ARGV->{log} if ($ARGV->{log});

my $FLOW_CAT   = $ARGV->{FLOW_CAT}   || '/usr/local/bin/flow-cat';
my $FLOW_PRINT = $ARGV->{FLOW_PRINT} || '/usr/local/bin/flow-print';

$Ipn->{debug} = 1 if ($debug > 2);
$conf{MB_SIZE} = $conf{KBYTE_SIZE} * $conf{KBYTE_SIZE};

my %PROTOCOLS = (
  'tcp' => 1,
  'udp' => 2
);
my $PROTOCOL = 0;    #(defined($PROTOCOLS{$PROTOCOL})) ? $PROTOCOLS{$PROTOCOL} : 0;

#Get users info from online log
$Ipn->user_ips({ NAS_ID => $NAS_IDS });

if (-f $log) {
  get_collector_data($log);
  processing();
  my $status = unlink("$log");
  exit;
}

$conf{IPN_FW_FIRST_RULE} = 20000 if (!$conf{IPN_FW_FIRST_RULE});
Time::HiRes->import(qw(gettimeofday));

if (defined($ARGV->{'-d'})) {
  while (1) {
    $begin_time = check_time();
    $Ipn->user_ips({ NAS_ID => $NAS_IDS });
    flow_capture();
    my $UPDATE_TIME = 10;
    sleep $UPDATE_TIME;
  }
}
else {
  flow_capture();
}

#**********************************************************
# Get information from flowtools
#**********************************************************
sub flow_capture {
  my ($attr) = @_;

  my $FLOWTOOLS_IP_AGGREGATION = '';
  if ($ARGV->{FLOWTOOLS_IP_AGGREGATION}) {
    $FLOWTOOLS_IP_AGGREGATION = 'awk \'BEGIN { ip1=0 };  { ips[$1"  "$2]+=$6 }; END { for (i in ips) { print i" "1" "0" "0" "ips[i]" "0; } }\' |';
  }

  #Get flow tools files
  opendir DIR, $flow_dir or die "Can't open dir '$flow_dir' $!\n";
  my @contents = grep /^ft*/, readdir DIR;
  closedir DIR;

  my $session_interval = 0;
  foreach $log (sort @contents) {
    print "$flow_dir/$log\n" if ($debug > 1);
    if ("$log" =~ /ft-(\w+)\.(\d+)\-(\d+)\-(\d+)\.(\d{2})(\d{2})(\d{2})[\-|\+](\d+)/) {
      my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = stat("$flow_dir/$log");

      #File date
      my $start_date = "$2-$3-$4 $5:$6:$7";
      $session_interval += $mtime - mktime(int($7), $6, ($5 - 1), int($4), int($3) - 1, int($2) - 1900);

      #Last modified
      my $end_date = strftime "%Y-%m-%d %H:%M:%S", localtime($mtime);
      get_collector_data("$FLOW_CAT $flow_dir/$log | $FLOW_PRINT | $FLOWTOOLS_IP_AGGREGATION", { START => $start_date });

      #Dont proccess files if only detalization
      if (!$ARGV->{DETAIL_ONLY}) {
        processing(
          {
            START            => $start_date,
            STOP             => $end_date,
            SESSION_INTERVAL => $session_interval,
            LOG              => $log
          }
        );
      }

      # Delete log file
      if ($ARGV->{FLOWTOOLS_FT_BACKUP}) {
        if (!-d $ARGV->{FLOWTOOLS_FT_BACKUP}) {
          print "Error: Can't find dir '$ARGV->{FLOWTOOLS_FT_BACKUP}'\n";
          exit;
        }
        my $status = system("mv $flow_dir/$log $ARGV->{FLOWTOOLS_FT_BACKUP}");
      }
      else {
        my $status = unlink("$flow_dir/$log");
      }
    }
    else {
      print "Unknow File name format\n";
    }
    $begin_time = check_time();
  }

  return 0;
}

#**********************************************************
# Processin by traffic
#**********************************************************
sub processing {
  my ($attr) = @_;

  foreach my $line (@{ $Ipn->{IN} }) {
    my ($from, $to, $size) = split(/\//, $line, 3);
    $Ipn->unknown_add($from, $to, $size, 0);
  }

  $Ipn->traffic_agregate_nets();

  my ($intervals, $tp_interval) = $Ipn->get_interval_params();

  my $ips           = $Ipn->{USERS_IPS};
  my $ips_interim   = $Ipn->{INTERIM};
  my $logins        = $Ipn->{USERS_INFO}->{LOGINS};
  my $tps           = $Ipn->{USERS_INFO}->{TPS};
  my $session_ids   = $Ipn->{SESSIONS_ID};
  my $interim_times = $Ipn->{INTERIM_TIME};

  my %RAD       = ();
  my $registred = '';

  foreach my $ip (sort keys %$session_ids) {
    if (length($ip) < 2) { next; }
    my $uid            = $ips->{$ip};
    my $login          = $logins->{$uid};
    my $tariif_plan    = $tps->{$uid} || 0;
    my $session_id     = $session_ids->{$ip};
    my $ip_stats       = $Ipn->{INTERIM}{$ip};
    my $interium_time  = $interim_times->{$session_id} || 0;
    my $total_in       = 0;
    my $total_out      = 0;
    my $extended       = '';
    my $total_user_sum = 0;

    # Get interval ID
    my $user_tp_interval = (defined($tp_interval->{$tariif_plan})) ? $tp_interval->{$tariif_plan} : 0;

    #Time tariffication
    if ($intervals->{$user_tp_interval}->{TIME_TARIFF}) {
      my $time_tariff = $intervals->{$user_tp_interval}->{TIME_TARIFF};
      $total_user_sum = ($time_tariff > 0) ? $interium_time / 60 / 60 * $time_tariff : 0;

      $extended .= sprintf("Time| Price:%5s %d=%f\n", $time_tariff, $interium_time, $total_user_sum);
    }

    my $ip_addr;
    if (length($ip) > 10) {
      my ($ip_, $mask_) = unpack('N4N4', $ip);
      $ip_addr = int2ip($ip_);
    }
    else {
      $ip_addr = int2ip($ip);
    }

    my %TRAFFIC_CLASS_SUM = ();

    #parse  traffic stats
    if ($Ipn->{INTERIM}{$ip}) {

      # Traffic type, traffic count
      # $k - traffic Class
      # $v - value
      while (my ($k, $v) = each %$ip_stats) {
        my $in  = (defined($v->{IN}))  ? int($v->{IN})  : 0;
        my $out = (defined($v->{OUT})) ? int($v->{OUT}) : 0;

        $TRAFFIC_CLASS_SUM{$k}{IN}  = $in;
        $TRAFFIC_CLASS_SUM{$k}{OUT} = $out;

        $total_in  += $in;
        $total_out += $out;
        my $sum_in  = 0;
        my $sum_out = 0;

        #Get price and calculate traffic
        my $OCTETS_DIRECTION = $Ipn->{$ip}{OCTET_DIRECTION};
        my $price_in         = (defined($intervals->{$user_tp_interval}->{ZONES}->{$k}->{PriceIn})) ? $intervals->{$user_tp_interval}->{ZONES}->{$k}->{PriceIn} : 0;
        my $price_out        = (defined($intervals->{$user_tp_interval}->{ZONES}->{$k}->{PriceOut})) ? $intervals->{$user_tp_interval}->{ZONES}->{$k}->{PriceOut} : 0;

        # Work with prepaid traffic
        if (defined($intervals->{$user_tp_interval}->{ZONES}->{$k}->{PREPAID_TSUM})) {
          my $used_traffic;
          if ($ARGV->{PREPAID_STORE}) {
            ($used_traffic) = $Ipn->traffic_user_get2(
              {
                UID         => $uid,
                ACTIVATE    => $Ipn->{USERS_INFO}->{ACTIVATE}->{$uid},
                JOIN_SERVICE=> $Ipn->{USERS_INFO}->{JOIN_SERVICE}->{$uid},
                TRAFFIC_IN  => $in,
                TRAFFIC_OUT => $out,
                TRAFFIC_ID  => $k
              }
            );
          }
          else {
            ($used_traffic) = $Ipn->traffic_user_get(
              {
                UID         => $uid,
                ACTIVATE    => $Ipn->{USERS_INFO}->{ACTIVATE}->{$uid},
                JOIN_SERVICE=> $Ipn->{USERS_INFO}->{JOIN_SERVICE}->{$uid},
                TRAFFIC_IN  => $in,
                TRAFFIC_OUT => $out,
                TRAFFIC_ID  => $k
              }
            );
          }
          my $online = 0;

          if ($OCTETS_DIRECTION == 1) {
            $used_traffic->{$k}{TRAFFIC_SUM} = ($used_traffic->{$k}{TRAFFIC_IN}) ? $used_traffic->{$k}{TRAFFIC_IN} : 0;
            $online = $in;
          }

          #Sent / Out
          elsif ($OCTETS_DIRECTION == 2) {
            $used_traffic->{$k}{TRAFFIC_SUM} = ($used_traffic->{$k}{TRAFFIC_OUT}) ? $used_traffic->{$k}{TRAFFIC_OUT} : 0;
            $online = $out;
          }
          else {
            $used_traffic->{$k}{TRAFFIC_SUM} = ($used_traffic->{$k}{TRAFFIC_IN}) ? $used_traffic->{$k}{TRAFFIC_OUT} + $used_traffic->{$k}{TRAFFIC_IN} : 0;
            $online = ($in + $out);
          }

          my $prepaid = $intervals->{$user_tp_interval}->{ZONES}->{$k}->{PREPAID_TSUM};
          if ($debug > 1) {
            print "Prepaid traffic: $prepaid CLASS: $k USED: $used_traffic->{$k}{TRAFFIC_SUM}\n";
          }

          #Check lost of prepaid traffic in log
          if ($used_traffic->{$k}{TRAFFIC_SUM} < $prepaid) {

            #if online have more then log + online make last traffic calculation
            if ($used_traffic->{$k}{TRAFFIC_SUM} + $online / $conf{MB_SIZE} > $prepaid) {
              my $not_prepaid = ($used_traffic->{$k}{TRAFFIC_SUM} * $conf{MB_SIZE} + $online) - $prepaid * $conf{MB_SIZE};
              my $sent        = ($OCTETS_DIRECTION == 2) ? $not_prepaid : $not_prepaid / 2;
              my $recv        = ($OCTETS_DIRECTION == 1) ? $not_prepaid : $not_prepaid / 2;
              $sum_in  = $recv / $conf{MB_SIZE} * $price_in  if ($price_in > 0);
              $sum_out = $sent / $conf{MB_SIZE} * $price_out if ($price_out > 0);
            }

            $price_in  = 0;
            $price_out = 0;
          }
        }

        $sum_in  += $in / $conf{MB_SIZE} * $price_in   if ($price_in > 0);
        $sum_out += $out / $conf{MB_SIZE} * $price_out if ($price_out > 0);

        my $traf_class_sum = $sum_in + $sum_out;
        $total_user_sum += $traf_class_sum;

        if ($uid > 0) {
          $Ipn->traffic_add_user(
            {
              START => $attr->{START} || undef,
              STOP  => $attr->{STOP}  || undef,
              UID   => "$uid",
              TARFFIC_CLASS => $k,
              INBYTE        => "$in",
              OUTBYTE       => "$out",
              NAS_ID        => $Ipn->{$ip}{NAS_ID} || $NAS_ID,
              IP            => $ip,
              INTERVAL      => $user_tp_interval,
              SESSION_ID    => $session_id,

              #SUM						 => ($k == 0) ? $total_user_sum : $traf_class_sum
              SUM => $traf_class_sum
            }
          );
        }

        $extended .= sprintf("   %d| %10s| %10s| Price:%5s%5s = %f/%f=%f\n", $k, $in, $out, $price_in, $price_out, $sum_in, $sum_out, $traf_class_sum);
      }
    }

    #If user Don't have interium traffic
    elsif ($total_user_sum > 0 && $uid > 0) {
    }

    #Put user data to database
    if ($uid > 0) {
      $Ipn->{$ip}{IN}  = (!$Ipn->{$ip}{IN})  ? $total_in  : $Ipn->{$ip}{IN} + $total_in;
      $Ipn->{$ip}{OUT} = (!$Ipn->{$ip}{OUT}) ? $total_out : $Ipn->{$ip}{OUT} + $total_out;

      %RAD = (
        NAS_PORT              => 0,
        INTERIUM_INBYTE       => $total_in,
        INTERIUM_OUTBYTE      => $total_out,
        INBYTE                => $Ipn->{$ip}{IN} || 0,
        OUTBYTE               => $Ipn->{$ip}{OUT} || 0,
        ACCT_INPUT_GIGAWORDS  => $Ipn->{$ip}{ACCT_INPUT_GIGAWORDS} || 0,
        ACCT_OUTPUT_GIGAWORDS => $Ipn->{$ip}{ACCT_OUTPUT_GIGAWORDS} || 0,
        INBYTE2               => ($TRAFFIC_CLASS_SUM{1}{IN}) ? $TRAFFIC_CLASS_SUM{1}{IN} : 0,
        OUTBYTE2              => ($TRAFFIC_CLASS_SUM{1}{OUT}) ? $TRAFFIC_CLASS_SUM{1}{OUT} : 0,
        FRAMED_IP_ADDRESS     => $ip_addr,
        USER_NAME             => $login,
        ACCT_SESSION_ID       => $session_id,
        ACCT_SESSION_TIME     => 0,
        ACCT_STATUS_TYPE      => 'Alive',
      );

      if ($Ipn->{INTERIM}{$ip}) {
        $Ipn->acct_update(
          {
            %RAD,
            NAS_ID => $Ipn->{$ip}{NAS_ID} || $NAS_ID,
            SUM => sprintf("%.6f", $total_user_sum || 0),
            UID => $uid
          }
        );
      }

      #Hangup users with negative deposit
      if ( !$Ipn->{USERS_INFO}->{PAYMENT_TYPE}->{$uid}
        && defined($Ipn->{USERS_INFO}->{DEPOSIT}->{$uid})
        && $Ipn->{USERS_INFO}->{DEPOSIT}->{$uid} < 0)
      {
        my @ip_array = split(/\./, $ip_addr, 4);
        my $num = 0;

        if ($conf{IPN_FW_RULE_UID}) {
          $num = $uid;
        }
        else {
          my @ip_array = split(/\./, $ip_addr, 4);
          $num = $ip_array[3];
        }

        my $rule_num = $conf{IPN_FW_FIRST_RULE} + 10000 + $num;
        print "$DATE $TIME Hangup UID: $uid DEPOSIT: $Ipn->{USERS_INFO}->{DEPOSIT}->{$uid}\n" if ($debug > 0);
        my $netmask = 32;
        my $cmd = $conf{IPN_FW_STOP_RULE} || '';

        #If session online hangup it
        if ($session_id) {
          if ($cmd eq '') {
            print 'Error: Not defined stop rules. Check $conf{IPN_FW_STOP_RULE}';
          }
          else {
            $cmd =~ s/\%IP/$ip_addr/g;
            $cmd =~ s/\%NUM/$rule_num/g;
            $cmd =~ s/\%MASK/$netmask/g;
            $cmd =~ s/\%LOGIN/$login/g;

            print "$cmd" if ($debug > 0);
            system("$cmd");
            $Ipn->acct_stop(
              {
                SESSION_ID           => $session_id,
                ACCT_TERMINATE_CAUSE => 10
              }
            );
          }
        }
      }

      #AMon
      elsif ($conf{IPN_AMON_ALIVE}
        && $Ipn->{CONNECT_INFO}{$session_id}
        && $Ipn->{CONNECT_INFO}{$session_id} =~ /^(\d{10}):\S+$/)
      {
        my $connect_update = $1;
        my $cut_time       = time();
        my $last_alive     = $cut_time - $connect_update;
        if ($last_alive > $conf{IPN_AMON_ALIVE} * 3) {
          my $num = 0;
          if ($conf{IPN_FW_RULE_UID}) {
            $num = $uid;
          }
          else {
            my @ip_array = split(/\./, $ip_addr, 4);
            $num = $ip_array[3];
          }

          my $rule_num = $conf{IPN_FW_FIRST_RULE} + 10000 + $num;
          print "$DATE $TIME Hangup. Lost AMON ALIVE: $last_alive UID: $uid DEPOSIT: $Ipn->{USERS_INFO}->{DEPOSIT}->{$uid}\n" if ($debug > 0);
          my $netmask = 32;
          my $cmd = $conf{IPN_FW_STOP_RULE} || '';
          print 'Error: Not defined stop rules. Check $conf{IPN_FW_STOP_RULE}' if ($cmd eq '');
          $cmd =~ s/\%IP/$ip_addr/g;
          $cmd =~ s/\%NUM/$rule_num/g;
          $cmd =~ s/\%MASK/$netmask/g;
          $cmd =~ s/\%LOGIN/$login/g;
          print "$cmd" if ($debug > 0);
          system("$cmd");
          $Ipn->acct_stop(
            {
              SESSION_ID           => $session_id,
              ACCT_TERMINATE_CAUSE => 10
            }
          );
        }
      }
    }

    $registred .= sprintf("%6s| %14s| %10s| %10s| %10s| %10s| %5s|\n%s", $uid, $RAD{FRAMED_IP_ADDRESS}, $RAD{INBYTE}, $RAD{OUTBYTE}, $total_in, $total_out, $interium_time, $extended) if ($debug > 0);
  }

  if ($debug > 0 || $ARGV->{LOG_FILE}) {
    my $GT = '';

    if ($begin_time > 0) {
      Time::HiRes->import(qw(gettimeofday));
      my $end_time = gettimeofday();
      my $gen_time = $end_time - $begin_time;
      $GT = sprintf(" GT: %2.5f", $gen_time);
    }

    my $log_message = '';
    if ($debug > 0) {
      $Ipn->{TRAFFIC_SUM}         = 0 if (!$Ipn->{TRAFFIC_SUM});
      $Ipn->{UNKNOWN_TRAFFIC_SUM} = 0 if (!$Ipn->{UNKNOWN_TRAFFIC_SUM});
      my $speed  = int2byte(($Ipn->{TRAFFIC_SUM} + $Ipn->{UNKNOWN_TRAFFIC_SUM}) / $attr->{SESSION_INTERVAL});
      my $output = "$registred$GT/Query: $Ipn->{query_count}/ Stats Rows: $Ipn->{TRAFFIC_ROWS}/" . int2byte($Ipn->{TRAFFIC_SUM}) . " Unknown: $Ipn->{UNKNOWN_TRAFFIC_ROWS}/" . int2byte($Ipn->{UNKNOWN_TRAFFIC_SUM}) . " Speed: $speed/sec.\n";
      $log_message .= $output;
    }

    $log_message .= "$attr->{LOG} $GT Query: $Ipn->{query_count} ROWS: $Ipn->{TOTAL_FLOWS}";
    mk_log('LOG_INFO', "$log_message");

    $Ipn->{TRAFFIC_SUM}         = 0;
    $Ipn->{UNKNOWN_TRAFFIC_SUM} = 0;
  }

}

#**********************************************************
# Get data from collectors
#**********************************************************
sub get_collector_data {
  my ($log, $attr) = @_;

  print "$log\n" if ($debug > 1);

  $Ipn->traffic_agregate_clean();
  $Ipn->{TOTAL_FLOWS} = 0;
  my %DATA = ();

  my %virus_allert_ips = ();

  open(LOG, $log) || die "Can't open log file '$log' $!\n";

  while (<LOG>) {

    # flow-capture
    if (/(\d+)\.(\d+)\.(\d+)\.(\d+)\s+(\d+)\.(\d+)\.(\d+)\.(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/) {
      $Ipn->{TOTAL_FLOWS}++;
      print "-$1.$2.$3.$4 $5.$6.$7.$8 $9 $10 $11 $12\n" if ($debug > 7);

      $DATA{SIZE} = $12;
      if ($ARGV->{VIRUS_ALERT} && $DATA{SIZE} < 150) {
        $virus_allert_ips{ (16777216 * $1 + 65536 * $2 + 256 * $3 + $4) }++;
        next;
      }

      ($DATA{SRC_IP}, $DATA{SRC_PORT}) = (16777216 * $1 + 65536 * $2 + 256 * $3 + $4, int($10));
      ($DATA{DST_IP}, $DATA{DST_PORT}) = (16777216 * $5 + 65536 * $6 + 256 * $7 + $8, int($11));

      $DATA{PROTOCOL} = $9;

      #$DATA{IF_NAME}  = '0';

      $Ipn->traffic_agregate_users({ %DATA, DEBUG => $debug, TRAFFIC_CLASS => (defined($ARGV->{TRAFFIC_CLASS}) ? $ARGV->{TRAFFIC_CLASS} : undef) });
    }

    #Ipcad log analize
    elsif (/ (\d+)\.(\d+)\.(\d+)\.(\d+)[ |\t]+(\d+)\.(\d+)\.(\d+)\.(\d+)[ |\t]+(\d+)[ |\t]+(\d+)[ |\t]+(\d+)[ |\t]+(\d+)[ |\t]+(\d+)[ |\t]+(\S+)/) {
      ($DATA{SRC_IP}, $DATA{SRC_PORT}) = (16777216 * $1 + 65536 * $2 + 256 * $3 + $4, $11);
      ($DATA{DST_IP}, $DATA{DST_PORT}) = (16777216 * $5 + 65536 * $6 + 256 * $7 + $8, $12);
      $DATA{SIZE}     = $10;
      $DATA{PROTOCOL} = 0;
      $DATA{SRC_PORT} = 0 if ($DATA{SRC_PORT} !~ /^\d+$/);
      $DATA{DST_PORT} = 0 if ($DATA{DST_PORT} !~ /^\d+$/);

      #$DATA{NAS_ID}=$NAS_ID;
      if ($14) {
        $DATA{IF_NAME} = $14;
      }

      $Ipn->traffic_agregate_users({ %DATA, DEBUG => $debug });
    }

    #trafdlog analize
    elsif (/^(\d+)\.(\d+)\.(\d+)\.(\d+)\s+([^\s]+)\s+(\d+)\.(\d+)\.(\d+)\.(\d+)\s+([^\s]+)\s+[a-z]+\s+\d+\s+(\d+)/) {
      ($DATA{SRC_IP}, $DATA{SRC_PORT}) = (16777216 * $1 + 65536 * $2 + 256 * $3 + $4, $5);
      ($DATA{DST_IP}, $DATA{DST_PORT}) = (16777216 * $6 + 65536 * $7 + 256 * $8 + $9, $10);
      $DATA{SIZE}     = $11;
      $DATA{PROTOCOL} = 0;
      $DATA{SRC_PORT} = 0 if ($DATA{SRC_PORT} !~ /^\d+$/);
      $DATA{DST_PORT} = 0 if ($DATA{DST_PORT} !~ /^\d+$/);

      #$DATA{NAS_ID}=$NAS_ID;
      $DATA{IF_NAME} = '0';

      $Ipn->traffic_agregate_users({ %DATA, DEBUG => $debug });
    }
  }
  close(LOG);

  if ($ARGV->{VIRUS_ALERT}) {
    my $virus_allert_log = '';
    my $DATETIME = strftime "%Y-%m-%d %H:%M:%S", localtime(time);
    while (my ($k, $v) = each %virus_allert_ips) {
      my $user = ($Ipn->{USERS_IPS}{$k}) ? $Ipn->{USERS_INFO}{LOGINS}->{ $Ipn->{USERS_IPS}{$k} } . ' ' . int2ip($k) : '!!! ' . int2ip($k);
      $virus_allert_log .= "$DATETIME $user $v\n" if ($v > int($ARGV->{VIRUS_ALERT}));
    }

    if ($virus_allert_log ne '') {
      open(FILE, ">> $flow_dir/virus_allert.log") || die "Can't open file '$log_file' $!\n";
      print FILE $virus_allert_log;
      close(FILE);
    }
  }

}

#**********************************************************
# Check running program
#**********************************************************
sub make_pid {
  my ($pid_file, $attr) = @_;

  if ($attr && $attr eq 'clean') {
    unlink($pid_file);
    return 0;
  }

  if (-f $pid_file) {
    open(PIDFILE, "$pid_file") || die "Can't open pid file '$pid_file' $!\n";
    my @pids = <PIDFILE>;
    close(PIDFILE);

    my $pid = int($pids[0]);
    if ($pid > 0 && verify($pid)) {
      print "Process running, PID: $pid\n";
      return 1;
    }
  }

  my $traffic2sql_pid = $$;
  open(PIDFILE, ">$pid_file") || die "Can't open pid file '$pid_file' $!\n";
  print PIDFILE $traffic2sql_pid;
  close(PIDFILE);

  return 0;
}

#**********************************************************
# Check running program
#**********************************************************
sub verify {
  my ($pid) = @_;

  my $me = $$;    # = $self->{verify};

  my @ps = split m|$/|, qx/ps -fp $pid/
  || die "ps utility not available: $!";
  s/^\s+// for @ps;    # leading spaces confuse us

  no warnings;         # hate that deprecated @_ thing
  my $n = split(/\s+/, $ps[0]);
  @ps = split /\s+/, $ps[1], $n;

  return ($ps[0]) ? 1 : 0;
}

#**********************************************************
#
#**********************************************************
sub daemonize {
  chdir '/';
  umask 0;

  #Save old out
  my $SAVEOUT;
  open($SAVEOUT, ">&", STDOUT) or die "XXXX: $!";

  #Reset out
  #open STDIN, '/dev/null';
  #open STDOUT, '/dev/null';
  #open STDERR, '/dev/null';

  if (fork()) {
    exit;
  }
  else {

    #setsid;
    if (make_pid($flow_dir . "/traffic2sql.pid") == 1) {

      #Close new out
      close(STDOUT);

      #Open old out
      open(STDOUT, ">&", $SAVEOUT);
      print "Already running!\n";
      exit;
    }
    return;
  }
}

#**********************************************************
# log_print local function
#**********************************************************
sub mk_log {
  my ($type, $message) = @_;

  if ($ARGV->{LOG_FILE} || defined($ARGV->{'-d'})) {
    my $DATETIME = strftime "%Y-%m-%d %H:%M:%S", localtime(time);
    $log_file = $ARGV->{LOG_FILE} if ($ARGV->{LOG_FILE});
    open(FILE, ">> $log_file") || die "Can't open file '$log_file' $!\n";
    print FILE "$DATETIME $type: $message\n";
    close(FILE);
  }
  else {
    print "$message\n";
  }
}

1
