DNS Cache - xapool/xapool.github.io GitHub Wiki

目录

DNS 缓存

Windows Mac 都有其自己的 DNS 缓存策略, Windows 可以使用 ipconfig /flushdns 命令来清除缓存,Mac 使用 dscacheutil -flushcache

但是在 Linux 下并没有系统级别的 DNS 缓存,除非系统安装并启用了 nscd。参见 Linux 下清除 DNS 缓存

Android DNS 缓存

Android 在 framework 层和虚拟机中,都对 DNS 的解析结果进行了缓存。应用查询 DNS 时,会先从 framework 层中查找,若没有再从虚拟机中查找,若还没有,则从网络查询。在 4.0 及其之前的版本中,framework 层中的 InetAddress 对查询成功结果缓存 10 分钟,失败的查询缓存 10s,之后 10s 内对于同一个域名的查询都会直接抛出 UnknownHostException。但在其后的版本,统一缓存为 2s,使用虚拟机的 DNS 缓存。

DNS caching In Android 4.0 (Ice Cream Sandwich) and earlier, DNS caching was performed both by InetAddress and by the C library, which meant that DNS TTLs could not be honored correctly.In later releases, caching is done solely by the C library and DNS TTLs are honored.

涉及到的类:

libcore/luni/src/main/java/java/net/InetAddress.java
libcore/luni/src/main/java/java/net/AddressCache.java

而虚拟机的 DNS 缓存时间 TTL,是可以使用 java 的 API 进行设置的。

Security.setProperty("networkaddress.cache.ttl", String.valueOf(0));
Security.setProperty("networkaddress.cache.negative.ttl", String.valueOf(0));

虚拟机层默认使用的缓存策略是将成功的查询永久缓存(在整个生命周期中),失败的查询只缓存 10s。

因此在应用开发中,针对远程服务器 IP 发生变化的情况,可以在 Application 的 onCreate() 里设置虚拟机不缓存DNS,这样每次解析域名时都会请求网络解析,确保得到的 IP 地址是最新的,至于 framework 层缓存的那 2s 就可以忽略了。或重启应用程序也可以。

但该方法在 4.0 及其之下的版本,并不起效,因为 framework 层对成功的解析结果会缓存 10min,因此可以在第一次域名解析成功后,将 IP 地址存到文件里,下次连接的时候优先使用保存的 IP 地址,只有当 IP 地址连接不上时或发生网络切换时,再进行域名解析,解析成功后,再次保存 IP。参考 android DNS cache

测试代码

参见 android/java设置DNS缓存

各 android 版本清空缓存方法

参见 resolver-commands

ping 抓包 DNS 解析过程

在 Android 上,把一个域名使用 iptables 禁止掉时,规则无法立即生效,在一定时间内依然 ping 的通。

参考 使用 Tcpdump 分析查看 DNS 通信过程,通过命令 tcpdump -i wlan0 -nt -s 500 -X port domain 观察其通信过程(还可以看到发送的16进制 ASCII 码),发现并没有任何请求通过,证明使用的是本地缓存,而且 iptables 规则中也无数据包通过。

但使用浏览器打开该网址时,是打不开的,查看 iptables 规则列表,发现数据包被成功 DROP 掉,tcpdump 也没有请求经过。难道是 ping 有自己的缓存策略?

⚠️ **GitHub.com Fallback** ⚠️