查看“︁编写一个TCP/IP栈1-以太网和ARP”︁的源代码
←
编写一个TCP/IP栈1-以太网和ARP
跳转到导航
跳转到搜索
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
编写自己的TCP/IP栈可能看起来是一项艰巨的任务。事实上,TCP在其三十多年的生命周期中积累了许多规范。然而,<sup>1</sup>核心规范看似紧凑——重要的部分是TCP头解析、状态机、拥塞控制以及传输超时计算。 最常见的第2层和第3层协议,分别是以太网和IP,与TCP的复杂性相形见绌。在本博客系列中,我们将实现一个适用于 Linux 的最小用户空间 TCP/IP 栈。 这些帖子和生成软件的目的纯粹是教育性的——在更深层次上学习网络和系统编程。 * = TUN/TAP 设备 = 为了拦截来自Linux内核的低级别网络流量,我们将使用Linux TAP设备。简而言之,TUN/TAP 设备经常被网络用户空间应用程序用于操作 L3/L2 流量。一个流行的例子是隧道,其中数据包被包裹在另一个数据包的有效载荷内。 TUN/TAP 设备的优点在于在用户空间程序中易于设置,并且已在众多程序(如 OpenVPN)中使用。 由于我们希望从第2层向上构建网络栈,因此需要一个TAP设备。我们这样进行即时验证: 之后,返回的文件描述符<code>fd</code>可以用来<code>read</code>而且<code>write</code>数据到虚拟设备的以太网缓冲区。 旗帜<code>IFF_NO_PI</code>这里至关重要,否则我们最终会收到预设在以太网帧的不必要的数据包信息。你实际上可以查看隧道设备驱动程序的内核源代码,并自行验证。 = 以太网帧格式 = ''多种不同的以太网网络技术是局域网''(LAN)中连接计算机的支柱。与所有物理技术一样,<sup>2</sup>以太网标准已从其1980年由数字设备公司、英特尔和施乐公司发布的首版2版大有演进。 以太网的首个版本在当今标准中较为缓慢——大约为10兆字节/秒,它采用了半双工通信技术,意味着您发送或接收数据,但并非同时进行。因此,''必须采用媒体访问控制''(MAC)协议来组织数据流。时至今日,如果在半双工模式下运行以太网接口,仍需要使用“载波感知”、带碰撞检测(CSMA/CD'')''的多重访问方式。 ''100BASE-T''采用100BASE-T以太网标准,采用双绞线,实现全双工通信和更高的传输速度。此外,以太网交换机的普及程度同时增加,使得CSMA/CD基本过时。 不同的以太网标准由IEEE <sup>802.3</sup> 3工作组维护。 接下来,我们将查看以太网帧头。如下所示,可以将其声明为C结构: <code>dmac</code>而且<code>smac</code>是相当不言自明的领域。它们包含通信方的MAC地址(分别为目的地和来源)。 超载的字段<code>ethertype</code>是一个2-ctet字段,根据其值表示有效载荷的长度或类型。具体来说,如果该字段的值大于或等于1536,则该字段包含有效载荷的类型(例如IPv4、ARP)如果值小于该值,则包含有效载荷的长度。 类型字段之后''tags'',以太网帧可能会出现多个不同的标签。''这些标签可用于描述帧的虚拟局域网''(VLAN)''或服务质量''(QoS)类型。以太网帧标签不在我们的实现中,因此相应的字段也不会显示在我们的协议声明中。 田野<code>payload</code>包含指向以太网帧有效载荷的指针。在我们的情况下,这将包含一个ARP或IPv4数据包。如果有效载荷长度小于所需最小48字节(不含标签),则将空格字节附加到有效载荷的末尾,以满足要求。 我们还包括<code>if_ether.h</code>Linux 头向提供 ethertypes 与其十六进制值之间的映射。 最后,''Frame Check Sequence''以太网帧格式还包含了帧勾选句字段,''Cyclic Redundancy Check''该字段与循环冗余检查(CRC)配合使用,以检查帧的完整性。我们将在实现此字段时省略处理。 = 以太网框架解析 = ''packed''结构体声明中包含的属性是一个实现细节——它用于指示GNU <sup>4</sup>C编译器不要针对数据对齐进行填充字节4的结构体内存布局进行优化。使用此属性完全源于我们“解析”协议缓冲区的方式,该缓冲区只是使用正确协议结构对数据缓冲区进行的一种类型转换: 一种便携且略显费力的方法,是手动对协议数据进行序列化。这样,编译器可以自由添加填充字节,以更好地满足不同处理器的数据对齐要求。 解析和处理传入的以太网帧的总体情况很简单: <code>handle_frame</code>函数只是看<code>ethertype</code>以太网标头字段,并根据值决定下一步操作。 = 解决协议 = ''Address Resolution Protocol''地址解析协议(ARP)用于动态地将48位以太网地址(MAC地址)映射到协议地址(例如IPv4 地址。关键是使用ARP,可以使用多种不同的L3协议:不仅使用IPv4,还可以使用其他协议,例如宣布16位协议地址的CHAOS。 通常情况下,你了解局域网中某个服务的IP地址,但要建立实际通信,硬件地址(MAC)也需要被知晓。因此,ARP 用于广播和查询网络,要求 IP 地址的所有者报告其硬件地址。 ARP 数据包格式相对简单: ARP头球(<code>arp_hdr</code>包含2-ctet<code>hwtype</code>确定所使用的链接层类型。这是我们的以太网,实际价值是<code>0x0001</code>。 两枚八胞胎<code>protype</code>字段表示协议类型。在我们的例子中,这是IPv4,它与值进行通信<code>0x0800</code>。 <code>hwsize</code>而且<code>prosize</code>字段大小均为1-八位,且分别包含硬件和协议字段的大小。在我们的情况下,这些地址为 MAC 地址为 6 字节,IP 地址为 4 字节。 两八分位<code>opcode</code>声明 ARP 消息的类型。可以是 ARP 请求(1)、ARP 回复(2)、RARP 请求(3)或 RARP 回复(4)。 <code>data</code>字段包含 ARP 消息的实际有效载荷,在我们的情况下,这将包含 IPv4 的特定信息: 这些领域相当自我解释。<code>smac</code>而且<code>dmac</code>分别包含发送方和接收方的6字节MAC地址。<code>sip</code>而且<code>dip</code>分别包含发送方和接收方的IP地址。 = 地址解析算法 = original specification原始规范描述了这种用于地址解析的简单算法: 即<code>translation table</code>用于存储 ARP 的结果,以便主机能够查看其缓存中是否已包含该条目。这可以避免为冗余的 ARP 请求发送网络垃圾邮件。 该算法在 arp.c 中实现。 最后,实现ARP的最终测试是,它是否能正确回复ARP请求: 内核的网络栈从我们的自定义网络堆栈中识别出ARP响应,随后通过输入我们的虚拟网络设备来填充其ARP缓存。成功! = 结论 = 以太网帧处理和自动处理处理的实现非常简单,只需几行代码即可完成。相反,奖励因素相当高,因为你可以使用自己的支持性以太网设备来填充Linux主机的ARP缓存! 该项目的源代码可在 GitHub 上找到。 在下一篇文章中,我们将继续使用ICMP回声与回复(ping)以及IPv4数据包解析来实现。 = 来源 = # <nowiki>https://tools.ietf.org/html/rfc7414</nowiki> ↩↩ # <nowiki>http://ethernethistory.typepad.com/papers/EthernetSpec.pdf</nowiki> ↩ # <nowiki>https://en.wikipedia.org/wiki/IEEE_802.3</nowiki> ↩ # <nowiki>https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attrites.html#Common-Type-Attributes</nowiki> ↩ # <nowiki>https://github.com/chobits/tapip</nowiki> ↩
返回
编写一个TCP/IP栈1-以太网和ARP
。
导航菜单
个人工具
登录
命名空间
页面
讨论
大陆简体
查看
阅读
查看源代码
查看历史
更多
搜索
导航
首页
最近更改
随机页面
特殊页面
工具
链入页面
相关更改
页面信息