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); }