例 -- DNS 更新

例 -- DNS 更新 -- RFC 2136 DNS 更新

RFC 2136 DNS 更新

特別な形式の DNS パケットを作成してネームサーバに送信すると、 動的な DNS 更新が簡単に実現できます。Net_DNS が更新の要求のために 用いる DNS パケットの使用は、RFC 2136 で定義されています。 ネームサーバが DNS 更新要求を受け付けるように設定されていることが 前提条件となります。また、クライアントとサーバの間で鍵が確立されている ことも必要です。さらにもっとも大切なのは、鍵の MD5 ダイジェストを 生成するため、PHP の mhash 拡張が組み込まれていなければならないことです。

DNS パケットの構造は非常に特殊なものであり、DNS 更新がどのような 動作をするのかについての深い知識が要求されます。 Net_DNS は、現時点では抽象化されたパケットを サポートしていません。パケットの作成と送信は手動で行う必要があります。 更新パケットの完全な仕様は RFC 2136 を参照してください。

DNS 更新パケットで有効な項目の完全な一覧は、RFC2136 (http://www.ietf.org/rfc/rfc2136.txt) を参照してください。 以下の例は、DNS 更新に最低限必要な項目のみを扱っています。

例 54-1動的 DNS 更新パケットをネームサーバに送信する

<?php
require_once 'Net/DNS.php';

$resolver = new Net_DNS_Resolver();

// リクエストを送信する対象は、そのゾーンに対する DNS 更新を
// 受け付けているマスタサーバに限られるべきです。
$resolver->nameservers = array('192.168.0.254');

// DNS 更新のためのパケットを手動で生成する必要があります。
// まず最初にパケットオブジェクトのインスタンスを生成しなければなりません。
$packet = new Net_DNS_Packet();

// 更新パケットのヘッダを生成します。ほとんどの項目はデフォルト値の
// ままで大丈夫ですが、OPCODE ヘッダは "UPDATE" としなければなりません。
$packet->header = new Net_DNS_Header();
$packet->header->id = $resolver->nextid();
$packet->header->qr = 0;
$packet->header->opcode = "UPDATE";

// RFC2136 で定義述べられているように、質問セクションが "ZONE" セクションと
// なります。ここには、これから我々が更新しようとしているゾーンを指定します。
// これは、ネームサーバの設定で指定されているようなゾーン設定を反映します。
$packet->question[0] = new Net_DNS_Question('example.com', "SOA", "IN");

// パケットの回答セクションが "PREREQUISITE(条件)" セクションとなります。
// RFC2136 の セクション 2.4 に、とりうる値が定義されています。
// ここでの例のように何も条件を指定しなかった場合、ネームサーバは無条件での
// 更新を試みます。
$packet->answer = array();

// 権限セクションが、"UPDATE(更新)" セクションとなります。更新セクションは
// 変更したいリソースレコードをまとめたものです。RR オブジェクトに設定した値
// により、RR を削除したり追加したりすることができます。これらの値については
// RFC2136 で定義されていますが、ここでもひととおりまとめておきます。
//
// RR を追加する
// ゼロ以外の TTL が設定されている完全な RR オブジェクトは、追加とみなされます。
//
// RR を削除する
// TTL にゼロが設定されている完全な RR オブジェクトは、削除とみなされます。
// TTL 以外のすべての値が(正確に)一致するオブジェクトが削除されます。
//
// 複数の RR を削除する
// TTL にゼロ、TYPE に ANY が設定されている完全な RR オブジェクトは、指定された
// 名前とタイプの RR をすべて削除します。TTL と TYPE 以外のすべての値が(正確に)
// 一致するオブジェクトが削除されます。
//
// ある名前の RR をすべて削除する
// TTL にゼロ、TYPE に ANY 、そしてクラスにも ANY が設定されている完全な
// RR オブジェクトは、指定された名前の RR をすべて削除します。name セクションが
// 一致するすべてのオブジェクトが削除されます。
//
// 次の設定は、名前が "example.com"・クラスが "IN"・タイプが "A"・
// そしてアドレスが "192.0.34.166" の RR を削除します。
$rrDelete =& Net_DNS_RR::factory("example.com. 0 IN A 192.0.34.166");
//
// 次の設定は、名前が example.com・TTL が 1 時間・クラスが "IN"・
// タイプが "A"・そしてアドレスが "192.0.34.155" の RR を追加します。
// 先ほどの例との違いは TTL の値だけであることに注目してください。
$rrAdd =& Net_DNS_RR::factory("example.com. 3600 IN A 192.0.34.166");
//
// RR の更新内容は、DNS パケットの権限(更新)セクションに追加します。
$packet->authority[0] = $rrDelete;
$packet->authority[1] = $rrAdd;
//
// ネームサーバが認証を要求している場合、送信されるすべてのパケットに署名を
// つけなければなりません。DNS パケットの付加セクションに、TSIG RR が付加さ
// れます。
$tsig =& Net_DNS_RR::factory("keyname.as.specified.in.server. TSIG ThisIsMyKey");
$packet->additional = array($tsig);
// Net_DNS は、それぞれのセクションのレコード数を自動計算しません。
// 手動で計算する必要があります。
$packet->header->qdcount = count($packet->question);
$packet->header->ancount = count($packet->answer);
$packet->header->nscount = count($packet->authority);
$packet->header->arcount = count($packet->additional);
//
// パケットが出来上がったら、処理を進めるためにそれをネームサーバに
// 送信します。 DNS 更新には send_tcp() メソッドを利用しなければなりません。
$response = $resolver->send_tcp($packet, $packet->data());
//
// サーバからの応答はいろいろ変化します。もし更新が成功した場合、サーバは
// "NOERROR" という応答コードを戻します。何かエラーが発生した場合、それは
// 応答パケットのヘッダの "rcode" に格納されます。
if ($response->header->rcode != "NOERROR") {
  return($response->header->rcode);
}

?>