Nagiosのcheck_pingが遅いのをなんとかする
Nagiosのcheck_pingコマンド、やたら遅いですよね。
# time sudo -u nagios /usr/lib64/nagios/plugins/check_ping -H 127.0.0.1 -w 200,40% -c 500,80% PING OK - Packet loss = 0%, RTA = 0.05 ms|rta=0.053000ms;200.000000;500.000000;0.000000 pl=0%;40;80;0 real 0m4.171s user 0m0.028s sys 0m0.112s
ほんと遅い。なんでこんなに遅いの。調べてみました。
check_pingの仕組み
check_pingのソースを読んだところpingコマンドの実行結果をパースしているだけでした。
check_pingはnagios-pluginsのconfigure時に指定されたpingコマンドを使ってコマンドを実行します。
特に指定がなかったり、rpmなどからインストールした場合は標準のpingコマンドが使用されます。
RHEL環境の場合、デフォルトのpingコマンドは次のようになるようです。
/bin/ping -n -U -w %d -c %d %s
引数の意味ですが、-nはDNS逆引きをしない、-Uは古いフォーマットで出力、-w %dはタイムアウト設定、-c %dは回数、%sはping対象ホストが入ります。
このpingコマンドにデフォルトのタイムアウト10秒、回数5回を設定して打ってみると、
# time /bin/ping -n -U -w 10 -c 5 127.0.0.1 PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data. 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.031 ms 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.068 ms 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.154 ms 64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.045 ms 64 bytes from 127.0.0.1: icmp_seq=5 ttl=64 time=4.51 ms --- 127.0.0.1 ping statistics --- 5 packets transmitted, 5 received, 0% packet loss, time 4044ms rtt min/avg/max/mdev = 0.031/0.963/4.518/1.778 ms real 0m4.063s user 0m0.006s sys 0m0.025s
あーなるほど。デフォルト設定だと1秒間隔で5回打つので、4秒+αになるんですね。そりゃ遅いわ。
解決方法を調べてみました。今のところ3つあります。
check_icmpもしくはcheck_fpingを使う
ping先がIPv4なアドレスなら、check_icmpもしくはcheck_fpingを使いましょう。
check_icmpを一般ユーザーが使う場合、setuidが必要です。rpmなどでインストールしていればすでに設定されていると思いますが、設定されていなければ手動で設定しましょう。以下はnagiosユーザで使用する例。
# ls -l check_icmp -rwx--x--- 1 root nagios 51840 Dec 7 16:20 check_icmp # chown root:nagios check_icmp # chmod u+s check_icmp # ls -l check_icmp -rws--x--- 1 root nagios 51840 Dec 7 16:20 check_icmp # sudo -u nagios check_icmp 127.0.0.1 OK - 127.0.0.1: rta 0.021ms, lost 0%|rta=0.021ms;200.000;500.000;0; pl=0%;40;80;; rtmax=0.064ms;;;; rtmin=0.009ms;;;;
Nagiosは実コマンドとコマンド定義を分離できるため、定義ファイルを修正するだけで対応が可能です。check_pingをcheck_icmpやcheck_fpingで置き換える場合は-pを-nに変えるだけで大体ok。
--- objects/commands.cfg.orig 2012-12-05 06:03:02.000000000 +0900 +++ objects/commands.cfg 2012-12-29 15:52:22.197402219 +0900 @@ -55,7 +55,7 @@ # 'check-host-alive' command definition define command{ command_name check-host-alive - command_line $USER1$/check_ping -H $HOSTADDRESS$ -w 3000.0,80% -c 5000.0,100% -p 5 + command_line $USER1$/check_icmp -H $HOSTADDRESS$ -w 3000.0,80% -c 5000.0,100% -n 5 } @@ -165,7 +165,7 @@ # 'check_ping' command definition define command{ command_name check_ping - command_line $USER1$/check_ping -H $HOSTADDRESS$ -w $ARG1$ -c $ARG2$ -p 5 + command_line $USER1$/check_icmp -H $HOSTADDRESS$ -w $ARG1$ -c $ARG2$ -n 5 }
ただし、check_pingはIPv6に対応していますが、check_icmpやcheck_fpingはIPv6に対応していません。
ping実行時に-i 0.2を入れるようnagios-pluginsを作り直す
最近のpingはping間隔を設定する-iオプションに1以下の数字を設定できます*1。お使いの環境でまず-iオプションが使えるか調べてみましょう。
$ ping -i 0.2 -c 5 127.0.0.1
0.2秒間隔でpingが打てれば問題ないです。check_pingが実行するpingに-i 0.2を設定してやればいいことになります。
そこで、nagios-pluginsのconfigure時に以下のように設定すればokです。
# ./configure \ --with-ping-command="/bin/ping -n -U -w %d -c %d -i 0.2 %s" \ --with-ping6-command="/bin/ping6 -n -U -w %d -c %d -i 0.2 %s" # make
specファイルからrpmを作るならspecファイルに追加してrpmbuildですね。
これで生成されたcheck_pingは5回試行する場合でも約1秒程度で処理ができます。
# time sudo -u nagios /usr/lib64/nagios/plugins/check_ping -H 127.0.0.1 -w 200,40% -c 500,80% PING OK - Packet loss = 0%, RTA = 2.16 ms|rta=2.164000ms;200.000000;500.000000;0.000000 pl=0%;40;80;0 real 0m0.932s user 0m0.019s sys 0m0.075s
やったね!
check_pingの脆弱性を突いて引数インジェクションで-i 0.2を無理矢理ねじ込む
check_pingは引数チェックの実装が甘く、ホスト名指定の部分で引数インジェクションが可能です。これを使って再コンパイルすることなく無理矢理オプションを追加することが可能です。
# time sudo -u nagios /usr/lib64/nagios/plugins/check_ping -H "127.0.0.1 -i 0.2" -w 200,40% -c 500,80% PING OK - Packet loss = 0%, RTA = 2.16 ms|rta=2.164000ms;200.000000;500.000000;0.000000 pl=0%;40;80;0 real 0m0.932s user 0m0.019s sys 0m0.075s
コマンド定義するならこんな感じ。
--- objects/commands.cfg.orig 2012-12-05 06:03:02.000000000 +0900 +++ objects/commands.cfg 2012-12-29 17:13:12.356065243 +0900 @@ -55,7 +55,7 @@ # 'check-host-alive' command definition define command{ command_name check-host-alive - command_line $USER1$/check_ping -H $HOSTADDRESS$ -w 3000.0,80% -c 5000.0,100% -p 5 + command_line $USER1$/check_ping -H "$HOSTADDRESS$ -i 0.2" -w 3000.0,80% -c 5000.0,100% -p 5 } @@ -165,7 +165,7 @@ # 'check_ping' command definition define command{ command_name check_ping - command_line $USER1$/check_ping -H $HOSTADDRESS$ -w $ARG1$ -c $ARG2$ -p 5 + command_line $USER1$/check_ping -H "$HOSTADDRESS$ -i 0.2" -w $ARG1$ -c $ARG2$ -p 5 }
ただし、将来のバージョンで脆弱性が修正されるかもしれないので未来はありません。
まとめ
*1:ただしroot権限でなければ0.2秒より短くできません