似乎存在数据截断或损坏的问题。具体来说,预期的数据 "Hello, this is a test message"
被截断成了 "ssage"
。这可能是由于以下几个原因造成的:
- 数据包大小问题:某些网络设备或中间件可能会对数据包的大小进行限制或截断。
- 数据偏移问题:在接收端解析数据时可能存在偏移,导致只读取了部分数据。
- 编码问题:虽然你在发送端已经正确地将字符串编码为字节,但在接收端可能存在解码问题。
为了进一步诊断和解决这个问题,我们可以采取以下几个步骤:
1. 检查发送的数据包大小
确保发送的数据包大小符合网络设备的要求。以太网帧的最大传输单元(MTU)通常是 1500 字节。你的数据包相对较小,应该不会遇到这个问题,但仍然值得检查。
2. 在接收端添加调试信息
在接收端添加调试信息,打印出完整的接收到的数据包内容,以便更好地理解数据包的结构和内容。
3. 使用 Scapy 进行接收端解析
使用 Scapy 来解析接收到的数据包,确保正确地提取和解码数据。
以下是一个示例代码,展示如何在接收端使用 Scapy 来捕获和解析数据包
-
0x0800
是一个十六进制数,转换为十进制是2048
。在以太网协议的类型字段标准定义中,0x0800
表示以太网帧的数据部分承载的是互联网协议(IP)版本 4(IPv4)的数据报。 - 这意味着当接收方看到以太网帧的
type
字段为0x0800
时,它会知道要将数据部分传递给 IP 协议栈进行进一步的处理,例如解析 IP 头部、根据 IP 头部中的协议字段(如 TCP 为0x06
、UDP 为0x11
)将数据再传递给相应的传输层协议进行处理等。
packet.haslayer(layer)
是 Scapy 中的一个方法,用于检查数据包是否包含指定的协议层。这个方法返回一个布尔值,如果数据包包含该协议层,则返回 True
,否则返回 False
。
详细解释
-
参数:
-
layer
:要检查的协议层类型。例如,Ether
表示以太网层,IP
表示 IP 层,TCP
表示 TCP 层等。
-
-
返回值:
-
True
:如果数据包包含指定的协议层。 -
False
:如果数据包不包含指定的协议层。
-
- 通过
if Ether in packet
语句来确认捕获到的数据包中包含以太网帧头部信息,也就是确认是一个以太网帧数据包,才继续后续处理。 -
判断类型字段:
if packet[Ether].type == 0x0800
语句用于检查以太网帧的type
字段是否等于0x0800
。如前面所说,0x0800
表示该以太网帧承载的是 IPv4 数据报,只有符合这个条件,才去进一步处理数据部分,确保是符合预期发送格式的数据。
- 以太网帧是数据链路层的协议数据单元(PDU),它主要负责在物理网络(如局域网)中传输数据。IPv4 数据报是网络层的协议数据单元,用于在不同网络之间实现端到端的通信。在实际通信中,IPv4 数据报通常被封装在以太网帧的数据部分进行传输。也就是说,以太网帧就像是一个 “包裹”,而 IPv4 数据报是 “包裹” 里的 “物品”。
- IP(互联网协议,这里主要指 IPv4)主要负责将数据包从源主机传输到目标主机,它基于 IP 地址进行路由选择。但 IP 协议是无连接的、不可靠的协议,它不保证数据的可靠传输和顺序。
- TCP(传输控制协议)是一种面向连接的、可靠的传输层协议,它运行在 IP 协议之上。TCP 使用 IP 提供的服务来传输数据,并通过序列号、确认号、重传机制等方式来确保数据的可靠传输、顺序正确以及流量控制和拥塞控制。例如,当你通过浏览器访问网页时,HTTP 协议通常会使用 TCP 协议来建立可靠的连接,而 TCP 又依赖 IP 协议将数据发送到目标服务器的 IP 地址。
- 在 Python 的 Scapy 库中,
Ether
类是用于创建和操作以太网帧的工具。Ether
类的实例代表一个以太网帧。 - 当你使用
Ether
类创建一个对象时,如ether_frame = Ether(dst = dst_mac, src = src_mac, type = 0x0800)
,实际上是在构建一个以太网帧的头部结构。其中dst
参数指定目的 MAC 地址,src
参数指定源 MAC 地址,type
参数指定以太网帧所承载的上层协议类型(如0x0800
表示 IPv4)。
- 以太网帧是链路层的传输单元,为 IP 数据包(包括 IPv4)提供物理网络上的传输服务。IP 数据包(以 IPv4 为例)被封装在以太网帧中进行局域网等物理网络环境中的传输。
- TCP 协议运行在 IP 协议之上,当通过以太网进行 TCP 通信时,TCP 数据段首先被封装成 IP 数据报(IPv4 数据报),然后 IP 数据报再被封装进以太网帧进行传输。从接收方角度看,以太网帧被接收后,会先解析出其中的 IP 数据报,然后 IP 数据报再被解析出上层的 TCP 数据段进行处理。这样的分层结构使得网络通信能够在不同层次上进行分工协作,实现复杂的网络应用和通信功能。
- 以太网帧本身就是一种数据传输的载体。从结构上来说,它包含目的 MAC 地址、源 MAC 地址、类型 / 长度字段和数据部分(还包括帧校验序列 FCS 用于校验)。其中数据部分就可以用来存储要发送的信息。
- 例如,你可以将简单的文本信息、二进制数据(如文件的一部分)等放入以太网帧的数据部分进行发送。在局域网环境(如通过交换机连接的一组设备或者通过无线接入点连接的设备之间)下,这样的以太网帧可以在设备之间传输数据。
- IP 是互联网协议(Internet Protocol)的总称,它是一种网络层协议,用于在不同网络之间实现数据包的路由和转发。IPv4(Internet Protocol version 4)是 IP 协议的一个版本,是目前广泛使用的网络层协议之一。
- IPv4 使用 32 位的地址(例如 192.168.1.1)来标识网络中的主机,它提供了一种基本的机制,用于将数据包从源主机发送到目标主机。在数据包传输过程中,IPv4 头部包含了源 IP 地址、目的 IP 地址、协议类型(用于指示上层协议是 TCP、UDP 等)、生存时间(TTL)等重要信息,这些信息帮助网络设备(如路由器)对数据包进行正确的路由和处理。
- TCP(Transmission Control Protocol)是一种传输层协议,它依赖于 IP(这里主要以 IPv4 为例)来提供网络层的服务。TCP 提供面向连接、可靠的字节流服务。
- 当应用程序(如网页浏览器、电子邮件客户端等)需要可靠的数据传输时,会使用 TCP 协议。TCP 将应用程序的数据分割成适当大小的段,并在每个段前添加 TCP 头部,其中包含源端口、目的端口、序列号、确认号等信息。然后,TCP 段被封装在 IPv4 数据包中(IPv4 数据包的数据部分包含 TCP 段),通过 IP 网络进行传输。
- 在接收端,网络层(IPv4)将接收到的数据包解封装,将其中的 TCP 段传递给 TCP 协议处理。TCP 协议根据序列号和确认号等机制来确保数据的顺序正确、无丢失,并进行流量控制和拥塞控制,为应用程序提供可靠的、按顺序的数据传输服务。
-
网络因素导致数据丢失或截断
- 信号干扰和噪声:在无线通信环境(如通过 Wi - Fi 连接手机热点)中,存在各种信号干扰源。例如,周围其他无线设备(如蓝牙设备、其他 Wi - Fi 网络)可能会产生同频段的干扰,导致以太网帧在传输过程中部分数据损坏或丢失。这种干扰可能会随机影响帧中的数据,使得接收方收到的数据不完整。
- 网络拥塞:如果网络中的设备同时传输大量数据,造成网络拥塞,那么数据包(包括以太网帧)可能会在传输过程中被丢弃或者部分数据丢失。例如,在一个繁忙的公共 Wi - Fi 热点环境下,多个用户同时进行视频播放、文件下载等大数据量的操作,就容易出现这种情况。
-
- 帧校验序列(FCS)错误:以太网帧包含帧校验序列,用于检测数据在传输过程中是否出错。如果接收方检测到 FCS 错误,可能会丢弃整个帧或者尝试修复,但在修复过程中可能会丢失部分数据。例如,数据在传输过程中由于电磁干扰等原因发生了比特翻转,导致 FCS 校验不通过,接收方在处理这种错误帧时可能会出现数据丢失情况。
- 数据分片和重组问题:虽然没有进行进一步的 IP 层构造,但如果网络设备(如路由器或交换机)对以太网帧进行了分片操作(这种情况在一些特殊的网络配置或者处理较大数据帧时可能会发生),而接收方没有正确地重组这些分片,就会导致接收到的数据不完整。
eth0 接口
-
接口状态及基本属性:
-
flags=4163<UP,BROADCAST,RUNNING,MULTICAST>
表示该接口处于启用(UP)状态,支持广播(BROADCAST)、可以接收和发送数据(RUNNING),并且支持多播(MULTICAST)。 -
mtu 1500
说明该接口的最大传输单元(Maximum Transmission Unit)是 1500 字节,即一次能传输的最大数据帧长度为 1500 字节。
-
-
IP 地址相关信息:
-
inet 2.0.0.1
表示该接口配置的 IPv4 地址是 2.0.0.1。 -
netmask 255.255.255.0
是子网掩码,表明该网络的子网划分情况,这里表示子网掩码为 24 位,也就是网络部分占前 24 位,主机部分占后 8 位。 -
broadcast 2.0.0.255
是广播地址,用于向该子网内的所有主机发送广播消息。 -
inet6 fe80::60fa:8569:b1d1:7169 prefixlen 64 scopeid 0x20<link>
显示了该接口配置的一个 IPv6 链路本地地址,prefixlen 64
表示前缀长度为 64 位,scopeid 0x20<link>
表示其作用范围是链路本地(仅在本地链路内有效通信)。
-
- 网络连接机制:当 Ubuntu 系统启动并连接到手机热点时,它会通过网络协议向热点请求获取一个 IP 地址,以实现与该网络中的其他设备进行通信。这个过程与 Windows 系统或其他设备连接到热点获取地址的原理是相同的。热点作为一个接入点,会从其地址池中为连接的设备分配一个可用的 IP 地址,从而使设备能够在该局域网内进行数据传输和通信。
-
查看 Ubuntu 的 WLAN 地址方法:
-
使用命令行:在 Ubuntu 的终端中,可以通过输入命令
ifconfig
或ip addr
来查看网络接口信息,其中包括了连接到 WLAN 的网卡所分配到的 IP 地址等信息。例如,执行ifconfig wlan0
,会显示 wlan0 网卡的详细信息,包括其 IP 地址、子网掩码、MAC 地址等,如果连接正常,就可以看到类似inet 192.168.43.100
这样的 IP 地址信息,其中192.168.43.100
就是该 Ubuntu 在 WLAN 下的 IP 地址 ,不同的网络环境分配到的具体地址会有所不同27. - 使用图形界面:点击屏幕右上角的网络图标,选择已连接的 WLAN 网络,在弹出的 “连接信息” 面板中,可以直接看到 “IPv4 地址” 字段显示的就是 Ubuntu 在该 WLAN 下的 IP 地址7.
-
使用命令行:在 Ubuntu 的终端中,可以通过输入命令
-
MAC 地址及传输统计信息:
-
ether 00:ff:e4:fb:28:e8
是该网络接口的 MAC 地址,用于在以太网中唯一标识这个网络接口设备。 -
txqueuelen 1000 (Ethernet)
表示该接口的以太网发送队列长度为 1000,也就是可以缓存一定数量的待发送数据帧。 -
RX packets 0 bytes 0 (0.0 B)
表示接收的数据包数量为 0,接收的数据总字节数为 0 字节,说明到目前为止该接口还没有接收到数据。 -
TX packets 7 bytes 578 (578.0 B)
表示已经发送了 7 个数据包,总字节数为 578 字节。 -
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
这一组信息表示发送过程中没有错误、没有数据包被丢弃、没有缓冲区溢出、载波错误以及冲突等情况,说明发送数据的过程比较顺利。
-
2. eth4 接口
-
接口状态及基本属性:
- 同样
flags=4163<UP,BROADCAST,RUNNING,MULTICAST>
表明接口处于正常启用等状态,mtu 1432
表示其最大传输单元是 1432 字节,和 eth0 的 MTU 有所不同,可能是基于特定网络环境设置的。
- 同样
-
IP 地址相关信息:
-
inet 192.168.107.177
是该接口的 IPv4 地址,结合netmask 255.255.255.0
和broadcast 192.168.107.255
可确定其所在子网情况及广播地址。 - 有多个 IPv6 地址配置,如
inet6 fe80::38eb:199b:6ea8:6b1b prefixlen 64 scopeid 0x20<link>
是链路本地地址,另外inet6 2409:8961:1331:1de:4c8b:8471:905a:27c3 prefixlen 128 scopeid 0x0<global>
和inet6 2409:8961:1331:1de:fde0:4b58:7dc2:c470 prefixlen 64 scopeid 0x0<global>
是不同的全球单播 IPv6 地址,全球单播地址可用于在互联网等更大范围进行通信。
-
-
MAC 地址及传输统计信息:
-
ether ac:74:b1:b3:95:98
是对应的 MAC 地址。 -
RX packets 37739 bytes 106900591 (106.9 MB)
表明已经接收了 37739 个数据包,总字节数达到了 106.9MB,说明该接口接收了较多的数据流量。 -
TX packets 28305 bytes 2627944 (2.6 MB)
表示发送了 28305 个数据包,总字节数为 2.6MB。 - 最后的
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
同样表示发送数据时没有出现各类异常情况。
-
-
- 网络桥接(Network Bridging)是一种将两个或多个网络段连接在一起的技术,使得这些网络段在数据链路层看起来就像一个单一的网络。它主要工作在 OSI(开放系统互连)模型的数据链路层,也就是第二层。通过桥接器(Bridge)这个设备或者在软件层面实现的类似功能来完成这种连接。
-
工作原理
- 桥接器会维护一个转发表(Forwarding Table),这个表记录了每个连接到桥接器的网络设备(通常是通过 MAC 地址来标识)所处的网络段。当一个数据帧从一个网络段进入桥接器时,桥接器会检查数据帧中的目的 MAC 地址。
- 如果目的 MAC 地址对应的设备在数据帧进入的同一个网络段,桥接器就不会转发这个数据帧,避免数据在同一个网络段内的不必要传播。如果目的 MAC 地址对应的设备在另一个网络段,桥接器就会将这个数据帧转发到相应的网络段,从而实现不同网络段之间的数据通信。
- 例如,假设有两个以太网段 A 和 B 通过一个桥接器相连。当网络段 A 中的设备 A1 要发送数据给网络段 B 中的设备 B1 时,数据帧首先到达桥接器。桥接器查看数据帧的目的 MAC 地址,发现它属于网络段 B,于是就把这个数据帧转发到网络段 B,这样设备 B1 就能接收到来自设备 A1 的数据。
-
应用场景
- 扩展网络覆盖范围:在有线网络中,当需要将多个局域网(LAN)连接在一起,扩展网络的物理覆盖范围时可以使用桥接。比如,在一个大型办公楼里,不同楼层的局域网可以通过网络桥接的方式连接起来,形成一个更大的网络,方便用户在不同楼层之间进行通信。
- 连接不同类型的网络:桥接还可以用于连接不同类型的网络,例如将以太网和无线局域网(WLAN)连接起来。当有一些设备只能通过有线连接,而另一些设备需要无线连接时,通过在有线网络和无线网络之间设置桥接,可以使所有设备都能在同一个网络环境中通信。
- 虚拟机网络连接:在虚拟化环境中,如在一台物理主机上运行多个虚拟机(VM)。为了让虚拟机能够与物理网络或者其他虚拟机所在的网络进行通信,也可以使用网络桥接。通过将虚拟机的虚拟网络接口与物理主机的网络接口进行桥接,虚拟机就能够获得与物理主机相同的网络访问权限,就好像它们直接连接在物理网络上一样。
- 与路由器的区别:路由器工作在网络层(第三层),主要功能是根据 IP 地址进行数据转发和网络间的路由选择。而桥接器主要根据 MAC 地址进行数据转发,并且桥接后的网络在逻辑上是一个单一的网络,没有像路由器那样进行网络隔离和子网划分。例如,路由器可以将一个内部局域网和互联网连接起来,实现不同网络之间的通信,并且会对数据包进行复杂的路由处理;而桥接器只是简单地将两个本地网络段连接起来,使它们之间能够直接通信。
- 与中继器的区别:中继器(Repeater)工作在物理层(第一层),主要功能是对信号进行放大和再生,以延长信号的传输距离。中继器只是简单地复制和转发信号,不涉及对数据帧的任何处理,也不会区分不同的网络段和设备。而桥接器会根据 MAC 地址来判断是否转发数据帧,并且能够连接不同的网络段。
- 网络桥接:主要工作在数据链路层(OSI 模型第二层)。它通过识别数据帧中的 MAC 地址,将两个或多个网络段连接成一个逻辑上统一的网络,在这个网络中,各个设备的 MAC 地址对于桥接设备是可见的。例如,当桥接器收到一个数据帧时,它会检查目的 MAC 地址,若该地址位于另一个连接的网络段,则将数据帧转发过去。
- 网络地址转换(NAT):工作在网络层(OSI 模型第三层)。NAT 主要用于修改数据包中的 IP 地址和端口信息,通常是在内部私有网络和外部公共网络之间进行转换,使内部网络中的多个设备能够共享一个或少数几个外部 IP 地址访问互联网。
-
网络桥接:
- 常用于扩展局域网的范围,比如在企业网络中,将不同楼层或建筑物中的局域网段连接起来,形成一个更大的园区网络。
- 在虚拟机环境中,将虚拟机的虚拟网络接口与主机的物理网络接口进行桥接,使虚拟机能够直接访问主机所在的物理网络,就好像虚拟机是物理网络中的一个普通设备一样。
-
网络地址转换(NAT):
- 广泛应用于家庭网络和小型办公室网络中,使多个内部设备能够通过一个外部 IP 地址访问互联网,节省 IP 地址资源。
- 在企业网络中,用于保护内部网络的安全,隐藏内部网络的细节,防止外部网络直接访问内部设备,同时允许内部设备有条件地访问外部网络。
-
- 在 WSL(Windows Subsystem for Linux)的网络设置中,采用了一种网络共享模式。WSL 通过与 Windows 主机共享网络连接来访问外部网络。这种共享机制使得 WSL 中的 Ubuntu 系统能够使用主机的网络接口。
- 具体来说,当 WSL 启动时,它会创建一个虚拟网络接口(如 eth4),这个接口被配置为与主机的网络接口(在这个例子中是 WLAN 接口)共享网络连接。这意味着 WSL 中的 Ubuntu 系统实际上是通过主机的 WLAN 接口来访问外部网络的。
-
相同 IP 地址和 MAC 地址的原因
- IP 地址方面:由于 WSL 是通过主机的网络连接来访问外部网络,为了方便管理和通信,WSL 中的 Ubuntu 系统被分配了与主机 WLAN 接口相同的 IP 地址。这是因为在网络共享模式下,从外部网络(如路由器)的角度看,WSL 中的 Ubuntu 系统就像是主机的一部分,所以使用相同的 IP 地址可以让外部网络设备正确地将数据发送到主机以及通过主机转发给 WSL 中的 Ubuntu 系统。
- MAC 地址方面:WSL 中的虚拟网络接口(eth4)的 MAC 地址与主机 WLAN 接口的 MAC 地址相同,是因为 WSL 在共享主机网络连接时,为了简化网络通信过程中的地址转换和数据转发,会将虚拟网络接口的 MAC 地址设置为与主机网络接口的 MAC 地址一致。这样,在网络通信过程中,当数据帧在主机的网络接口和 WSL 的虚拟网络接口之间传递时,不需要进行额外的 MAC 地址转换操作,减少了网络通信的复杂性,提高了网络通信的效率。
-
网络连接与接口存在的区别
- 主机未连接网络,只是意味着主机无法与外部网络进行数据通信,但并不会影响 WSL 内部虚拟网络接口的存在。eth4 等虚拟网络接口是为了构建 WSL 内部的网络环境以及与主机网络进行交互而存在的,其存在与否与主机当前的网络连接状态无关。
- 例如,在一个局域网环境中,即使主机暂时断开与局域网的连接,其内部的虚拟机网络接口依然存在,只是无法通过该接口与局域网中的其他设备通信而已
-
- 通常情况:对于普通的计算机设备,物理网络接口数量在硬件层面一般是固定的。这些接口是在计算机生产过程中就确定好的。例如,一台普通的笔记本电脑可能有一个或两个以太网接口(用于连接网线),以及一个 Wi - Fi 接口(用于无线连接)。这些接口的数量和类型取决于电脑的设计用途和硬件配置。
- 特殊情况:不过,通过一些硬件扩展手段可以增加物理网络接口数量。比如,可以使用外接的网络接口扩展卡,插入计算机的 PCI - E 插槽来增加以太网接口。这种方式可以在一定程度上灵活地改变物理网络接口的数量,但受到计算机硬件扩展槽数量和兼容性等因素的限制。
-
虚拟网络接口
- 操作系统层面:在操作系统层面,网络接口数量不是固定的。操作系统可以创建和管理虚拟网络接口。例如,在 Linux 系统中,可以使用软件工具(如 TUN/TAP 设备)来创建虚拟网络接口。这些虚拟网络接口可用于各种网络应用场景,如创建虚拟专用网络(VPN)、容器网络或者在虚拟化环境中为虚拟机提供网络连接。
- 虚拟化环境:在虚拟机软件(如 VMware、VirtualBox 等)中,每一个虚拟机都有自己的虚拟网络接口,这些接口的数量可以根据虚拟机的网络配置需求进行设置。例如,一个虚拟机可以配置一个或多个虚拟以太网接口,用于连接不同的虚拟网络或者与主机及外部网络进行通信。而且,随着虚拟机的创建和销毁,虚拟网络接口的数量也会相应地变化。
-
获取网络接口信息:
info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', iface.encode('utf-8')))
-
s.fileno()
获取套接字的文件描述符。 -
0x8927
是一个常量,表示请求获取网络接口的硬件地址。 -
struct.pack('256s', iface.encode('utf-8'))
将网络接口名称iface
编码为字节,并打包成长度为256字节的字符串。 -
fcntl.ioctl
发送请求并接收返回的信息。
-
def get_local_mac(iface):
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0003))
info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', iface.encode('utf-8')))
return info[18:24]
-
fcntl.ioctl
是一个系统调用,用于执行各种设备相关的操作。在这个上下文中,它用于获取网络接口的硬件地址(即MAC地址)。 -
s.fileno()
返回套接字的文件描述符,这是操作系统用来标识文件或套接字的整数。 -
0x8927
是一个常量,表示请求获取网络接口的硬件地址。 -
struct.pack('256s', iface.encode('utf-8'))
将网络接口名称iface
编码为字节,并打包成长度为256字节的字符串,作为请求的参数。
-
info
是fcntl.ioctl
返回的数据,它是一个包含网络接口信息的字节序列。 - 这个字节序列包含了多种信息,包括但不限于网络接口的名称、IP地址、子网掩码和MAC地址。
- 在返回的字节序列
info
中,第18到第24个字节(即索引18到23)存储了MAC地址。 - MAC地址是一个6字节的值,因此
info[18:24]
提取了这6个字节,正好是MAC地址。
格式字符串 "!6s6sH"
的含义
-
!
:这是字节顺序标识符号,表示采用网络字节顺序(大端序,也就是高位字节在前、低位字节在后的存储顺序)来打包数据。在网络通信中,通常遵循网络字节顺序来确保不同设备间数据解读的一致性。 -
6s
:表示一个长度为 6 字节的字符串类型数据。在这里,第一个6s
对应的是要填入的目的 MAC 地址(dst_mac
),因为 MAC 地址就是由 6 个字节组成的物理地址信息,会按照网络字节顺序将dst_mac
的 6 字节数据进行打包。 -
6s
:同样是长度为 6 字节的字符串类型数据,第二个6s
对应的是通过调用get_local_mac(iface)
函数获取到的本地网络接口的 MAC 地址,也就是源 MAC 地址,同样以 6 字节长度按网络字节顺序进行打包。 -
H
:代表一个无符号短整型(2 字节)的数据类型。在这里用于存放以太网帧头部的类型字段,它通过socket.htons(0x0800)
将十六进制数值0x0800
(这是表示上层承载 IPv4 数据报的类型标识)转换为网络字节顺序的 2 字节无符号短整型数据后进行打包。
-
dst_mac
:这是一个事先定义好的变量,应该存储着接收方的 MAC 地址信息,以字节串(bytes 类型,长度为 6 字节)的形式传递给struct.pack
函数,按照前面提到的格式要求被打包到以太网帧头部的相应位置,作为目的 MAC 地址字段。 -
get_local_mac(iface)
:这是一个自定义函数,它的作用是获取本地指定网络接口(iface
表示接口名称)的 MAC 地址,返回的也是一个 6 字节的字节串,会被当作源 MAC 地址按照格式要求打包到以太网帧头部中。 -
socket.htons(0x0800)
:htons
是 Pythonsocket
模块中的函数,用于将主机字节顺序(不同机器可能不同,与网络字节顺序相对)的短整型数据转换为网络字节顺序。这里将十六进制值0x0800
(在以太网帧中表示上层协议为 IPv4 的标准类型标识)转换为网络字节顺序的 2 字节无符号短整型数据后,填充到以太网帧头部的类型字段位置,以便接收方收到数据包后,能通过这个类型标识知道后续的数据部分是按照 IPv4 协议来解析的。
- IPv4(Internet Protocol version 4)是一种网络层协议,它主要负责在互联网中将数据包从源节点发送到目标节点。在 IPv4 中,数据确实是以数据报(Datagram)的形式进行传输的。每个 IPv4 数据报都包含一个头部和数据部分。头部包含了源 IP 地址、目的 IP 地址、协议类型(用于指示上层协议,如 TCP 或 UDP)等重要信息,数据部分则承载了上层协议传递下来的实际数据,如 TCP 或 UDP 段。
- 当 IPv4 数据报承载 TCP(Transmission Control Protocol)数据时,数据传输具有可靠性。TCP 通过一系列的机制来确保数据的可靠交付,例如序列号、确认应答、重传机制等。发送方会为每个发送的数据字节分配一个序列号,接收方收到数据后会返回确认应答。如果发送方在一定时间内没有收到确认应答,就会重新发送数据。这使得基于 TCP 的 IPv4 数据报适用于对数据完整性和准确性要求较高的应用,如网页浏览(HTTP)、文件传输(FTP)等。
- 连接导向:TCP 是一种面向连接的协议。在数据传输之前,通信双方需要先建立一个连接,这个连接是通过三次握手过程来建立的。在连接建立后,数据才开始传输,传输结束后还需要通过四次握手来关闭连接。这种连接导向的方式可以更好地管理通信状态,但也会带来一定的开销,如连接建立和拆除的时间和资源消耗。
- 流量控制和拥塞控制:TCP 具有流量控制和拥塞控制机制。流量控制是为了防止发送方发送数据的速度过快,导致接收方无法及时处理。它通过接收方返回的窗口大小信息来控制发送方的数据发送量。拥塞控制则是为了避免网络出现拥塞,TCP 会根据网络的拥塞状况动态调整发送窗口大小。
-
<< 4
: 这是一个位移操作。4
的二进制表示是0100
,左移 4 位后变成01000000
,即十进制的64
。 -
+ 5
: 将64
和5
相加,得到69
。这个值在二进制中表示为01000101
。 - 前 4 位 (
0100
) 表示 IPv4 版本号。 - 后 4 位 (
0101
) 表示 IHL(Internet Header Length),即报头长度。IHL 的单位是 32 位字(4 字节),所以5
表示报头长度为5 * 4 = 20
字节。
-
-
- 后 4 位 (
0101
) 表示 IHL(Internet Header Length),即报头长度。IHL 的单位是 32 位字(4 字节),所以5
表示报头长度为5 * 4 = 20
字节。
- 后 4 位 (
-
-
+ 20
: 加上 20 字节,因为 IPv4 报头的固定长度是 20 字节。
IPv4 报头长度
- 固定部分: IPv4 报头的固定部分长度是 20 字节。
- 可变部分: IPv4 报头还可以包含选项字段,这些选项字段的长度是可变的。如果存在选项字段,报头长度会超过 20 字节。
- IHL (Internet Header Length): 报头长度以 32 位字(4 字节)为单位表示。最小值为 5,表示 20 字节的固定报头。
- 计算方法: 报头长度(字节) = IHL * 4
示例
- 固定报头: IHL = 5,报头长度 = 5 * 4 = 20 字节。
- 带选项的报头: 假设 IHL = 6,报头长度 = 6 * 4 = 24 字节。
-
版本号 (Version) 和 报头长度 (IHL): 1 字节
-
版本号 (Version): 占用前 4 位,表示 IP 协议版本,对于 IPv4,这部分始终为
0100
(即十进制的 4)。 - 报头长度 (IHL): 占用后 4 位,表示报头长度(以 32 位字为单位)。最小值为 5,表示 20 字节的固定报头。
-
版本号 (Version): 占用前 4 位,表示 IP 协议版本,对于 IPv4,这部分始终为
-
服务类型 (Type of Service, TOS): 1 字节
- 用于指定数据报的优先级和服务类型。
-
总长度 (Total Length): 2 字节
- 表示整个数据报的总长度(以字节为单位),包括报头和数据负载。
-
标识符 (Identification): 2 字节
- 用于唯一标识一个数据报,通常用于重组分片数据报
-
标志 (Flags) 和 片偏移 (Fragment Offset): 2 字节
- 标志 (Flags): 占用前 3 位,用于控制分片行为。
- 片偏移 (Fragment Offset): 占用后 13 位,表示当前片在原始数据报中的位置。
网络字节序(Network Byte Order)是指在计算机网络中传输数据时,多字节数据的字节顺序。在网络字节序中,最高有效字节(Most Significant Byte, MSB)总是先传输,也称为大端序(Big Endian)。
网络字节序的主要目的是确保不同字节序的计算机系统之间能够正确地交换数据。不同的计算机架构可能使用不同的字节序:
- 大端序(Big Endian): 最高有效字节放在内存的最低地址处。
- 小端序(Little Endian): 最低有效字节放在内存的最低地址处。
例如,数字 0x12345678
在大端序和小端序中的存储方式如下:
-
大端序(Big Endian):
12 34 56 78
-
小端序(Little Endian):
78 56 34 12
在网络通信中,为了确保发送方和接收方对数据的解释一致,通常约定使用大端序作为标准。这样,无论发送方和接收方的本地字节序如何,数据都能正确传输和解析
struct.pack
通过格式字符串中的字节序标志来确定数据是以大端序(Big Endian)还是小端序(Little Endian)排列。具体来说,格式字符串的第一个字符决定了字节序:
-
!
: 网络字节序(大端序,Big Endian) -
<
: 小端序(Little Endian) -
>
: 大端序(Big Endian) -
@
: 本机字节序(默认)
-
truct.pack
函数用于将数据按照指定的格式打包成字节串。!
是格式字符串的第一个字符,它表示使用网络字节序(大端序)进行打包。 - 大端序是一种数据存储顺序,高位字节存于低地址,低位字节存于高地址。在网络通信中,通常要求数据以网络字节序进行传输,这样不同字节序的计算机系统(如大端序的主机和小端序的主机)在交换数据时才能正确理解数据的内容。
-
最高有效字节(Most - Significant Byte,MSB)
-
定义:在一个多字节的数据表示中,最高有效字节是指包含数据最重要部分的字节。对于有符号整数来说,最高有效字节可能包含符号位(最高位)和数值的高位部分;对于无符号整数,它包含数值的高位部分。例如,对于 32 位整数
0x12345678
,0x12
是最高有效字节,因为它代表了这个整数的最高位部分。 -
举例说明:
- 假设我们要表示一个 16 位整数
0xABCD
,其中0xAB
是最高有效字节,0xCD
是最低有效字节。0xAB
在这个数字中占的权重更大,因为它代表的数值部分更高。如果把这个整数看作是一个数字的编码,0xAB
部分对这个数字的大小影响更大。 - 再比如一个 32 位的 IP 地址
192.168.1.1
,如果将其转换为 32 位整数表示(使用网络字节序,通常是大端序),那么最高有效字节对应的是192
部分,它在确定 IP 地址范围等方面起到更关键的作用。
- 假设我们要表示一个 16 位整数
-
定义:在一个多字节的数据表示中,最高有效字节是指包含数据最重要部分的字节。对于有符号整数来说,最高有效字节可能包含符号位(最高位)和数值的高位部分;对于无符号整数,它包含数值的高位部分。例如,对于 32 位整数
内存的最低地址
- 内存地址概念:计算机的内存可以看作是一个连续的字节数组,每个字节都有一个唯一的地址,就像街道上的门牌号一样。这些地址是按照一定的顺序排列的,地址值较小的位置被称为内存的低地址部分,地址值较大的位置被称为内存的高地址部分。
-
- 使用了一个联合体(union)。联合体中的成员共享同一块内存空间。在这里,定义了一个短整型(short)变量
value
和一个字符数组(char)bytes
,它们占用相同的 2 个字节内存。当把0x0102
赋值给value
后,在内存中这两个字节的存储顺序就反映了系统的字节序。如果bytes[0]
存储的是0x01
(高位字节),那么系统是大端序;如果bytes[0]
存储的是0x02
(低位字节),则系统是小端序。
- 使用了一个联合体(union)。联合体中的成员共享同一块内存空间。在这里,定义了一个短整型(short)变量
-
- 保证数据完整性:IPv4 校验和主要目的是检测在 IP 数据包传输过程中头部信息是否出现错误。由于 IP 数据包在网络中传输时,可能会受到各种因素的干扰,如电磁干扰、网络设备故障等,这些因素可能导致数据包头部的某些比特位发生翻转或损坏。校验和提供了一种简单的机制来验证头部信息是否被正确传输,从而确保数据的完整性。
- 早期错误检测:在网络通信的早期阶段(如在网络层)就对数据进行错误检测。这有助于减少不必要的处理,因为如果头部信息错误,那么整个数据包可能无法正确地被后续的网络处理流程(如路由、传输层处理等)所处理。通过尽早发现错误,可以避免浪费网络资源在错误的数据包上,提高网络的整体效率。
- 计算机制和验证过程:IPv4 校验和是基于 IP 头部的内容计算得出的。发送方在构建 IP 数据包时,会将 IP 头部(包括版本、首部长度、服务类型、总长度、标识符、标志位、片偏移、生存时间、协议、首部校验和、源 IP 地址和目的 IP 地址等字段)视为 16 - bit(位)字的序列。将这些 16 - bit 字相加(如果相加的结果产生了进位,则将进位加到和的最低位),然后取反码得到校验和。这个校验和被填充到 IP 头部的 “首部校验和” 字段中。
- 接收方验证:当接收方收到 IP 数据包时,它会以相同的方式对 IP 头部的 16 - bit 字进行相加(包括 “首部校验和” 字段),如果结果为全 1(0xFFFF),则表示头部信息在传输过程中没有出现错误(至少在校验和覆盖的范围内没有错误)。如果计算结果不是全 1,则表明头部信息出现了错误,接收方通常会丢弃这个数据包,避免使用错误的头部信息进行后续处理。
-
数据长度检查:如果数据长度不是偶数,则在末尾添加一个字节
b'\0'
使其变为偶数。 -
初始化校验和:初始化校验和变量
s
为0。 -
遍历数据:以每两个字节为一组进行遍历:
- 将每组的两个字节组合成一个16位的整数
w
。 - 将
w
加到校验和s
上。 - 处理可能的进位:将
s
的高16位加到低16位上,确保s
始终为16位。
- 将每组的两个字节组合成一个16位的整数
- 最终处理:对校验和取反并截取低16位,返回结果
-
- ARP(Address Resolution Protocol)即地址解析协议,是一种用于将网络层(IP 层)地址解析为链路层(MAC 层)地址的协议。它工作在 TCP/IP 协议栈的网络接口层。
-
ARP 协议的目的
- 在基于以太网等局域网技术构建的网络环境中,网络设备之间的通信需要知道彼此的物理地址(MAC 地址)。然而,应用程序和网络层协议通常使用 IP 地址来标识目的主机。例如,当主机 A 要发送一个 IP 数据包给主机 B 时,主机 A 知道主机 B 的 IP 地址,但不知道其 MAC 地址,这时候就需要 ARP 协议来帮助获取主机 B 的 MAC 地址,从而实现数据链路层的帧封装和准确的数据传输。
在局域网内(同一广播域)
- 以太网帧的转发主要是基于 MAC 地址。当设备 A 要向同一局域网内的设备 B 发送数据时,它会先通过 ARP 协议获取设备 B 的 MAC 地址。然后,设备 A 将数据封装成以太网帧,在帧头中填写设备 B 的 MAC 地址作为目的地址,自己的 MAC 地址作为源地址。
-
ARP 协议的作用
-
地址解析功能
- 当一个主机需要发送数据给同一局域网内的另一个主机时,它会首先检查自己的 ARP 缓存表。ARP 缓存表是一个存储了 IP 地址和 MAC 地址映射关系的表。如果在缓存表中找到了目的主机的 MAC 地址,就可以直接使用这个 MAC 地址来封装以太网帧进行发送。
- 如果缓存表中没有目的主机的 MAC 地址,发送方主机就会发送一个 ARP 请求广播帧。这个广播帧会在局域网中传播,其目的 MAC 地址是广播地址(FF - FF - FF - FF - FF - FF),表示局域网上的所有设备都能收到这个请求。ARP 请求帧中包含了发送方的 IP 地址和 MAC 地址,以及想要查询的目的 IP 地址。
- 当目的主机收到这个 ARP 请求,并且发现请求中的目的 IP 地址与自己的 IP 地址相匹配时,就会发送一个 ARP 应答帧,这个应答帧中包含了目的主机的 MAC 地址,发送给请求主机。请求主机收到应答后,就会将目的主机的 MAC 地址添加到自己的 ARP 缓存表中,方便后续通信使用,同时使用这个 MAC 地址来封装以太网帧并发送数据。
-
支持动态地址更新
- ARP 缓存表中的条目不是固定不变的。为了适应网络中设备的 MAC 地址或 IP 地址可能发生的变化,ARP 协议会定期更新缓存表中的信息。例如,当一个设备的网卡更换后,其 MAC 地址会改变,通过 ARP 协议的动态更新机制,网络中的其他设备可以及时更新自己的 ARP 缓存表,以确保通信的准确性。
-
跨网段通信的辅助作用
- 在跨网段通信的场景下,虽然主要的路由转发是由路由器完成的,但 ARP 协议仍然起到辅助作用。当数据包从源主机到达路由器的一个接口时,路由器需要通过 ARP 协议获取下一跳设备(可能是另一个路由器接口或者目的主机所在局域网的网关)的 MAC 地址,以便将数据包正确地转发到下一个链路。
-
地址解析功能
- 虽然最终的以太网帧转发在每一个局域网段还是基于 MAC 地址,但 IP 地址起到了关键的路由决策作用。当设备 A 要向另一个不同局域网(不同子网)的设备 B 发送数据时,设备 A 首先会根据自己的子网掩码和设备 B 的 IP 地址判断设备 B 是否在同一子网。
- 如果不在同一子网,设备 A 会将数据包发送给它所配置的默认网关(路由器)。设备 A 通过 ARP 协议获取默认网关的 MAC 地址,然后将数据包封装成以太网帧,目的 MAC 地址填写为默认网关的 MAC 地址。路由器收到这个以太网帧后,会根据数据包中的 IP 地址信息进行路由决策,确定下一跳的 IP 地址,然后通过 ARP 协议获取下一跳设备的 MAC 地址,再将数据包封装成新的以太网帧转发出去。
以太网帧的基本结构如下:
- 目标MAC地址 (Destination MAC Address): 6字节
- 源MAC地址 (Source MAC Address): 6字节
- 以太类型 (Ethertype): 2字节
- 数据字段 (Payload): 可变长度
- 填充 (Padding): 如果数据字段长度小于46字节,则需要填充到46字节
- 帧校验序列 (FCS): 4字节(通常由硬件生成)
-
目标地址 (
iface
): 这里是指网络接口名称,例如"eth4"
。对于原始套接字(AF_PACKET
),这个参数实际上是网络接口的名称,而不是一个真正的IP地址或MAC地址。 -
端口号 (
0
): 对于原始套接字(AF_PACKET
),端口号通常是被忽略的。在原始套接字的上下文中,端口号参数通常设置为0
,因为它并不适用于这种类型的套接字。原始套接字直接操作链路层数据,不需要端口号来区分不同的应用程序或服务。
以太网帧结构
一个典型的以太网帧结构如下:
- Preamble (56 bits): 用于接收设备同步数据流。
- SFD (1 bit): 表示帧的开始。
- Destination MAC Address (48 bits): 目标设备的 MAC 地址。
- Source MAC Address (48 bits): 发送设备的 MAC 地址。
- Ethertype (16 bits): 表示上层协议类型(如 0x0800 表示 IPv4)。
- Payload (Variable length): 实际的数据负载。
- FCS (Frame Check Sequence, 32 bits): 帧校验序列,用于错误检测。
IPv4 数据报结构
一个典型的 IPv4 数据报结构如下:
- Version (4 bits): IPv4 版本号,固定为 4。
- IHL (Internet Header Length, 4 bits): IPv4 首部长度,以 32 位字为单位。
- Type of Service (TOS, 8 bits): 服务类型。
- Total Length (16 bits): IPv4 数据报的总长度,包括首部和数据负载。
- Identification (16 bits): 数据报的唯一标识符。
- Flags and Fragment Offset (16 bits): 标志和片偏移。
- Time to Live (TTL, 8 bits): 数据报在网络中的生存时间。
- Protocol (8 bits): 上层协议类型(如 6 表示 TCP)。
- Header Checksum (16 bits): IPv4 首部校验和。
- Source IP Address (32 bits): 源 IP 地址。
- Destination IP Address (32 bits): 目的 IP 地址。
- Options (Variable length, optional): 可选字段。
- Payload (Variable length): 实际的数据负载。
结论
在构建以太网帧和 IPv4 数据报时,你不需要手动添加帧定界符(如 Preamble 和 SFD)和 EOF 终止符。这些细节由底层网络协议栈和驱动程序自动处理。你需要关注的是帧和数据报的结构和字段,确保它们符合相应的协议规范
有没有和wireShark类似的在线抓包工具?不需要下载的那种?