现在 Internet(因特网)使用的主流协议族是 TCP/IP 协议族,它是一个分层、多协议的通信体系。本章简要讨论 TCP/IP 协议族各层 包含的主要协议,以及它们之间是 如何协作完成网络通信的
1、TCP/IP 协议族体系结构 以及主要协议
1.1 数据链路层
1、数据链路层 实现了 网卡接口的网络驱动程序,以处理数据在物理媒介(比如以太网、令牌环等)上的传输。不同的物理网络 具有不同的电气特性,网络驱动程序 隐藏了这些细节,为上层协议 提供一个统一的接口
数据链路层 两个常用的协议是 ARP 协议(地址解析协议)和 RARP 协议(逆地址解析协议)。实现了 IP 地址和机器物理地址(通常是 MAC 地址,以太网、令牌环 和 802.11 无线网络都使用 MAC 地址)之间的相互转换
网络层使用 IP 地址寻址一台机器,而数据链路层 使用物理地址寻址一台机器,因此网络层 必须先将目标机器的 IP 地址转化成其物理地址,才能使用 数据链路层提供的服务,这就是 ARP 协议的用途。RARP 协议 仅用于网络上的某些无盘工作站。因为 缺乏存储设备,无盘工作站 无法记住自己的 IP 地址,但它们可以利用 网卡上的物理地址来 向网络管理者(服务器或网络管理软件)查询自身的 IP 地址。运行 RARP 服务的网络管理者 通常存有该网络上所有机器的 物理地址到 IP 地址的映射
1.2 网络层
1、网络层 实现数据包的选路和转发。WAN(广域网)通常使用 众多分级的路由器来 连接分散的主机或 LAN(局域网),因此,通信的两台主机 一般不是直接相连的,而是 通过多个中间节点(路由器)连接的。网络层的任务就是 选择这些中间节点,以确定 两台主机之间的通信路径。同时,网络层对上层协议 隐藏了网络拓扑连接的细节,使得在传输层和网络应用程序看来,通信的双方是 直接相连的
2、网络层最核心的协议是 IP 协议(因特网协议)。IP 协议 根据数据包的目的 IP 地址 来决定如何投递它。如果数据包 不能直接发送给目标主机,那么 IP 协议就为它寻找 一个合适的下一跳路由器,并将数据包 交付给该路由器来转发。多次重复这一过程,数据包 最终到达目标主机,或者 由于发送失败而被丢弃。可见,IP 协议 使用逐跳的方式 确定通信路径
3、网络层 另外一个重要的协议是 ICMP 协议(因特网控制报文协议)。它是 IP 协议的重要补充,主要用于检测网络连接
8 位类型字段 用于区分报文类型。它将 ICMP 报文分为两大类:一类是 差错报文,这类报文主要用来 回应网络错误,比如 目标不可到达(类型值为 3)和重定向(类型值为 5,当路由器接收到一个数据包 并发现有更好的路径可以将数据包传输到目标时,它会向源主机 发送一条 ICMP 重定向报文);另一类是 查询报文,这类报文用来 查询网络信息,比如 ping 程序就是使用 ICMP 报文 查看目标是否可达(类型值为 8)的
有的 ICMP 报文还使用 8 位代码字段 来进一步细分不同的条件。比如 重定向报文使用代码值 0 表示对网络重定向,代码值 1 表示对主机重定向。ICMP 报文 使用 16 位校验和字段 对整个报文(包括头部和内容部分)进行循环冗余校验(CRC),以检验报文在传输过程中 是否损坏。不同的 ICMP 报文类型 具有不同的正文内容
ICMP 协议并非严格意义上的网络层协议,因为它使用 处于同一层的 IP 协议提供的服务(一般来说,上层协议使用下层协议提供的服务)
1.3 传输层
1、传输层为两台主机上的应用程序 提供端到端的通信。与网络层使用的 逐跳通信方式不同,传输层只关心 通信的起始端和目的端,而不在于 数据包的中转过程
垂直的实线箭头 表示 TCP/IP 协议族各层之间的实体通信(数据包 确实是 沿着这些线路传递的),而水平的虚线箭头 表示逻辑通信线路
数据链路层(驱动程序)封装了 物理网络的电气细节; 网络层封装了 网络连接的细节; 传输层 则为应用程序封装了一条 端到端的逻辑通信链路,它负责数据的收发、链路的超时重连等
2、传输层协议 主要有三个:TCP 协议、UDP 协议 和 SCTP 协议
TCP 协议(传输控制协议)为应用层提供可靠的、面向连接的 和 基于流的服务。TCP 协议使用 超时重传、数据确认等方式 来确保数据包 被正确地发送至目的端,因此 TCP 服务是可靠的。使用 TCP 协议通信的双方必须先建立 TCP 连接,并在内核中 为该连接维持一些必要的数据结构,比如连接的状态、读写缓冲区,以及 诸多定时器等。当通信结束时,双方必须关闭连接 以释放这些内核数据
TCP 服务是基于流的。基于流的数据 没有边界(长度)限制,它源源不断地 从通信的一端流入另一端。发送端 可以逐个字节地 向数据流中写入数据,接收端也可以 逐个字节地将它们读出
UDP 协议(用户数据报协议)则与 TCP 协议完全相反,它为应用层提供 不可靠、无连接 和 基于 数据报的服务。“不可靠” 意味着 UDP 协议 无法保证 数据从发送端正确地传送到目的端。如果数据在中途丢失,或者 目的端 通过数据校验 发现数据错误而将其丢弃,则 UDP 协议只是简单地 通知应用程序发送失败。因此,使用 UDP 协议的应用程序 通常要自己处理数据确认、超时重传等逻辑
UDP 协议是无连接的,即通信双方不保持一个长久的联系,因此应用程序 每次发送数据都要明确指定接收端的地址(IP 地址等信息)。基于数据报的服务,是相对基于流的服务而言的。每个 UDP 数据报都有一个长度,接收端必须以该长度为最小单位 将其所有内容一次性读出,否则数据将被截断(接收端 必须以数据报文的长度为单位,一次性 接收完整的数据报。如果接收端提供的缓冲区长度 小于数据报文的长度,超出的部分将会被截断,导致数据丢失)
SCTP 协议(流控制传输协议)是一种 相对较新的传输层协议,它是为 在因特网上传输电话信号而设计的
1.4 应用层
1、 应用层 负责处理应用程序的逻辑。数据链路层、网络层和传输层 负责处理网络通信细节,这部分 必须既稳定又高效,因此 都在内核空间中实现。而应用层 则在用户空间实现,因为 它负责处理众多逻辑,比如 文件传输、名称查询 和 网络管理等。如果 应用层也在内核中实现,则会使内核变得非常庞大。当然,也有少数服务器程序是 在内核中实现的,这样代码 就无须 在用户空间和内核空间来回切换(主要是数据的复制)
2、应用层协议很多:
ping 是应用程序,而不是协议,它利用 ICMP 报文检测网络连接,是调试网络环境的必备工具
telnet 协议是一种远程登录协议,它使我们 能在本地完成远程任务,本书后续章节将会多次使用 telnet 客户端登录到其他服务上
OSPF(开放最短路径优先)协议 是一种动态路由更新协议,用于路由器之间的通信,以告知对方各自的路由信息
DNS(域名服务)协议提供机器域名到 IP 地址的转换
3、应用层协议(或程序)可能跳过 传输层 直接使用网络层提供的服务,比如 ping 程序和 OSPF 协议。应用层协议(或程序)通常 既可以使用 TCP 服务,也可以 使用 UDP 服务,比如 DNS 协议
2、封装
1、上层协议是 如何使用下层协议提供的服务的呢?其实这是通过封装 实现的。应用程序数据 在发送到物理网络上之前,将沿着协议栈 从上往下依次传递。每层协议都将在上层数据的基础上 加上自己的头部信息(有时还包括尾部信息),以实现该层的功能,这个过程就称为 封装
经过 TCP 封装后的数据 称为 TCP 报文段,或者简称 TCP 段。TCP 协议为通信双方维持一个连接,并且在内核中存储相关数据。这部分数据中的 TCP 头部信息 和 TCP 内核缓冲区(发送缓冲区或接收缓冲区)数据一起构成了 TCP 报文段
当发送端应用程序 使用 send(或者 write)函数 向一个 TCP 连接写入数据时,内核中的 TCP 模块 首先把这些数据 复制到与该连接对应的 TCP 内核发送缓冲区中,然后 TCP 模块调用 IP 模块提供的服务,传递的参数包括 TCP 头部信息和 TCP 发送缓冲区中的数据,即 TCP 报文段
经过 UDP 封装后的数据 称为 UDP 数据报。UDP 对应用程序数据的封装 与 TCP 类似。不同的是,UDP 无须为应用层数据 保存副本,因为它的服务是不可靠的。当一个 UDP 数据报 被成功发送之后,UDP 内核缓冲区中的该数据报就被丢弃了。如果应用程序检测到 该数据报未能被接收端正确接收,并打算 重发这个数据报,则应用程序需要 重新从用户空间将该数据报拷贝到 UDP 内核发送缓冲区中
经过 IP 封装后的数据称为 IP 数据报。IP 数据报 也包括头部信息和数据部分,其中数据部分就是一个 TCP 报文段、UDP 数据报或者 ICMP 报文
经过数据链路层封装的数据 称为帧。传输媒介不同,帧的类型也不同。比如,以太网上传输的是 以太网帧,令牌环网络上传输的是 令牌环帧。以以太网帧为例
以太网帧 使用 6 字节的目的物理地址 和 6 字节的源物理地址 来表示通信的双方。4 字节 CRC 字段对帧的其他部分提供 循环冗余校验
帧的最大传输单元(MTU),即帧最多能携带 多少上层协议数据(比如 IP 数据报),通常受到网络类型的限制。以太网帧的 MTU 是 1500 字节。正因为如此,过长的 IP 数据报 可能需要被分片传输
3、分用
1、当帧到达目的主机时,将沿着协议栈自底向上 依次传递。各层协议 依次处理帧中本层负责的头部数据,以获取所需的信息,并最终 将处理后的帧 交给目标应用程序。这个过程称为分用。分用是依靠头部信息中的类型字段实现的
因为 IP 协议、ARP 协议和 RARP 协议都使用帧传输数据,所以帧的头部 需要提供某个字段(具体情况取决于帧的类型)来区分它们。以 以太网帧为例,它使用 2 字节(16位)的类型字段来标识上层协议
如果主机接收到的 以太网帧类型字段的值为 0x800,则帧的数据部分为 IP 数据报,以太网驱动程序就将帧交付给 IP 模块;若类型字段的值为 0x806,则帧的数据部分为 ARP 请求或应答报文,以太网驱动程序就将帧交付给 ARP 模块;若类型字段的值为 0x835,则帧的数据部分为 RARP 请求或应答报文,以太网驱动程序就将帧交付给 RARP 模块
2、同样,因为 ICMP 协议、TCP 协议和 UDP 协议都使用 IP 协议,所以 IP 数据报的头部采用 16 位的协议字段来区分它们
TCP 报文段 和 UDP 数据报 则通过其头部中的 16 位的端口号字段 来区分上层应用程序。比如 DNS 协议对应的端口号是 53,HTTP 协议(超文本传送协议)对应的端口号是 80。所有知名应用层协议 使用的端口号都可在 /etc/services
文件中找到
帧 通过上述分用步骤后,最终 将封装前的原始数据送至目标服务( ARP 服务、RARP 服务、ICMP 服务或者应用程序)。这样,在顶层目标服务看来,封装和分用似乎没有发生过
4、测试网络
包括两台主机 A 和 B,以及 一个连接到因特网的路由器。所有测试硬件 指的都是该网络
该测试网络主要用于 分析 ARP 协议、IP 协议、ICMP 协议、TCP 协议和 DNS 协议。通过 抓取该网络上的以太网帧,查看其中的以太网帧头部、IP 数据报头部、TCP 报文段头部信息,以获取网络通信的细节
5、ARP 协议工作原理
1、ARP 协议 能实现任意网络层地址 到任意物理地址的转换,仅讨论从 IP 地址到以太网地址(MAC 地址)的转换。其工作原理是: 主机向自己所在的网络 广播一个 ARP 请求,该请求 包含目标机器的网络地址。此网络上的其他机器 都将收到这个请求,但只有被请求的目标机器会回应一个 ARP 应答,其中包含自己的物理地址
5.1 以太网 ARP 请求 / 应答报文详解
- 硬件类型字段 定义 物理地址的类型,它的值为 1 表示 MAC 地址
- 协议类型字段 表示 要映射的协议地址类型,它的值为 0x800,表示 IP 地址
- 硬件地址长度字段 和 协议地址长度字段,其单位是字节。对 MAC 地址来说,其长度为 6;对 IP(v4)地址来说,其长度为 4
- 操作字段指出 4 种操作类型: ARP 请求(值为 1)、ARP 应答(值为 2)、RARP 请求(值为 3)和 RARP 应答(值为 4)
- 最后 4 个字段 指定通信双方的以太网地址 和 IP 地址。发送端填充 除目的端以太网地址外 的其他 3 个字段,以构建 ARP 请求并发送之。接收端 发现该请求的目的端 IP 地址是自己,就把自己的以太网地址填进去,然后交换两个目的端地址和两个发送端地址,以构建 ARP 应答并返回之(操作字段需要设置为 2)
ARP 请求 / 应答报文的长度为 28 字节。如果再加上 以太网帧头部和尾部的 18 字节,
则一个携带 ARP 请求 / 应答报文的以太网帧长度为 46 字节。不过有的实现要求 以太网帧数据部分长度至少为 46 字节,此时 ARP 请求 / 应答报文 将增加一些填充字节,以满足这个要求。在这种情况下,一个携带 ARP 请求 / 应答报文的以太网帧长度为 64(46+18) 字节
ARP 请求和应答报文 是在数据链路层上发送的,通常 封装在以太网帧中
5.2 ARP 高速缓存的查看和修改
1、ARP 维护一个高速缓存,其中包含 经常访问(比如网关地址)或 最近访问的机器的 IP 地址到物理地址的映射。这样就避免了重复的 ARP 请求
Linux 下可以使用 arp 命令来查看和修改 ARP 高速缓存。比如,ernest-laptop 在某一时刻(注意,ARP 高速缓存是动态变化的)的 ARP 缓存内容如下(使用 arp-a 命令)
Kongming20 (192.168.1.109) at 08:00:27:53:10:67 [ether] on eth0
? (192.168.1..1) at 14:e6:e4:93:5b:78 [ether] on eth0
其中,第一项描述的是 另一台测试机器 Kongming20(注意,其 IP 地址、MAC 地址都与图 1-8 描述的一致),
Kongming20
: 这是主机名,对应 IP 地址 192.168.1.109 的设备的主机名
192.168.1.109
: 这是与主机名 Kongming20 关联的 IP 地址
08:00:27:53:10:67
: 这是该设备的 MAC 地址(硬件地址)
[ether]
: 表示这个设备的硬件类型是以太网设备
on eth0
: 表示这个设备在网络接口 eth0 上可见,即通过这个网络接口与该设备通信
第二项描述的是 路由器
下面两条命令则 分别删除和添加一个 ARP 缓存项:
sudo arp -d 192.168.1.109 # 删除 Kongming20 对应的 ARP 缓存项
sudo arp -s 192.168.1.109 08:00:27:53:10:67 # 添加 Kongming20 对应的 ARP 缓存项
5.3 使用 tcpdump 观察 ARP 通信过程
1、从 ernest-laptop 上执行 telnet 命令登录 Kongming20 的 echo 服务(已经开启),并用 tcpdump 抓取这个过程中 两台测试机器之间交换的以太网帧
sudo arp -d 192.168.1.109 # 清除 ARP 缓存中 Kongming20 对应的项
# tcpdump 命令尝试捕获以太网接口 eth0 上,源地址和目标地址在 192.168.1.108 与 192.168.1.109 之间的网络通信
sudo tcpdump -i eth0 -e '(dst 192.168.1.109 and src 192.168.1.108) or (dst 192.168.1.108 and src 192.168.1.109)'
# 如无特殊声明,抓包都在机器 ernest-laptop 上执行
telnet 192.168.1.109 echo
# 开启另一个终端执行 telnet 命令
Trying 192.168.1.109...
Connected to 192.168.1.109.
Escape character is '^]'.
^](回车) # 调出 telnet 程序的命令提示符
telnet> quit(回车)
Connection closed.
sudo tcpdump -i eth0 -e '(dst 192.168.1.109 and src 192.168.1.108) or (dst 192.168.1.108 and src 192.168.1.109)'
:
-i eth0
: 指定 eth0 网络接口
-e
: 在输出中显示以太网头信息
(dst 192.168.1.109 and src 192.168.1.108)
: 捕获目标地址为 192.168.1.109 且源地址为 192.168.1.108 的流量
or
: 逻辑或操作符
(dst 192.168.1.108 and src 192.168.1.109)
: 捕获目标地址为 192.168.1.108 且源地址为 192.168.1.109 的流量
telnet 192.168.1.109
试图连接到 192.168.1.109 上的默认 Telnet 端口(23 端口),并执行 echo(用于在终端或控制台中 输出文本信息。它的作用是 将参数作为字符串输出到标准输出)
在执行 telnet 命令之前,应先清除 ARP 缓存中与 Kongming20 对应的项,否则 ARP 通信不被执行(强制主机重新发起 ARP 请求,如果有记录就不会发了),也无法抓取到 期望的以太网帧。执行 telnet 命令 并在两台通信主机之间建立连接后(telnet 输出“Connected to 192.168.1.109”)。tcpdump 抓取到的众多数据包中,只有最靠前的两个和 ARP 通信有关系
00:16:d3:5c:b9:e3 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Request who-has 192.168.1.109 tell 192.168.1.108, length 28
08:00:27:53:10:67 > 00:16:d3:5c:b9:e3, ethertype ARP (0x0806), length 60: Reply 192.168.1.109 is-at 08:00:27:53:10:67, length 46
由 tcpdump 抓取的数据包 本质上是以太网帧,通过该命令的众多选项来 控制帧的过滤(比如用 dst 和 src 指定通信的目的端 IP 地址和源端 IP 地址)和显示(比如用 -e 选项开启以太网帧头部信息的显示)
第一个数据包中,ARP 通信的源端的物理地址是 00:16:d3:5c:b9:e3
(ernest-laptop:192.168.1.108),目的端的物理地址是 ff:ff:ff:ff:ff:ff
,这是以太网的广播地址,用以表示整个 LAN。该 LAN 上的所有机器都会收到并处理这样的帧
数值 0x806 是以太网帧头部的类型字段的值,它表示 分用的目标是 ARP 模块。该以太网帧的长度为 42 字节(实际上是 46 字节,tcpdump 未统计以太网帧尾部 4 字节的 CRC 字段),其中数据部分长度为 28 字节
“Request” 表示这是一个 ARP 请求,“who-has 192.168.1.109 tell 192.168.1.108
” 则表示是 ernest-laptop(192.168.1.108) 要查询 Kongming20(192.168.1.109) 的 IP 地址
第二个数据包中,ARP 通信的源端的物理地址是 08:00:27:53:10:67
(Kongming20:192.168.1.109),目的端的物理地址是 00:16:d3:5c:b9:e3
(ernest-laptop:192.168.1.108)。“Reply” 表示这是一个 ARP 应答,“192.168.1.109 is-at 08:00:27:53:10:67
” 则表示目标机器 Kongming20 报告其物理地址。该以太网帧的长度为 60 字节(实际上是 64 字节),可见它使用了填充字节来满足最小帧长度
ARP 请求和应答 是从以太网驱动程序发出的,并非像图中描述的那 样从 ARP 模块直接发送到以太网上,所以 将它们用虚线表示,这主要是为了 体现携带 ARP 数据的以太网帧和其他以太网帧(比如携带 IP 数据报的以太网帧)的区别
路由器也将收到以太网帧 1,因为该帧是一个广播帧。路由器并没有回应其中的 ARP 请求
6、DNS 工作原理
使用机器的域名(www.x.cn)来访问这台机器,而不直接使用其 IP 地址。如何将机器的域名转换成 IP 地址呢?需要 使用域名查询服务
6.1 DNS 查询和应答报文详解
1、DNS 是一套分布式的域名服务系统。每个 DNS 服务器上 都存放着大量的机器名和 IP 地址的映射,并且是动态更新的。众多网络客户端程序 都使用 DNS 协议来向 DNS 服务器查询目标主机的 IP 地址
16 位标识字段 用于标记一对 DNS 查询和应答(每个查询请求会有一个唯一的事务 ID,服务器在生成应答时 会将该事务 ID 原样返回给客户端),以此区分一个 DNS 应答是哪个 DNS 查询的回应
16 位标志字段 用于协商具体的通信方式 和 反馈通信状态
- QR,查询 / 应答标志。0 表示这是一个查询报文,1 表示这是一个应答报文
- opcode,定义查询和应答的类型。0 表示标准查询,1 表示反向查询(由 IP 地址获得主机域名),2 表示请求服务器状态
- AA,授权应答标志,仅由应答报文使用。1 表示域名服务器是授权服务器
- TC,截断标志,仅当 DNS 报文使用 UDP 服务时使用。因为 UDP 数据报有长度限制,所以过长的 DNS 报文将被截断。1 表示 DNS 报文超过 512 字节,并被截断
- RD,递归查询标志。1 表示执行递归查询,即如果目标 DNS 服务器无法解析某个主机名,则它将向其他 DNS 服务器继续查询,如此递归,直到获得结果并把该结果返回给客户端。0 表示执行迭代查询,即如果目标 DNS 服务器无法解析某个主机名,则它将自己知道的其他 DNS 服务器的 IP 地址返回给客户端,以供客户端参考
- RA,允许递归标志。仅由应答报文使用,1 表示 DNS 服务器支持递归查询
- zero,这 3 位未用,必须都设置为 0
- rcode,4 位返回码,表示应答的状态。常用值有 0(无错误)和 3(域名不存在)
接下来的 4 个字段 则分别指出 DNS 报文的最后 4 个字段的资源记录数目。对查询报文而言,它一般包含 1 个查询问题,而应答资源记录数、授权资源记录数 和 额外资源记录数则为 0。应答报文的应答资源记录数则至少为 1,而授权资源记录数 和 额外资源记录数可为 0 或非 0
-
查询问题数:
该字段是一个 16 位的无符号整数,表示 DNS 消息中 查询部分的问题数目。通常,对于大多数标准的 DNS 查询,这个值是 1,因为一个 DNS 查询消息 通常只包含一个查询问题 -
应答资源记录数:
该字段也是一个 16 位的无符号整数,表示 DNS 消息中应答部分 包含的资源记录数目。这些记录通常是对查询问题的直接回答 -
授权资源记录数:
该字段同样是一个 16 位的无符号整数,表示 DNS 消息中授权部分(即授权信息部分)包含的资源记录数目。授权记录通常提供 有关该区域的权威名称服务器信息
授权部分主要用于以下情况:
1)指引客户端: 当某个 DNS 服务器无法直接回答查询时,它可能会返回授权部分中的记录,告知客户端 应该查询 哪个权威名称服务器以获取所需的信息
2)递归查询: 在递归查询过程中,DNS 服务器 可以返回授权部分中的名称服务器记录,使得客户端(或递归 DNS 服务器)能够继续向正确的名称服务器查询 -
额外资源记录数:
该字段也是一个 16 位的无符号整数,表示 DNS 消息中 额外部分 包含的资源记录数目。额外记录可以包括补充信息,例如 为了优化解析过程而添加的记录
其中 查询问题的格式
查询名 以一定的格式封装了 要查询的主域名。16 位查询类型表示 如何执行查询操作,常见的类型有如下几种:
- 类型 A,值是 1,表示获取目标主机的 IP 地址
- 类型 CNAME,值是 5,表示获得目标主机的别名
将一个域名的多个别名指向同一个规范域名,将一个域名的别名(或别称)映射到另一个“规范”域名上
www.example.com 是 example.com 的别名
example.com 的 A 记录指向 IP 地址 192.0.2.1
当客户端请求 www.example.com 的 IP 地址时,DNS 服务器会先解析 www.example.com 的 CNAME 记录,发现它是 example.com 的别名,接着解析 example.com 的 A 记录,最终返回 IP 地址 192.0.2.1 - 类型 PTR,值是 12,表示反向查询
16 位查询类通常为 1,表示获取因特网地址(IP 地址)
应答字段、授权字段 和 额外信息字段 都使用资源记录格式
32 位域名是 该记录中与资源对应的名字,其格式 和 查询问题中的查询名字段相同。16 位类型和 16 位类字段的含义 也与 DNS 查询问题的对应字段相同
32 位生存时间表示 该查询记录结果 可被本地客户端程序缓存多长时间,单位是秒
16 位资源数据长度字段 和 资源数据字段的内容 取决于类型字段。对类型 A 而言,资源数据是 32 位的 IPv4 地址,而资源数据长度则为 4(以字节为单位)
6.2 Linux 下访问 DNS 服务
1、要访问 DNS 服务器,就必须先知道 DNS 服务器的 IP 地址。Linux 使用 /etc/resolv.conf 文件来存放 DNS 服务器的 IP 地址。机器 ernest-laptop 上,该文件的内容如下:
# Generated by Network Manager
nameserver 219.239.26.42
nameserver 124.207.160.106
两个 IP 地址分别是 首选 DNS 服务器地址和备选 DNS 服务器地址。文件中的注释语句 “Generated by Network Manager” 告诉我们,这两个 DNS 服务器地址是 由网络管理程序写的
2、访问 DNS 服务器的客户端程序是 host
# 向首选 DNS 服务器 219.239.26.42 查询机器 www.baidu.com 的 IP 地址
$ host -t A www.baidu.com 219.239.26.42
www.baidu.com is an alias for www.a.shifen.com.
www.a.shifen.com has address 119.75.217.56
www.a.shifen.com has address 119.75.218.77
host 命令的输出 告诉我们,机器名 www.baidu.com 是 www.a.shifen.com. 的别名,并且 该机器名对应两个 IP 地址。host 命令 使用 DNS 协议和 DNS 服务器通信,其 -t 选项告诉 DNS 协议使用哪种查询类型(见上一节 查询问题的格式)。这里使用的是 A 类型,即通过机器的域名 获得其 IP 地址
6.3 使用 tcpdump 观察 DNS 通信过程
在 ernest-laptop 上运行 host 命令 以查询主机 www.baidu.com 对应的 IP 地址,并使用 tcpdump 抓取这一过程中 LAN 上传输的以太网帧
$ sudo tcpdump -i eth0 -nt -s 500 port domain
$ host -t A www.baidu.com
$ sudo tcpdump -i eth0 -nt -s 500 port domain
:
tcpdump
: 这是一个常用的网络抓包工具,用于捕获和分析 通过网络接口传输的数据包-i eth0
: 这里的 -i 选项指定了 要监听的网络接口。eth0 是被监听的网络接口。eth0 通常是系统中的 第一个以太网接口,但在不同的系统中,接口名称可能不同(如 ens33, enp0s3 等)-n
: 这个选项告诉 tcpdump 不要尝试将 IP 地址解析为主机名(即禁用反向 DNS 查询),直接显示 IP 地址,这样可以加快输出 并避免网络延迟-t
: 这个选项告诉 tcpdump 不要显示时间戳(默认情况下每行输出会带有时间戳)-s 500
: 这个选项指定捕获的数据包大小,单位是字节。-s 500 表示每个数据包最多捕获 500 字节。默认情况下,tcpdump 只捕获 每个数据包的前 96 字节(数据包头部),而使用 -s 可以调整捕获的字节数。500 字节通常足以捕获完整的 DNS 查询和应答数据包port domain
: 这个过滤器指定 只捕获与 DNS 通信相关的数据包。port domain 是一个通用表达式,等效于 port 53,因为 DNS 服务默认使用端口 53(UDP 或 TCP)
使用 “port domain” 来过滤数据包,表示只抓取使用 domain(域名)服务的数据包,即 DNS 查询和应答报文。tcpdump 的输出如下:
1. IP 192.168.1.108.34319 > 219.239.26.42.53: 57428+ A? www.baidu.com. (31)
2. IP 219.239.26.42.53 > 192.168.1.108.34319: 57428 3/4/4 CNAME www.a.shifen.com., A 119.75.218.77, A 119.75.217.56 (226)
这两个数据包开始的 “IP” 指出,它们后面的内容 描述的是 IP 数据报。topdump 以 “IP 地址.端口号” 的形式来描述通信的某一端;以“>”表示数据传输的方向,“>”前面是源端,后面是目的端
可见,第一个数据包是测试机器 ernest-laptop(IP 地址是 192.168.1.108)向其首选 DNS 服务器(IP 地址是 219.239.26.42)发送的 DNS 查询报文(目标端口 53 是 DNS 服务使用的端口),第二个数据包是服务器反馈的 DNS 应答报文
第一个数据包中,数值 57428 是 DNS 查询报文的标识值(前面查询报文格式),因此该值也出现在 DNS 应答报文中。“+”表示启用递归查询标志。“A?”表示使用 A 类型的查询方式。“www.baidu.com”则是 DNS 查询问题中的查询名。括号中的数值 31 是 DNS 查询报文的长度(以字节为单位)
第二个数据包中,“3/4/4” 表示该报文中包含 3 个应答资源记录、4 个授权资源记录 和 4 个额外信息记录。“CNAME wwwa.shifen.com.,A 119.75.218.77,A 119.75.217.56
”则表示 3 个应答资源记录的内容。其中 CNAME 表示紧随其后的记录是机器的别名,A 表示 紧随其后的记录是 IP 地址。该应答报文的长度为 226 字节
在 DNS 响应示例中,存在两个 A 记录的原因是 为了提供多个 IP 地址,这可以用于 负载均衡(多个 A 记录可以指向不同的服务器,每个服务器都有 相同的内容或服务。DNS 服务器可以通过轮询、随机选择 或 基于区域划分的方式,将客户端请求 分配到不同的 IP 地址)、冗余(如果一个 IP 地址对应的服务器出现故障,另一个 IP 地址对应的服务器 可以继续提供服务)或 根据地理位置(用户可以连接到 地理位置更接近的服务器,从而提高访问速度和降低延迟)优化用户体验
客户端在解析域名时,可以选择 其中一个 IP 地址进行连接,或按顺序 尝试连接多个 IP 地址
7、socket 和 TCP/IP 协议族的关系
1、数据链路层、网络层、传输层协议 是在内核中实现的。因此操作系统需要实现一组系统调用,使得应用程序能够 访问这些协议提供的服务
由 socket 定义的 这一组 API 提供如下两点功能:一是 将应用程序数据 从用户缓冲区中 复制到 TCP/UDP 内核发送缓冲区,以交付内核来 发送数据(比如图 1-5 所示的 send 函数),或者是 从内核 TCP/UDP 接收缓冲区中复制数据到 用户缓冲区,以读取数据;二是 应用程序可以通过它们来修改 内核中各层协议的某些头部信息 或 其他数据结构,从而精细地控制底层通信的行为(比如 可以设置 setsockopt 函数来设置 IP 数据报在网络上的存活时间)
2、socket 是一套通用网络编程接口,它不但可以 访问内核中 TCP/IP 协议栈,而且 可以访问其他网络协议栈(比如 X.25 协议栈、UNIX 本地域协议栈等)