eval 'exec perl -x $0 ${1+"$@"}' # -*-perl-*-
  if 0;
#!perl -w
#
# ======================================================================
# This file is Copyright 1998,1999 by the Purdue Research Foundation and
# may only be used under license.  For terms of the license, see the
# file named COPYRIGHT included with this software release.
# AAFID is a trademark of the Purdue Research Foundation.
# All rights reserved.
# ======================================================================
#
# AAFID2 system
# Agent name:        SYNflood
# Agent description: Detect SYN flooding attacks
# Author:            Diego Zamboni
#
# History of modifications:
# 
# Known bugs:
# 
# Things to do:
# 
# Future work:
# 
# Suggestions made by people:
# 
# Generated automatically by ../bin/makeagent.pl on Tue Sep  7 23:55:56 1999.
# 
###### AUTOMATICALLY GENERATED FILE --- DO NOT EDIT ##########
#

# 10 "SYNflood.aas"
package SYNflood;

# Version number
# 13 "SYNflood.aas"
$VERSION=eval {do { my @r = (q$Revision: 1.6 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }}; $VERSION=$VERSION;

# Agent parameters
%PARAMETERS=(
             Description        => "Detect SYN flooding attacks",
             CheckPeriod        => eval {undef},
# 38 "SYNflood.aas"
             Step	  => 2,
             AvgPeriod => 60,
             CheckPeriod => 10,
# 32 "SYNflood.aas"
             FiltersNeeded => {   ActiveSockets => [{ Domain => 'TCP', State => 'SYN_RCVD' }, 'Check'] }
            );

# Package loading
use AAFID::Agent;
use AAFID::Log;
use AAFID::Common;


use vars qw (
             @ISA
             $VERSION
             %PARAMETERS
            );

# Define the superclass.
 @ISA=qw(AAFID::Agent);

=head1 SYNflood


This agent attempts to detect SYN flooding attacks by counting the average
number of half-open TCP connections (connections in SYN_RCVD) state that
have been seen in a period of time. Normally the half-open state of a
connection occurs very quickly and is almost never seen, so if the
average goes above 2, we start signaling things wrong. The status
increases by 1 for each 2 open connections, so 4 open connections results
in a status of 2, 6 open connections gives a status of 3, etc.

The step value for increments in the status can be controlled using
the C<Step> parameter.

The C<AvgPeriod> controls the period, in seconds, over which the
average number of half-open connections is computed.

=cut

# Preamble code
# 35 "SYNflood.aas"
	use Util::NumQueue;

# Provide an Init function.
sub Init {
  my $self=checkref(shift);
# 43 "SYNflood.aas"
  my $queuecnt=Util::NumQueue->new;
  my $queuetrack=Util::FiniteQueue->new;
  $queuecnt->timelength($self->getParameter('AvgPeriod'));
  $queuetrack->timelength($self->getParameter('CheckPeriod'));
  $self->setParameter(QueueCount => $queuecnt);
  $self->setParameter(QueueTrack => $queuetrack);
  return $self;
}

# The Check function.
sub Check {
  my $self=checkref(shift);
# 51 "SYNflood.aas"
  my ($filter, $fh, $line)=@_;
  my $step=$Params{Step};
  my $queuecnt=$Params{QueueCount};
  my $queuetrack=$Params{QueueTrack};
  my $period=$Params{AvgPeriod};
  my $status=$Params{Status};
  my $message=$Params{Message};

  # Each line we get represents one half-open connection.
  # We count all the lines that come from a single netstat process
  # by using the PID field of the line.
  my $lastpid=$Params{LastPid} || 0;
  my $lastcnt=$Params{"MyCount_$lastpid"} || 0;
  $self->Log("debug", "lastpid=$lastpid, lastcnt=$lastcnt\n");
  if ($line) {
    $self->Log("debug", "Got line: $line\n");
    # QueueTrack keeps track of the last time there was an update.
    $queuetrack->add(1);
    $self->Log("debug", "queuetrack now has length ".$queuetrack->length."\n");
    # We are only interested in the PID.
    my $pid;
    (undef, $pid, undef)=split(" ", $line);
    $Params{"MyCount_$pid"}++;
    $self->Log("debug", "pid=$pid, MyCount_$pid=".$Params{"MyCount_$pid"}."\n");
    if ($pid != $lastpid) {
      $queuecnt->add($lastcnt);
      $self->Log("debug", "Added $lastcnt to queuecnt\n");
      delete $Params{"MyCount_$lastpid"};
      $lastpid=$pid;
      $Params{LastPid}=$pid;
      # Compute the status
      my $avg=($queuecnt->sum/$period);
      $status=int($avg/$step);
      $self->Log("debug", "Reporting ($status, $lastcnt)\n");
      return ($status,  $lastcnt);
    }
  }
  else {
    # This is the case when it is called as a periodic callback
    $self->Log("debug", "Got no line\n");
    # Update things when there has been no input for a while
    $queuetrack->update;
    if ($queuetrack->isEmpty) {
      $self->Log("debug", "Setting MyCount_$lastpid to zero\n");
      $Params{"MyCount_$lastpid"}=0;
      $lastcnt=0;
      # Compute the status
      my $avg=($queuecnt->sum/$period);
      $status=int($avg/$step);
      $self->Log("debug", "Reporting ($status, $lastcnt)\n");
      return ($status,  $lastcnt);
    }
  }
  return ($status, $message);
}
# Agent commands

# End of entity marker
_EndOfEntity;
