#!/usr/bin/perl
# Program: scan-subnet.pl
# Description: Front-end to scan any given subnet and SMTP servers
# Version: 1.1
# Last Update: 15 October 2003
# Written by: Dusan U. Baljevic
#
# Copyright 2003-2014 Dusan Baljevic
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
# Make the script very tight.
#
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/sbin';
$ENV{'SHELL'} = '/bin/sh' if $ENV{'SHELL'} ne '';
$ENV{'IFS'} = '' if $ENV{'IFS'} ne '';
use strict;
no strict 'subs';
use Net::Ping;
use POSIX 'uname';
use Getopt::Long qw(:config ignore_case_always require_order);
use Socket;
use vars qw($RecipientX @values $header $fh $msg $a $h $stop_time
$addr $sockaddr @machines $machines $subnet @port @addrs $host $p $n
$REMOTE $HostIP $Portproto $proto $port $SERVERNAME $defdomain
$help $opt_n %Opts $Usage $IPnet $Defsubnet $addrs $rev_ip $ip);
$Usage = "Usage: $0 [-n subnet] [-h]
-n 192.168.5 (C-class subnet to scan, default is 192.168.33.0/24)
-h (help command)\n";
# Only privileged user should execute LAN scanning.
#
if ( $> != 0 ) {
print STDERR q[ERROR: You cannot run this as non-privileged user!];
print STDERR "\n";
exit(1);
}
# If no command line arguments, default subnet to
# scan...
#
$Defsubnet = '192.168.33';
# Port to check and possibly figure out the SMTP server version.
#
@port = (25);
$defdomain = "yourcompanyXXX.com";
( undef, $SERVERNAME, undef, undef, undef ) = uname;
# Any command line options?
#
my ($IPnet) = '';
GetOptions( 'n=s' => \$IPnet, 'h' => \$help );
die $Usage if $help;
$subnet = $IPnet || $Defsubnet;
#use Regexp::Common;
#while() {
# if(/$RE{net}{IPv4}{dec}{-keep}/) {
# print "IP Address: $1\n";
# }
#}
$ip = "${subnet}.0";
# Is the IP address valid. For example, 300.201.33.12 is INVALID.
#
sub CheckIP {
my $ip = shift;
my ( $addrs, $rev_ip );
( $addrs = inet_aton($ip) ) and ( $rev_ip = inet_ntoa($addrs) );
return ( defined($addrs) and defined($rev_ip) and $ip eq $rev_ip );
}
if ( !CheckIP($ip) ) {
die "Invalid or incomplete subnet: $ip\n";
}
# Array of all valid hosts on a given subnet.
#
@machines = map { "$subnet\.$_" } ( 1 .. 254 );
# Subroutine to open a socket and talk to SMTP server.
#
sub sendemail {
use Socket;
$REMOTE = $_[0];
$port = $_[1];
if ( $REMOTE =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ ) {
$addr = pack( 'C4', $1, $2, $3, $4 );
}
else { die("Bad IP address: $!"); }
$port = getservbyname( $port, 'tcp' ) if $port =~ /\D/;
$proto = getprotobyname('tcp');
socket( S, PF_INET, SOCK_STREAM, $proto ) or die("Socket failed: $!");
$sockaddr = 'S n a4 x8';
if ( connect( S, pack( $sockaddr, AF_INET, $port, $addr ) ) ) {
select(S);
$| = 1;
select(STDOUT);
$a = ;
print $a;
print S "quit";
close(S);
}
else {
"Unable to connect: $!";
}
}
# Resolve hostname (find its IP address).
#
print "Testing Subnet $subnet on port @port\n";
print "=====================================\n";
foreach $host (@machines) {
my $PING = 0;
print "\nChecking $host...\n";
( undef, undef, undef, undef, @addrs ) = gethostbyname($host);
foreach my $a (@addrs) {
$HostIP = join( '.', unpack( 'C4', $a ) );
}
if ( !defined($HostIP) ) {
print "Check hostname resolution for server \"$host\".\n";
exit(1);
}
# First check if the server is responding to ICMP...
#
$h = Net::Ping->new();
if ( !$h->ping($host) ) {
print "WARN: $host is NOT reachable (first type ICMP).\n";
$PING++;
}
$h->close();
# Second type of ping test.
#
$h = Net::Ping->new("icmp");
if ( !$h->ping( $host, 2 ) ) {
print "WARN: $host is NOT reachable (second type ICMP).\n";
$PING++;
}
$h->close();
# Third type of ping test.
#
$h = Net::Ping->new( "tcp", 2 );
while ( $stop_time > time() ) {
print "WARN: $host is NOT not reachable (TCP ping)",
scalar( localtime() ), "\n"
unless $h->ping($host);
$PING++;
}
undef($h);
# Now, check the ports.
#
if ( $PING < 3 ) {
foreach my $n (@port) {
my $p = Net::Ping->new("tcp");
$Portproto = getservbyport( $n, 'tcp' );
$p->{port_num} = $n if $n;
if ( $p->ping($host) ) {
print " Port $n\@$host is ACTIVE\n";
&sendemail( $host, $n );
}
else {
print " Port $n\@$host is INACTIVE or FILTERED\n";
}
print;
}
}
}
# Exit gracefully.
#
exit(0);