Node.js DNS モジュール
1. DNS モジュールの紹介
DNS (Domain Name System) モジュールは、Node.js において名前解決(Name Resolution)機能を提供します。
このモジュールは主に 2 つの API を提供しています。
- コールバックベース API: 従来の Node.js スタイルであるコールバック関数を使用した API
- プロミスベース API:
dns.promisesを介した、モダンな async/await 対応の API
主な機能は以下の通りです。
- ドメイン名を IP アドレス(A/AAAA レコード)に解決する
- 逆引き DNS ルックアップ(PTR レコード)の実行
- 各種 DNS レコードタイプ(MX, TXT, SRV 等)のクエリ
- 特定の設定を持つカスタム DNS リゾルバー の作成
- プログラムによる DNS サーバー設定の構成
注意: DNS モジュールには、オペレーティングシステム(OS)の機能を利用するモードと、ネットワーク経由で直接 DNS クエリを実行するモードの 2 つの異なる動作モードがあります。これは、アプリケーション内でのホスト名解決の挙動に影響を与えます。
2. DNS 操作の開始
以下は、DNS モジュールを使用してドメインの IP アドレスをルックアップする簡単な例です。
2.1 基本的な DNS ルックアップ
const dns = require('dns');
// ドメイン名をルックアップ
dns.lookup('example.com', (err, address, family) => {
if (err) {
console.error('ルックアップエラー:', err);
return;
}
console.log(`IPアドレス: ${address}`);
console.log(`IPバージョン: IPv${family}`);
});2.2 インポートとセットアップ
Node.js アプリケーションで DNS モジュールを使用するには、コールバックベースまたはプロミスベースの API のいずれかをインポートします。
コールバックベース API
const dns = require('dns');
dns.lookup('example.com', (err, address, family) => {
if (err) throw err;
console.log(`解決済み: ${address} (IPv${family})`);
});プロミスベース API (Node.js 10.0.0+)
// プロミス API をインポート
const { promises: dns } = require('dns');
// または: const dns = require('dns').promises;
// async/await を使用した例
async function lookupDomain(domain) {
try {
const address = await dns.lookup(domain);
console.log(`解決済み: ${address.address} (IPv${address.family})`);
} catch (err) {
console.error('ルックアップ失敗:', err);
}
}
lookupDomain('example.com');注意: モダンな async/await パターンと親和性が高く、エラーハンドリングが容易なため、新規のコードではプロミスベースの API が一般的に推奨されます。
3. 基本的な DNS ルックアップ
DNS モジュールは、ドメイン名と IP アドレスをルックアップするためのいくつかのメソッドを提供します。最も一般的な操作は以下の通りです。
dns.lookup(): オペレーティングシステムの機能を使用してホスト名を解決dns.resolve*(): ネームサーバーに対して直接 DNS クエリを実行dns.reverse(): 逆引き DNS ルックアップ(IP からホスト名)を実行
3.1 ドメイン名を IP アドレスに解決する
コールバックベース API
const dns = require('dns');
dns.lookup('www.example.com', (err, address, family) => {
if (err) throw err;
console.log('IPアドレス: %s', address);
console.log('IPバージョン: IPv%s', family);
});プロミスベース API
const dns = require('dns').promises;
async function lookupExample() {
try {
const result = await dns.lookup('www.example.com');
console.log('IPアドレス:', result.address);
console.log('IPバージョン: IPv' + result.family);
} catch (err) {
console.error('ルックアップ失敗:', err);
}
}
lookupExample(); 注意:dns.lookup() メソッドは名前解決に OS の機能を使用するため、必ずしもネットワーク通信が発生するとは限りません(hosts ファイルなどが参照される場合があります)。
3.2 ドメインのすべての IP アドレスを取得する
const dns = require('dns');
// すべての IPv4 アドレスを取得
dns.resolve4('www.google.com', (err, addresses) => {
if (err) throw err;
console.log('IPv4 アドレス一覧:');
addresses.forEach(address => {
console.log(` ${address}`);
});
// 最初に見つかった IP に対して逆引きを実行
dns.reverse(addresses[0], (err, hostnames) => {
if (err) throw err;
console.log(`${addresses[0]} の逆引き結果:`);
hostnames.forEach(hostname => {
console.log(` ${hostname}`);
});
});
});4. DNS レコードタイプ
DNS モジュールは、さまざまな リソースレコード タイプのルックアップをサポートしています。
| メソッド | レコードタイプ | 説明 |
|---|---|---|
resolve4() | A | IPv4 アドレス |
resolve6() | AAAA | IPv6 アドレス |
resolveMx() | MX | メール交換レコード |
resolveTxt() | TXT | テキストレコード |
resolveSrv() | SRV | サービスレコード |
resolveNs() | NS | ネームサーバーレコード |
resolveCname() | CNAME | 正規名レコード |
resolveSoa() | SOA | 権威開始レコード |
resolvePtr() | PTR | ポインターレコード |
resolveAny() | ANY | 利用可能なすべてのレコード |
5. 高度な DNS 操作
5.1 カスタム DNS リゾルバー
DNS ルックアップをより細かく制御するために、特定の設定を持つカスタムリゾルバーを作成できます。
const dns = require('dns');
// 新しいリゾルバーを作成
const resolver = new dns.Resolver();
// カスタムサーバーを設定 (Google Public DNS)
resolver.setServers(['8.8.8.8', '8.8.4.4']);
// カスタムリゾルバーを使用
resolver.resolve4('www.example.com', (err, addresses) => {
if (err) throw err;
console.log('Google DNS を使用して解決されたアドレス:');
addresses.forEach(addr => {
console.log(` ${addr}`);
});
});
// 設定されているサーバーを確認
console.log('現在のリゾルバーサーバー:', resolver.getServers());5.2 ネットワークレベル vs OS レベルの解決
DNS モジュールには、名前解決に対して 2 つの異なるアプローチがあります。
| 関数 | 実装 | ネットワークコール | 用途 |
|---|---|---|---|
dns.lookup() | getaddrinfo() システムコールを使用 | 直接のネットワークコールなし(通常) | ローカル設定(hosts ファイル等)に従う |
dns.resolve*(), dns.reverse() | 実際のネットワークリクエストを実行 | 常に DNS サーバーに接続 | ローカル設定をバイパスし、直接クエリを行う |
警告: これらの違いにより、特にカスタムホスト設定がある環境では、dns.lookup() と dns.resolve*() の結果が常に一致するとは限りません。
5.3 エラーハンドリング
堅牢な DNS 処理には適切なエラー管理が不可欠です。
const dns = require('dns');
function lookupWithErrorHandling(domain) {
dns.lookup(domain, (err, address, family) => {
if (err) {
console.error(`${domain} の DNS ルックアップに失敗しました`);
// 特定のエラーコードをチェック
switch (err.code) {
case 'ENOTFOUND':
console.error(' ドメイン名が見つかりません');
break;
case 'ETIMEDOUT':
console.error(' DNS ルックアップがタイムアウトしました');
break;
case 'ENODATA':
console.error(' ドメインは存在しますが、リクエストされたタイプのデータがありません');
break;
case 'ESERVFAIL':
console.error(' DNS サーバーが一般的な失敗を返しました');
break;
default:
console.error(` エラーコード: ${err.code}`);
}
return;
}
console.log(`${domain} のルックアップ成功`);
console.log(` IPアドレス: ${address}`);
});
}6. パフォーマンス最適化
DNS ルックアップはアプリケーションの ボトルネック になる可能性があります。以下の戦略で最適化を図りましょう。
6.1 キャッシュの実装
同じドメインに対する繰り返しのルックアップを避けるため、シンプルな DNS キャッシュを実装します。
const dns = require('dns');
const util = require('util');
const lookup = util.promisify(dns.lookup);
const dnsCache = new Map();
async function cachedLookup(domain) {
if (dnsCache.has(domain)) {
console.log('キャッシュヒット:', domain);
return dnsCache.get(domain);
}
console.log('キャッシュミス:', domain);
const result = await lookup(domain);
dnsCache.set(domain, result);
return result;
}6.2 並列ルックアップ
Promise.all() を使用して、複数の DNS ルックアップを並列に実行します。
const dns = require('dns').promises;
async function lookupMultiple(domains) {
try {
const lookups = domains.map(domain => dns.lookup(domain));
const results = await Promise.all(lookups);
return domains.map((domain, i) => ({
domain,
...results[i]
}));
} catch (err) {
console.error('1つ以上のルックアップに失敗しました:', err);
throw err;
}
}7. DNS モジュール vs サードパーティライブラリ
| 機能 | Node.js DNS モジュール | サードパーティライブラリ |
|---|---|---|
| インストール | 標準内蔵、依存関係なし | インストールと管理が必要 |
| 機能セット | 基本的な DNS 操作 | より包括的な機能が多い |
| キャッシュ | 内蔵されていない | キャッシュ機能を含むことが多い |
| 高度な機能 | 限定的 | DNSSEC, DoH, DoT サポートなど |
人気のサードパーティライブラリ:
- dns-packet: 低レベルの DNS パケットエンコード/デコード
- native-dns: より完全な DNS 実装
- dns2: プロミスをサポートするモダンな DNS ライブラリ
8. まとめ
Node.js の DNS モジュールは、ドメインネームシステムと対話するための不可欠な機能を提供します。
- ドメイン名に対する IP アドレスの取得
- 多様な DNS レコードタイプ(A, AAAA, MX, TXT 等)の解決
- 逆引き DNS ルックアップの実行
- カスタムサーバーを使用したリゾルバーの構成
- コールバックとプロミスの両 API のサポート
ドメイン名を介してネットワークリソースにアクセスしたり、カスタムの名前解決ロジックを実装したり、ドメイン関連の情報を検証したりする必要があるアプリケーションにとって、このモジュールの理解は非常に重要です。