CS144计算机网络 Lab5

一、简介

这里记录了笔者学习 CS144 计算机网络 Lab5 的一些笔记 - 网络接口 network interface(也被称为适配器) 的实现

CS144 Lab5 实验指导书 - Lab Checkpoint 5: down the stack (the network interface)

个人 CS144 实验项目地址 - github

二、环境配置

当前我们的实验代码位于 master 分支,而在完成 Lab 之前需要合并一些依赖代码,因此执行以下命令:

1
git merge origin/lab5-startercode

之后重新 make 编译即可。

三、TCP报文的数据传输方式

TCP报文有三种方式可被传送至远程服务器,分别是:

  • TCP-in-UDP-in-IP:用户提供 TCP 包,之后可以使用 Linux 提供的接口,让内核来负责构造 UDP 报头、IP报头以及以太网报头,并将构造出的数据包发送至下一个层。因为这一切都是内核完成的任务,因此内核可以确保每个套接字都具有本地地址与端口,以及远程地址与端口的唯一组合,同时能保证不同进程之前的隔离。

  • TCP-in-IP:通常,TCP数据包是直接放进 IP 包作为其 payload,这也因此被称为 TCP/IP。但用户层如果想直接操作构造 IP 报文的话,需要使用到 Linux 提供的 TUN 虚拟网络设备来作为中转。当用户将 IP 报文发送给 TUN 设备后,剩余的以太网报头构造、发送以太网帧等等的操作均会由内核自动进行,无需用户干预。

    这一个正是之前 Lab4 中 CS144 所使用的机制,感兴趣可以仔细读读代码。

  • TCP-in-IP-in-Ethernet:上面两种方式仍然依赖Linux内核来实现的协议栈操作。每次用户向TUN设备写入IP数据报时,Linux 内核都必须构造一个适当的链路层(以太网)帧,并将IP数据报作为其 payload。因此 Linux 必须找出下一跳的以太网目的地址,给出下一跳的IP地址。如果 Linux 无法得知该映射关系,则将会发出广播探测请求以查找到下一跳的地址等信息。而这种功能是由网络接口 network interface (也被称为适配器,两者等价)所实现,它将会把待出口的 IP 报文转换成链路层(以太网)帧等等,之后将链路层帧发送给 TAP 虚拟网络设备,剩下的发送操作将会由它来代为完成。

    比较熟悉的网络接口分别是 eth0, eth1, whan0 等等。

    网络接口的大部分工作是:为每个下一跳IP地址查找(和缓存)以太网地址。而这种协议被称为地址解析协议ARP

    在本实验中,我们将会完成一个这样的网络接口实现(有点小期待)。

四、地址解析协议 ARP

在编写代码前,我们需要简单的了解一下 ARP 协议。

主机或路由器不具有链路层地址,而是它们的适配器(即网络接口)具有链路层地址。链路层地址通常称为 MAC 地址。当某个适配器要向某些目的适配器发送一个帧时,发送适配器将目的适配器的 MAC 地址插入至该帧中,并将该帧发送到局域网上。一块适配器可能因为广播操作,接收到了一个并非向它寻址的帧,因此当适配器接收到一个帧时,将检查并丢弃帧的目的MAC地址不与自己MAC地址匹配的以太网帧。

为什么适配器除了有**网络层地址(IP地址)以外,还会有链路层地址(MAC地址)**呢?有两个原因:

  • 局域网是为了任意网络层协议而设计,并非只用于 IP 和因特网。
  • 如果适配器使用 IP地址而不使用 MAC 地址,那么每次适配器移动或重启时,均需重新配置地址

由于适配器同时拥有网络层和链路层地址,因此需要相互转化。而这种转换的任务就由 地址解析协议 来完成。ARP 类似于 DNS 服务,但不同的是,DNS 为任何地方的主机来解析主机名,但 ARP 只能为在同一个子网上的主机和路由器接口解析 IP 地址。

每台主机或路由器在其内存中保存了一张 ARP 表,该表包含了 IP 地址到 MAC 地址的映射关系,同时还包含了一个寿命值(TTL),用以表示从表中删除每个映射的时间,例如:

IP 地址 MAC 地址 TTL
222.222.222.221 aa-bb-cc-dd-ee-ff 13:45:00
222.222.222.223 11-22-33-44-55-66 4:34:12

若 ARP 表中已经存放了目标 IP 地址的 MAC 地址映射,那么适配器将会很容易的找出目标 MAC 地址并构造一个以太网帧。但如果找不到,那么发送方将会构造一个 ARP 分组的特殊分组。

ARP 分组中的字段包括发送和接收 IP 地址以及 MAC 地址,同时 ARP 查询分组和响应分组都具有相同的格式。ARP 查询分组的目的是询问子网上所有其他主机和路由器,以确定对应于要解析的 IP 地址的那个 MAC 地址。

当发送适配器需要查询目的适配器的 MAC 地址时,发送适配器会设置分组的目的地址为 MAC 广播地址(FF-FF-FF-FF-FF-FF),这样做的目的是为了让所有子网上的其他适配器都接收到。当其他适配器接收到了该 ARP 查询分组后,只有 IP 匹配的适配器才会返回一个 ARP 响应分组,之后发送适配器便可更新自己的 ARP 表,并开始发送 IP 报文。

查询ARP报文是在广播帧中发送,而响应ARP报文只在一个标准帧中发送。同时 ARP 表是自动建立的,无需人为设置。若主机与子网断开连接,那么该节点留在其他节点的 ARP 表中对应的条目也会被自动删除。

与之相对的,ARP欺骗攻击可以利用 ARP 协议不提供对网络上的 ARP 回复进行身份验证 这样的一个缺陷,来轻易执行中间人攻击或者 DOS 攻击。

其他详细信息可以看看 RFC826 规范。

五、Network Interface 具体实现

首先, 我们需要额外设置三个数据结构,分别是:

  • _arp_table:ARP 表,用以查询 IP至MAC地址的映射,同时还保存当前 ARP 条目的 TTL。

    ARP条目 TTL 为 30s。

  • _waiting_arp_response_ip_addr:已经发送了的 ARP 报文。必须确保每个 ARP 报文在5秒内不重复发送。

  • _waiting_arp_internet_datagrams:这里存放着等待ARP返回报文的 IP 报文。只有对应 ARP 返回报文到来,更新了 ARP 表后,网络接口才会知道这些 IP 报文要发送至哪个 MAC 地址。

在实现整个网络接口时,必须确保几点

  • ARP条目 TTL 为30s,时间到期后需要将其从 ARP Table 中删除。
  • 若发送 IP 报文时,发现 ARP Table 中无目标 MAC 地址,则立即发送 ARP 请求报文,同时将当前 IP 报文暂时缓存,直至获取到目标 MAC 地址后再重新发送。
  • 不同目标 IP 的 ARP 请求报文之间的发送间隔,不能超过 5s
  • 如果 ARP 请求报文在 5 秒内仍然无响应,则重新发送
  • 当网络接口接收到一个以太网帧时,
    • 必须丢弃目的 MAC 地址不为当前网络接口 MAC 地址
    • 除了 ARP 协议需要比较自己的 IP 地址以外,不要在其他任何地方进行 IP 比较,因为网络接口位于链路层。
    • 如果是发给自己的 ARP 请求,那么要忽略掉发送来的 ARPMessage::target_ethernet_address,因为发送者自己也不知道这个要填写什么,该字段无意义。
    • 无论接收到的是 ARP 请求包或者 ARP 响应包,只要是明确发给自己的,那么这里面的 src_ip_addr 和 src_eth_addr 都可用于更新当前的 ARP 表。

具体代码可以看这里:

测试结果:

image-20211118164207822

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2020-2021 Kiprey
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~