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
構造体の内部を確認できるようにしました。
これは、VMwareインフラストラクチャの前にあるジュニパーファイアウォールのルールセットが過度に制限されていることが原因でした。
会話の両側を確認できるようにテストリゾルバーを作成しました。Kempniuの優れた回答で特定された欠落パケットは、実際に途中でドロップされていました。その回答で述べたように、アドレスファミリが指定されていないgetaddrinfo()
はallサポートされるファミリに関する回答を待ってから戻ります(または、私の場合はタイムアウトします)。
ネットワークを運営している私の同僚は、
Juniperファイアウォールのデフォルトの動作では、そのセッションに一致するDNS応答が受信されるとすぐに、DNS関連のセッションが閉じられます。
そのため、ファイアウォールはIPv4応答を確認し、VMのクエリに応答したことを指摘し、そのポートの受信パスを閉じました。したがって、次のIPv6応答パケットはドロップされました。なぜ両方のパケットが2回目に通過したのかはわかりませんが、ファイアウォールでこの機能を無効にすると問題が解決しました。
これはジュニパーKBからの関連する抜粋です。
DNS応答パケットがドロップされるシナリオは次のとおりです。
- 最初のDNSクエリパケットがファイアウォールに到達し、許可ポリシーが構成されている場合、DNSトラフィックのセッションが作成されます。デフォルトのタイムアウトは60秒です。
- セッションが閉じる直前に、新しいDNSクエリが送信され、既存のセッションと一致するため(送信元と宛先のポート/ IPペアは常に同じであるため)、ファイアウォールによって転送されます。セッションタイムアウトは、新しく到着したパケットに従って更新されないことに注意してください。
- 作成されたDNSセッションは、タイムアウトがどれだけ残っていても、最初のDNSクエリ応答(応答)がデバイスに到達すると期限切れになります。
- DNS応答がファイアウォールを通過すると、セッションは期限切れになります。
- セッションが存在しないため、後続のすべてのDNS応答はファイアウォールによってドロップされます。
この回答に賛成することを考えている場合は、ケンプニウの回答にも賛成してください。それがなくても、VMの構成に関する問題を見つけようとするのはやはりおもしろいでしょう。
最初の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>...
_行を出力しました(つまり、その時点で名前はすでに解決されています)。