Test that Socket!

There are times when you need to know if you can communicate from one system to another.  You don’t always have the luxury of having an application listening to connect to, or you don’t have an easy way of establishing a connection (eg. a UDP connection to a specific port).  So, now you can Test that Socket!

This actually came up recently when doing some troubleshooting during an incident, made me recall an earlier script I had written!
The following 2 scripts allow you to (a) listen for a connecting socket and (b) try to establish a connection.  Both scripts allow for tests using either TCP or UDP.  This can be particularly useful when trying diagnose connection problems through firewalls.  The other useful feature is that you can use it to test multiple servers

listenSocket.pl

#!/bin/perl

#-#
#-# Author: Andrew Barnes
#-#

#-#
#-# This script listens on a TCP port to a Network Socket
#-#

#-# Modules to Include
use IO::Socket;         # IO Sockets
use Net::hostent;       # for 00 version of gethostbyaddr

#-#
#-# Define Variables:
#-#
# Define the Protocol to use
my $proto=tcp;
# Define the Port to listen on
my $port=9999;

#-# Test connection to the socket
sub listenSocket {
  my $server = IO::Socket::INET->new( Proto => $proto,
    LocalPort => $port,
    Listen => SOMAXCONN,
    Reuse => 1);
  die "Can't setup server on port $port: $!\n" unless $server;
  print STDERR "Server started on port $port\n";

  my $client;
  while ($client = $server->accept()) {
    print STDERR "Incoming connection\n";
    $client->autoflush(1);
  }
}

main: {
  &listenSocket;
};

testSocket.pl

#!/bin/perl

#-#
#-# Author: Andrew Barnes
#-#

#-#
#-# This script tests connectivity to a Network Socket
#-# The script operates in two modes - standard ("alert-only") mode
#-# and "verbose" mode, whereby it reports successful connections too
#-#

#-# Modules to Include
use IO::Socket;	   	# IO Sockets
#-# use sigtrap;	# Simple Signal Trapping
#-# use Time::Piece;	# Object Oriented time objects
#-# use Time::Seconds;	# Object Oriented time objects
use Getopt::Long;	# Handle Options

#-# -------------------------- #-#
#-# BEGIN Variable Definitions
#-# -------------------------- #-#

#-# Time/Date Stamps
#-# our $currentDate	= localtime;
#-# my $dateStamp		= $currentDate->ymd("") . "-" . $currentDate->hms("");

#-# Define the local hostname
#-# chomp( my $localNodeName = `/bin/hostname` );    # Get the local hostname

#-# Create a new global variable to store each of the config lines in
our @configLines;

#-# ------------------------ #-#
#-# END Variable Definitions
#-# ------------------------ #-#

#-#-----------------#-#
#-# BEGIN Sub Routines
#-#-----------------#-#

#-# Print Out help message(s)
  sub printHelp {
  print "\n";
  print "Required Input:\n";
  print "  --config ////\n";
  print "Optional Input:\n";
  print "  --verbose|showsuccess|showSuccess\n";
  print "  --help|syntax|?\n";
  print "\n";
}

#-# Validate Configuration File and read in values
sub validateConfig {
  #-# Clear the array
  our @configLines = ();

  #-# Check the config file exists
  if ( -e $config ) {
    #-# Open the config file and read in the values
    open (configFile, "< $config")
      || die "WARNING - Configuration file $config does not exist, or cannot be read\nPlease verify the config file to be used and try again\n";
    while (  ) {
      #-# Ignore comments by erasing them
      s/#.*//;
      #-# Skip blank lines
      next if /^(\s)*$/;
      #-# remove trailing newline characters
      chomp;
      #-# Push the remaining data into the array
      push @configLines, $_;
    }
  } else {	#-# Otherwise quit
      die "WARNING - Configuration file $config does not exist, or cannot be read\nPlease verify the config file to be used and try again\n"
  }
}

#-# Test connection to the socket
sub testSocket {
  my $sock = new IO::Socket::INET (
    PeerAddr => $remoteAddr,
    PeerPort => $remotePort,
    Proto => $remoteProto,
    Timeout => 5,
  );
  if ($sock) {
    if ($verbose) {
      print "$remoteAddr\:$remotePort = connected\n";
    }
  } else {
    #-# die "$remoteAddr\:$remotePort = $!\n" unless $sock;
    print "$remoteAddr\:$remotePort = $!\n" unless $sock;
  }
  close($sock);
}

#-# Sub Routine to Process Config and run commands
sub processConfigAndGetValues {
  #-# now process the netstat output
  foreach $lineContents (@configLines) {
    #-# Now get the config for each line - split by whitespace
    our ($remoteAddr, $remotePort, $remoteProto) = split (/\s+/, $lineContents);

    #-# Run UpdateGraph Routines
    #-# updateGraphs($currentIP, $community, $sslEnabled);
    &testSocket;
  }
}

#-# ---------------- #-#
#-# END Sub Routines
#-# ---------------- #-#

#-# ---------------- #-#
#-# BEGIN Main Loop
#-# ---------------- #-#

main: {
  #-----------------#
  # Get Options From Command line
  #-----------------#
  GetOptions ( "config=s" => \$config,	#-# Configuration file - requires a string
      "verbose|showsuccess|showSuccess" => \$verbose,		#-# Sleep Time - requires an integer
      "help|syntax|?"  => \$help, );	#-# --help or --syntax or --?

  #-----------------#
  # Test options and use if appropriate - otherwise echo syntax to screen
  #-----------------#
  if ($help) {
    #-# Run the printHelp sub-routine
    &printHelp;
    exit;
  }

  if ($config) {
    if ($help) {
      #-# Run the printHelp sub-routine
      &printHelp;
    } else {
      #-# Validate the configuration file and read in the values
      &validateConfig;
      #-# Run the funky command
      &processConfigAndGetValues
    }
  } else {
    #-# Run the printHelp sub-routine
    &printHelp;
    die "No Configuration File Defined - Please agin using the syntax indicated above";
  }
}

testSocket.conf

#-#
#-# Configuration File for Network Socket Test Script
#-# Author:	Andrew Barnes
#-#

#-# Syntax as below - ::NOTE:: TAB-deliminated
#-# Followed by an example:
#hostname/IP	#Port	#Protocol [tcp/udp]
#testhost	22	tcp
#127.0.0.1	22	tcp