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 호환을 시도합니다. 두 개의 레코드가 수신될 때까지 결과를 반환하지 않습니다.이 동작과 관련된 몇 가지 문제) - strace
위와 같은 내용이 설명됩니다. 예를 들어 IPv4를 강제로 사용하는 경우 curl -4
내부적으로 레코드만 gethostbyname()
쿼리됩니다 A
.
이것으로부터 tcpdump
우리는 다음을 볼 수 있습니다:
-> A?
처음에 두 개의 요청을 보냅니다.-> AAAA?
(IPv6 주소 요청)<- AAAA
회신하다-> A?
IPv4 주소를 다시 요청하세요.<- A
답장을 받았습니다-> AAAA?
IPv6 다시 요청<- AAAA
회신하다
A
어떤 이유로 답글이 삭제되었으며 다음과 같은 오류 메시지가 표시됩니다.
error sending response: host unreachable
AAAA
그러나 두 번째 쿼리가 필요한 이유는 명확하지 않습니다 .
동일한 문제가 발생하는지 확인하려면 다음에서 시간 초과를 업데이트할 수 있습니다 /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
다른 두 가지 관련 옵션이 있습니다 man resolv.conf
.
단일 요청(glibc 2.10부터)설정 기본적
RES_SNGLKUP
으로_res.options
glibc는 버전 2.9부터 IPv4 및 IPv6 조회를 병렬로 수행합니다. 일부 장치 DNS 서버는 이러한 쿼리를 올바르게 처리하지 않아 요청 시간이 초과됩니다. 이 옵션은 이 동작을 비활성화하고 glibc가 IPv6 및 IPv4 요청을 순차적으로 수행하도록 합니다(구문 분석 프로세스가 느려지지만).단일 요청 다시 열기(glibc 2.9부터) 확인자는 A 및 AAAA 요청에 동일한 소켓을 사용합니다. 일부 하드웨어는 하나의 응답만 잘못 돌려보냅니다. 이런 일이 발생하면 클라이언트 시스템은 앉아서 두 번째 응답을 기다립니다. 이 옵션을 켜면 이 동작이 변경되어 동일한 포트의 두 요청이 올바르게 처리되지 않으면 두 번째 요청을 보내기 전에 소켓을 닫고 새 소켓을 엽니다.
관련 질문:
답변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 확인자 라이브러리를 사용하는 모든 애플리케이션을 다시 시작해야 합니다.
named
IPv6 연결 없이 BIND 서버를 사용하는 경우 IPv6를 비활성화 하고 루트 프롬프트에서 IPv6 주소를 가져오는 것이 좋습니다 . 분명히 여전히 AAAA 주소를 확인하려고 시도할 것입니다.
따라서 BIND 구성의 경우
/etc/default/bind9에서 IPv4 주소에 -4를 추가합니다.
OPTIONS="-4 -u bind"
그리고 .NET에서 /etc/bind/db.root
AAAA DNS 루트가 있는 모든 행을 삭제합니다 .
답변3
BIND9를 사용하여 비슷한 문제가 발생했습니다. 이 문제를 해결하려면 다음을 추가해야 합니다.
filter-aaaa-on-v4 yes;
내 옵션 named.conf
.
(추가 정보)
답변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