Node.jsでDNSサーバーを確認!dns.getServers()の活用とトラブルシューティング

2025-05-27

dnsモジュールは、DNS (Domain Name System) の名前解決機能を提供します。dns.getServers()はその中の1つで、現在システムがDNSクエリを送信しているDNSサーバーのアドレスを文字列の配列として返します。

使い方

非常にシンプルで、引数は必要ありません。

const dns = require('dns');

const dnsServers = dns.getServers();
console.log('現在のDNSサーバー:', dnsServers);

返される値

このメソッドは、RFC 5952形式のIPアドレスの文字列の配列を返します。例えば、['8.8.8.8', '8.8.4.4'] のようになることがあります。もしカスタムポートが使用されている場合、ポート番号も'IPアドレス:ポート番号'の形式で含まれることがあります。

注意点

  • 非同期ではない: このメソッドは同期的に動作し、すぐに結果を返します。
  • dns.setServers()との関連: dns.setServers()メソッドを使って、プログラム内で一時的に使用するDNSサーバーを設定することができます。dns.setServers()で設定されたサーバーは、dns.getServers()で取得されるリストに反映されます。
  • システムの設定に依存: dns.getServers()が返すDNSサーバーのリストは、Node.jsアプリケーションが動作しているOSのDNS設定(例えば、Linuxの/etc/resolv.confやWindowsのネットワーク設定など)に基づいています。
  • DNS関連のツールやユーティリティを作成する際、現在の設定を把握するために。
  • 特定のDNSサーバーを使用していることを確認したい場合。
  • 現在のDNSサーバーの設定を確認するデバッグ時。


dns.getServers()自体は、Node.jsのdnsモジュールの中でも非常にシンプルなメソッドであり、それ自体が直接エラーを発生させることは稀です。ほとんどの場合、関連するDNS設定や環境の問題によって、予期しない動作や結果につながることがあります。

ここでは、dns.getServers()に関連する一般的な問題とそのトラブルシューティングについて説明します。

予期しないDNSサーバーリストが返される

問題の症状
dns.getServers()が、期待していたDNSサーバーのIPアドレスとは異なる、あるいは空の配列を返す。

考えられる原因

  • コンテナ環境(Dockerなど)
    コンテナは独自のDNS設定を持つことが多く、ホストOSのDNS設定とは異なる場合があります。
  • ネットワーク設定の誤り
    DHCPでDNSサーバーが正しく割り当てられていない、あるいは静的に設定したIPアドレスやDNSサーバーが間違っている。
  • dns.setServers()による上書き
    アプリケーションのどこかでdns.setServers()が呼び出されており、それがOSのデフォルト設定を上書きしている可能性があります。特に、ライブラリやフレームワークが内部的にこれを呼び出しているケースもあります。
  • OSのDNS設定の不一致
    Node.jsは、多くの場合、実行されているOSのDNS設定(Linuxの/etc/resolv.conf、Windowsのネットワークアダプター設定など)を参照します。手動でDNS設定を変更したつもりでも、OSがそれを認識していない、あるいは古いキャッシュが残っている可能性があります。

トラブルシューティング

  • ネットワーク接続の確認
    インターネットに接続されているか、他のツール(ping google.comなど)で名前解決ができるか確認します。
  • コンテナ設定の確認
    Dockerを使っている場合、docker runコマンドの--dnsオプションやdocker-compose.ymldns設定を確認します。
  • アプリケーションコードの確認
    グローバルにdns.setServers()を呼び出している箇所がないか、コードベースを検索します。特に、開発環境と本番環境で挙動が異なる場合、環境変数などによる条件分岐がないか確認します。
  • OSのDNS設定を確認
    • Linux/macOS
      /etc/resolv.confの内容を確認します。nameserverエントリがDNSサーバーを示します。
    • Windows
      ネットワークアダプターの設定でIPv4/IPv6のDNSサーバー設定を確認します。ipconfig /allコマンドも有用です。

DNSサーバーの変更が反映されない

問題の症状
OSのDNS設定を変更したにもかかわらず、Node.jsアプリケーションがdns.getServers()で古いDNSサーバーのリストを返す。

考えられる原因

  • DNSキャッシュ
    OSやネットワーク機器、アプリケーション自身がDNSキャッシュを持っている場合、新しい設定がすぐに反映されないことがあります。
  • Node.jsプロセスの再起動忘れ
    Node.jsアプリケーションは、起動時にOSのDNS設定を読み込むことがほとんどです。OSのDNS設定を変更した後、Node.jsアプリケーションを再起動していないと、古い設定を使い続けることがあります。

トラブルシューティング

  • ルーター/ファイアウォールの確認
    場合によっては、ルーターやファイアウォールが独自のDNSサーバーをキャッシュしていることがあります。
  • OSのDNSキャッシュのクリア
    • macOS
      sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
    • Windows
      ipconfig /flushdns
    • Linux
      ディストリビューションや設定によりますが、systemd-resolvedを使用している場合はsudo systemd-resolve --flush-cachesなど。
  • Node.jsアプリケーションの再起動
    OSのDNS設定を変更したら、必ずNode.jsプロセスを終了し、再起動してください。

問題の症状
特定の仮想環境やクラウド環境でdns.getServers()の動作が異なる。

考えられる原因

  • VPN接続
    VPNに接続すると、そのVPNが提供するDNSサーバーが優先的に使用されることがあります。
  • クラウドプロバイダのネットワーク設定
    AWS VPC、Azure VNetなどのクラウド環境では、内部DNSサーバーが自動的に設定されることが多く、ホストOSの/etc/resolv.confが通常の物理サーバーとは異なる場合があります。

トラブルシューティング

  • ネットワークインターフェースの確認
    ifconfig (Linux/macOS) や ipconfig (Windows) で、アクティブなネットワークインターフェースとそのDNS設定を確認します。
  • 環境固有のドキュメント確認
    使用しているクラウドプロバイダやVPNサービスのドキュメントを参照し、DNS解決の仕組みを理解します。

dns.getServers()自体はエラーを吐きにくいですが、その結果が期待と異なる場合は、多くの場合、以下の点を順番に確認することが重要です。

  1. OSのDNS設定
    Node.jsが依存するシステム設定。
  2. Node.jsアプリケーションのコード
    dns.setServers()が意図せず呼び出されていないか。
  3. プロセスのライフサイクル
    設定変更後に再起動しているか。
  4. ネットワーク環境
    コンテナ、VPN、クラウド環境などの特殊な設定。


以下にいくつかの例を挙げます。

例1: 現在設定されているDNSサーバーをシンプルに取得する

これは最も基本的な使用例です。

const dns = require('dns');

console.log('Node.jsアプリケーションが現在使用しているDNSサーバーリストを取得します...');

try {
    const dnsServers = dns.getServers();
    if (dnsServers.length > 0) {
        console.log('現在のDNSサーバー:', dnsServers);
        console.log(`\nサーバーの数は ${dnsServers.length} 個です。`);
    } else {
        console.log('現在、DNSサーバーが設定されていません(または取得できませんでした)。');
        console.log('これは、システムのDNS設定に問題があるか、特定の環境ではDNSサーバーが明示的に設定されていないことを意味する可能性があります。');
    }
} catch (error) {
    // dns.getServers()自体がエラーを投げることは稀ですが、念のため
    console.error('DNSサーバーの取得中にエラーが発生しました:', error.message);
}

// 出力例 (環境によって異なります):
// Node.jsアプリケーションが現在使用しているDNSサーバーリストを取得します...
// 現在のDNSサーバー: [ '192.168.1.1', '8.8.8.8' ]
//
// サーバーの数は 2 個です。

例2: dns.setServers()で設定を変更し、dns.getServers()で確認する

dns.setServers()を使うと、Node.jsプロセス内でのみDNSサーバーの設定を一時的に変更できます。dns.getServers()は、この変更が正しく反映されたことを確認するのに役立ちます。

const dns = require('dns');

console.log('--- DNSサーバー設定のテスト ---');

// 1. 初期状態のDNSサーバーを取得
console.log('1. 初期状態のDNSサーバー:');
const initialServers = dns.getServers();
console.log(initialServers.length > 0 ? initialServers : 'なし');

// 2. カスタムDNSサーバーを設定
const customServers = ['1.1.1.1', '8.8.8.8']; // Cloudflare DNSとGoogle Public DNS
console.log(`\n2. DNSサーバーを ${customServers.join(', ')} に設定します...`);
try {
    dns.setServers(customServers);
    console.log('設定が完了しました。');
} catch (error) {
    // 無効なIPアドレスなど、setServers()がエラーを投げる可能性があります
    console.error('DNSサーバーの設定中にエラーが発生しました:', error.message);
    process.exit(1); // エラーが発生した場合は終了
}


// 3. 設定後のDNSサーバーを再度取得して確認
console.log('\n3. 設定後のDNSサーバー:');
const afterSetServers = dns.getServers();
console.log(afterSetServers);

// 4. 設定したDNSサーバーを使って名前解決を試す (オプション)
// これは、設定が実際に機能していることを確認するのに役立ちます。
console.log('\n4. 設定したDNSサーバーを使ってgoogle.comの名前解決を試します...');
dns.lookup('google.com', (err, address, family) => {
    if (err) {
        console.error('名前解決に失敗しました:', err.message);
    } else {
        console.log(`google.com のIPアドレス: ${address} (IPv${family})`);
    }

    // 元のDNSサーバーに戻す (クリーンアップ)
    console.log('\n5. DNSサーバーを元の状態に戻します...');
    try {
        if (initialServers.length > 0) {
            dns.setServers(initialServers);
        } else {
            // initialServersが空の場合、OSデフォルトに戻す方法はありませんが、
            // 新しいサーバーを設定しないことで間接的に元の状態に戻すことを試みます
            console.warn('初期状態のDNSサーバーが取得できなかったため、元の状態への正確な復元はできません。');
        }
        console.log('DNSサーバーが元の状態に戻されました。');
    } catch (error) {
        console.error('DNSサーバーの復元中にエラーが発生しました:', error.message);
    }

    console.log('\n6. 最終的なDNSサーバーの状態:');
    console.log(dns.getServers());
});


/*
出力例 (環境によってIPアドレスは異なります):
--- DNSサーバー設定のテスト ---
1. 初期状態のDNSサーバー:
[ '192.168.1.1', '8.8.8.8' ]

2. DNSサーバーを 1.1.1.1, 8.8.8.8 に設定します...
設定が完了しました。

3. 設定後のDNSサーバー:
[ '1.1.1.1', '8.8.8.8' ]

4. 設定したDNSサーバーを使ってgoogle.comの名前解決を試します...
google.com のIPアドレス: 142.250.199.14 (IPv4)

5. DNSサーバーを元の状態に戻します...
DNSサーバーが元の状態に戻されました。

6. 最終的なDNSサーバーの状態:
[ '192.168.1.1', '8.8.8.8' ]
*/

アプリケーションが実行されている環境のDNS設定がどうなっているかを確認するための簡単なスクリプトとして活用できます。

const dns = require('dns');
const os = require('os');

console.log('--- システムDNS設定診断ツール ---');
console.log(`ホスト名: ${os.hostname()}`);
console.log(`OSタイプ: ${os.type()} ${os.release()}`);
console.log(`Node.jsバージョン: ${process.version}`);
console.log('--------------------------------');

try {
    const servers = dns.getServers();
    if (servers.length > 0) {
        console.log('\nNode.jsが認識しているDNSサーバー:');
        servers.forEach((server, index) => {
            console.log(`  ${index + 1}. ${server}`);
        });

        // 最初のDNSサーバーを使って簡単な逆引きを試す (オプション)
        if (servers[0] && (servers[0].includes('.') || servers[0].includes(':'))) { // IPv4またはIPv6形式のチェック
            console.log(`\n最初のDNSサーバー (${servers[0]}) のホスト名を逆引きします...`);
            dns.reverse(servers[0].split(':')[0], (err, hostnames) => { // ポート番号があれば取り除く
                if (err) {
                    if (err.code === 'ENODATA' || err.code === 'ENOTFOUND') {
                        console.log(`  逆引きデータが見つかりませんでした (${err.message})`);
                    } else {
                        console.error(`  逆引きに失敗しました: ${err.message}`);
                    }
                } else {
                    console.log(`  ホスト名: ${hostnames.join(', ')}`);
                }
            });
        } else {
            console.log('\n最初のDNSサーバーが有効なIPアドレス形式ではありません。逆引きをスキップします。');
        }

    } else {
        console.log('\nNode.jsは現在、DNSサーバーを認識していません。これは設定の問題を示している可能性があります。');
    }
} catch (error) {
    console.error('\nDNSサーバーの取得中に予期せぬエラーが発生しました:', error.message);
}

// 出力例 (Linux環境の場合):
// --- システムDNS設定診断ツール ---
// ホスト名: my-dev-machine
// OSタイプ: Linux 5.15.0-101-generic
// Node.jsバージョン: v20.12.2
// --------------------------------
//
// Node.jsが認識しているDNSサーバー:
//   1. 127.0.0.53
//   2. 192.168.1.1
//
// 最初のDNSサーバー (127.0.0.53) のホスト名を逆引きします...
//   逆引きデータが見つかりませんでした (ENODATA)


dns.getServers()はNode.jsアプリケーションが現在使用しているDNSサーバーのリストをプログラム的に取得する直接的な方法ですが、代替手段は「何を達成したいか」によって大きく異なります。dns.getServers()は主にNode.jsプロセス自身が参照するDNS設定を知るためのものであり、OSレベルの設定を読み取る他の方法とは少し異なります。

以下に、dns.getServers()の「代替」と見なせるかもしれない、異なる目的を持つ方法をいくつか説明します。

OSのDNS設定ファイルを直接読み込む (非Node.jsネイティブ、非推奨)

これは、Node.jsのdnsモジュールを介さずに、OSが実際に使用しているDNS設定ファイルを直接読み取る方法です。

  • Windowsの場合: WindowsのDNS設定はレジストリに格納されているため、直接ファイルを読み込むのは困難です。ipconfig /allコマンドの出力をパースするなどの方法が考えられますが、非常に複雑で信頼性が低いです。
  • Linux/macOSの場合: /etc/resolv.confファイルを読み込みます。

Pros

  • Node.jsのdns.setServers()による上書きの影響を受けません。
  • OSが実際に参照している設定をより正確に知ることができます(ただし、キャッシュの影響は考慮する必要があります)。

Cons

  • 複雑性: 読み込んだファイルのパースロジックを自分で実装する必要があります。
  • 権限の問題: /etc/resolv.confの読み取りは通常可能ですが、他の設定ファイルでは権限の問題が発生する可能性があります。
  • 信頼性が低い: ファイルのフォーマットが変更される可能性がある、OSがファイルを直接参照しないケース(例: systemd-resolvedを使用しているLinuxの一部ディストリビューション)がある、など。
  • プラットフォーム非依存ではない: OSごとに異なるパスやパースロジックが必要です。

コード例 (Linux/macOSの/etc/resolv.confの場合)

const fs = require('fs');
const path = require('path');

const resolvConfPath = '/etc/resolv.conf'; // Linux/macOSの標準パス

if (process.platform === 'linux' || process.platform === 'darwin') {
    fs.readFile(resolvConfPath, 'utf8', (err, data) => {
        if (err) {
            if (err.code === 'ENOENT') {
                console.warn(`${resolvConfPath} が見つかりません。DNS設定を直接読み取れません。`);
            } else {
                console.error(`Error reading ${resolvConfPath}:`, err);
            }
            return;
        }

        const lines = data.split('\n');
        const nameservers = [];
        lines.forEach(line => {
            const trimmedLine = line.trim();
            if (trimmedLine.startsWith('nameserver')) {
                const parts = trimmedLine.split(/\s+/); // スペースで分割
                if (parts.length > 1) {
                    nameservers.push(parts[1]);
                }
            }
        });

        console.log(`\n${resolvConfPath} から読み取ったDNSサーバー:`, nameservers);
        if (nameservers.length === 0) {
            console.log('resolv.conf からnameserverエントリが見つかりませんでした。');
        }
    });
} else {
    console.log(`OS (${process.platform}) は ${resolvConfPath} に対応していません。`);
    console.log('この方法はLinux/macOS専用です。');
}

OSコマンドを実行してDNS設定を取得する

OS固有のコマンドを実行し、その標準出力をパースしてDNSサーバー情報を取得する方法です。

  • Windows: ipconfig /all
  • macOS: scutil --dns
  • Linux: cat /etc/resolv.conf (上記と同じだがコマンド実行)、nmcli device show (NetworkManagerを使用している場合)、resolvectl status (systemd-resolvedを使用している場合)

Pros

  • Node.jsのdns.setServers()による影響を受けません。
  • OSが提供するツールなので、多くの場合、信頼性が高い情報が得られます。

Cons

  • 権限の問題: 一部のコマンドは管理者権限を必要とすることがあります。
  • 出力フォーマットの変更: OSのバージョンアップやツールの更新により、出力フォーマットが変わる可能性があり、パースロジックのメンテナンスが必要です。
  • 外部プロセス実行のオーバーヘッド: child_processモジュールを使用するため、同期的に実行するとブロックが発生し、非同期的に実行してもオーバーヘッドがあります。
  • プラットフォーム非依存ではない: OSごとに異なるコマンドとパースロジックが必要です。

コード例 (Windowsのipconfig /allの場合)

const { exec } = require('child_process');

if (process.platform === 'win32') {
    exec('ipconfig /all', (err, stdout, stderr) => {
        if (err) {
            console.error(`exec error: ${err}`);
            return;
        }
        if (stderr) {
            console.error(`stderr: ${stderr}`);
            // stderrは必ずしもエラーではないこともあるので注意
        }

        const lines = stdout.split('\n');
        const dnsServers = [];
        let inAdapterSection = false;

        lines.forEach(line => {
            const trimmedLine = line.trim();

            // アダプターセクションの開始を検出
            if (trimmedLine.includes('Adapter')) {
                inAdapterSection = true;
            }

            if (inAdapterSection && trimmedLine.startsWith('DNS Servers') || trimmedLine.startsWith('DNS サーバー')) {
                const parts = trimmedLine.split(':');
                if (parts.length > 1) {
                    const servers = parts[1].trim().split(/\s*,\s*|\s+/); // カンマまたはスペースで分割
                    servers.forEach(server => {
                        if (server && (server.includes('.') || server.includes(':')) && !dnsServers.includes(server)) {
                            dnsServers.push(server);
                        }
                    });
                }
            }
        });

        console.log(`\n'ipconfig /all' から取得したDNSサーバー:`, dnsServers);
        if (dnsServers.length === 0) {
            console.log('ipconfig /all からDNSサーバーが見つかりませんでした。');
        }
    });
} else {
    console.log(`OS (${process.platform}) は 'ipconfig /all' に対応していません。`);
    console.log('この方法はWindows専用です。');
}

これはDNSサーバーのリストを直接取得するものではありませんが、「どのDNSサーバーが使われているか」という目的で、実際に名前解決を試みることで、間接的に確認する方法です。特定のDNSサーバーへのリクエストを明示的に行うことで、そのサーバーが機能しているかを確認できます。

Pros

  • 特定のDNSサーバーに対して名前解決をテストできます。
  • 実際に名前解決が行われるため、設定だけでなく「機能しているか」の確認もできます。

Cons

  • テスト対象のDNSサーバーのIPアドレスを事前に知っている必要があります。
  • DNSサーバーのリストそのものは取得できません。
const dns = require('dns');

const targetDomain = 'example.com';
const specificDnsServer = '1.1.1.1'; // Cloudflare DNS

console.log(`\nカスタムDNSサーバー (${specificDnsServer}) を使って ${targetDomain} の名前解決を試みます...`);

// dns.lookup()は、デフォルトでNode.jsが認識しているサーバーを使う
// 特定のサーバーを使いたい場合は、dns.Resolverクラスを使う
const resolver = new dns.Resolver();
resolver.setServers([specificDnsServer]); // ここで一時的にリゾルバのサーバーを設定

resolver.lookup(targetDomain, (err, address, family) => {
    if (err) {
        console.error(`カスタムDNSサーバー (${specificDnsServer}) を使った名前解決に失敗しました:`, err.message);
    } else {
        console.log(`${targetDomain} のIPアドレス (${specificDnsServer} 経由): ${address} (IPv${family})`);
    }
});