为了学习,我目前正在尝试创建一个简单的python porgram来向某个设备发送ICMP ping数据包.为了开始,我查看了python模块Pyping:https://github.com/Akhavi/pyping/blob/master/pyping/core.py的源代码
我试图了解发送和构建数据包时发生的所有情况,但是我已经设法卡在代码的一部分上,似乎无法弄清楚它的功能和用途究竟是什么.我一直在研究ICMP数据包,我知道它们包含类型代码校验和和数据现在困扰我的代码是:
self.own_id = os.getpid() & 0xFFFF
header = struct.pack(
"!BBHHH", ICMP_ECHO, 0, checksum, self.own_id, self.seq_number
)
padBytes = []
startVal = 0x42
for i in range(startVal, startVal + (self.packet_size)):
padBytes += [(i & 0xff)] # Keep chars in the 0-255 range
data = bytes(padBytes)
我的问题是:
>将self.own_id和self.seq_number添加到标题中有什么用?
>在for循环中计算的是什么,为什么它具有特定的起始值0x42?
我是网络新手,任何帮助都会非常感激.
解决方法:
ICMP Echo Request数据包的描述
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type(8) | Code(0) | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Payload |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
这里是上面wiki链接中各个字段的描述:
The Identifier and Sequence Number can be used by the client to match the reply with the request that caused the reply.
In practice, most Linux systems use a unique identifier for every ping process, and sequence number is an increasing number within that process. Windows uses a fixed identifier, which varies between Windows versions, and a sequence number that is only reset at boot time.
pyping代码的描述
标头生成
查看send_one_ping的完整函数体,这是您的代码所在的位置.我将用一些信息对其进行注释:
def send_one_ping(self, current_socket):
"""
Send one ICMP ECHO_REQUEST
"""
# Header is type (8), code (8), checksum (16), id (16), sequence (16)
# Annotation: the Type is 8 bits, the code is 8 bits, the
# header checksum is 16 bits
# Additional Header Information is 32-bits (identifier and sequence number)
# After that is Payload, which is of arbitrary length.
所以这一行
header = struct.pack(
"!BBHHH", ICMP_ECHO, 0, checksum, self.own_id, self.seq_number
)
这一行使用struct with layout!BBHHH创建包头,这意味着:
> B – 无符号字符(8位)
> B – 无符号字符(8位)
> H – 无符号短路(16位)
> H – 无符号短路(16位)
> H – 无符号短路(16位)
所以标题看起来像这样:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ICMP_ECHO | 0 | checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| self.own_id | self.seq_number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
请注意:
> self.own_id设置发送此数据的应用程序的标识符.对于此代码,它只使用程序的程序标识符编号.
> self.seq_number设置序列号.这有助于您识别连续发送多个ICMP请求数据包.它可以帮助您执行计算ICMP数据包丢失等操作.
客户端可以使用组合的标识符和序列号字段来匹配回应请求的回应答复.
有效负载生成
现在让我们转到Payload部分.有效负载具有任意长度,但Ping类此代码从默认值获取为总数据包有效负载大小55 bytes.
所以下面的部分只是创建了一堆任意字节来填充有效载荷部分.
padBytes = []
startVal = 0x42
# Annotation: 0x42 = 66 decimal
# This loop would go from [66, 66 + packet_size],
# which in default pyping means [66, 121)
for i in range(startVal, startVal + (self.packet_size)):
padBytes += [(i & 0xff)] # Keep chars in the 0-255 range
data = bytes(padBytes)
在它结束时,byte(padBytes)实际上看起来像这样:
>> bytes(padBytes)
b'BCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwx'
为什么选择0x42?
据我所知,0x42作为有效载荷标识符没有实际意义,所以这似乎相当随意.这里的有效载荷实际上毫无意义.正如您在“有效载荷生成”部分中所看到的,它只是生成一个并不真正意味着什么的连续序列.如果他们想要,他们可能刚刚决定用0x42字节填充整个数据包有效负载.
标签:python,networking,byte,icmp