网络通信一直都是所有的框架的基础
经过TCP封装后的数据称为TCP报文段,TCP协议为通讯双方维持一个连接,并且在内核中存储相关数据。这部分数据中的TCP头部信息和TCP内核缓冲区(发送缓冲区或者接受缓冲区)数据一起构成了TCP报文段。
当发送端应用程序使用send(或者write)函数向一个TCP连接写入数据时,内核中的TCP模块首先把这些数据复制到与该连接对应的TCP内核发送缓冲区中,然后TCP模块调用IP模块提供的服务,传递的参数包括TCP头部信息和TCP发送缓冲区中的数据,即TCP报文段。
经过IP封装后的数据称为IP数据报。IP数据报也包括头部信息和数据部分,其中数据部分就是一个TCP报文段,UDP数据报或者ICMP报文。
经过数据链路层封装的数据称为帧(frame)。 传输媒介不同,帧的类型也不同。比如,以太网上传输的是以太网帧(ethernet frame),而令牌环网络上传输的则是令牌环帧(token ring frame)。
以太网帧使用6字节的目的物理地址和6字节的源物理地址来表示通信的双方。关于类型(type)字段,4字节CRC字段对帧的其他部分提供循环冗余校验。
帧的最大传输单元(max transmit unit, MTU), 即帧最多能携带多少上层协议数据(比如IP数据报),通常受到网络类型的限制。以太网帧的MTU 1500字节。正因为如此,过长的IP数据报可能需要被分片(fragment)传输。
当帧到达目的主机时, 将沿着协议栈自低向上依次传递。各层协议依次处理帧中本层负责的头部数据, 以获取所需的信息,并最终处理后的帧交给目标应用程序。这个过长称为分用(demultiplexing)。
因为IP协议,ARP协议和RARP协议都使用帧传输数据,使用帧的头部需要提供某个字段(具体情况取决于帧的类型)来区分他们。以以太网帧为例, 它使用2字节的类型字段来标识上层协议。如果主机接受到的以太网帧类型字段的值位0x800,则帧的数据部分为IP数据报,以太网驱动程序将帧交付给IP模块;若类型字段的值为0x806,则帧的数据部分为ARP请求或者应答报文,以太网驱动程序就将帧交付给ARP模块;若类型字段的值为0x835,则帧的数据报部分为RARP请求或者应答报文,以太网驱动程序就将帧交付给RARP模块。
同样,因为ICMP协议,TCP协议和UDP协议都使用IP协议, 使用IP数据报的头部采用16位的协议(protocol)字段来区分他们。
TCP报文段和UDP数据报则通过其头部中的16位的端口号(port number)字段来区分上层应用程序。比如DNS协议对应的端口号是53,HTTP协议(Hyper-Text Transfer protocol, 超文本传送协议)对应的端口号是80。 所有知名应用层协议使用的端口号都可在/etc/services 文件中找到。
帧通过上述分用步骤后, 最终将封装前的原始数据送至目标服务(ARP服务,RARP服务,ICMP服务或者应用程序)。这样在顶层目标服务看来,封装和分用是乎没有发生过。
ARP协议能实现任意网络层地址到任意物理地址的转换仅讨论从IP地址到以太网自动(MAC地址)的转换。其工作原理是:主机向自己所在网络广播一个ARP请求,该请求包含目标机器的网络地址。此网络上的其他机器都将收到这个请求,但只有被请求的目标机器会回应一个ARP应答,其中包含自己的物理地址。
以太网ARP请求/应答报文的格式
介绍:
上图所知, ARP请求/应答报文的长度为28字节。如果再加上以太网帧头部和尾部的18字节,则一个携带ARP请求/应答报文的以太网帧长度为46字节。不过有的实现要求以太网帧数据部分长度至少为46字节,此时ARP请求/应答报文将增加一些填充字节,以满足中国要求。在这种情况下,一个携带ARP请求/应答报文的以太网帧长度为64字节。
通常,ARP维护一个高速缓存,其中包含经常访问(比如网关地址)或者最近访问的机械的IP地址到物理地址的映射。这样就避免了重复的ARP请求,提高了发送数据包的速度。
linux下可以使用arp命令来查看和修改ARP高速缓存。比如,ernest-laptop在某一时刻(注意,ARP高速缓存是动态变化的)的ARP缓存内容如下
arp -a
描述是路由器 下面是两条命令则分别删除和添加一个ARP缓存项。
arp -d ip # 删除一个IP对应的ARP缓存项
arp -s ip mac # 添加ip和mac对应的ARP缓存项
为了清楚了解ARP的运作过程,使用telnet命令测试一下
arp -d 192.168.64.128 # 清除ARP缓存中ip地址对应缓存
tcpdump -i ens33 -ent ‘(dst 192.168.64.128 and src 192.168.64.132) or (dst 192.168.64.132 and src 192.168.64.129)’
在192.168.64.128上登录
telnet 192.168.64.128 echo
在执行telent命令之前,应先清除ARP缓存中与IP对应的项,否则ARP通信不被执行,我们也就无法抓取到期望的以太网帧。当执行telent命令并在两台通信主机之间建立TCP连接,tcpdump抓取到的众多数据包中,只有最靠前的两个和ARP通信有关系。
在 192.168.64.132抓取的数据
由tcpdump抓取的数据包本质上是以太网帧,我们通过该命令的众多选项了扩展帧的过滤(比如dst和src指定通信的目的端IP地址和源端IP地址)和显示(比如用-e 选项开启以太网帧头部选项的显示)。
第一数据包中ARP通信的源端的物理地址是00:0c:29:b8:08:9f,目的端的物理地址是00:0c:29:af:12:59, 这是以太网的广播地址,用以表示整个LAN。该LAN上所有的机械都会收到并处理这样的帧。数值0x806是以太网帧头部的类型字段的值,它表示分用的目标是ARP模块。该以太网帧的长度为42字节(实际上是46字节,tcpdump未统计以太网帧尾部4字节的CRC字段),其中数据部分长度为28字节。"Request"表示这个是ARP请求,"who-has 192.168.64.132 tell 192.168.64.129"则表示是 129机械要查询132的IP地址。
第二数据包中,ARP通信的源端的物理地址是00:0c:29:b8:08:9f,目的端的物理地址是00:0c:29:af:12:59。"Reply"表示这是一个ARP应答,"192.168.64.129 is-at 00:0c:29:b8:08:9f"则表示目标机器129报告其物理地址。该以太网帧的长度为60字节(实际上是64字节),可见它使用了填充字节来满足最小帧长度。
我们通常使用机器的域名来访问这个机器,而不直接使用其IP地址,比如访问因特网上的各种网站。那么如何将机械的域名转换成IP地址呢?这就需要使用域名查询服务。域名查询服务有很多实现方式,比如NIS(Network information Service, 网络信息服务),DNS和本地静态文件等。
DNS是一套分布式的域名服务系统。每个DNS服务器上都存放着大量的机器名和IP地址的映射,并且是动态更新的。众多网络客户端程序都使用DNS协议来向DNS服务器查询目标主机的IP地址。DNS查询和应答报文的格式
16位标识字段用于标记一对DNS查询和应答,以此区分一个DNS应答是哪个DNS查询的回应。
16位标志字段用于协商具体的通信方式和反馈通信状态。NDS报文头部的16位标志字段的细节
NDS报文标志的含义
接下来的4个字段则分别指出DNS报文的最后4个字段的资源记录数目。对查询报文而言,它一般包含1个查询问题,而应答资源记录数,授权资源记录数和额外资源记录数则为0。应答报文的应答资源记录数据则至少为1,而授权资源记录数和额外资源记录数可为0或者非0。
查询问题的格式
查询名以一定的格式封装了要查询的主机域名。16位查询类型表示如何执行查询操作,常见的类型有如下几种:
16位查询类通常为1,表示获取因特网地址(IP地址)。
应答字段,授权字段和额外信息字段都使用资源记录(Resource record, RR)格式。
32位域名是该记录中与资源对应的名字,其格式和查询问题中的查询名字段相同。16位类型和16位类字段的含义也与DNS查询问题的对应字段相同。
32位生存时间表示该查询记录结果可被本地客户端程序缓存多长时间,单位是秒。
16位资源数据长度字段和资源数据字段的内存取决于类型字段。对类型A而言,资源数据是32位IPv4地址,而资源数据长度则为4(以字节为单位)。
我们要访问DNS服务, 就必须先字段DNS服务器的IP地址。linux使用/etc/resolv.conf 文件来存放DNS服务器的IP地址。
为了清楚了解NDS通信的过程,使用tcpdump抓取这一过程中LAN上传输的以太网帧。
tcpdump -i eth0 -nt -s 500 port domain
这一次执行tcpdump抓包是,我们使用"port domain"来过滤数据包,表示只抓取使用domain(域名)服务的数据包,即DNS查询和应答报文。
这两个数据包开始的"IP"指出,它们后面的内容描述的是IP数据报。tcpdump以"IP地址,端口号"的形式来描述通信的某一端:以">“表示数据传输的方向,”>"前面是源端,后面是目的端,可见,第一个数据包是我的机器(IP地址是172.20.137.125) 向其首选DNS服务器(IP地址是100.100.2.128)发送的DNS查询报文(目标端口53是DNS服务事业的端口),第二个数据包是服务器反馈的DNS应答报文。
第二个数据包中,“4/0/0” 表示该报文中包含4个应答资源记录,0个授权资源记录和0个额外信息记录。"CNAME www.a.shifen.com, CNAME www.wshifen.com., A 104.193.88.123, A 104.193.88.77 " 则表示4个应答资源记录的内容。其中CNAME表示紧跟其后的记录是机器的别名, A表示紧随后其后的记录是IP地址。该应答报文的长度为226字节。
韩老师的视频学习,在这里感谢韩老师的视频
位置的分析
可用的IP选项包含:
抓包分析 开启二进制查看 [-x]
sudo tcpdump -ntx -i lo
IPv4头部各个字段详解
十六进制数 | 十进制数表示 | IP头部信息 |
---|---|---|
0x4 | 4 | IP版本号 |
0x5 | 5 | 头部长度为5个32位(20字节) |
0x10 | TOS选项中最小延时服务被开启 | |
0x003c | 60 | 数据报总长度,60字节 |
0x17a9 | 数据报标识(动态的) | |
0x4 | 设置了禁止分片标志 | |
0x000 | 0 | 分片偏移 |
0x40 | 64 | TTL被设为64 |
0x06 | 6 | 协议字段为6,表示上层协议是TCP协议 |
0x2501 | IP头部校验和 | |
0x7f000001 | 32位源端IP地址127.0.0.1 | |
0x7f000001 | 32位目的端IP地址127.0.0.1 | |
telnet服务选择使用具有最小延时的服务
包工具分析
当IP数据报的长度超过帧的MTU时,它将被分片传输。分片可能发送在发送端,也可能发生在中转路由器上,而且可能在传输过程中被多次分片,当只有在最终的目标机器上,这些分片才会被内核中的IP模块重新组装。
IP头部中的三个字段给IP的分片和重组提供了足够的信息,数据报标识,标志和片偏移。一个IP数据报的每个分片都具有自己的IP头部,它们具有相同的标识值,但具有不同的片偏移。并且除了最后一个分片外,其他分片都将设置MF标志。此外,每个分片的IP头部的总长度字段将被设置为该分片的长度。
以太网帧的MTU1500字节(可以通过ifconfig命令或者netstat命令查看),因此它携带的IP数据报的数据部分最多是1480字节(IP头部占用20字节)。考虑用IP数据报封装一个长度为1481字节的ICMP报文(包括8字节的ICMP头部,所以其数据部分长度为1473字节),则该数据报在使用以太网帧传输时必须被分片,长度为1501字节的IP数据报被拆分成两个IP分片,第一个IP分片长度为1500字节,第二个IP分片的长度为21字节。每个IP分片都包含字节的IP头部(20字节),其第一个IP分片的IP头部设置了MF标志,而第二个IP分片的IP头部则没有设置该标志,因为它已经是最后一个发片了。原始IP数据报中的ICMP头部内容被完整的复制到了第一个IP分片中。第二个IP分片不包含ICMP头部信息,因为IP模块重组该ICMP报文的时候只需要一份ICMP头部信息,重复传送这个信息没有任何益处。1473字节的ICMP报文数据的前1472字节被IP模块复制到第一IP分片中,使其总长度为1500字节,从而满足MTU的要求:而多出的最后1字节则被复制到第二个IP分片中。
需要指出的是,ICMP报文的头部长度取决于报文的类型,其变化范围很大。上图中以8字节为例,因为后面的例子用到了ping程序,而ping程序使用的ICMP回显和应答报文的头部长度是8字节。
为了看清楚IP分片的具体过程,从129机器到320机器的ping过程,每次传送1473字节的数据(这是ICMP报文的数据部分)以强制引起IP分片,并用tcpdump抓取这一过程中双方交换的数据包。
$ tcpdump -ntv -i ens33 icmp #只抓取ICMP报文
$ ping 192.168.64.129 -s 1473 # 用-s 选项指定每次发送1473字节的数据
抓取的数据报
前两个IP分片的标识值都15881,说明它们是同一个IP数据报的分片。第一个分片的片偏移值为0,而第二个则是1480。很显然,第二个分片的片偏移值实际上也是第一个分片的ICMP报文的长度。第一个分片设置了MF标志以表示还有后续分片,所以tcpdump输出"flags[+]", 而第二个分片则没有设置任何标志,所以tcpdump输出"flags[none]"。 这个两个分片的长度分别为1500字节和21字节。
最后,IP层传递给数据链路层的数据可能是一个完整的IP数据报,也可能是一个IP分片,它们统称为IP分组(packet)。
IP协议的一个核心任务是数据报的路由,即决定发送数据报到目标机器的路径。为了理解IP路由过程,我们先简要分析IP模块的基本工作流程。
我们从右往左来分析,当IP模块收到来自数据链路层的IP数据报时,它首先对该数据报的头部做了CRC校验,确认无误之后就分析其头部的具体信息。
如果该IP数据报的头部设置了源站选路选项(松散源路由选择或严格源路由选择),则IP模块调用数据报转发自模块来处理该数据报。如果该IP数据报的头部中目标IP地址是本机的某个IP地址,或者是广播地址,即该数据报是发送给本机的,则IP模块就根据数据报头部中的协议字段来决定将它派发给你个上层应用(分用)。如果IP模块发现这个数据报标识发送给本机的,则也调用数据报转发自模块来处理该数据报。
IP数据报应该发送至你个下一跳路由(或者目标机器),以及价格哪个网卡来发送,就是IP路由过程,即上图中"计算下一跳路由"子模块。IP模块实现数据报路由的核心数据结构是路由表。这个表按照数据报的目标IP地址分类,同一类型的IP数据报将被发往相同的下一跳路由器(或者目标机器)。
IP输出队列中存放的是所有等待发送的IP数据报,其中除了需要转发的IP数据报外,还包括封装了本机上上层数据(ICMP报文,TCP报文段和UDP数据报)的IP数据报。
上图中的虚线箭头显示了路由表更新的过程。这一过程是指过程路由需要或者route命令调整路由表,使之更适应更新的网络拓扑结构,称为IP路由策略。
要研究IP路由机制,需要先了解路由表的内容。我们可以使用route命令或者netstat命令查看路由表。 我阿里云机器查看
$route
该路由表包含三项,每一项都包含8个字段
路由表内容
字段 | 含义 |
---|---|
Destination | 目标网络或者主机 |
Gateway | 网关地址,*表示目标和本机在同一个网络,不需要路由 |
Genmask | 网络掩码 |
Flags | 路由项标志,常见标志有如下5中(更多标志见route命令的man手册);U:该路由项是活动的, H: 该路由项的目标是一台主机,G: 该路由项的目标是网关, D: 该路由项是由重定向生成的,M: 该路由项被重定向修改过 |
Metric | 路由距离,即到达重定网络所需的中转数 |
Ref | 路由项被引用的次数(linux未使用) |
Use | 该路由项被使用的次数 |
Iface | 该路由项对应的输出网卡接口 |
第一项的目标地址是default,即所谓的默认路由项。该项包含一个"G"标志,说明路由的下一跳目标是网关,其地址是0.0.0.0(这是阿里云网络中路由器的本地IP地址)。另外一个路由项的目标地址是172.20.128.0,它指的是本地局域网。该路由项的物理地址为0.0.0.0,说明数据报不需要路由中转,可以直接发送到目标机器。
那么路由表是如何按照IP地址分类的呢?或者是给定数据报的目标IP地址,它将匹配路由表中的哪一项呢?这就是IP的路由机制,分为3个步骤:
路由表必须能够更新,以反映网络连接的变化,这样IP模块才能准确,高效地转发数据报,route命令可以修改路由表。我们看几个例子
$ route add -host 192.168.1.109 dev eth0
$ route del -net 192.168.1.0 netmask 255.255.255.0
$ route del default
$ route add default gw 192.168.1.109 dev eth0
第一行表示添加主机192.168.1.109对应的路由项。这样设置之后,所有从这台机器发送到109的IP数据报将通过网卡eth0 直接发送至目标机器的接收网卡。第2行表示上层网络192.168.1.0对应的路由项。这样,除了机器192外,测试机器将无法访问giant局域网上任何其他机器(能访问到192是由于执行了上一条命令)。第三行表示上层默认路由项,这样做的后果是无法访问因特网。第四行表示重新设置默认路由项,不过这次其网关是机器192(而表示能直接服务器因特网的路由器) 经过上述修改后的路由表
这个新的路由表中,第一个路由项是主机路由项,使用它被设置了"H"标志
通过route命令或者其他工具手工修改路由表,是具体的路由更新方式。对于大型的路由器,它们通常通过BGP(Border Gateway Protocol, 边际网关协议),RIP(Routing Information Portocol, 路由信息协议),OSPF等协议来发现路径,并更新自己的路由表。这中更新方式是动态的,自动的。
前文提到,不是发送给本机的IP数据报将由数据报转发子模块来处理。路由器都你执行数据报的转发操作,而主机一般只发送和接收数据报,这是因为主机上/proc/sys/net/ipv4/ip_forward内核陈松默认被设置为0。我们可以通过相关它来使能主机的数据报转发功能
echo 1 > /proc/sys/net/ipv4/ip_forward
对于IP数据报转发的系统(主机或路由器),数据报转发子模块将对期望转发的数据报执行如下操作:
理解网关服务器的, 服务器中路由原理
个人博客地址:https://chensongpoixs.github.io