通常情况下如果需要了解DNS服务器的工作状态往往需要telnet或ssh到服务器上以命令的方式来获取。该方式不但麻烦而且不直观。本文介绍一种通过SNMP来对DNS服务器进行图形化监控的方法。
该系统主要是基于Cacti,由于cacti在网络监控中应用很多,这里对其安装配置不做介绍。Cacti本身不支持监控DNS的功能。

监控模板和脚本下载地址:或在本文附件中下载
下载完成后解压该文件包,里面有local和snmp两个文件夹,分别对应本地监控方式和远端snmp监控方式。由于系统管理员安装cacti不仅用于监控DNS服务器,还可以监控网内的其他网络设备和服务器,应当选取snmp方式。

 

一、首先配置DNS服务器,

1、确认文件路径

确认 /opt/bin/runstats.sh 中的named.stats路径和你的named.conf中的 named.stats 中的路径相同,并且此文件存在,rndc有权限访问。
以下是的我的文件:
[root@test local]# cat /var/named/chroot/etc/named.conf | grep statistics
        statistics-file "/var/log/named.stats";  如果没有请在named.conf文件的options里面添加
        zone-statistics yes;
[root@test local]#

[root@test local]# ll /var/named/chroot/var/log/named.stats       因为dns使用chroot后 目录就在这个下面了,注意不是 /var/log/named.stats
-rw-r--r-- 1 named named 12434 Nov 16 19:05 /var/named/chroot/var/log/named.stats
[root@test local]#

 

2、编写相关脚本

[root@test bin]# more /opt/bin/runstats.sh
#!/bin/sh

rm -rf /var/named/chroot/var/log/named.stats
rndc stats
cat /var/named/chroot/var/log/named.stats | /opt/bin/dnsstats.pl

 

[root@test bin]# more /opt/bin/dnsstats.pl
#!/usr/bin/perl
#
# [email protected]
#
# code sucks but it does its job
#

    use strict;
#    use warnings;
    my %sections = (
            "Incoming Queries" => 1,
            "Outgoing Queries" => 1,
            "Resolver Statistics" => 1,
            "Socket I/O Statistics" => 1,
    );

    my $active;
    my $new_line;

#global
    my ($a,$ns,$cname,$soa,$ptr,$mx,$txt,$aaaa,$srv,$naptr,$a6,$spf,$any);
#resolver statistics
    my ($rsnx,$rsfail,$rserr,$rsmismatch,$rsipv4qs,$rsipv4rr,$rsqr,$rsqt,$rsrtt10,$rsrtt10100,$rsrtt100500,$rsrtt500800,$rsrtt8001600,$rsrtt1600);
#incoming queries
    my ($ina,$inns,$incname,$insoa,$inptr,$inmx,$intxt,$inaaaa,$insrv,$innaptr,$ina6,$inspf,$inany);
#outgoing queries
    my ($outa,$outns,$outcname,$outsoa,$outptr,$outmx,$outtxt,$outaaaa,$outsrv,$outnaptr,$outa6,$outspf,$outany);
#i/o stats
    my ($sockopen,$sockclosed,$sockbf,$consest,$recverr);

    while(my $line = ) {
            $line =~ s/^\s+//;
            $line =~ s/\s+$//;
            if ($line =~ /^\+\+\s+(.+)\s+\+\+$/) {
                    $active = $1;
            }
         if ($active and exists $sections{$active}) {$new_line=$active.":".$line."\n"}
#        print $new_line;
         if ($new_line=~ /Incoming Queries:(\d+)\s+A$/){ $ina=$1; }
         if ($new_line=~ /Incoming Queries:(\d+) NS/){ $inns=$1; }
         if ($new_line=~ /Incoming Queries:(\d+) CNAME/){ $incname=$1; }
         if ($new_line=~ /Incoming Queries:(\d+) SOA/){ $insoa=$1; }
         if ($new_line=~ /Incoming Queries:(\d+) PTR/){ $inptr=$1; }
         if ($new_line=~ /Incoming Queries:(\d+) MX/){ $inmx=$1; }
         if ($new_line=~ /Incoming Queries:(\d+) TXT/){ $intxt=$1; }
         if ($new_line=~ /Incoming Queries:(\d+) AAAA/){ $inaaaa=$1; }
         if ($new_line=~ /Incoming Queries:(\d+) SRV/){ $insrv=$1; }
         if ($new_line=~ /Incoming Queries:(\d+) NAPTR/){ $innaptr=$1; }
         if ($new_line=~ /Incoming Queries:(\d+) A6/){ $ina6=$1; }
         if ($new_line=~ /Incoming Queries:(\d+) SPF/){ $inspf=$1; }
         if ($new_line=~ /Incoming Queries:(\d+) ANY/){ $inany=$1; }

         if ($new_line=~ /Outgoing Queries:(\d+)\s+A$/){ $outa=$1; }
         if ($new_line=~ /Outgoing Queries:(\d+) NS/){ $outns=$1; }
         if ($new_line=~ /Outgoing Queries:(\d+) CNAME/){ $outcname=$1; }
         if ($new_line=~ /Outgoing Queries:(\d+) SOA/){ $outsoa=$1; }
         if ($new_line=~ /Outgoing Queries:(\d+) PTR/){ $outptr=$1; }
         if ($new_line=~ /Outgoing Queries:(\d+) MX/){ $outmx=$1; }
         if ($new_line=~ /Outgoing Queries:(\d+) TXT/){ $outtxt=$1; }
         if ($new_line=~ /Outgoing Queries:(\d+) AAAA/){ $outaaaa=$1; }
         if ($new_line=~ /Outgoing Queries:(\d+) SRV/){ $outsrv=$1; }
         if ($new_line=~ /Outgoing Queries:(\d+) NAPTR/){ $outnaptr=$1; }
         if ($new_line=~ /Outgoing Queries:(\d+) A6/){ $outa6=$1; }
         if ($new_line=~ /Outgoing Queries:(\d+) SPF/){ $outspf=$1; }
         if ($new_line=~ /Outgoing Queries:(\d+) ANY/){ $outany=$1; }

         if ($new_line=~ /Resolver Statistics:(\d+) mismatch responses received/){ $rsmismatch=$1; }
         if ($new_line=~ /Resolver Statistics:(\d+) IPv4 queries sent/){ $rsipv4qs=$1; }
         if ($new_line=~ /Resolver Statistics:(\d+) IPv4 responses received/){ $rsipv4rr=$1; }
         if ($new_line=~ /Resolver Statistics:(\d+) NXDOMAIN received/){ $rsnx=$1; }
         if ($new_line=~ /Resolver Statistics:(\d+) SERVFAIL received/){ $rsfail=$1; }
         if ($new_line=~ /Resolver Statistics:(\d+) FORMERR received/){ $rserr=$1; }
         if ($new_line=~ /Resolver Statistics:(\d+) query retries/){ $rsqr=$1; }
         if ($new_line=~ /Resolver Statistics:(\d+) query timeouts/){ $rsqt=$1; }
         if ($new_line=~ /Resolver Statistics:(\d+) queries with RTT < 10ms/){ $rsrtt10=$1; }
         if ($new_line=~ /Resolver Statistics:(\d+) queries with RTT 10-100ms/){ $rsrtt10100=$1; }
         if ($new_line=~ /Resolver Statistics:(\d+) queries with RTT 100-500ms/){ $rsrtt100500=$1; }
         if ($new_line=~ /Resolver Statistics:(\d+) queries with RTT 500-800ms/){ $rsrtt500800=$1; }
         if ($new_line=~ /Resolver Statistics:(\d+) queries with RTT 800-1600ms/){ $rsrtt8001600=$1; }
         if ($new_line=~ /Resolver Statistics:(\d+) queries with RTT > 1600ms/){ $rsrtt1600=$1; }

         if ($new_line=~ /Socket I\/O Statistics:(\d+) UDP\/IPv4 sockets opened/){ $sockopen=$1; }
         if ($new_line=~ /Socket I\/O Statistics:(\d+) UDP\/IPv4 sockets closed/){ $sockclosed=$1; }
         if ($new_line=~ /Socket I\/O Statistics:(\d+) UDP\/IPv4 socket bind failures/){ $sockbf=$1; }
         if ($new_line=~ /Socket I\/O Statistics:(\d+) UDP\/IPv4 connections established/){ $consest=$1; }
         if ($new_line=~ /Socket I\/O Statistics:(\d+) UDP\/IPv4 recv errors/){ $recverr=$1; }
    }

$a=$ina+$outa;
$a6=$ina6+$outa6;
$aaaa=$inaaaa+$outaaaa;
$any=$inany+$outany;
$cname=$incname+$outcname;
$mx=$inmx+$outmx;
$naptr=$innaptr+$outnaptr;
$ns=$inns+$outns;
$ptr=$inptr+$outptr;
$soa=$insoa+$outsoa;
$spf=$inspf+$outspf;
$srv=$insrv+$outsrv;
$txt=$intxt+$outtxt;

print "a:".$a." a6:".$a6." aaaa:".$aaaa." any:".$any." cname:".$cname." mx:".$mx." naptr:".$naptr." ns:".$ns." ptr:".$ptr." soa:".$soa." spf:".$spf." srv:".$srv." txt:".$txt." rsnx:".$rsnx." rsfail:".$rsfail." rserr:".$rserr." rsipv4qs:".$rsipv4qs." rsipv4rr:".$rsipv4rr." rsmismatch:".$rsmismatch." rsqr:".$rsqr." rsqt:".$rsqt." rsrtt10:".$rsrtt10." rsrtt100500:".$rsrtt100500." rsrtt10100:".$rsrtt10100." rsrtt1600:".$rsrtt1600." rsrtt500800:".$rsrtt500800." rsrtt8001600:".$rsrtt8001600." sockopen:".$sockopen." sockclosed:".$sockclosed." sockbf:".$sockbf." consest:".$consest." recverr:".$recverr;

[root@test bin]#
[root@test bin]# chmod +x /opt/bin/runstats.sh
[root@test bin]# chmod +x /opt/bin/dnsstats.pl
[root@test bin]#

3、修改snmpd配置文件

在snmpd.conf文件加入以下一行:
[root@test bin]# echo “extend .1.3.6.1.4.1.18689.0.1 dnscache-stats /opt/bin/runstats.sh” >>/etc/snmp/snmpd.conf

修改完成后重新启动snmpd服务,重启完成后进行一个测试,在cacti端输入以下命令:
[root@test bin]# snmpwalk -v 1 -c COM_NAME   IP_ADDR .1.3.6.1.4.1.18689.0.1 (COM_NAME为DNS服务器的snmp字符串 ,IP_ADDR为DNS服务器的ip地址),如果有数据显示,说明DNS服务器端的配置成功,需要说明的是这里采用的perl的版本是5.10.1,net-snmp的版本是5.5,在centos 6 上安装测试均没有问题。

二、配置cacti端

1、导入模板(本文的cacti版本是 0.8.8a,测试没有问题,其它版本未测试)

接下来在cacti端做一些简单的导入配置,在浏览器中打开cacti界面,选择Console,点击Import Templates,导入cacti_host_template_bind9_7.xml文件,保存,即完成操作。

2、编写脚本

[root@hyperic snmp_queries]#vi /var/www/html/cacti/scripts/bind-stats.sh
#!/bin/sh
 
# $1 hostname
 
/usr/bin/snmpwalk -v 1 -Ovq -c COM_NAME $1 .1.3.6.1.4.1.18689.0.1.4.1.2.14.100.110.115.99.97.99.104.101.45.115.116.97.116.115.1 | sed 's/"//g'

[root@hyperic snmp_queries]# 

[root@hyperic snmp_queries]# chmod +x /var/www/html/cacti/scripts/bind-stats.sh

3、新建cacti监控

导入模板后新建监控时,Host Template 选择 ”BIND9.7"

三、错误解决

1、有图无数据

现象:有图无数据

分析:在cacti服务器上进行如下测试

[root@hyperic ~]# /var/www/html/cacti/scripts/bind-stats.sh  IP_ADDR  ( IP_ADDR为DNS服务器的ip地址) 如果有输入说明成功,如果出错:"/opt/bin/runstats.sh: Permission denied",

 

在DNS服务器上输入如下命令

[root@ test   ~]# getenforce 

Enforcing

[root@ test   ~]#

 

解决方法:此问题是DNS服务器上的selinux引起的,请将selinux关闭。

[root@ test   ~]# setenforce 0

[root@ test   ~]# getenforce  

Permissive

[root@ test   ~]#

同时修改 /etc/sysconfig/selinux