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
IPv4を強制的にcurl
使用すると、状況ははるかに良くなります。
$ 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)
これは同じDNSサーバーを使用nslookup
または使用するため、ファイアウォールの問題ではないようです。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
とロギングのためにソケットを強制的に再利用することです。AAAA
A
/etc/resolv.conf
options single-request-reopen
この問題の実際の原因は次のとおりです。
- 誤って設定されたファイアウォールまたはルーター(例:ここで説明するジュニパーファイアウォールの設定) は
AAAA
DNS パケット損失を引き起こします。 - DNSサーバーエラー
長い答え:
curl
wget
glibcの機能に似ているか、それを使用するプログラム住所情報の取得()、DNSレコードを並列に照会し、IPv4およびIPv6の互換性を試みます。 2つのレコードが受信されるまで結果は返されません。この動作に関連するいくつかの問題) -strace
上記の内容を説明します。たとえば、IPv4を強制的に使用すると、curl -4
内部的にレコードのみが照会gethostbyname()
されますA
。
これからtcpdump
私たちは以下を見ることができます:
-> A?
最初に2つのリクエストを送信します。-> AAAA?
(IPv6 アドレス要求)<- AAAA
返信する-> A?
IPv4アドレスをもう一度リクエストしてください。<- A
返信をいただきました-> AAAA?
IPv6の再リクエスト<- AAAA
返信する
A
何らかの理由で返信が削除され、次のエラーメッセージが表示されます。
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解像度のタイムアウトを待つと遅延が発生します。
もう1つの可能性は、/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リゾルバーライブラリを使用するすべてのアプリケーションを再起動する必要があります。
named
IPv6接続なしでBINDサーバーを使用している場合は、IPv6を無効にしてルートプロンプトからIPv6アドレスを取得することをお勧めします。明らかにまだAAAAアドレスを確認しようとします。
したがって、BIND構成の場合
/etc/default/bind9 で IPv4 アドレスに -4 を追加します。
OPTIONS="-4 -u bind"
そして、.NETから/etc/bind/db.root
AAAA DNSルートを持つすべての行を削除します。
答え3
答え4
誰かがカール形式.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