web-dev-qa-db-ja.com

DNSルックアップに5秒かかることがある

VM実行中のDebian Wheezyで、リゾルバがすぐに応答しても、ホスト名の検索が完了するまでに数秒かかる場合があります。奇妙なことに、getaddrinfo()による検索は影響を受けますが、gethostbyname()はそうではありません。

ローカルリゾルバが壊れている可能性を除外するためにGoogleリゾルバに切り替えたので、私の_/etc/resolv.conf_は次のようになります。

_search my-domain.com
nameserver 8.8.4.4
nameserver 8.8.8.8
_

私の_nsswitch.conf_には次の行があります:

_hosts: files dns
_

そして、私の_/etc/hosts_には異常なものが含まれていません。

_telnet webserver 80_を試してみると、名前解決を行う前に数秒間ハングします。 ltrace出力[1]は、ハングがgetaddrinfo()呼び出しにあることを示しています。

_getaddrinfo("ifconfig.me", "telnet", { AI_CANONNAME, 0, SOCK_STREAM, 0, 0, NULL, '\000', NULL }, 0x7fffb4ffc160) = 0 <5.020621>
_

ただし、tcpdumpは、ネームサーバーがすぐに応答したことを明らかにし、telnetのブロックが解除されたのは2番目の応答でのみでした。返信は同じように見えます:

_05:52:58.609731 IP 192.168.1.75.43017 > 8.8.4.4.53: 54755+ A? ifconfig.me. (29)
05:52:58.609786 IP 192.168.1.75.43017 > 8.8.4.4.53: 26090+ AAAA? ifconfig.me. (29)
05:52:58.612188 IP 8.8.4.4.53 > 192.168.1.75.43017: 54755 4/0/0 A 219.94.235.40, A 133.242.129.236, A 49.212.149.105, A 49.212.202.172 (93)

[...five second pause...]

05:53:03.613811 IP 192.168.1.75.43017 > 8.8.4.4.53: 54755+ A? ifconfig.me. (29)
05:53:03.616424 IP 8.8.4.4.53 > 192.168.1.75.43017: 54755 4/0/0 A 219.94.235.40, A 133.242.129.236, A 49.212.149.105, A 49.212.202.172 (93)
05:53:03.616547 IP 192.168.1.75.43017 > 8.8.4.4.53: 26090+ AAAA? ifconfig.me. (29)
05:53:03.618907 IP 8.8.4.4.53 > 192.168.1.75.43017: 26090 0/1/0 (76)
_

ホストファイアウォールのログを確認しましたが、ポート53で何もブロックされていません。

最初のDNS応答が無視される原因は何ですか?

[1] _ltrace.conf_に数行追加して、addrinfo構造体の内部を確認できるようにしました。

11
Flup

これは、VMwareインフラストラクチャの前にあるジュニパーファイアウォールのルールセットが過度に制限されていることが原因でした。

会話の両側を確認できるようにテストリゾルバーを作成しました。Kempniuの優れた回答で特定された欠落パケットは、実際に途中でドロップされていました。その回答で述べたように、アドレスファミリが指定されていないgetaddrinfo()allサポートされるファミリに関する回答を待ってから戻ります(または、私の場合はタイムアウトします)。

ネットワークを運営している私の同僚は、

Juniperファイアウォールのデフォルトの動作では、そのセッションに一致するDNS応答が受信されるとすぐに、DNS関連のセッションが閉じられます。

そのため、ファイアウォールはIPv4応答を確認し、VMのクエリに応答したことを指摘し、そのポートの受信パスを閉じました。したがって、次のIPv6応答パケットはドロップされました。なぜ両方のパケットが2回目に通過したのかはわかりませんが、ファイアウォールでこの機能を無効にすると問題が解決しました。

これはジュニパーKBからの関連する抜粋です。

DNS応答パケットがドロップされるシナリオは次のとおりです。

  1. 最初のDNSクエリパケットがファイアウォールに到達し、許可ポリシーが構成されている場合、DNSトラフィックのセッションが作成されます。デフォルトのタイムアウトは60秒です。
  2. セッションが閉じる直前に、新しいDNSクエリが送信され、既存のセッションと一致するため(送信元と宛先のポート/ IPペアは常に同じであるため)、ファイアウォールによって転送されます。セッションタイムアウトは、新しく到着したパケットに従って更新されないことに注意してください。
  3. 作成されたDNSセッションは、タイムアウトがどれだけ残っていても、最初のDNSクエリ応答(応答)がデバイスに到達すると期限切れになります。
  4. DNS応答がファイアウォールを通過すると、セッションは期限切れになります。
  5. セッションが存在しないため、後続のすべてのDNS応答はファイアウォールによってドロップされます。

この回答に賛成することを考えている場合は、ケンプニウの回答にも賛成してください。それがなくても、VMの構成に関する問題を見つけようとするのはやはりおもしろいでしょう。

9
Flup

最初のDNS応答は無視されません。 getaddrinfo()は、最初のAAAAクエリ(ID:26090)への応答を受け取るまで戻りませんでした。したがって、ここでの実際の問題は、Aクエリ(ID:54755)の応答を受信して​​いるのに、マシンがAAAAクエリへの応答をすぐに受信していない理由です。

getaddrinfo()gethostbyname()の違いの1つは、前者はIPv4とIPv6の両方をサポートし、後者はIPv4のみをサポートすることです。したがって、_ai_family_を0(_AF_UNSPEC_)に設定してgetaddrinfo()を呼び出すと、bothの応答を受け取る(またはタイムアウトになる)まで戻りません提供されたドメイン名に対するAおよびAAAAクエリ。 gethostbyname()は、Aレコードに対してのみクエリを実行します。

特にtcpdumpの出力をいくつか切り取ってしまったなど、問題の原因をリモートで特定するのは困難です。 VMとGoogleパブリックDNSリゾルバの間でDNSトラフィックを選択的にフィルタリング/ドロップしている可能性があります。KVM Debian Wheezy VMを使用して問題を再現しようとしました、しかし_telnet ifconfig.me_は、ほぼすぐに_Trying <IP_address_here>..._行を出力しました(つまり、その時点で名前はすでに解決されています)。

13
Kempniu