TCP Socket Collection Agent Source Code

#!/usr/bin/perl -w

###########################################################################
###                                                                     ###
###  NetworkLens TCP Client                                             ###
###                                                                     ###
###  NetworkLens                                                        ###
###  Copyright (C) 2002, I-Link Incorporated                            ###
###                                                                     ###
###  This perl script will open a listening socket on the networklens   ###
###  port (port 9002) and attempt to create new NetworkLens events      ###
###  from any message that arrive.                                      ###
###                                                                     ###
###  To Do:  (*) Check for new event vs. mod to existing event          ###
###              (rudimentary event correlation)                        ###
###                                                                     ###
###          (*) Provide some sort of filtering to remove events or     ###
###              messages that we don't care about                      ###
###                                                                     ###
###  Change Log:                                                        ###
###                                                                     ###
###  01/09/2002  Greg Bailey                                            ###
###    Initial Version                                                  ###
###                                                                     ###
###  01/10/2002  Greg Bailey                                            ###
###    Change data for IP address to character string X.X.X.X           ###
###                                                                     ###
###########################################################################

###########################################################################
#    Configuration settings                                               #
###########################################################################

$debug = 0;

$daemon_mode = 1;
$api_version = "1.0";

$dbi_datasource = "DBI:mysql:lens:localhost:3306";
$dbi_username   = "root";
$dbi_password   = "";

$lens_port = 9002;

$MAXLINE = 65535;

$severity_map{"unknown"} = 0;
$severity_map{"alert"} = 1;
$severity_map{"critical"} = 2;
$severity_map{"error"} = 3;
$severity_map{"warning"} = 4;
$severity_map{"notification"} = 5;
$severity_map{"informational"} = 6;
$severity_map{"debugging"} = 7;

###########################################################################
#    Package definitions                                                  #
###########################################################################

use DBI;
use IO::Socket;
use POSIX;

###########################################################################
#    Make a background process                                            #
###########################################################################

if ( $daemon_mode )
{
  $pid = fork();
  exit if $pid;
  die "Couldn't fork: $1" unless defined( $pid );
}

POSIX::setsid()
  or die "Can't start a new session: $!";

$time_to_die = 0;

sub signal_handler
{
  $time_to_die = 1;
}

if ( $daemon_mode )
{
  $SIG{INT} = $SIG{TERM} = $SIG{HUP} = \&signal_handler;
}

###########################################################################
#    Connect to the NetworkLens database                                  #
###########################################################################

$dbh = DBI->connect( $dbi_datasource, $dbi_username, $dbi_password,
                     { RaiseError => 1 } )
  or die "connecting: $DBI::errstr\n";

###########################################################################
#    Open the NetworkLens socket                                          #
###########################################################################

$lens_socket = IO::Socket::INET->new( LocalPort => $lens_port,
                                      Type => SOCK_STREAM,
                                      Reuse => 1,
                                      Listen => SOMAXCONN )
  or die "socket: $@";

###########################################################################
#    Main Loop                                                            #
###########################################################################

until ( $time_to_die )
{
  $client = $lens_socket->accept();

  $client_ip = $client->peeraddr();
  $client_hostname = gethostbyaddr( $client_ip, AF_INET );
  $client_ip_address = $client->peerhost();

  if ( $debug )
  {
    printf( "\n" );
    printf( "Connection from %s (%s) OPEN\n",
            $client_hostname, $client->peerhost() );
  }

  $greeting = sprintf( "NetworkLens v1.0 TCP Agent (%s): HELLO %s (%s)\n",
                       $api_version, $client_hostname, $client->peerhost() );

  $client->send( $greeting );

  $message = "";

  $client->recv( $message_part, $MAXLINE );
  $message = $message . $message_part;

  while ( $message_part !~ /[^0-9a-zA-Z=&+%_]/ )
  {
    $client->recv( $message_part, $MAXLINE );
    $message = $message . $message_part;
  }

  $message =~ /([0-9a-zA-Z=&+%_]*)/;
  $message = $1;

  @pairs = split( /&/, $message );
  foreach $pair ( @pairs )
  {
    ( $name, $value ) = split( /=/, $pair );
    if ( ! defined( $value ) )
    {
      $value = "";
    }
    $name =~ tr/+/ /;
    $name =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
    $value =~ tr/+/ /;
    $value =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;

    $args{$name} = $value;

    if ( $debug )
    {
      printf( "  [%-15s] = <%s>\n", $name, $value );
    }
  }

  if ( $debug )
  {
    printf( "Connection from %s (%s) CLOSED\n",
            $client_hostname, $client->peerhost() );
  }

  $client->close();

  ##---------------------------------------------------------------------##
  ##-  At this point, remove/filter events we don't care about...       -##
  ##---------------------------------------------------------------------##

  if ( 0 )  # we dont care about this record
  {
    next;
  }

  ##---------------------------------------------------------------------##
  ##-  At this point, we want to create a new event                     -##
  ##---------------------------------------------------------------------##

  if ( exists $args{"severity"} )
  {
    if ( exists $severity_map{$args{"severity"}} )
    {
      $severity = $severity_map{$args{"severity"}};
    }
    else
    {
      $severity = 0;
    }
  }
  else
  {
    $severity = 0;
  }

  if ( exists $args{"ref_id"} )
  {
    $ref_id = $args{"ref_id"};
  }
  else
  {
    $ref_id = 0;
  }

  if ( exists $args{"category"} )
  {
    $category = $args{"category"};
  }
  else
  {
    $category = "";
  }

  $category =~ s/(['"])/\\$1/g;

  if ( exists $args{"summary"} )
  {
    $summary = $args{"summary"};
  }
  else
  {
    $summary = "";
  }

  $summary =~ s/(['"])/\\$1/g;

  $sql = sprintf( "insert into lens_event "
                . "  ( status, severity, created, ip_addr, ref_id, "
                . "    category, summary ) "
                . "values "
                . "  ( 0, %d, now(), '%s', %d, '%s', '%s' )",
                  $severity, $client_ip_address, $ref_id, $category, $summary );

  if ( $debug )
  {
    printf( "severity = %d (%s)\n", $severity, $args{"severity"} );
    printf( "ref_id   = %d\n", $ref_id );
    printf( "category = %s\n", $category );
    printf( "summary  = %s\n", $summary );
    printf( "SQL      = %s\n", $sql );
    printf( "\n" );
  }

  $dbh->do( $sql );
}

close( $lens_socket );

###########################################################################
#    Disconnect from the NetworkLens database                             #
###########################################################################

$dbh->disconnect()
  or die "disconnecting: $DBI::errstr\n";

###########################################################################
###  END OF SOURCE FILE                                                 ###
###########################################################################