Send in your Unix questions today! |
See additional Unix tips and tricks
Last week, we looked at how nmap, the well known port mapper, can be used to help monitor applications and services on a network or subnet with very little overhead and surprisingly little effort. In this week's column, the findAppl script has been enhanced at a reader's request that it include the system name for each line of output.
For example, if we are trying to determine which systems on the 10.1.2.x subnet are running Oracle, we might expect output such as this:
bash-2.03# ./findAppl 1521 10.1.2.0/24
10.1.2.42 moth oracle
10.1.2.73 spider oracle
10.1.2.74 grasshopper oracle
10.1.2.91 katydid oracle
10.1.2.92 ant oracle
10.1.2.99 housefly oracle
10.1.2.100 gnat oracle
10.1.2.191 butterfly oracle
10.1.2.199 dragonfly oracle
|
The addition of the host names make this output much more useful for those of us who don't think of or particularly recognize our systems by their IP addresses.
Since the goal of the script is to derive the information about what is running on what port as quickly and efficiently as possible, we want to use a similarly low cost method to obtain the host names. The obvious choice is to do a reverse lookup. For this, I use nslookup:
@nameinfo=`nslookup $IP 2> /dev/null`;
This Perl command runs nslookup against each IP address, sending standard error to /dev/null. The nslookup output is saved in the @nameinfo array for evaluation.
This syntax doesn't make it easy to determine whether the lookup operation was successful. The status code, available as $?, reflects the success of running the nslookup command, not whether nslookup found a name for the system. We can, however, examine the contents of the array to determine whether the system responded with a host name or a "can't find
" message, indicating that no PTR record exists for the host. In fact, we can determine this easily from looking at the size of the array.
In this piece of code, we conclude that the host name was not found if the array contains less than three elements. Otherwise, we will find the host name in the fourth (element number three) position in the array.
if ( $#nameinfo < 4 ) {
$hostname="unknown";
} else {
$_=$nameinfo[3];
($hostname)=/Name:\s*(\w+)/;
}
I have used the \w+ expression so that my output contains only the simple name (not the fully qualified name) of the system. Displaying the fully qualified domain names in a single domain is probably less than useful. However, if you prefer to include the full names, simply change \w+ to \S+ and the full names will be listed.
Finally, in printing the IP address, host name and service listings, I use the length of each host name to determine whether to add one or two tabs to space out the output in columns.
$len=length $hostname;
if ($len < 8) {
print "$IP\t$hostname\t\t$SVC\n";
} else {
print "$IP\t$hostname\t$SVC\n";
}
|
The modified script, in its entirety, is printed below for your convenience.
#!/usr/bin/perl -w
#
# Find services on a subnet: findAppl port subnet
# e.g.,: findAppl 80 10.3.2.0/24
#
# NOTE: The output we're handling looks like this:
# Interesting ports on 10.3.2.11:
# PORT STATE SERVICE
# 1521/tcp open oracle
if ( $#ARGV >= 1 ) {
$port=$ARGV[0];
$subnet=$ARGV[1];
} else {
print "Please provide a port> ";
$port=;
print "Please provide a subnet> ";
$subnet=;
}
@results=`nmap -p $port -P0 -sT $subnet 2> /dev/null`;
foreach (@results) {
if ($_ =~ /Interesting/)
{
($IP)=/(\d+\.\d+\.\d+\.\d+)/;
}
if ($_ =~ /open/)
{
($SVC)=/(\S+)\s*$/;
@nameinfo=`nslookup $IP 2> /dev/null`;
if ( $#nameinfo < 4 ) {
$hostname="unknown";
} else {
$_=$nameinfo[3];
($hostname)=/Name:\s*(\w+)/;
}
$len=length $hostname;
if ($len < 8) {
print "$IP\t$hostname\t\t$SVC\n";
} else {
print "$IP\t$hostname\t$SVC\n";
}
}
}
|
Finding services on a subnet, Part 1