やりたい事
DNSサーバ(Bind)にはzoneごとの正引き用zoneファイルが沢山あって、それらを全部読み込んで指定したIPアドレスに合致したFQDNを全て表示したい。
なお、逆引き設定ファイルは無い前提。
目的
- 正引き設定の間違い探しをしたい。
- 一つのIPに複数の名前が設定されているケースを見つけたい。
使用言語等
PHPを使用して、専用のクラスを作成する。
プログラムの処理概要
コンストラクタでは、指定したフォルダに置いてあるファイルを全部読み込んで、$ORIGIN行のドメイン名と、その後に続くサブドメインを繋げたFQDNとそれに対応して設定されているIPアドレス全てのテーブルを構築する。
その際に、AレコードだけでなくCNAMEレコードも考慮して、CNAMEで設定されているAレコードを辿ってIPアドレスを引き出してテーブルに格納する。
getFqdnメソッドでは、引数のIPアドレスを元にコンストラクタが構築したテーブルの中から合致したFQDNを配列に入れて返す。
ZONEファイルの記載例
ahoaho.jp.zone
$ORIGIN .
$TTL 600 ; 10 minutes
ahoaho.jp IN SOA ns1.hogehoge.jp. root.ns1.hogehoge.jp. (
1234567890 ; serial
10800 ; refresh (3 hours)
3600 ; retry (1 hour)
604800 ; expire (1 week)
86400 ; minimum (1 day)
)
NS ns1.hogehoge.jp.
NS ns2.hogehoge.jp.
NS ns3.hogehoge.jp.
NS ns4.hogehoge.jp.
$ORIGIN ahoaho.jp.
hogeaho A 222.222.222.222
ahohoge A 222.222.222.222
uhouho CNAME ahohoge.ahoaho.jp.
コード
getzoneinfo
class getzoneinfo{
// Constructor
function __construct($dirPath){
$fileList = array();
$fqdnAndIp = array();
$domain = '';
$fqdn = '';
$cnameFqdn = '';
$cnameIpaddr = '';
$cnameOrigin = '';
$cnameTrio = array();
$cnameList = array();
global $fqdnList;
$iterator = new RecursiveDirectoryIterator($dirPath);
$iterator = new RecursiveIteratorIterator($iterator);
$fileList = array();
foreach ($iterator as $fileinfo) {
if ($fileinfo->isFile()) {
$fileList[] = $fileinfo->getPathname();
}
}
// Get file path from file list.
foreach ($fileList as $filePath) {
$contents = @file($filePath);
$isFirstOrigin = 1;
// Get word from line
foreach($contents as $line){
//echo $line."<br />";
$line = trim($line);
$line = preg_replace("/[ \s]+/"," ",$line);
$line_array = explode(" ", $line);
// Detect ORIGIN
if ( $line_array[0] == '$ORIGIN' ) {
// Ignore first ORIGIN
if ( $isFirstOrigin == 1 ) {
$isFirstOrigin = 0;
continue;
} else {
$domain = $line_array[1];
continue;
}
}
// Detect Domain only
if ( $line_array[0] == 'A' ) {
$fqdn = $domain;
$ipAddr = $line_array[1];
$fqdnAndIp[] = $fqdn;
$fqdnAndIp[] = $ipAddr;
$fqdnList[] = $fqdnAndIp;
$fqdnAndIp = array();
$fqdn = '';
$ipAddr = '';
continue;
}
// Detect records
if ( array_key_exists(1, $line_array) ) {
switch ( $line_array[1] )
{
case "IN":
$domain = $line_array[0];
continue 2;
case "A":
$fqdn = $line_array[0].'.'.substr($domain, 0, -1);
$ipAddr = $line_array[2];
break;
case "CNAME":
// Stash CNAME Records
$cnameFqdn = $line_array[0].'.'.substr($domain, 0, -1);
$cnameIpaddr = $line_array[2];
$cnameOrigin = $domain;
$cnameTrio[] = $cnameFqdn;
$cnameTrio[] = $cnameIpaddr;
$cnameTrio[] = substr($cnameOrigin, 0, -1);;
$cnameList[] = $cnameTrio;
$cnameIpaddr = '';
$cnameIpaddr = '';
$cnameTrio = array();
continue 2;
default:
continue 2;
}
}
// Store fqdn and ipaddr
if ( $fqdn != '' ) {
$fqdnAndIp[] = $fqdn;
$fqdnAndIp[] = $ipAddr;
$fqdnList[] = $fqdnAndIp;
$fqdnAndIp = array();
$fqdn = '';
$ipAddr = '';
}
}
}
// Store CNAME Records
$cnamenum = count($cnameList);
$fqdnnum = count($fqdnList);
for ($i=0; $i < $cnamenum; $i++) {
for ($j=0; $j < $fqdnnum; $j++) {
if ($cnameList[$i][1].'.'.$cnameList[$i][2] == $fqdnList[$j][0]) {
$fqdn = $cnameList[$i][0];
$ipAddr = $fqdnList[$j][1];
$fqdnAndIp[] = $fqdn;
$fqdnAndIp[] = $ipAddr;
$fqdnList[] = $fqdnAndIp;
$fqdnAndIp = array();
$fqdn = '';
$ipAddr = '';
}
}
}
//print "FQDN Table";
//print "<pre>";
//print_r($fqdnList);
//print "</pre>";
}
function getFqdn($ipAddr){
global $fqdnList;
$fqdns = array();
$num = count($fqdnList);
for ($i=0; $i < $num; $i++) {
if ( $fqdnList[$i][1] == $ipAddr ) {
$fqdns[] = $fqdnList[$i][0];
}
}
return $fqdns;
}
使用例
getFqdn.php
$fqdn = new getzoneinfo('/var/www/html/zone');
$result = $fqdn->getFqdn('222.222.222.222');
print "-------------------------------<br>";
print "Query Result of 222.222.222.222";
print "<pre>";
print_r($result);
print "</pre>";
余談
PHPのクラスは今回初めて書きましたが、期限までに時間が無くて大急ぎでとりあえず動くものを作らなければならなかったので、文法を調べながら勢いで書いてリファクタリングも全くしていません。
なので、リファクタリング大歓迎です!w