TCP/IP协议栈之LwIP(三)---网际寻址与路由(IPv4 + ARP + IPv6)

本文详细介绍了TCP/IP协议栈中的LwIP实现,涵盖网际寻址原理,包括IPv4和IPv6的网络地址结构、地址转换与IP隧道。此外,讨论了ARP协议的作用、缓存表管理以及防御ARP攻击的策略,并简述了IP协议的分片与路径MTU发现,以及IPv4和IPv6数据报的结构和处理函数。
摘要由CSDN通过智能技术生成

一、网际寻址原理

前一篇网络接口层管理介绍了数据链路层可以靠MAC地址在同一个数据链路局域网内寻址。拿以太网为例,在一个数据链路中主机常与以太网交换机(可以看作是有多个端口的网桥)相连,它们根据数据链路层中每个帧的目标MAC地址,决定从哪个网桥接口发送数据,选择发送接口的依据就是交换机的地址转发表(Forwarding Table,可根据交换机自学算法自动生成)。

当网络设备地址总数并不是很多的情况下,有了唯一地址(比如MAC地址)就可以定位相互通信的主体。然而,当地址总数越来越多时,如何高效地从中找出通信的目标地址将成为一个重要的问题。为此人们发现地址除了具有唯一性还需要具有层次性。MAC地址虽然具有唯一性,但没有层次性,也即当网络设备增加到一定程度,需要将网络分成多个数据链路时,MAC地址无法跨链路寻址,是真正负责最终通信的地址。要实现跨局域网的网际寻址,就要靠具有层次性的网络IP地址实现了。

1.1 网络地址IPv4

网络IP地址是怎样实现分层的呢?IP地址由网络号和主机号两部分组成,即使通信主体的IP地址不同,若主机号不同,网络号相同,说明它们处于同一个网段。网络号相同的主机在组织结构、提供商类型和地域分布上都比较集中,为IP寻址带来了极大的方便。下面先看下IP地址的分类:
网络地址分类
网络IP地址是一个32bit整数地址,只有具有有效IP地址的主机才能跨越数据链路实现网际寻址。目前的IP地址多采用分类编址,把所有IP地址划分为A/B/C/D/E五类,前三类由网络号和主机号组成,D类都是组播地址,E类保留未用,各类IP地址特点如下表示:
各类IP地址特点
MAC地址中除了单播地址还有多播和广播地址,在IP地址中也有一些特殊的网络地址。列举几个如下:

  • 网络地址:主机号全部取0;
  • 直接广播地址:主机号全部取1;
  • 受限广播地址:IP地址32位全部为1,将广播限制在最小范围内,若采用标准IP编址则跟直接广播地址一致,若采用子网编址则广播被限制在本子网内,属于E类地址;
  • 多播地址:即上面介绍的D类地址;
  • 本网络上的特定主机:网络号全部取0;
  • 本网络本主机:IP地址32位全部为0;
  • 环回地址:127.x.x.x,通常使用127.0.0.1;

前面介绍的特殊地址不能被分配给任何主机使用,下面还有一些专用地址(也叫私有地址)可以被分配给多个主机使用,当然这些主机应该处于互相独立的专用网内,例如以太网局域网:
专用网地址
随着互联网的覆盖范围逐渐增大,网络地址会越来越不足以应对需求,直接使用A/B/C类地址显得浪费资源,为了根据需求更精细的使用IP地址,又增加了“子网掩码”的识别码将A/B/C类网络地址细分为更多的子网。子网掩码也是一个32位的整数地址,它对应IP地址网络标识部分的位全部为“1”,对于IP地址主机标识的部分全部为“0”,由此一个IP地址可以不再受限于自己的类别,而是可以用这样的子网掩码自由地定位自己的网络标识长度。举例图示如下:
子网掩码图示

1.2 网际寻址与路由协议

前面谈到MAC地址只能在本数据链路内寻址,不能跨局域网寻址,这里介绍的网络IP地址可以实现跨局域网实现网际寻址。MAC寻址靠交换机的地址转发表(记录MAC地址与发送接口的表),IP寻址则靠路由控制表(Routing Table)。路由控制表中记录着网络地址与下一步应该发送至路由器的地址,在发送IP数据包时,根据IP包首部中的目标IP地址从路由控制表中找到与该地址具有相同网络地址的记录,根据该记录将IP数据包转发给相应的下一个路由器,如果路由控制表中存在多条相同的网络地址记录,则根据最长匹配原则选择相同位数最多网络地址的下一个路由器作为转发目标。

路由控制表的生成有静态和动态两种方式,静态路由控制表需要手工配置且不自动刷新,动态路由控制表可以根据路由协议自动生成并自动刷新,所以一般使用动态路由表。由于网络地址的分层特性,可以将内部的多个子网掩码合并,对外呈现出同一个网络地址,通过这种路由信息的聚合有效减少了路由表的项数。但路由控制表也很难包含所有的网络及子网信息,一般都会配置一个默认路由(默认网关),当在路由控制表中查不到匹配项时,就把默认路由作为该IP数据包的转发目标。

动态路由控制表是靠路由协议交换路由信息生成的,那么路由协议是如何生成路由控制表的呢?前面介绍网络号相同的主机在组织结构、提供商类型和地域分布上都比较集中,实际上制定路由策略时对一个企业或组织内部的网络授权给该企业或组织内部自行决定,这样可以根据自己的需求构建合适的网络也能对外屏蔽企业内部的网络细节,以此为准在一个或多个网络群体中采用的小型网络单位叫做自治系统(AS: Autonomous System),自治系统内部动态路由采用的是域内路由协议(IGP: Interior Gateway Protocol),自治系统之间的路由控制则采用域间路由协议(EGP: Exterior Gateway Protocol)。下面给出一个关系图示:
域内域间路由协议
路由协议被分为EGP和IGP两个层次:EGP主要在区域网络之间进行路由选择,常用的路由协议是BGP(Border Gateway Protocol);IGP主要在区域网络内部进行路由选择,常用的路由协议有RIP(Routing Information Protocol)、RIP2、OSPF(Open Shortest Path First)等,主要路由协议的特点如下表示:
主要路由协议
距离向量算法是根据距离和方向决定目标网络或目标主机位置的,路由器之间可以互换目标网络的方向及其距离信息,并以此为基础制作路由控制表。其中RIP/RIP2就是使用距离向量算法实现的协议,这里的距离单位是“跳数“(所经过的路由器个数),通过定期全网广播,每经过一个路由器距离增加1,根据距离向量生成距离向量表,再抽出较小距离的路由生成路由控制表,大概图示如下:
距离向量算法
链路状态算法是路由器在了解网络整体连接状态的基础上生成路由控制表的一种方法,在该方法中每个路由器必须保持同样的信息才能进行正确的路由选择。OSPF就是一种链路状态型路由协议,路由器之间交换链路状态生成网络拓扑信息,然后根据这个拓扑信息生成路由控制表。RIP/RIP2路由协议中要求途中所经过的路由器个数越少越好,OSPF路由协议则可以给每条链路赋予一个权重(每种链路的网络带宽不同),并始终选择一个总权重最小的路径作为最终路由。这里使用了图论中的最短路径算法,RIP/RIP2使用了无权最短路径算法,OSPF使用了有权最短路径算法(参考Dijkstra算法),算法原理这里就不展开介绍了。给出OSPF路由协议的工作原理图示如下:
链路状态算法
BGP边界网关协议所使用的路径向量算法跟距离向量算法类似,不过RIP/RIP2是以所经过的路由器个数作为距离代价,BGP则把所要经过的AS自治系统的个数作为距离代价。BGP路由协议一般选择所经过AS数最少的路径,但需要遵循各个AS之间签约的细节进行更细颗粒度的路由选择。

1.3 网络地址IPv6

IPv6是为了从根本上解决IPv4地址耗尽的问题而被标准化的网际协议,IPv4的地址长度为4个8位字节即32比特,而IPv6的地址长度为8个16位字节即128比特,地址空间是IPv4的2^96倍,足以为人们所能想象到的所有主机和路由器分配地址了。IPv6位数是IPv4的四倍,如果还用IPv4的十进制表示方法显得太长,所以IPv6采用16位字节为一组,且中间出现连续的0时可以将这些0省略一次,IPv6的表示方法如下:
IPv6表示法
IPv6地址也分单播地址与多播地址,但没有广播地址,主要是考虑到广播降低了网络性能,IPv6使用多播地址来替代IPv4中必须使用广播的情况。IPv6的全局单播地址格式如下:
全局单播地址
现在IPv6的网络中常使用的格式为:广域网络ID n = 48,子网ID m = 16,主机接口ID 128-n-m = 64。多播地址第一字节全1,可简略表示为FF00::/8。除了单播与多播地址外,跟IPv4类似,也有一些私有地址,在不与互联网直接接入的局域网内部,可以使用唯一本地地址,在不跨路由器的同一链路上可以使用链路本地单播地址。这些地址结构如下表示:
IPv6地址分类
在IPv6的环境下,可以同时将这些IP地址(上表列举的多种类型IP地址)同时配置在同一个NIC上,按需灵活使用。

1.4 网络地址转换与IP隧道

前面介绍的IP地址除了全局地址还有私有地址,私有地址只能在局域网内使用,不能直接接入互联网,这主要是为了缓解IPv4地址短缺问题出现的局域网私有地址复用方案。那么,局域网内被分配私有IP地址的主机如何访问互联网呢?这就需要路由器通过NAT(Network Address Translation)功能来实现了,一个支持NAT功能的路由器至少要有一个内部地址和一个外部地址,内部地址也即私有地址是用于与局域网内的用户通信的,外部地址也即全局地址是用于与外部互联网通信的。当局域网内主机访问外部互联网时,NAT将用户的内部IP地址转换为一个外部公共IP地址;反之,数据从外部返回时,NAT将目的地址替换为用户的内部IP地址,实现多个私有地址共有一个全局地址访问互联网的功能。NAT工作过程如下图示:
NAT工作过程
在NAT路由器内部会自动生成一张地址转换表,用于记录私有地址与全局地址的映射关系。当局域网内的多台主机同时都要与外部进行通信时,仅仅转换IP地址已经不够用了,需要将传输层TCP/UDP的端口号一起转换,这种转换方式称为NAPT(Network Address Port Translation),转换过程如下图示:
NAPT转换过程
现在IPv6使用率还比较低,IPv4到IPv6的切换需要一个循序渐进的过程,因此很长一段时间内免不了IPv4与IPv6共存的情况,IPv4与IPv6混合组网也需要能互相通信。借鉴前面介绍的全局地址与私有地址的转换方案,IPv4与IPv6能否实现相互转换呢?为了解决这个问题,出现了NAT-PT(Network Address Translator - Protocol Translator)技术,能实现IPv6与IPv4网络地址的相互转换,转换过程如下图示:
NAT-PT转换过程
NAT网络地址转换都依赖于自己生成的转换表,存在一些限制或开销较大等缺点,比如两个互相通信的主机都处于IPv6网络,这两个IPv6网络无法直接进行通信,需要通过中间的IPv4网络相互通信,如果在两个IPv6间建立一个IP隧道,显然比两端都进行NAT地址转换更加简单高效。IP隧道怎么建立呢?通常情况下一个数据包只有一个IP首部,要进入中间网络时为了符合待穿越网络的IP地址要求,需要在原IP首部前再追加一个IP首部,待离开该网络时再删除临时追加的IP首部,从而完成数据包穿越中间网络的目的,这个利用临时追加、过后删除IP首部的技术称为IP隧道,穿越过程如下图示:
IP隧道穿越

二、ARP协议

2.1 ARP协议简介

前面分别介绍了IP地址进行网际寻址,MAC地址进行链路内寻址,需要两者配合一起完成主机寻址的任务。数据包从一个主机发送到另一个主机时,目标IP地址一直不变,作为查询路由控制表进行路由转发的依据,但实际转发还是需要在链路层根据MAC地址选择相应的转发接口,所以目标MAC地址一直指向下一个网络接口,整个寻址过程如下:
IP与MAC寻址过程
前面介绍路由控制表的下一个路由地址是一个IP地址,但实际是通过把数据帧的目标MAC地址设置为下一个路由接口的MAC地址实现转发的,这就要知道每个IP地址对应的MAC地址。

ARP(Address Resolution Protocol)就是一种解决IP地址与MAC地址映射问题的协议,以目标IP地址为线索,用来定位下一个应该接收数据包的网络设备对应的MAC地址。为了实现IP地址与MAC地址的转换,ARP协议引入了ARP缓存表的概念,ARP缓存表中记录了一条条<IP地址,MAC地址>对,如果目标主机在同一个链路上,通过查询ARP缓存表可以直接将匹配的MAC地址装入以太网帧首部发送到目标主机,如果目标主机不在同一链路上,通过查询ARP缓存表将匹配的下一跳路由器的MAC地址装入以太网帧首部转发给下一跳路由器继续寻址。ARP缓存表结构如下图示:
ARP缓存表
从上图看ARP缓存表也分静态与动态,静态主要是多播与广播地址,实际寻址时常靠ARP协议自动生成并动态刷新维护。ARP缓存表的建立跟ARP数据包密切相关,在以太网中,ARP数据包与IP数据包是两个相互独立的部分,它们都封装在以太网帧中发送。ARP数据包有两种:一是ARP请求包,它是通过以太网广播的方式发送的,用于向具有某个IP地址的主机发送请求,希望该主机返回其MAC地址;二是ARP应答包,收到ARP请求的主机会比对该数据包中的IP地址与自己的IP地址是否相符,若是,则该主机向源主机返回一个ARP应答包,向源主机报告自己的MAC地址,源主机通过提取ARP应答包中的相关字段来更新ARP缓存表。

RARP(Reverse Address Resolution Protocol)是将ARP反过来,从MAC地址定位IP地址的一种协议。平时我们使用电脑设置IP地址常通过DHCP(Dynamic Host Configuration Protocol)自动分配获取IP地址,但对于受限的嵌入式设备,在无法通过DHCP动态获取到IP地址的情况下,可以假设一台RARP服务器,并在这个服务器上注册设备的MAC地址及其IP地址。当设备接入网络插电启动时,通过向该服务器发送RARP请求包向RARP服务器请求IP地址,该设备通过来自RARP服务器的应答包设置自己的IP地址。

2.2 ARP缓存表描述

ARP协议的核心在于ARP缓存表的建立、更新与查询,ARP缓存表由缓存表项(entry)组成,每个表项记录一组IP地址与MAC地址的绑定信息,为了便于管理,还包含了与数据包发送控制、缓存表项管理相关的状态、控制信息等。LwIP中描述缓存表项的数据结构与图示如下:

// rt-thread\components\net\lwip-1.4.1\src\netif\etharp.c

struct etharp_entry {
   
#if ARP_QUEUEING
  /** Pointer to queue of pending outgoing packets on this ARP entry. */
  struct etharp_q_entry *q;
#else /* ARP_QUEUEING */
  /** Pointer to a single pending outgoing packet on this ARP entry. */
  struct pbuf *q;
#endif /* ARP_QUEUEING */
  ip_addr_t ipaddr;
  struct netif *netif;
  struct eth_addr ethaddr;
  u8_t state;
  u8_t ctime;
};

struct etharp_q_entry {
   
  struct etharp_q_entry *next;
  struct pbuf *p;
};

enum etharp_state {
   
  ETHARP_STATE_EMPTY = 0,
  ETHARP_STATE_PENDING,
  ETHARP_STATE_STABLE,
  ETHARP_STATE_STABLE_REREQUESTING
#if ETHARP_SUPPORT_STATIC_ENTRIES
  ,ETHARP_STATE_STATIC
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
};

static struct etharp_entry arp_table[ARP_TABLE_SIZE];

ARP缓存表项
ARP缓存表是以数组方式定义的,每个缓存表项etharp_entry除了保存IP地址与MAC地址外,还保存因暂时查不到表项而不知道目的MAC地址的数据包,在接收到目标主机的ARP应答前,可能有不止一个数据包待发送,这里可以使用数据包缓冲队列etharp_q_entry(实际上是一个单向链表)来描述这些数据包。

缓存表项还包含了描述该entry状态的成员state,使用枚举类型etharp_state进行管理,初始化时ARP缓存表项的状态都为ETHARP_STATE_EMPTY;若该表项只记录了IP地址还未记录对于的MAC地址则其状态为ETHARP_STATE_PENDING;若该表项记录了一对完整的IP地址与MAC地址则其状态为ETHARP_STATE_STABLE;由于ARP缓存表项需要定期更新,原本处于stable状态的表项处于更新过程中,还未接收到ARP应答包完成更新时的状态为ETHARP_STATE_STABLE_REREQUESTING。

为了保持缓存表中各个表项的有效性,ARP模块必须设置一定的超时检查机制,每个处于非ETHARP_STATE_EMPTY状态的表现都有生存时间,用ctime成员描述该缓存表项entry定时器的超时时间,若该表项的生存时间超时系统将会删除该表项。最后一个字段是前面网络接口层介绍过的netif结构体指针,在发送数据包时起着至关重要的作用。

2.3 ARP数据包描述

前面介绍ARP缓存表的生成是靠ARP请求与应答数据包实现的,下面介绍下ARP数据包的组织结构,由于ARP数据包是被封装在以太网帧中发送的,所以下图也列出了以太网帧首部(前篇网络接口层介绍过):
ARP数据报
以太网首部这里就不再介绍了,ARP数据包中硬件类型字段表示发送方想要知道的硬件接口类型,对于以太网MAC地址该类型值为1;协议类型字段表示要映射的协议地址类型,若要映射为IP地址该类型值为0x0800(与以太网帧首部的帧类型字段使用相同的一组值)。硬件地址长度字段对于以太网MAC地址该长度值为6,协议地址字段对于ARP协议表示IP地址的长度,由于ARP协议只适用于IPv4,不能用于IPv6(IPv6使用ICMPv6中的邻居探索消息替代ARP协议的功能),所以该协议长度值为4。

操作字段OP指出ARP数据包的类型,它们可以是ARP请求(值为1)、ARP应答(值为2)、RARP请求(值为3)、RARP应答(值为4)。剩余的四个字段比较好理解就不解释了,ARP数据包的描述如下:

// rt-thread\components\net\lwip-1.4.1\src\include\netif\etharp.h

#ifndef ETHARP_HWADDR_LEN
#define ETHARP_HWADDR_LEN     6
#endif

PACK_STRUCT_BEGIN
struct eth_addr {
   
  PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END

PACK_STRUCT_BEGIN
/** Ethernet header */
struct eth_hdr 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流云IoT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值