IPv4协议详解

IPv4

为上层协议提供无连接,无状态,不可靠的服务

  1. 无状态:IP通信双方不同步传输数据的状态信息,所以IP数据报的发送,传输和接收都是相互独立的,没有上下文关系 (IP模块无法处理IP数据报的乱序和重复,IP模块只要接收到完整的IP数据报就会发给上层协议模块)
  2. 无连接:IP通信双方都不长久的维持对方任何信息,(所以每次发送数据都要指出对方IP地址)
  3. 不可靠: IP协议不能保证IP数据报准确地到达接收端(只是best effort),发送端的IP模块检测到IP数据报发送失败就通知上层协议发送失败,并不会重传

IPv4头部结构

ipv4

  1. Version 4bit: IP版本号,IPv4 = 4

  2. Header Length 4bit: IP头部有多少个4字节(32bit),2^4-1=15,15*5=60Byte,所以IP头部最长60Byte

  3. Type of Service 8bit: 服务类型TOS,8bit,前3bit弃用,中间4bit表示如下,最后1bit必须置0

    4bit分别表示:最小延时,最大吞吐量,最高可靠性,最小费用

    1000:最小延时

    0100:最大吞吐量

    0010:最高可靠性

    0001:最小费用

    3bit弃用+4bit类型+1bit0

    4bit中最多只用1个可以置1,全0表示一般服务,ftp这种需要最大吞吐,ssh和telnet需要最小延时

  4. Total Length: 16bit: 整个IP数据报的长度,所以IP数据报最大长度(2^16-1=65535字节),因为数据链路层MTU限制(现在一般都是以太网MTU=1500),长度超过MTU的数据报都将被分片传输

  5. Identitfier 16bit: 唯一的标识主机发送的每一个数据报,由OS随机生成,同一个数据报的所有分片都具有相同标识值

  6. Flags 3bit: 第1bit保留,第2bit Don't Fragment DF位=1表示禁止分片,如果此IP数据报长度超过MTU则IP模块将会丢弃并返回ICMP报文,第3bitMore Fragment MF位=1表示更多分片,除了数据报最后一个分片外,其他分片此bit都=1

  7. Fragmented offset: 13bit:分片位移,是分片相对于原始IP数据报开始处(数据部分)的偏移,实际值=该值左移3bit,所以偏移都是8的倍数,,那么除了最后一个分片外,其他分片的长度都是8的倍数

  8. Time to live TTL: 8bit: 允许经过的路由器转跳次数,Win发送时TTL=64,Linux发送是TTL=128

  9. Protocol: 8bit: 表示上层协议是谁: /etc/protocols可查看各上层协议,ICMP=1,TCP=6,UDP=17

  10. Header CheckSum: 16bit: 仅校验数据报头部

    到这里已经用了12Byte

  11. Source Address: 32bit:源IP地址

  12. Destination Address: 32bit目标IP地址

    到这里用了20Byte

  13. Options,剩下的40字节是可变长可选择信息

本实验的网络结构

虚拟机A和B都是Vmware的NAT网络模式

主机A IP:192.168.247.148
主机B IP:192.168.247.147
网关IP: 192.168.247.2

tcpdump实际查看一下包头部结构

sudo tcpdump -ntx -i lo #回环地址网卡

telnet 127.0.0.1
数据包
​ 网络数据都是大端的,从头开始对应看

  1. 0x04: ipv4
  2. 0x05:4*5=20Byte,所以头部长20字节
  3. 0x10: 中间4bit:1000 标识最小延时(上层telnet需要最小延时服务)
  4. 0x3c:整个IP数据报长度=60字节
  5. 0x7239:整个IP数据报标识,每发送一个IP数据报值+1
  6. 0x40: TTL = 60
  7. 0x06: 表示上层协议是TCP协议(telnet基于tcp)
  8. 0xca70:校验和
  9. 0x7f000001:转化为点分十进制: 127.0.0.1
  10. 同上

​ 每发送一个IP,id+1
id


IP分片

IP数据报长度超过数据链路层的MTU,将被分片传输,在IP层进行分片(网络层)

IP头部第2个4字节提供了分片的信息,

  1. 数据报标识
  2. 3bit分片flags
  3. 13bit数据偏移值

特点:

  1. 每个IP分片具有自己的IP头部,具有相同的标识值和不同的片偏移

  2. 除了最后一个分片,其他分片的flags=MF

  3. 每个分片的IP头部的总长度字段将被设置为该分片的长度

ifconfig查看mtu
ifconfig

不被分片的话IP数据报的数据部分长度最长是1480字节(IP头部20字节),构造一个数据部分长度为1481字节的数据报来查看如何分片

用ICMP来封装一个1481字节的ICMP报文,ping命令使用的ICMP回显和应答报文头部长度是8字节,则构造数据长度是1473字节的ICMP数据就行

sudo tcpdump -ntv -i ens33 icmp #只抓ICMP报文

ping -s 1473 192.168.247.148 #在主机B向我ping,并且指定ICMP数据包的数据长度
icmp报文

  1. 2个ip分片的id相同,
  2. 第二个分片的offset=第一个分片的数据长度,
  3. 第一个分片的flags = MF = flags[+]
  4. 第一个分片长度1500,第二个分片长度=21字节

分片图解
分片


IP模块工作大概流程

接收来自数据链路层IP数据报,

  1. 对数据报头部做CRC校验
  2. 判断是否发送给自己(或者是广播地址),是就给上层协议的模块
  3. 不是就根据路由表转发,如果OS配置不允许转发的话就丢弃

路由表大概机制

查看路由表
route

  1. default:默认路由项,网关地址这里没显示,在这实验的网络结构是192.168.247.2, G标识下一跳目标是Gateway网关,网卡是ens33
  2. 192.168.247.0+子网掩码255.255.255.0:表示可以直接发送此网段的所有主机192.168.247.*

匹配规则:

  1. IP数据包目标地址完全匹配路由表中目的IP地址
  2. 上面的第二项,属于同一网段
  3. 选择默认路由项

路由表更新

如下例子

  1. 在主机A上添加对主机B的路由

    sudo route add -host 192.168.247.147 dev ens33

  2. 删除上面route表的第二项

    sudo route del -net 192.168.247.0 netmask 255.255.255.0

  3. 删除default

    sudo route del default

    注意此时我们就无法连接internet了

  4. 将主机B作为默认网关

    sudo route add default gw 192.168.247.147 dev ens33

    此时还是不能连接上Internet (原因下面讲)

IP转发

为什么主机A访问Internet的IP包发给网关(主机B)后不能上网呢,

回顾IP模块处理流程:判断是否发送给自己,这里不是,然后让转发模块来处理,根据OS配置来判断是否转发,那么A访问不了Internet的原因可能是主机B并没有转发主机A的包

主机一般只接收和发送数据报

开启主机B的IP转发功能:

1
2
sudo -s 
echo 1 > /proc/sys/net/ipv4/ip_forward

然后在主机A,访问Internet,

ping www.baidu.com
icmp重定向

这里返回了ICMP重定向报文,告诉主机此IP数据报更应该使用哪一个路由器来转发,并且更新此主机(主机A)的路由表

为什么主机A把主机B作为网关(把包发给B)不是最优路由路径,因为主机A和B都要通过网关192.168.247.2来访问Internet)

  • 一般来说主机只能接收ICMP重定向报文,而路由器只能发送ICMP重定向报文 (可设置)

参考 <<Linux高性能服务器编程>>