#!/usr/local/bin/perl -w # $Id: check.pl,v 3.1 2000-06-03 03:12:12+09 nagoya Exp $ # dhcpd.leases を読み結果をダンプに追加して HTML を吐くだけ # # usage: $0 [-s] [-p] -l dhcpd.leases [-d D] [-r R] [-c C] [-n N] # -s : site_local_check() を呼び出す # -p : ping check をおこなう(要 root 権限) # -l dhcpd.leases : dhcpd.leases のパスを指定(必須) # -d DUMPFILE : dump file のパスを指定(オプションなしならば dump しない) # -r REFRESH-TIME : (デフォルトは 60) # -c CRON-RERIOD : (デフォルトは 180) # -n NETMASK : サブネットマスク(VLSM未対応、デフォルトは 24) use strict; use vars qw($opt_s $opt_p $opt_l $opt_d $opt_r $opt_c $opt_n); use Getopt::Std; use Time::Local; use FileHandle; use Fcntl ':flock'; use Net::Ping; use POSIX; getopts('spl:d:r:c:n:'); my $refresh_time = $opt_r || 60; my $cron_period = $opt_c || 180; my $network_address = make_network_address($opt_n || 24); my $ping_timeout = 1; # てきとうな秒数( >0, by perldoc Net::Ping) my $nkf = 'nkf -j'; my %color = ( 'body' => '#faf0e6', # linen 'text' => '#000000', # black 'Alive' => '#ffff00', # yellow 'Dead' => '#87cefe', # LightSkyBlue 'warn' => '#ff0000', # red ); my $footer = "戻る"; # see print_html() my $now = time; my (%lease, %current); read_leases_file($opt_l, \%lease); check_entries(\%lease, \%current); site_local_check(\%current) if $opt_s; summary_entries(\%current); dump_entries($opt_d, \%current) if $opt_d; $now = time; # check_entries() に時間がかかる(ping のため)ので再設定する print_html(\%current); # $_[0] (dhcpd.leases) を読んで $_[1] を次のような hash への参照とする # 参考: dhcpd.leases(5) # # $_[1]->{IPアドレス} = { # 'starts' => starts, ; epoch # 'ends' => ends, ; epoch # 'macaddr' => hardware ethernet address, # 'hostname' => client-hostname|hostname, # 'other' => スカラー配列への参照 # } sub read_leases_file { my $f = new FileHandle "< $_[0]" or die "$_[0] $!"; my $ipaddr; while ($_ = $f->getline) { chomp; if (/^lease ([\d+\.]+) \{$/o) { $ipaddr = $1; # ipaddr が重複しているときは最後のものを優先する(OK?) delete $_[1]->{$ipaddr}; } elsif (/^\t(starts|ends) \S+ (\S+) (\S+);$/o) { $_[1]->{$ipaddr}{$1} = epoch($2, $3); } elsif (/^\thardware \S+ (\S+);$/o) { $_[1]->{$ipaddr}{macaddr} = $1; } elsif (/^\t(?:client-)hostname \"(.*)\";$/o) { $_[1]->{$ipaddr}{hostname} = $1 } elsif (/^\t(\S+);$/o) { push @{$_[1]->{$ipaddr}{other}}, $1; } elsif (/^\}/o) { # no operation in here } else { # no operation in here } } $f->close; } # $_[0] は read_leases_file で与えられる hash への参照 # $_[1] は以下のような hash への参照になる # # $_[1]->{'networks'} = サブネットのスカラー配列への参照 # $_[1]->{サブネット} = { # 'total_lease' => number of effective leased addresses, # 'total_ping' => number of leased addresses which alive by ping, # 'total_warn' => number of leased addresses which has some trouble, # 'hosts' => IPアドレスのスカラー配列への参照 # 'host' => $_[0]->{IPアドレス} のコピー(というか参照) # 'host' => {'ping'} => 'Alive'|'Dead' # } sub check_entries { # ping への反応をチェックするにはroot権限が必要 # ping の並列化をすれば速くなるのだけど… my $p = $opt_p ? Net::Ping->new('icmp', $ping_timeout) : undef; while (my ($ipaddr, $a) = each %{$_[0]}) { # タイムオーバーしたエントリは無視 $now > $_[0]->{$ipaddr}{ends} and next; my $net = &$network_address($ipaddr); $_[1]->{$net}{host}{$ipaddr} = $_[0]->{$ipaddr}; $_[1]->{$net}{host}{$ipaddr}{ping} = $opt_p ? ($p->ping($ipaddr) ? 'Alive' : 'Dead') : ''; } $p->close if $opt_p; $_[1]->{networks} = [sort ipaddr_cmp keys %{$_[1]}]; for (@{$_[1]->{networks}}) { $_[1]->{$_}{hosts} = [sort ipaddr_cmp keys %{$_[1]->{$_}{host}}]; for my $k (qw(lease ping warn)) { $_[1]->{$_}{"total_$k"} = 0; } } } sub summary_entries { for (@{$_[0]->{networks}}) { my $a = $_[0]->{$_}; for (@{$a->{hosts}}) { my $b = $a->{host}{$_}; $a->{'total_lease'}++; $a->{'total_ping'}++ if $b->{ping} eq 'Alive'; $a->{'total_warn'}++ if $b->{warn}; } } for (@{$_[0]->{networks}}) { for my $k (qw(lease ping warn)) { $_[0]->{"total_$k"} += $_[0]->{$_}{"total_$k"}; } } } # HTML モジュールを使うべきなのかなあ sub print_html { my $o = new FileHandle "| $nkf" or die "$nkf $!"; my $t = strftime "%Y/%m/%d %H:%M:%S", localtime($now); my $e = strftime "%a, %d %b %Y %H:%M:%S GMT", gmtime($now + $cron_period); $o->print(<<"HTML_HEADER");
サブネット | 有効期間内である 割り当て済みアドレス数 |
unicast ping に 反応したアドレス数 |
登録に問題の あるアドレス数 |
---|---|---|---|
$_ | $_[1]->{$_}{total_lease} | $_[1]->{$_}{total_ping} | $S$_[1]->{$_}{total_warn}$E |
合計 | $_[1]->{total_lease} | $_[1]->{total_ping} | $S$_[1]->{total_warn}$E |
$net | Lease: $lease | Alive: $alive | Dead: $dead |
---|
$_ | "}($ip, $m, $p, $s, $e, $o); my $c = $opt_p ? " bgcolor=\"$color{$a->{ping}}\"" : ''; $_[0]->print("