Jamal的博客

gethostbyname与DNS

首先,这个文档不错:https://lfckop.github.io/gethostbyname-and-DNS/

下午验证商户的时候发现一个奇怪的问题,商户本地没绑host,但是仍然只能访问到一个ip,后来排查是因为对方机器本地有nscd进程在跑(这里不得不吐槽,不是自己的机器找人执行命令真是难),中间有一个比较有意思的事情,ping的时候只能ping到一个ip,但是dig能跑出两个,这个其实比较容易知道是什么原因导致的,但是这里就有一个比较有意思的点可以去探究的:
我们都清楚或者说知道DNS解析的大概流程,也大概知道可能会有host绑定、缓存等等的情况出现,但是细想一下好像都说不清具体在代码层面Linux系统是怎么去做这件事情的,所以不妨手动做一下测试,看看究竟是怎么做的。

我们从ping开始,首先ltrace跟踪一下ping的代码执行过程:ltrace ping -c 1 baidu.com 2>&1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@izj6c3cqwumhn7qc8it7wiz log]# ltrace ping -c 1 baidu.com 2>&1 | grep get
cap_get_proc(0x7ffcb9159230, 0x7ffcb9159348, 0x7ffcb9159370, 0) = 0x55dc4ce20014
cap_get_flag(0x55dc4ce20014, 12, 1, 0x7ffcb9159194) = 0
cap_get_flag(0x55dc4ce20014, 13, 1, 0x7ffcb9159194) = 0
getuid() = 0
getuid() = 0
geteuid() = 0
getopt(4, 0x7ffcb9159348, "h?4bRT:6F:N:aABc:dDfi:I:l:Lm:M:n"...) = 99
getopt(4, 0x7ffcb9159348, "h?4bRT:6F:N:aABc:dDfi:I:l:Lm:M:n"...) = -1
cap_get_proc(13, 1, 3, 0) = 0x55dc4ce20014
cap_get_flag(0x55dc4ce20014, 13, 1, 0x7ffcb9159194) = 0
cap_get_proc(13, 0, 1, -1) = 0x55dc4ce20014
cap_get_flag(0x55dc4ce20014, 13, 1, 0x7ffcb9159194) = 0
getaddrinfo("baidu.com", nil, 0x7ffcb9159200, 0x7ffcb91591d8) = 0
getsockname(4, 0x55dc4c3fa070, 0x7ffcb9158cec, -1) = 0
getsockopt(3, 1, 8, 0x7ffcb9158ca0) = 0
getpid() = 16594
gettimeofday(0x55dc4c3fc6c0, nil) = 0
gettimeofday(0x55dc4c3fe6f0, nil) = 0
gettimeofday(0x7ffcb9157ad0, nil) = 0
getnameinfo(0x7ffcb9157c00, 16, "", 1025, nil, 0, 33) = 0
getnameinfo(0x7ffcb9157c00, 16, "", 1025, nil, 0, 32) = 0

至于为啥我要执行grep get,只是知道以前写echoserver这种tcp应用的时候会用到gethostbyname而已,哈哈。
不过这里是没有这个函数的,但是我注意到了有这么一个函数:getaddrinfo,man一下看到了

1
2
3
4
Given node and service, which identify an Internet host and a service, getaddrinfo() returns one or more addrinfo structures, each
of which contains an Internet address that can be specified in a call to bind(2) or connect(2). The getaddrinfo() function combines
the functionality provided by the gethostbyname(3) and getservbyname(3) functions into a single interface, but unlike the latter
functions, getaddrinfo() is reentrant and allows programs to eliminate IPv4-versus-IPv6 dependencies.

其实就是gethostbyname和getservbyname的结果封装了一下,只是gethostbyname被认为是一个已经过期的函数,正好我这个系统是centos7的,ping的版本也比较高,默认用了getaddrinfo,这里我们忽略其中的差异,直接用gethostbyname来做实验,先写一串代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[root@izj6c3cqwumhn7qc8it7wiz c]# cat gethostbyname.c
#include <sys/types.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
main(int argc, char *argv[])
{
struct hostent *hp;
struct in_addr ip_addr;
/* Verify a "hostname" parameter was supplied */
if (argc <1 || *argv[1] == '\0')
exit(EXIT_FAILURE);
/* call gethostbyname() with a host name. gethostbyname() returns a */
/* pointer to a hostent struct or NULL. */
hp = gethostbyname(argv[1]);
if (!hp) {
printf("%s was not resolved\n",argv[1]);
exit(EXIT_FAILURE);
}
/* move h_addr to ip_addr. This enables conversion to a form */
/* suitable for printing with the inet_ntoa() function. */
ip_addr = *(struct in_addr *)(hp->h_addr);
printf("Hostname: %s, was resolved to: %s\n",
argv[1],inet_ntoa(ip_addr));
exit(EXIT_SUCCESS);
}

编译一下,用./gethostbyname “intl.alipay.com” 就能直接运行,于是下面开始做实验。

实验过程

  • 常规使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
[root@izj6c3cqwumhn7qc8it7wiz c]# strace ./gethostbyname "intl.alipay.com" 2>&1 | grep -vE "mmap|munmap|mprotect"
execve("./gethostbyname", ["./gethostbyname", "intl.alipay.com"], [/* 26 vars */]) = 0
brk(NULL) = 0x2522000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=50151, ...}) = 0
close(3) = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2127336, ...}) = 0
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7fe0a622f740) = 0
brk(NULL) = 0x2522000
brk(0x2543000) = 0x2543000
brk(NULL) = 0x2543000
getpid() = 15961
open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=108, ...}) = 0
read(3, "nameserver 100.100.2.138\nnameser"..., 4096) = 108
read(3, "", 4096) = 0
close(3) = 0
uname({sysname="Linux", nodename="izj6c3cqwumhn7qc8it7wiz", ...}) = 0
socket(AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ECONNREFUSED (Connection refused)
close(3) = 0
socket(AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ECONNREFUSED (Connection refused)
close(3) = 0
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=1747, ...}) = 0
read(3, "#\n# /etc/nsswitch.conf\n#\n# An ex"..., 4096) = 1747
read(3, "", 4096) = 0
close(3) = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=50151, ...}) = 0
close(3) = 0
open("/lib64/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\220\20\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=27776, ...}) = 0
close(3) = 0
open("/lib64/libresolv.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\3209\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=111080, ...}) = 0
close(3) = 0
open("/etc/host.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=9, ...}) = 0
read(3, "multi on\n", 4096) = 9
read(3, "", 4096) = 0
close(3) = 0
socket(AF_INET, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("100.100.2.136")}, 16) = 0
poll([{fd=3, events=POLLOUT}], 1, 0) = 1 ([{fd=3, revents=POLLOUT}])
sendto(3, "\3146\1\0\0\1\0\0\0\0\0\0\4intl\6alipay\3com\0\0\1\0"..., 33, MSG_NOSIGNAL, NULL, 0) = 33
poll([{fd=3, events=POLLIN}], 1, 2000) = 1 ([{fd=3, revents=POLLIN}])
ioctl(3, FIONREAD, [263]) = 0
recvfrom(3, "\3146\201\200\0\1\0\3\0\4\0\6\4intl\6alipay\3com\0\0\1\0"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("100.100.2.136")}, [16]) = 263
close(3) = 0
fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
write(1, "Hostname: intl.alipay.com, was r"..., 60Hostname: intl.alipay.com, was resolved to: 205.204.107.201
) = 60
exit_group(0) = ?
+++ exited with 0 +++

这里可以看到gethostbyname(也就是ping)的具体执行流程,具体来说分为:

  1. 读/etc/resolv.conf文件,将dnsserver读入到内存中;
  2. 连接本地/var/run/nscd/socket(即有nscd在跑的时候就会有nscd的socket,AF_LOCAL说明连接是本地socket),连接通的话直接从nscd缓存请求,如果两次不通则进入3;
  3. 读/etc/nsswitch.conf文件,寻找其中的hosts: files dns myhostname配置,其中files表示只从hosts文件取数据,dns表示执行DNS请求拿数据,这里表示优先从hosts拿,拿不到就执行DNS请求
  4. 读/etc/host.conf文件,其中
1
2
3
order hosts,bind # 表示优先从hosts取信息,然后从bind取信息
#order bind,hosts
multi on # multi on指定是否/etc/hosts文件中指定的主机可以有多个地址,拥有多个IP地址的主机一般称为多穴主机。
  1. 最后如果hosts中无信息或未配置可以从hosts中取数据,那就发起DNS请求获取结果。
    其中需要关注:
  2. 条件必须要顺序满足才能生效:即如果要在步骤4中执行host文件查找,步骤3一定要支持host。但是步骤3执行host,不需要步骤4支持host
  • /etc/host.conf中配置order bind,hosts && /etc/hosts中绑定198.11.148.201 intl.alipay.com
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
[root@izj6c3cqwumhn7qc8it7wiz c]# strace ./gethostbyname "intl.alipay.com" 2>&1 | grep -vE "mmap|munmap|mprotect"
execve("./gethostbyname", ["./gethostbyname", "intl.alipay.com"], [/* 26 vars */]) = 0
brk(NULL) = 0x82a000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=50151, ...}) = 0
close(3) = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2127336, ...}) = 0
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f2905d51740) = 0
brk(NULL) = 0x82a000
brk(0x84b000) = 0x84b000
brk(NULL) = 0x84b000
getpid() = 16063
open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=108, ...}) = 0
read(3, "nameserver 100.100.2.138\nnameser"..., 4096) = 108
read(3, "", 4096) = 0
close(3) = 0
uname({sysname="Linux", nodename="izj6c3cqwumhn7qc8it7wiz", ...}) = 0
socket(AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ECONNREFUSED (Connection refused)
close(3) = 0
socket(AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ECONNREFUSED (Connection refused)
close(3) = 0
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=1747, ...}) = 0
read(3, "#\n# /etc/nsswitch.conf\n#\n# An ex"..., 4096) = 1747
read(3, "", 4096) = 0
close(3) = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=50151, ...}) = 0
close(3) = 0
open("/lib64/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\220\20\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=27776, ...}) = 0
close(3) = 0
open("/lib64/libresolv.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\3209\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=111080, ...}) = 0
close(3) = 0
open("/etc/host.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=26, ...}) = 0
read(3, "order hosts,bind\nmulti on\n", 4096) = 26
read(3, "", 4096) = 0
close(3) = 0
socket(AF_INET, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("100.100.2.136")}, 16) = 0
poll([{fd=3, events=POLLOUT}], 1, 0) = 1 ([{fd=3, revents=POLLOUT}])
sendto(3, "v\255\1\0\0\1\0\0\0\0\0\0\4intl\6alipay\3com\0\0\1\0"..., 33, MSG_NOSIGNAL, NULL, 0) = 33
poll([{fd=3, events=POLLIN}], 1, 2000) = 1 ([{fd=3, revents=POLLIN}])
ioctl(3, FIONREAD, [263]) = 0
recvfrom(3, "v\255\201\200\0\1\0\3\0\4\0\6\4intl\6alipay\3com\0\0\1\0"..., 1024, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("100.100.2.136")}, [16]) = 263
close(3) = 0
fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
write(1, "Hostname: intl.alipay.com, was r"..., 59Hostname: intl.alipay.com, was resolved to: 198.11.148.201
) = 59
exit_group(0) = ?
+++ exited with 0 +++
[root@izj6c3cqwumhn7qc8it7wiz c]# ping intl.alipay.com
PING ihome.alipaydns.com (205.204.107.201) 56(84) bytes of data.
64 bytes from 205.204.107.201: icmp_seq=1 ttl=44 time=161 ms
64 bytes from 205.204.107.201: icmp_seq=2 ttl=44 time=161 ms
^C
--- ihome.alipaydns.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 3089ms
rtt min/avg/max/mdev = 161.470/161.489/161.508/0.019 ms
[root@izj6c3cqwumhn7qc8it7wiz c]# vi /etc/host.conf
[root@izj6c3cqwumhn7qc8it7wiz c]# ping intl.alipay.com
PING ihome.alipaydns.com (198.11.148.201) 56(84) bytes of data.
64 bytes from 198.11.148.201 (198.11.148.201): icmp_seq=1 ttl=42 time=163 ms
64 bytes from 198.11.148.201 (198.11.148.201): icmp_seq=2 ttl=42 time=163 ms
^C
--- ihome.alipaydns.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 163.456/163.460/163.464/0.004 ms
  • /etc/nsswitch.conf中配置hosts: files && /etc/hosts不绑定host时
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
[root@izj6c3cqwumhn7qc8it7wiz c]# cat /etc/nsswitch.conf | grep hosts
#hosts: db files nisplus nis dns
#hosts: files dns myhostname
hosts: files
[root@izj6c3cqwumhn7qc8it7wiz c]# strace ./gethostbyname "intl.alipay.com" 2>&1 | grep -vE "mmap|munmap|mprotect|brk"
execve("./gethostbyname", ["./gethostbyname", "intl.alipay.com"], [/* 26 vars */]) = 0
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=50151, ...}) = 0
close(3) = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2127336, ...}) = 0
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7f07bdf5c740) = 0
getpid() = 16099
open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=108, ...}) = 0
read(3, "nameserver 100.100.2.138\nnameser"..., 4096) = 108
read(3, "", 4096) = 0
close(3) = 0
uname({sysname="Linux", nodename="izj6c3cqwumhn7qc8it7wiz", ...}) = 0
socket(AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ECONNREFUSED (Connection refused)
close(3) = 0
socket(AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = -1 ECONNREFUSED (Connection refused)
close(3) = 0
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=1765, ...}) = 0
read(3, "#\n# /etc/nsswitch.conf\n#\n# An ex"..., 4096) = 1765
read(3, "", 4096) = 0
close(3) = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=50151, ...}) = 0
close(3) = 0
open("/lib64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320!\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=62184, ...}) = 0
close(3) = 0
open("/etc/host.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=44, ...}) = 0
read(3, "#order hosts,bind\norder bind,hos"..., 4096) = 44
read(3, "", 4096) = 0
close(3) = 0
open("/etc/hosts", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=224, ...}) = 0
read(3, "127.0.0.1 localhost localhost."..., 4096) = 224
read(3, "", 4096) = 0
close(3) = 0
fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
write(1, "intl.alipay.com was not resolved"..., 33intl.alipay.com was not resolved
) = 33
exit_group(1) = ?
+++ exited with 1 +++
  • nscd开启,相关的配置如下
    配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[root@izj6c3cqwumhn7qc8it7wiz ~]# nscd -g
nscd configuration:
5 server debug level
3m 13s server runtime
4 current number of threads
32 maximum number of threads
0 number of times clients had to wait
no paranoia mode enabled
3600 restart internal
3 reload count
hosts cache:
yes cache is enabled
yes cache is persistent
yes cache is shared
211 suggested size
216064 total data pool size
232 used data pool size
10 seconds time to live for positive entries
5 seconds time to live for negative entries
0 cache hits on positive entries
0 cache hits on negative entries
36 cache misses on positive entries
25 cache misses on negative entries
0% cache hit rate
1 current number of cached values
6 maximum number of cached values
1 maximum chain length searched
0 number of delays on rdlock
0 number of delays on wrlock
0 memory allocations failed
yes check /etc/hosts for changes

其中hosts cache代表是host文件的缓存配置,具体每个参数的含义可以参考这里:https://linux.die.net/man/5/nscd.conf 这里代表的意思是host中配置的,每15s(10+5,不知道为啥要两个值分开这样设计?) reload一次,reload 3次仍然无新连接的话就从缓存中删除。但是查文档没有看到没在host文件中的域名的缓存策略。
下面是相关的实验:

  • /etc/hosts中绑定205.204.107.201 intl.alipay.com
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    [root@izj6c3cqwumhn7qc8it7wiz c]# strace ./gethostbyname "intl.alipay.com" 2>&1 | grep -vE "mmap|munmap|mprotect|brk"
    execve("./gethostbyname", ["./gethostbyname", "intl.alipay.com"], [/* 26 vars */]) = 0
    access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
    open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=50151, ...}) = 0
    close(3) = 0
    open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
    read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0755, st_size=2127336, ...}) = 0
    close(3) = 0
    arch_prctl(ARCH_SET_FS, 0x7f3a4277d740) = 0
    getpid() = 16555
    open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=108, ...}) = 0
    read(3, "nameserver 100.100.2.138\nnameser"..., 4096) = 108
    read(3, "", 4096) = 0
    close(3) = 0
    uname({sysname="Linux", nodename="izj6c3cqwumhn7qc8it7wiz", ...}) = 0
    socket(AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
    connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = 0
    sendto(3, "\2\0\0\0\r\0\0\0\6\0\0\0hosts\0", 18, MSG_NOSIGNAL, NULL, 0) = 18
    poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 5000) = 1 ([{fd=3, revents=POLLIN|POLLHUP}])
    recvmsg(3, {msg_name(0)=NULL, msg_iov(2)=[{"hosts\0", 6}, {"\310O\3\0\0\0\0\0", 8}], msg_controllen=20, [{cmsg_len=20, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS, [4]}], msg_flags=MSG_CMSG_CLOEXEC}, MSG_CMSG_CLOEXEC) = 14
    close(4) = 0
    close(3) = 0
    socket(AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
    connect(3, {sa_family=AF_LOCAL, sun_path="/var/run/nscd/socket"}, 110) = 0
    sendto(3, "\2\0\0\0\4\0\0\0\20\0\0\0intl.alipay.com\0", 28, MSG_NOSIGNAL, NULL, 0) = 28
    poll([{fd=3, events=POLLIN|POLLERR|POLLHUP}], 1, 5000) = 1 ([{fd=3, revents=POLLIN|POLLHUP}])
    read(3, "\2\0\0\0\1\0\0\0\20\0\0\0\0\0\0\0\2\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0", 32) = 32
    readv(3, [{"intl.alipay.com\0", 16}, {"\315\314k\311", 4}], 2) = 20
    close(3) = 0
    fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
    write(1, "Hostname: intl.alipay.com, was r"..., 60Hostname: intl.alipay.com, was resolved to: 205.204.107.201
    ) = 60
    exit_group(0) = ?
    +++ exited with 0 +++

确实是走的nscd的缓存去请求dns的(仍然是连接nscd的socket,只是这是一个本地请求,从这一句中可以看出来:connect(3, {sa_family=AF_LOCAL, sun_path=”/var/run/nscd/socket”}, 110) )
请求后状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Thu 14 Dec 2017 01:26:15 AM CST - 16531: handle_request: request received (Version = 2) from PID 16555
Thu 14 Dec 2017 01:26:15 AM CST - 16531: GETFDHST
Thu 14 Dec 2017 01:26:15 AM CST - 16531: provide access to FD 7, for hosts
Thu 14 Dec 2017 01:26:15 AM CST - 16531: handle_request: request received (Version = 2) from PID 16555
Thu 14 Dec 2017 01:26:15 AM CST - 16531: GETHOSTBYNAME (intl.alipay.com)
Thu 14 Dec 2017 01:26:15 AM CST - 16531: Haven't found "intl.alipay.com" in hosts cache!
Thu 14 Dec 2017 01:26:15 AM CST - 16531: add new entry "intl.alipay.com" of type GETHOSTBYNAME for hosts to cache (first)
Thu 14 Dec 2017 01:26:36 AM CST - 16531: pruning hosts cache; time 1513185996
Thu 14 Dec 2017 01:26:36 AM CST - 16531: considering GETAI entry "icashier.alipay.com", timeout 1513186041
Thu 14 Dec 2017 01:26:36 AM CST - 16531: considering GETHOSTBYNAME entry "intl.alipay.com", timeout 1513185985
Thu 14 Dec 2017 01:26:36 AM CST - 16531: Reloading "intl.alipay.com" in hosts cache!
Thu 14 Dec 2017 01:26:51 AM CST - 16531: pruning hosts cache; time 1513186011
Thu 14 Dec 2017 01:26:51 AM CST - 16531: considering GETAI entry "icashier.alipay.com", timeout 1513186041
Thu 14 Dec 2017 01:26:51 AM CST - 16531: considering GETHOSTBYNAME entry "intl.alipay.com", timeout 1513186006
Thu 14 Dec 2017 01:26:51 AM CST - 16531: Reloading "intl.alipay.com" in hosts cache!
Thu 14 Dec 2017 01:27:06 AM CST - 16531: pruning hosts cache; time 1513186026
Thu 14 Dec 2017 01:27:06 AM CST - 16531: considering GETAI entry "icashier.alipay.com", timeout 1513186041
Thu 14 Dec 2017 01:27:06 AM CST - 16531: considering GETHOSTBYNAME entry "intl.alipay.com", timeout 1513186021
Thu 14 Dec 2017 01:27:06 AM CST - 16531: Reloading "intl.alipay.com" in hosts cache!
Thu 14 Dec 2017 01:27:21 AM CST - 16531: pruning hosts cache; time 1513186041
Thu 14 Dec 2017 01:27:21 AM CST - 16531: considering GETAI entry "icashier.alipay.com", timeout 1513186041
Thu 14 Dec 2017 01:27:21 AM CST - 16531: considering GETHOSTBYNAME entry "intl.alipay.com", timeout 1513186036
Thu 14 Dec 2017 01:27:21 AM CST - 16531: remove GETHOSTBYNAME entry "intl.alipay.com"

第一段是因为手动清理过缓存的原因,实际上应用启动时会首次加载,这里由于清理过缓存,需要请求触发加载。
第一段到第二段中间耗时是21s,这个值是怎么来的,官方文档中没有说明,暂时也先不看了,有空看下代码实现。二三四五中间是耗时15s,是符合预期的,第五次的时候intl域名的缓存就被清理掉了,要想加载就只能请求触发。
而不在hosts中的cache,就比较诡异了,看一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Thu 14 Dec 2017 01:45:34 AM CST - 16531: handle_request: request received (Version = 2) from PID 16576
Thu 14 Dec 2017 01:45:34 AM CST - 16531: GETFDHST
Thu 14 Dec 2017 01:45:34 AM CST - 16531: provide access to FD 7, for hosts
Thu 14 Dec 2017 01:45:34 AM CST - 16531: handle_request: request received (Version = 2) from PID 16576
Thu 14 Dec 2017 01:45:34 AM CST - 16531: GETAI (icashier.alipay.com)
Thu 14 Dec 2017 01:45:34 AM CST - 16531: Haven't found "icashier.alipay.com" in hosts cache!
Thu 14 Dec 2017 01:45:34 AM CST - 16531: add new entry "icashier.alipay.com" of type GETAI for hosts to cache (first)
Thu 14 Dec 2017 01:45:34 AM CST - 16531: handle_request: request received (Version = 2) from PID 16576
Thu 14 Dec 2017 01:45:34 AM CST - 16531: GETHOSTBYADDR (205.204.107.155)
Thu 14 Dec 2017 01:45:34 AM CST - 16531: Haven't found "205.204.107.155" in hosts cache!
Thu 14 Dec 2017 01:45:38 AM CST - 16531: add new entry "205.204.107.155" of type GETHOSTBYADDR for hosts to cache (first)
Thu 14 Dec 2017 01:45:43 AM CST - 16531: pruning hosts cache; time 1513187143
Thu 14 Dec 2017 01:45:43 AM CST - 16531: considering GETHOSTBYADDR entry "205.204.107.155", timeout 1513187143
Thu 14 Dec 2017 01:45:43 AM CST - 16531: considering GETAI entry "icashier.alipay.com", timeout 1513187194
Thu 14 Dec 2017 01:45:58 AM CST - 16531: pruning hosts cache; time 1513187158
Thu 14 Dec 2017 01:45:58 AM CST - 16531: considering GETHOSTBYADDR entry "205.204.107.155", timeout 1513187143
Thu 14 Dec 2017 01:45:58 AM CST - 16531: considering GETAI entry "icashier.alipay.com", timeout 1513187194
Thu 14 Dec 2017 01:45:58 AM CST - 16531: remove GETHOSTBYADDR entry "205.204.107.155"
Thu 14 Dec 2017 01:46:34 AM CST - 16531: pruning hosts cache; time 1513187194
Thu 14 Dec 2017 01:46:34 AM CST - 16531: considering GETAI entry "icashier.alipay.com", timeout 1513187194
Thu 14 Dec 2017 01:46:49 AM CST - 16531: pruning hosts cache; time 1513187209
Thu 14 Dec 2017 01:46:49 AM CST - 16531: considering GETAI entry "icashier.alipay.com", timeout 1513187194
Thu 14 Dec 2017 01:46:49 AM CST - 16531: Reloading "icashier.alipay.com" in hosts cache!
Thu 14 Dec 2017 01:47:49 AM CST - 16531: pruning hosts cache; time 1513187269
Thu 14 Dec 2017 01:47:49 AM CST - 16531: considering GETAI entry "icashier.alipay.com", timeout 1513187269
Thu 14 Dec 2017 01:48:04 AM CST - 16531: pruning hosts cache; time 1513187284
Thu 14 Dec 2017 01:48:04 AM CST - 16531: considering GETAI entry "icashier.alipay.com", timeout 1513187269
Thu 14 Dec 2017 01:48:04 AM CST - 16531: Reloading "icashier.alipay.com" in hosts cache!
Thu 14 Dec 2017 01:48:04 AM CST - 16531: add new entry "icashier.alipay.com" of type GETAI for hosts to cache (first)
Thu 14 Dec 2017 01:48:04 AM CST - 16531: remove GETAI entry "icashier.alipay.com"
Thu 14 Dec 2017 01:48:04 AM CST - 16531: freed 232 bytes in hosts cache

实在没找出啥规律,后面再找找文档研究下吧。唯一确定的是在访问后确实缓存住了,重新访问的时候是直接从缓存取的,商户的请求每分钟都有十几笔,所以缓存也不会过期。