ホスト名の解決には5秒かかります

ホスト名の解決には5秒かかります

bind9私は、IPv4 (Debian Jessie) 上で動作するマスター DNS サーバーと 2 つのスレーブ サーバーを所有しており、以下を使用しています/etc/bind/named.conf:

listen-on-v6 { none; };

異なるサーバーから接続しようとすると、各接続に少なくとも5秒かかります(私はジョセフのタイミング情報デバッグ用):

$ curl -w "@curl-format.txt" -o /dev/null -s https://example.com
            time_namelookup:  5.512
               time_connect:  5.512
            time_appconnect:  5.529
           time_pretransfer:  5.529
              time_redirect:  0.000
         time_starttransfer:  5.531
                            ----------
                 time_total:  5.531

によるとcurl、検索に最も時間がかかりますが、標準はnslookup非常に高速です。

$ time nslookup example.com > /dev/null 2>&1

real    0m0.018s
user    0m0.016s
sys     0m0.000s

curlIPv4 の使用を強制すると、状況は大幅に改善されます。

$ curl -4 -w "@curl-format.txt" -o /dev/null -s https://example.com

            time_namelookup:  0.004
               time_connect:  0.005
            time_appconnect:  0.020
           time_pretransfer:  0.020
              time_redirect:  0.000
         time_starttransfer:  0.022
                            ----------
                 time_total:  0.022

ホスト上で IPv6 を無効にしました:

echo 1 > /proc/sys/net/ipv6/conf/eth0/disable_ipv6

問題は解決しません。straceタイムアウトの原因を確認するために実行してみました:

write(2, "*", 1*)                        = 1
write(2, " ", 1 )                        = 1
write(2, "Hostname was NOT found in DNS ca"..., 36Hostname was NOT found in DNS cache
) = 36
socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP) = 4
close(4)                                = 0
mmap(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f220bcf8000
mprotect(0x7f220bcf8000, 4096, PROT_NONE) = 0
clone(child_stack=0x7f220c4f7fb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f220c4f89d0, tls=0x7f220c4f8700, child_tidptr=0x7f220c4f89d0) = 2004
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, NULL, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
poll(0, 0, 4)                           = 0 (Timeout)
rt_sigaction(SIGPIPE, NULL, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
poll(0, 0, 8)                           = 0 (Timeout)
rt_sigaction(SIGPIPE, NULL, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
poll(0, 0, 16)                          = 0 (Timeout)
rt_sigaction(SIGPIPE, NULL, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
poll(0, 0, 32)                          = 0 (Timeout)
rt_sigaction(SIGPIPE, NULL, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
poll(0, 0, 64)                          = 0 (Timeout)

nslookup(または) は同じ DNS サーバーを使用しているため、ファイアウォールの問題ではないようですcurl -4。何が問題なのか、何かお分かりですか?

tcpdumpホストからのメッセージtcpdump -vvv -s 0 -l -n port 53:

tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
20:14:52.542526 IP (tos 0x0, ttl 64, id 35839, offset 0, flags [DF], proto UDP (17), length 63)
    192.168.1.1.59163 > 192.168.1.2.53: [bad udp cksum 0xf9f3 -> 0x96c7!] 39535+ A? example.com. (35)
20:14:52.542540 IP (tos 0x0, ttl 64, id 35840, offset 0, flags [DF], proto UDP (17), length 63)
    192.168.1.1.59163 > 192.168.1.2.53: [bad udp cksum 0xf9f3 -> 0x6289!] 45997+ AAAA? example.com. (35)
20:14:52.543281 IP (tos 0x0, ttl 61, id 63674, offset 0, flags [none], proto UDP (17), length 158)
    192.168.1.2.53 > 192.168.1.1.59163: [udp sum ok] 45997* q: AAAA? example.com. 1/1/0 example.com. [1h] CNAME s01.example.com. ns: example.com. [10m] SOA ns01.example.com. ns51.domaincontrol.com. 2016062008 28800 7200 1209600 600 (130)
20:14:57.547439 IP (tos 0x0, ttl 64, id 36868, offset 0, flags [DF], proto UDP (17), length 63)
    192.168.1.1.59163 > 192.168.1.2.53: [bad udp cksum 0xf9f3 -> 0x96c7!] 39535+ A? example.com. (35)
20:14:57.548188 IP (tos 0x0, ttl 61, id 64567, offset 0, flags [none], proto UDP (17), length 184)
    192.168.1.2.53 > 192.168.1.1.59163: [udp sum ok] 39535* q: A? example.com. 2/2/2 example.com. [1h] CNAME s01.example.com., s01.example.com. [1h] A 136.243.154.168 ns: example.com. [30m] NS ns01.example.com., example.com. [30m] NS ns02.example.com. ar: ns01.example.com. [1h] A 136.243.154.168, ns02.example.com. [1h] A 192.168.1.2 (156)
20:14:57.548250 IP (tos 0x0, ttl 64, id 36869, offset 0, flags [DF], proto UDP (17), length 63)
    192.168.1.1.59163 > 192.168.1.2.53: [bad udp cksum 0xf9f3 -> 0x6289!] 45997+ AAAA? example.com. (35)
20:14:57.548934 IP (tos 0x0, ttl 61, id 64568, offset 0, flags [none], proto UDP (17), length 158)
    192.168.1.2.53 > 192.168.1.1.59163: [udp sum ok] 45997* q: AAAA? example.com. 1/1/0 example.com. [1h] CNAME s01.example.com. ns: example.com. [10m] SOA ns01.example.com. ns51.domaincontrol.com. 2016062008 28800 7200 1209600 600 (130)

編集: バインド ログに次のメッセージが頻繁に表示されます:

error sending response: host unreachable

ただし、各クエリは最終的に回答されます (5 秒かかるだけです)。すべてのマシンは物理サーバーです (NAT のせいではありません)。パケットがルーターによってブロックされている可能性が高くなります。関連する可能性のある質問は次のとおりです。DNSルックアップには5秒かかることがある

答え1

短い答え:

回避策としては、 に次の行を追加して、およびレコードglibcの検索にソケットを強制的に再利用することです。AAAAA/etc/resolv.conf

options single-request-reopen

この問題の本当の原因は次のようになります:

長い答え:

glibcの関数のようなプログラムcurlwgetglibcの関数を使用するプログラムgetaddrinfo()は、両方のDNSレコードを並行して検索することで、IPv4とIPv6の両方に対応しようとします。両方のレコードを受信するまで結果は返されません(このような行動に関連するいくつかの問題) - これはstrace上記を説明しています。 IPv4 が強制される場合、curl -4内部的にはレコードのみgethostbyname()を照会しますA

次のtcpdumpことがわかります:

  • -> A?最初に2つのリクエストが送信されます
  • -> AAAA?(IPv6 アドレスを要求)
  • <- AAAA返事
  • -> A?IPv4アドレスを再度要求
  • <- A返信が届きました
  • -> AAAA?IPv6を再度要求
  • <- AAAA返事

A何らかの理由で1 つの返信がドロップされ、次のエラー メッセージが表示されます。

error sending response: host unreachable

AAAAしかし、なぜ 2 番目のクエリが必要なのかは私にはわかりません。

同じ問題が発生しているかどうかを確認するには、次のタイムアウトを更新します/etc/resolv.conf

options timeout:3

まずテキストファイルを作成し、カスタム時間レポート設定:

cat >./curl-format.txt  <<-EOF
   time_namelookup: %{time_namelookup}\n
      time_connect: %{time_connect}\n
   time_appconnect: %{time_appconnect}\n
     time_redirect: %{time_redirect}\n
  time_pretransfer: %{time_pretransfer}\n
time_starttransfer: %{time_starttransfer}\n
                    ----------\n
time_total: %{time_total}\n
EOF

次にリクエストを送信します:

$ curl -w "@curl-format.txt" -o /dev/null -s https://example.com

            time_namelookup:  3.511
               time_connect:  3.511
            time_appconnect:  3.528
           time_pretransfer:  3.528
              time_redirect:  0.000
         time_starttransfer:  3.531
                            ----------
                 time_total:  3.531

には、他に 2 つの関連オプションがありますman resolv.conf

単一リクエスト (glibc 2.10 以降)を設定しますRES_SNGLKUP_res.optionsデフォルトでは、glibc はバージョン 2.9 以降、IPv4 と IPv6 のルックアップを並行して実行します。アプライアンス DNS サーバーによっては、これらのクエリを適切に処理できず、要求がタイムアウトになるものがあります。このオプションは、この動作を無効にし、glibc が IPv6 と IPv4 の要求を順番に実行するようにします (解決プロセスが若干遅くなります)。

単一要求再オープン (glibc 2.9 以降) リゾルバは、A 要求と AAAA 要求に同じソケットを使用します。一部のハードウェアは、誤って 1 つの応答のみを返します。その場合、クライアント システムは 2 番目の応答を待機します。このオプションをオンにすると、この動作が変更され、同じポートからの 2 つの要求が正しく処理されない場合、2 番目の要求を送信する前にソケットを閉じて新しいソケットを開きます。

関連する問題:

答え2

@Tombart が言うように、遅延は IPv6 解決のタイムアウトを待つために発生します。

もう一つの可能​​な対策としては、/etc/gai.confでIPv4を優先させることです。

/etc/gai.confのコメントより

#   For sites which prefer IPv4 connections change the last line to
#
precedence ::ffff:0:0/96  100

変更後gai.conf、変更を有効にするには、DNS リゾルバ ライブラリを使用しているすべてのアプリを再起動する必要があります。

ただし、IPv6 接続のない BIND サーバーを使用している場合は、IPv6 を無効にしてnamed、ルート ヒントから IPv6 アドレスを取得することをお勧めします。当然、AAAA アドレスの解決は引き続き試行されます。

BINDの設定については、

/etc/default/bind9 で、IPv4 アドレスの場合は -4 を追加します。

OPTIONS="-4 -u bind"

およびで/etc/bind/db.root、AAAA DNS ルートを含むすべての行を削除します。

答え3

BIND9 を使用しているときにも同様の問題が発生しました。これを修正するには、以下を追加する必要がありました。

filter-aaaa-on-v4 yes;

私のオプションnamed.conf

詳しくは

答え4

curl-format.txt を探している人がいる場合に備えて、これをシェルに貼り付けると、フォーマット ファイルが作成されます。元のリンクは機能しませんでした。この例を見つけました。ここ

cat >./curl-format.txt  <<-EOF
   time_namelookup: %{time_namelookup}\n
      time_connect: %{time_connect}\n
   time_appconnect: %{time_appconnect}\n
     time_redirect: %{time_redirect}\n
  time_pretransfer: %{time_pretransfer}\n
time_starttransfer: %{time_starttransfer}\n
                    ----------\n
time_total: %{time_total}\n
EOF

関連情報