Port Test - Client Side

Description

This page is added to show how one can test that ports are open from client to server, at any time. This script is used just like "ping" is, but where ping only checks the main ICMP ping port, this script can be used to check against any port thats UDP or TCP based. This is very useful for telling when a service comes up on a remote host, or if the firewall is allowing connectivity or not.

Most often, I use this script to check from my workstation to a remote server, to see if services are up or not. From that, it grew to become the central part of much of our suite of monitoring applications, and since gone on to bigger and better things.

Usage is very straightforward. Below is the usage line as reported from the script when called with no options :

$ ping_port.pl

TCP port check -
You must pass in the host and port
USAGE : ping_port.pl [-u|-t|-c COUNT] [IPADDRESS] [PORT]

As you can see, it takes at minimum, 2 arguments : the hostname or IP of the target you are checking, followed by the port number to check. Space is used as the separator of command line arguments. You can also specify the "-u" option for UDP checks, and force TCP checking with the "-t" argument. One of the newer options is the "-c" followed by an integer number, to indicate how many pings before quitting.

By default, the script will run indefinitely, so the "-c" option was needed for us to be able to write monitoring scripts to query things like our Web ports on target servers. Without the "-c", the script will never complete - it will just ping forever - so in that case we use options like "-c 1" to run one ping, and then parse the results.

In essence, this is just a very simple Perl socket client, that can be used in standalone mode, or in combination with the perl_socket_XXXX.pl scripts to check both client and server side ports.

Process/Implementation

Just copy this code, save it as "ping_port.pl" and run it on the command line, in the foreground, so you can kill it when done testing.

#! /usr/bin/perl
#
#####
#####  Hacked, stolen, and compiled by Paul A. Luzzi
#####    script named ping_port.pl
#####
#####  Purpose is to be able to use perl's socket communication
#####    to be able to ping on a non-standard port.
#####
#####  Version 1 - only does tcp port checking.
#####  Version 2 - updated 11-26-2001 to allow use of udp port checks also
#####  Version 3 - updated 09-12-2003 to allow packet count option
#####  Version 4 - updated 03-18-2007 to allow time to display
#####
#####  USAGE :  "ping_port.pl [-u|-t|-c COUNT] [IPADDRESS] [PORT]";
#####    where the "-u" will return udp port checks, and "-t" or 
#####    nothing at all will return tcp port checks.
#####

#####
#####  Include this module for ping
#####
use Net::Ping;

#####
#####  Include this module for sockets
#####
use IO::Socket;

#####
#####  Just some debug stuff
#####
## print "\n 0 = $ARGV[0] \n";
## print " 1 = $ARGV[1] \n";
## print " 2 = $ARGV[2] \n";
 
if ( $ARGV[0] eq "-u" ) {
  $option = "UDP" ;
  print "\n$option port check - " ;
  shift;
  } elsif ( $ARGV[0] eq "-t" ) {
  $option = "TCP" ;
  print "\n$option port check - " ;
  shift;
  } elsif ( $ARGV[0] eq "-c" ) {
  shift ;
  $max_count = $ARGV[0] ;
  $option = "TCP" ;
  $count_enabled = 1 ;
  print "\n$option port check with count of $max_count - " ;
  shift;
  } else {
  $option = "TCP" ;
  print "\n$option port check - " ;
  }

#####
#####  Check that the right amount of arguments are correct
#####    there should be two - first is server name, and
#####    second is the port number
#####
if ( $ARGV[1] eq "" && $ARGV[2] eq "" ) {
    print "\nYou must pass in the host and port";
    print "\nUSAGE : ping_port.pl [-u|-t|-c COUNT] [IPADDRESS] [PORT]";
    print "\n";
    print "\n";
    exit
  }

##### 
#####  Ports to check :
#####    make this a hash, so that the name can be easily printed 
#####    out along with the port number
#####    Not all ports checked...use the Cheswick and Bellovin
#####    approach
#####

#####
#####  This is how it was for regular vulnerability checking
#####
## 
## @tcp_ports = (21,	  #ftp		banner
## 	           23,	  #telnet
## 	           25,	  #SMTP		banner
##               80,    #HTTP		banner
## 	           110,	  #POP3		banner
##               1500); #adsm
##           
#####
#####  This is how it was for accepting input of which ports
#####
##
## @tcp_ports = (@ARGV) ;
##           

#####
#####  Setup our header
#####
$target = shift;
print "checking $target...\n";

#####
#####  main section
#####
$ip = name($target);
$count = 1;
$max = $max_count + 1 ;
$curr_time=` date '+%m-%d-%Y @ %H:%M:%S' `;chomp($curr_time);
if ( $max < 2 ) { $max = 2 } ;
foreach $port (@ARGV) {
  while ( $count < $max ) {
    if ( $option eq "UDP" ) {
      check_udp_port($ip,$port);
      }
     else
      {
      check_tcp_port($ip,$port);
     }
    sleep 1;
    $count = $count + 1 ;
    if ( $count_enabled != 1 ) { $max = $max + 1 } ;
  }
  print "\n";
}

#####
#####  Get name or IP, return IP address
#####
sub name {
  my ($host) = @_;
  eval {
    $ipaddr = inet_ntoa(inet_aton($host));
    print "IP for $host :\t$ipaddr\n\n";
    return $ipaddr;
  }  || die "Could not find host.\n";
}

#####
#####  Ping the host
#####
sub ping {
 my ($host) = @_;

  $p = Net::Ping->new("icmp");
  print "$host is ";
  print "NOT " unless $p->ping($host, 2);
  print "alive.\n";
  $p->close();
}

#####
#####  Check to see if a port is open
#####
sub check_tcp_port {
  my ($host,$port) = @_;
  $curr_time=` date '+%m-%d-%Y @ %H:%M:%S' `;chomp($curr_time);
  $remote = IO::Socket::INET -> new (
             Proto => "tcp",
	     Timeout => 3,
             PeerAddr => $host,
             PeerPort => $port );
  if ($remote) { 
    close $remote;
    print "$host:$port ($option) =>\tActive ($count - $curr_time)\n";
  }
  else { print "$host:$port ($option) =>\tInactive ($count - $curr_time)\n"; }  
}

#####
#####  Check to see if a udp port is open
#####
sub check_udp_port {
  my ($host,$port) = @_;
  $curr_time=` date '+%m-%d-%Y @ %H:%M:%S' `;chomp($curr_time);
  $remote = IO::Socket::INET -> new (
             Proto => "udp",
	     Timeout => 3,
             PeerAddr => $host,
             PeerPort => $port );
  if ($remote) { 
    close $remote;
    print "$host:$port ($option) =>\tActive ($count - $curr_time)\n";
  }
  else { print "$host:$port ($option) =>\tInactive ($count - $curr_time)\n"; }  
}

#####
#####  UDP Ping - dont know if I will ever use this one or not
#####
sub udp_ping {
  my ($host) = @_;
  $p = Net::Ping->new();
  print "$host is alive.\n" if $p->ping($host);
  $p->close();
}

#####
#####  End of ping_port.sh
#####

Make sure its executable too.

Tuning / Customization

There really isn't anything to tune or customize as far as being required.  The client is simple, and takes command line args, so the script really doesnt need tuning or customization. You are free to modify to your hearts content, and use in any way that helps, but its completely usable as is, with no tweaks needed. I have run this as is on Linux, Solaris, AIX, HP-UX, and Windows.

This is easy enough to test. Assuming you have Internet connectivity, you could test against www.pluzzi.com on port 80, the web http port.

$ ping_port.pl -c 1 www.pluzzi.com 80

TCP port check with count of 1 - checking www.pluzzi.com...
IP for www.pluzzi.com :         74.92.107.93

74.92.107.93:80 (TCP) =>        Active (1 - 07-03-2008 @ 07:49:21)

$

Thats an example of a good / successful test. In a case where there is no connectivity, you would see something like this :

$ ping_port.pl -c 1 www.yahoo.com 80

TCP port check with count of 1 - checking www.yahoo.com...
IP for www.yahoo.com :  69.147.76.15

69.147.76.15:80 (TCP) =>       Inactive (1 - 07-03-2008 @ 07:50:22)

$

In that example, I don't have internet connectivity, so my test to the internet fails. You could also just let it keep running if doing firewall testing, because it polls once per second and helps the firewall troubleshootin because it continues to show in the logs, and helps with testing and configuring.

Because this is ignorant to whether its testing against secure or non-secure traffic, it can help with establishing connectivity for https and SSL based ports as well - although it wont establish a proper secure connection - but will confirm port access.

Further Information

As the whole purpose of this, is to test that ports are open, if you find they are not, you probably have some firewall or network related ussue (ISP wont forward, firewall blocking, etc). I'm not sure of all the different possible causes, and definitely do not pretend to - so the problem would be something specific in your own case.

Other assumptions here - if you are not familiar with Perl, these still should be usable. The design is that anyone can cut and paste, and run the commands - and even interpret the output. This is far easier (in my opinion) than using the telnet testing method.

Also added perl_socket_8151.pl page as well, for the other half of socket testing.

 

Tag page
You must login to post a comment.