Net::Pingを使ってみる。

とある事情で、大量のマシンの生存確認をすることに。
Net::Pingを使えば、pingのほかにもTCP/IPのサービスが使えるかどうかも一度にチェックできて便利すぎる。

Net::Ping - check a remote host for reachability - metacpan.org

use strict;
use warnings;
use Net::Ping;

my $host = shift;
my @serv = qw(telnet ftp ssh);

# ICMP(ping) ckeck
my $p = Net::Ping->new('icmp');

# set 1 if you want Time::HiRes time
$p->hires(1);

print "connectivity check of $host\n\n";
my ($ret, $duration, $ip) = $p->ping($host);
printf("icmp\t: %s (%.3f sec)\n", ($ret ? 'OK' : 'NG'), $duration);
$p->close();

# TCP check
$p = Net::Ping->new('tcp');
$p->hires(1);

foreach my $s (@serv){
  # if port_number is set, $p->service_check(1) is automatically called to check ECONNREFUSED
  $p->port_number(scalar getservbyname($s, 'tcp'));
  ($ret, $duration, $ip) = $p->ping($host);
  printf("%s\t: %s (%.3f sec)\n", $s, ($ret ? 'OK' : 'NG'), $duration);
}
$p->close();
$ perl ckip.pl hostname
connectivity check of hostname

icmp    : OK (0.004 sec)
telnet  : NG (4.993 sec)
ftp     : NG (4.999 sec)
ssh     : OK (0.002 sec)

こんな感じかなあ。

デフォルトの挙動では、TCP echoで接続しようとするらしいので、明示的にping(ICMP)を送りたいときは 'icmp' を指定してnewする必要があります。

また、TCP echoで接続した結果、RSTが返されても結果は成功と判断されるので、それがイヤな場合は service_check(1) を実行しておくと3-way handshakeが成功したときに結果が成功という風にしてくれるようです。

明示的にTCP portを指定した場合は、暗黙的にservice_check(1)が実行されるのでご注意。それがイヤなら*1port_numberを実行してからpingを実行する間に service_check(0) を呼んでおけばOK。

余談ですが、cygwinの/etc/servicesにはsshのエントリーがないみたい。ssh使えるのに結果が失敗って、どういうことだ・・・と一瞬悩んでしまった。ssh関連のパッケージをインストールすれば、追加してくれるのかも(未確認)。

*1:まあ、イヤなケースは少ないだろうけど