my $ip = inet_aton('192.168.0.1');
my $saddr = sockaddr_in(0,$ip);
####
socket(SOCK,PF_INET,SOCK_RAW,getprotobyname('icmp');
####
use strict;
use Socket;
#use FileHandle;
my $ICMP_PORT = 0; #ICMP, no port !
my $ICMP_FLAGS = 0; #No special flag
my $ICMP_SUBCODE = 0;
my $SEQ = 1; #cuz we're going to send single packet
my $pid = $$ & 0xffff; #get the PID
my $checksum = 0; #starter
if(!defined $ARGV[0] || !defined $ARGV[1] || !defined $ARGV[2]) { usage(); }
my $ip = inet_aton($ARGV[0]);
length($ip) or die "$ARGV[0] is not valid or $ARGV[0] is Unreachable\n";
my $time_out = 10;
if(defined $ARGV[3] && defined $ARGV[4]) {
die "Unknown options $ARGV[3] - You should try with -t \n" if ($ARGV[3] ne "-t") ;
$time_out = $ARGV[4];
}
socket(SOCK,PF_INET,SOCK_RAW,getprotobyname('icmp')) || die "Can not create socket $! \n";
my $saddr = sockaddr_in($ICMP_PORT,$ip);
if(defined $ARGV[1]) {
if($ARGV[2] eq 'ec') {
print "send icmp echo request \n";
ping_icmp_echo_req();
}
elsif($ARGV[2] eq 'ts') {
print "send timestamp request \n";
ping_icmp_timestamp_req();
}
elsif($ARGV[2] eq 'in') {
print "send information request \n";
ping_icmp_information_req();
}
elsif($ARGV[2] eq 'am') {
print "send address mask request \n";
ping_icmp_addressmask_req();
}
else {
print "unknown request type \n";
kill_sock();
exit(1);
}
}
else { usage(); kill_sock(); }
sub ping_icmp_echo_req {
my $msg = pack("C2 n3",8,0,$checksum,$pid,$SEQ);
#someone said i must pack the minimum of icmp packet
#with this -> "C2 S3", but it's work with "C2" n3",
#what do you think ?
$checksum = checksum($msg);
$msg = pack("C2 n3",8,0,$checksum,$pid,$SEQ);
send(SOCK,$msg,$ICMP_FLAGS,$saddr) || die "error sending : $! \n";
#$socket->autoflush(1);
#im not sure to add this line to this code, any advices ?
my $buff = timing();
my($icmp_type, $icmp_subcode,$icmp_cksum,$icmp_pid,$icmp_seq) = unpack("C2 n3",substr($buff,20,8));
alive($icmp_type);
kill_sock();
}
sub ping_icmp_timestamp_req {
my $msg = pack("C2 n3 N3",13,$ICMP_SUBCODE,$checksum,$pid,$SEQ,0,0,0);
$checksum = checksum($msg);
$msg = pack("C2 n3 N3",13,$ICMP_SUBCODE,$checksum,$pid,$SEQ,0,0,0);
send(SOCK,$msg,$ICMP_FLAGS,$saddr);
#SOCK->autoflush(1); #hmmm ?
my $buff = timing();
my($icmp_type,$icmp_subcode) = unpack("C2",substr($buff,20,2)) ;
alive($icmp_type);
kill_sock();
}
sub ping_icmp_information_req {
my $ICMP_STRUCT_INFORM = "C2 n3 N";
my $ICMP_INFORM_REQ = 15;
my $ICMP_INFORM_REPLY = 16; #echo req code
my $msg = pack("C2 n3 N",15,$ICMP_SUBCODE,$checksum,$pid,$SEQ,0);
$checksum = checksum($msg);
$msg = pack("C2 n3 N",15,$ICMP_SUBCODE,$checksum,$pid,$SEQ,0);
send(SOCK,$msg,$ICMP_FLAGS,$saddr) || die "error sending : $! \n";
#$socket->autoflush(1); #im not sure to add this line to this code, any advices ?
my $buff= timing();
my($icmp_type, $icmp_subcode) = unpack("C2",substr($buff,20,2));
kill_sock();
}
sub ping_icmp_addressmask_req {
my $msg = pack("C2 n3 N",17,$ICMP_SUBCODE,$checksum,$pid,$SEQ,0);
$checksum = checksum($msg);
$msg = pack("C2 n3 N",17,$ICMP_SUBCODE,$checksum,$pid,$SEQ,0);
send(SOCK,$msg,$ICMP_FLAGS,$saddr) || die "error sending : $! \n";
#$socket->autoflush(1);
my $buff = timing();
my($icmp_type, $icmp_subcode) = unpack("C2 n3 N",substr($buff,20,2));
alive($icmp_type);
kill_sock();
}
sub alive {
my ($type) = @_;
# 0 = icmp echo reply,
# 14 = icmp timestamp reply
# 16 = icmp infoemation reply
# 18 = icmp address mask reply
if($type == 0) { print "Received ICMP echo reply from $ARGV[0], alive ! \n" }
elsif($type == 14) { print "Received ICMP timestamp reply from $ARGV[0], alive ! \n" }
elsif($type == 16) { print "Received ICMP information reply from $ARGV[0], alive ! \n"}
elsif($type == 18) { print "Received ICMP address mask reply from $ARGV[0], alive ! \n"}
else { print "I never expect to received this kind of ICMP reply, Uknown type ! \n"
}
}
sub kill_sock {
close(SOCK) || warn "Can not close socket $! \n";
}
sub timing {
my $buff="";
print "time out set to $time_out\n";
$SIG{ALRM} = sub { die "TIMED OUT \n" };
eval {
alarm($time_out);
recv(SOCK,$buff,1500,$ICMP_FLAGS);
alarm(0);
};
kill_sock() if (length($buff) == 0);
die "timed out \n" if (length($buff) == 0);
return $buff;
}
sub checksum {
my ($msg) = @_;
my ($len_msg, $num_short, $short, $chk);
$len_msg = length($msg);
$num_short = int($len_msg / 2);
$chk = 0;
foreach $short (unpack("n$num_short", $msg)){
$chk += $short;
}
$chk += (unpack("C", substr($msg, $len_msg - 1, 1)) << 8) if $len_msg % 2;
$chk = ($chk >> 16) + ($chk & 0xffff); # Fold high into low
return(~(($chk >> 16) + $chk) & 0xffff); # Again and complement
}
sub usage {
print "Usage $0 : -c -t \n";
exit(1);
}