面试小抄本之网络协议篇

    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

    1. DNS 客户端(如 Chrome 浏览器)解析某个域名时,会自动补全 FQDN,并查询客户端DNS缓存;Chrome DNS 缓存 TTL 是1分钟

    2. 当客户端 DNS 缓存不存在时,查询操作系统 DNS 缓存;如果仍不存在,尝试读取本地 hosts 文件

    3. 发送查询请求至 Local DNS,Local DNS 一般是由 ISP 分配。查询方式为递归解析,即 Local DNS 作为客户端持续向其它 DNS 服务器进行查询,直至解析成功或失败

      1. $ cat /etc/resolv.conf
      2. nameserver 8.8.8.8
    4. Local DNS 首先检查自己是否能够给出权威应答,即是否是为该 DNS Zone 的管理者

    5. 如果是非权威服务器时,则首先查询请求域名是否存在于缓存,如果有则直接返回;否则从 DNS 保存的根域 Zone File 中读取根服务器地址,并发起请求

      1. ; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> wyh.life +trace
      2. ;; global options: +cmd
      3. . 9095 IN NS a.root-servers.net.
      4. . 9095 IN NS b.root-servers.net.
      5. . 9095 IN NS c.root-servers.net.
      6. ...
      7. . 9095 IN NS m.root-servers.net.
      8. ;; Received 397 bytes from 8.8.8.8#53(8.8.8.8) in 5125 ms
    6. 根服务器返回 .life 域的权威 DNS 服务器(即 NS 记录)

      1. life. 172800 IN NS demand.gamma.aridns.net.au.
      2. life. 172800 IN NS demand.delta.aridns.net.au.
      3. life. 172800 IN NS demand.beta.aridns.net.au.
      4. life. 172800 IN NS demand.alpha.aridns.net.au.
      5. ;; 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).

    7. 请求得到 wyh.life. 的权威 DNS 服务器

      1. wyh.life. 86400 IN NS f1g1ns2.dnspod.net.
      2. wyh.life. 86400 IN NS f1g1ns1.dnspod.net.
      3. ;; Received 684 bytes from 37.209.196.7#53(demand.gamma.aridns.net.au) in 634 ms
    8. 请求得到A记录,地址解析完成

      1. wyh.life. 86400 IN A 192.30.252.154
      2. wyh.life. 86400 IN A 192.30.252.153
      3. wyh.life. 86400 IN NS f1g1ns1.dnspod.net.
      4. wyh.life. 86400 IN NS f1g1ns2.dnspod.net.
      5. ;; 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上有如下记录:

    1. test.a.com. IN NS B.test.a.com.
    2. 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. 暴风影音导致断网

    1. 由于游戏私服互斗,DNSPod 遭受了 DDoS 攻击
    2. 由于流量压力,电信 IDC 在路由上封禁了 DNSPod 的IP地址,导致 DNSPod 的域名解析服务不可用
    3. 暴风影音自启的后台程序每15s左右与服务器通信,当解析不到地址会不断重试;而该域名解析服务由 DNSPod 提供
    4. 全国各地千万级别的电信暴风用户不断进行 DNS 查询,形成了对 DNS 递归查询服务器的 DDoS 攻击。UDP 传输是没有流控功能的,导致部分地区电信出口链路出现拥塞
    5. 网通因为有 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)输出格式:

    1. [Domain] [TTL] IN [RR Type] [[RR Data]]

    参考:http://anouar.adlani.com/2011/12/useful-dig-command-to-troubleshot-your-domains.html

    实验:查询 IP

    1. $ dig wyh.life
    2. ;; ANSWER SECTION:
    3. wyh.life. 85276 IN CNAME pages.coding.me.
    4. pages.coding.me. 246 IN A 23.91.98.188
    5. # Test on VPS
    6. $ dig wyh.life
    7. ;; ANSWER SECTION:
    8. wyh.life. 96 IN A 192.30.252.153
    9. 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 字段来识别的

    1. $ curl --header "host: wyh.life" 192.30.252.153
    2. $ curl --header "host: wyh.life" pages.coding.me

    实验:查询 CNAME, NS

    1. $ dig +short wyh.life cname
    2. pages.coding.me.
    3. # Test on VPS
    4. $ dig wyh.life ns
    5. f1g1ns1.dnspod.net.
    6. f1g1ns2.dnspod.net.

    实验:指定 DNS Server 查询

    1. $ dig wyh.life @8.8.8.8 +short
    2. 192.30.252.153
    3. 192.30.252.154
    4. $ dig wyh.life @114.114.114.114 +short
    5. pages.coding.me.
    6. 23.91.98.188

    实验:查询 SOA

    1. $ dig wyh.life soa +multiline
    2. ;; ANSWER SECTION:
    3. wyh.life. 600 IN SOA f1g1ns1.dnspod.net. freednsadmin.dnspod.com. (
    4. 1460108051 ; serial
    5. 3600 ; refresh (1 hour)
    6. 180 ; retry (3 minutes)
    7. 1209600 ; expire (2 weeks)
    8. 180 ; minimum (3 minutes)
    9. )
    • f1g1ns1.dnspod.net.: SOA 主机地址
    • freednsadmin.dnspod.com.: 标识联系邮件,即 freednsadmin@dnspod.com
    • 1460108051; serial: 标识域名信息变化的序列号,每次域名变化时该项数值增大
    • 3600; refresh: 标识备用 DNS 服务器查询主服务器中序列号是否增加(即域文件变化)的间隔时间
    • 180; retry: 标识备用 DNS 服务器无法连接主服务器时重试间隔时间
    • 1209600; expire: 标识备用 DNS 服务器无法连接主服务器时,可以在多长时间内认为缓存有效
    • 180; minimum: 标识缓存 DNS 服务器可以缓存记录多长时间

    实验:查询 MX

    1. $ dig mx gmail.com
    2. ;; ANSWER SECTION:
    3. gmail.com. 3263 IN MX 10 alt1.gmail-smtp-in.l.google.com.
    4. gmail.com. 3263 IN MX 30 alt3.gmail-smtp-in.l.google.com.
    5. gmail.com. 3263 IN MX 5 gmail-smtp-in.l.google.com.
    6. gmail.com. 3263 IN MX 20 alt2.gmail-smtp-in.l.google.com.
    7. gmail.com. 3263 IN MX 40 alt4.gmail-smtp-in.l.google.com.
    8. # Or try
    9. $ nslookup -query=mx gmail.com

    MX 应答的格式:

    1. [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 对应的主机名

    1. $ dig -x 114.114.114.114 +short
    2. public1.114dns.com.

    实验:查询顶级域名的 NS

    1. $ dig NS life. +short
    2. demand.alpha.aridns.net.au.
    3. demand.beta.aridns.net.au.
    4. demand.delta.aridns.net.au.
    5. demand.gamma.aridns.net.au.

    可以从 ICANN 官方 Wiki 查看顶级域名(TLD)详细信息,如 http://icannwiki.com/.life

    1. $ dig NS com. +short | sort
    2. a.gtld-servers.net.
    3. b.gtld-servers.net.
    4. c.gtld-servers.net.
    5. d.gtld-servers.net.
    6. e.gtld-servers.net.
    7. f.gtld-servers.net.
    8. g.gtld-servers.net.
    9. h.gtld-servers.net.
    10. i.gtld-servers.net.
    11. j.gtld-servers.net.
    12. k.gtld-servers.net.
    13. l.gtld-servers.net.
    14. m.gtld-servers.net.

    测试根域 / com域 的权威解析服务,可以尝试如下脚本(参考自 http://blog.fenghe.org/archives/1839#more-1839

    1. for i in a b c d e f g h i j k l m; do
    2. echo $i.root-servers.net
    3. dig wyh.life @$i.root-servers.net | grep 'Query time'
    4. # echo @$i.gtld-servers.net
    5. # dig wyh.life @$i.gtld-servers.net | grep 'Query time'
    6. echo
    7. 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 内。

    参考:https://plus.google.com/+IlyaGrigorik/posts/WhpTG92ta3f