面试小抄本之网络协议篇
DNS 基本概念
- 域名 ( Domain Name ) 是一串点号分割的名字,不区分大小写;完全域名 ( Fully Qualified Domain Name, FQDN ) 包含所有的域名级别,能够完全定位在 DNS 树状图下的位置。
- DNS ( Domain Name System ) 即负责域名和 IP 地址映射的分布式数据库。早期主机名和 IP 地址的映射保存在 NIC 的 hosts 文件中,该方案随着互联网规模的膨胀而变得压力巨大;DNS 的分布式结构缓解了单一主机的瓶颈。
- 域名服务器 ( Domain Name Server ) 存储并管理所辖区域的域名数据库,负责接收来自地址解析器 ( Resolver ) 的请求并返回响应,按照请求的类型、进行递归与非递归查询。
1. 根域名服务器
DNS 中最高级别的域名服务器(即 .
) 负责返回顶级域名的权威域名服务器的地址。全球众多的根服务器被编号为A~M共13个编号,借助任播 ( Anycast ) 技术,编号相同的根服务器使用同一个 IP,全球都具备这些 IP 的镜像站点。关于根域的详细信息可以查看:http://www.iana.org/domains/root/
13个根域服务器是指逻辑上(相同 IP 地址)、而非物理上13台服务器。至于13怎么来的,原因是13组响应 ( 32 bytes IPv4 Address ) 是一个 512-Bytes UDP 包能容纳的数目
根域的运营主体(如 ICANN)可以中止镜像服务器的路由,比如国内因为发生 DNS 污染而被中断路由的事件。
2. 顶级域名
- 一般顶层域名 ( Generic TLDs, gTLD ) 如 .com, .gov, 包括一些新启用的域名如 .me
- 国家码顶层域名 ( Country code TLDs, ccTLD ) 如 .cn
各层 DNS 能够授权管理自己辖下的主机名或子域名,比如 .com 记录 example.com 的信息;每层 DNS 只能管理直接下级域中的主机。
层级结构带来的好处:
- 域名修改时,只需知会直接上一级域名服务器即可
- DNS 的分布式解析架构,也可以平衡流量压力
3. DNS 解析流程
当浏览器输入网址 wyh.life
-
DNS 客户端(如 Chrome 浏览器)解析某个域名时,会自动补全 FQDN,并查询客户端DNS缓存;Chrome DNS 缓存 TTL 是1分钟
-
当客户端 DNS 缓存不存在时,查询操作系统 DNS 缓存;如果仍不存在,尝试读取本地 hosts 文件
-
发送查询请求至 Local DNS,Local DNS 一般是由 ISP 分配。查询方式为递归解析,即 Local DNS 作为客户端持续向其它 DNS 服务器进行查询,直至解析成功或失败
$ cat /etc/resolv.conf nameserver 8.8.8.8
-
Local DNS 首先检查自己是否能够给出权威应答,即是否是为该 DNS Zone 的管理者
-
如果是非权威服务器时,则首先查询请求域名是否存在于缓存,如果有则直接返回;否则从 DNS 保存的根域 Zone File 中读取根服务器地址,并发起请求
; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> wyh.life +trace ;; global options: +cmd . 9095 IN NS a.root-servers.net. . 9095 IN NS b.root-servers.net. . 9095 IN NS c.root-servers.net. ... . 9095 IN NS m.root-servers.net. ;; Received 397 bytes from 8.8.8.8#53(8.8.8.8) in 5125 ms
-
根服务器返回 .life 域的权威 DNS 服务器(即 NS 记录)
life. 172800 IN NS demand.gamma.aridns.net.au. life. 172800 IN NS demand.delta.aridns.net.au. life. 172800 IN NS demand.beta.aridns.net.au. life. 172800 IN NS demand.alpha.aridns.net.au. ;; Received 576 bytes from 192.228.79.201#53(b.root-servers.net) in 114 ms
NS records identify an authoritative name server for a domain (more correctly, a DNS zone). They tell a DNS query where to look for authoritative detail about a domain (zone).
-
请求得到 wyh.life. 的权威 DNS 服务器
wyh.life. 86400 IN NS f1g1ns2.dnspod.net. wyh.life. 86400 IN NS f1g1ns1.dnspod.net. ;; Received 684 bytes from 37.209.196.7#53(demand.gamma.aridns.net.au) in 634 ms
-
请求得到A记录,地址解析完成
wyh.life. 86400 IN A 192.30.252.154 wyh.life. 86400 IN A 192.30.252.153 wyh.life. 86400 IN NS f1g1ns1.dnspod.net. wyh.life. 86400 IN NS f1g1ns2.dnspod.net. ;; Received 133 bytes from 182.140.167.188#53(f1g1ns2.dnspod.net) in 286 ms
注:如果得到的不是A地址,而是别名记录(CNAME,即将某个别名指向A记录),查询中止、并重新发起对别名的查询请求。
参考资料:How does dig +trace actually work?
注:DNS 负载均衡
- 循环 DNS ( Round-robin DNS) 单个域名、多个 IP 列表循环应对 DNS 查询,缺点是客户端一旦解析成功会使用缓存的解析记录,继而绕过了 DNS 服务器负载均衡。
4. 域名区域 ( DNS Zone )
DNS 数据库中针对每个域 ( Domain ) 的记录,称为一个域名区域 ( Zone )
关于区域和域的划分,参考文章:关于DNS的杂七杂八
每个区域通常包含:
- 名称服务器记录 ( Name Server, NS ) 表明有哪些 DNS 服务器负责解析
- 起始授权机构 ( Start of Authority, SOA ) 表明哪个 DNS 服务器是主服务器
- 主机记录 ( A / AAAA ) 将主机名映射到 IPv4 / IPv6 地址
(以下摘自:关于DNS的杂七杂八)
例如,服务器A是 a.com 的权威域名服务器,它将 test.a.com 子域授权给服务器B. 服务器A上有如下记录:
test.a.com. IN NS B.test.a.com.
B.test.com. IN A 1.2.3.4
B.test.a.com. 是服务器B的 FQDN,下边一条A记录称为 glue 记录,这样 test.com 域外的服务器能够通过 glue 记录找到服务器B.
服务器B作为区域 test.a.com 的权威域名服务器,包含一条 SOA 记录和一条 NS 记录。
DNS 攻击
DNS 污染
由于通常的 DNS 查询没有任何认证机制,且 DNS 查询主要基于无连接不可靠的 UDP,因此 DNS 查询非常容易被篡改。攻击者伪装成目标域名的解析服务器(NS)给查询者返回虚假结果,查询者只接受最先返回的格式正确结果,因此得到错误的 DNS 解析结果。
此外各级 DNS 服务器为了减少重复查询,会缓存 DNS 解析结果,一旦 DNS 查询被污染、后继查询请求都会被污染。
DNS 劫持
即 DNS 服务器返回非正确的查询结果,常见于 ISP 恶意劫持,比如 jQuery 等类库的 CDN 请求被调包为包含恶意或广告代码的返回文件。CDN 本质上也是一种 DNS 劫持(良性劫持)。
参考阅读:Google DNS劫持背后的技术分析
DNS 安全事件
1. 暴风影音导致断网
- 由于游戏私服互斗,DNSPod 遭受了 DDoS 攻击
- 由于流量压力,电信 IDC 在路由上封禁了 DNSPod 的IP地址,导致 DNSPod 的域名解析服务不可用
- 暴风影音自启的后台程序每15s左右与服务器通信,当解析不到地址会不断重试;而该域名解析服务由 DNSPod 提供
- 全国各地千万级别的电信暴风用户不断进行 DNS 查询,形成了对 DNS 递归查询服务器的 DDoS 攻击。UDP 传输是没有流控功能的,导致部分地区电信出口链路出现拥塞
- 网通因为有 DNS 绑架(解析不出来会返回网通广告页地址,而非返回 DNS SERVFAIL),所以网通线路基本没受影响
2. 百度域名劫持
社工攻击,黑客冒充管理员请求域名注册代理服务商 Register.com 修改了 baidu.com 的管理员邮箱,进而重置了管理员帐号、并修改了 baidu.com 的域名指向
DNS 安全策略
- 采用 UDP 随机端口,避免 DNS 缓存攻击
- 对于少数重要网站采用IP静态映射,不使用缓存或向上一级进行迭代查询,减少 DNS 欺骗攻击
- 限制查询,以避免泄漏内部的网络拓扑结构:在一个信任网域下,将 DNS 资料列出是没有问题的(即正常的主从服务器的 Zone Transfer),需要避免的是从外界进行任意查询。参考:DNS域传送信息泄露
相关实验
dig 介绍
工具可用 dig, host, nslookup.
dig (domain information groper) is a flexible tool for interrogating DNS name servers. It performs DNS lookups and displays the answers that are returned from the name server(s) that were queried.
A typical invocation of dig looks like:
dig @server name type
使用 dig 查看一条记录(RR, Resource Record)输出格式:
[Domain] [TTL] IN [RR Type] [[RR Data]]
参考:http://anouar.adlani.com/2011/12/useful-dig-command-to-troubleshot-your-domains.html
实验:查询 IP
$ dig wyh.life
;; ANSWER SECTION:
wyh.life. 85276 IN CNAME pages.coding.me.
pages.coding.me. 246 IN A 23.91.98.188
# Test on VPS
$ dig wyh.life
;; ANSWER SECTION:
wyh.life. 96 IN A 192.30.252.153
wyh.life. 96 IN A 192.30.252.154
对于国外线路,A记录指向了 Github Pages 的 DNS Zone ( 192.30.252.* ),详见 https://help.github.com/articles/setting-up-an-apex-domain/,国内线路则 CNAME 到 Coding Pages.
Github Pages / Coding Pages 主机上托管了无数站点,而对于这些站点的请求是通过 HTTP 头部的 Host 字段来识别的
$ curl --header "host: wyh.life" 192.30.252.153
$ curl --header "host: wyh.life" pages.coding.me
实验:查询 CNAME, NS
$ dig +short wyh.life cname
pages.coding.me.
# Test on VPS
$ dig wyh.life ns
f1g1ns1.dnspod.net.
f1g1ns2.dnspod.net.
实验:指定 DNS Server 查询
$ dig wyh.life @8.8.8.8 +short
192.30.252.153
192.30.252.154
$ dig wyh.life @114.114.114.114 +short
pages.coding.me.
23.91.98.188
实验:查询 SOA
$ dig wyh.life soa +multiline
;; ANSWER SECTION:
wyh.life. 600 IN SOA f1g1ns1.dnspod.net. freednsadmin.dnspod.com. (
1460108051 ; serial
3600 ; refresh (1 hour)
180 ; retry (3 minutes)
1209600 ; expire (2 weeks)
180 ; minimum (3 minutes)
)
f1g1ns1.dnspod.net.
: SOA 主机地址freednsadmin.dnspod.com.
: 标识联系邮件,即 freednsadmin@dnspod.com1460108051; serial
: 标识域名信息变化的序列号,每次域名变化时该项数值增大3600; refresh
: 标识备用 DNS 服务器查询主服务器中序列号是否增加(即域文件变化)的间隔时间180; retry
: 标识备用 DNS 服务器无法连接主服务器时重试间隔时间1209600; expire
: 标识备用 DNS 服务器无法连接主服务器时,可以在多长时间内认为缓存有效180; minimum
: 标识缓存 DNS 服务器可以缓存记录多长时间
实验:查询 MX
$ dig mx gmail.com
;; ANSWER SECTION:
gmail.com. 3263 IN MX 10 alt1.gmail-smtp-in.l.google.com.
gmail.com. 3263 IN MX 30 alt3.gmail-smtp-in.l.google.com.
gmail.com. 3263 IN MX 5 gmail-smtp-in.l.google.com.
gmail.com. 3263 IN MX 20 alt2.gmail-smtp-in.l.google.com.
gmail.com. 3263 IN MX 40 alt4.gmail-smtp-in.l.google.com.
# Or try
$ nslookup -query=mx gmail.com
MX 应答的格式:
[Domain] [TTL] IN MX [Preference] [Exchange]
Preference 标识优先级(0~65535,越小优先级越高),Exchange 为主机域名。
The domain names that a Sender-SMTP sends in MAIL and RCPT commands MUST have been “canonicalized”, i.e., they must be fully-qualified principal names or domain literals, not nicknames or domain abbreviations. A canonicalized name either identifies a host directly or is an MX names; it cannot be a CNAME
- 某条 MX 记录的 Exchange 不可访问(比如被 Block)、可能导致邮件发送失败,原因可能在于邮件发送服务没有遵循 RFC 定义的 MX 重试规则。
- 一些海外邮件代收服务,也是通过添加 MX 记录来实现的。
实验:查询 IP 对应的主机名
$ dig -x 114.114.114.114 +short
public1.114dns.com.
实验:查询顶级域名的 NS
$ dig NS life. +short
demand.alpha.aridns.net.au.
demand.beta.aridns.net.au.
demand.delta.aridns.net.au.
demand.gamma.aridns.net.au.
可以从 ICANN 官方 Wiki 查看顶级域名(TLD)详细信息,如 http://icannwiki.com/.life
$ dig NS com. +short | sort
a.gtld-servers.net.
b.gtld-servers.net.
c.gtld-servers.net.
d.gtld-servers.net.
e.gtld-servers.net.
f.gtld-servers.net.
g.gtld-servers.net.
h.gtld-servers.net.
i.gtld-servers.net.
j.gtld-servers.net.
k.gtld-servers.net.
l.gtld-servers.net.
m.gtld-servers.net.
测试根域 / com域 的权威解析服务,可以尝试如下脚本(参考自 http://blog.fenghe.org/archives/1839#more-1839)
for i in a b c d e f g h i j k l m; do
echo $i.root-servers.net
dig wyh.life @$i.root-servers.net | grep 'Query time'
# echo @$i.gtld-servers.net
# dig wyh.life @$i.gtld-servers.net | grep 'Query time'
echo
done
对于不常访问的域名,各地的递归服务器里没有缓存,会向上查询。而上一级的权威NS(如com/net域)、以及根DNS都大规模访问失败,从而导致域名解析超时,或无法解析。
摘自:http://blog.fenghe.org/archives/927,原文有更精彩的内容
通过 Chrome 查看 DNS 解析情况
- Chrome 访问 chrome://net-internals#dns 查看 DNS 记录
- Chrome 访问 chrome://histograms/DNS.ResolveSuccess 查看 DNS 解析的耗时分布统计
左侧第一栏数字为解析耗时(毫秒),从直方图可以看出解析耗时的分布,比如 ~50% 的 DNS 解析在 50ms 内完成,90% 是在 150ms 内。