我正在向服务器注入ICMP“需要碎片,DF位设置”,理想情况下服务器应该开始发送ICMP中“next-hop MTU”字段中提到的大小的数据包。但这不起作用。
这是服务器代码:
#!/usr/bin/env python
import socket # Import socket module
import time
import os
range= [1,2,3,4,5,6,7,8,9]
s = socket.socket() # Create a socket object
host = '192.168.0.17' # Get local machine name
port = 12349 # Reserve a port for your service.
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host, port)) # Bind to the port
rand_string = os.urandom(1600)
s.listen(5) # Now wait for client connection.
while True:
c, addr = s.accept() # Establish connection with client.
print 'Got connection from', addr
for i in range:
c.sendall(rand_string)
time.sleep(5)
c.close()
以下是客户端代码:
#!/usr/bin/python # This is client.py file
import socket # Import socket module
s = socket.socket() # Create a socket object
host = '192.168.0.17' # Get local machine name
port = 12348 # Reserve a port for your service.
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.connect((host, port))
while 1:
print s.recv(1024)
s.close()
Scapy注入ICMP:
###[ IP ]###
version= 4
ihl= None
tos= 0x0
len= None
id= 1
flags= DF
frag= 0
ttl= 64
proto= ip
chksum= None
src= 192.168.0.45
dst= 192.168.0.17
\options\
###[ ICMP ]###
type= dest-unreach
code= fragmentation-needed
chksum= None
unused= 1300
Send(ip/icmp)
未使用的字段显示为wireshark中的下一跳MTU。服务器是否足够智能,以便在与客户端通信时检查DF位是否未设置,并且仍在接收ICMP“需要分段,DF位设置”消息?如果不是那么为什么服务器没有将其数据包大小从1500减少到1300?
答案 0 :(得分:3)
首先,让我们回答您的第一个问题(通过TCP发送ICMP吗?)。
ICMP直接通过IP运行,如RFC 792:
中所述使用基本IP标头发送ICMP消息。
这可能有点令人困惑,因为ICMP is classified as a network layer protocol rather than a transport layer protocol但考虑到它只是IP的一个附加物来携带错误,路由和控制消息和数据,这是有道理的。因此,由于TCP层依赖于ICMP帮助管理和排除故障的IP层,因此它无法依靠TCP层进行自身传输。
现在,让我们处理你的第二个问题(如果ICMP没有通过TCP发送,TCP如何了解MTU?)。我依靠官方规范尽力回答这个问题,但也许最好的方法是分析一些开源网络堆栈的实现,以便了解真正发生的事情。 ...
即使ICMP消息没有在TCP上分层,TCP层也可能知道路径的MTU值。由网络堆栈实现操作系统以通知MTU的TCP层,然后它可以使用该值来更新其MSS值。
RFC 1122要求ICMP消息包含IP头以及触发该ICMP消息的有问题数据报的前8个字节:
每个ICMP错误消息都包含Internet标头和至少触发错误的数据报的前8个数据八位字节;可以发送超过8个八位字节;此标头和数据必须与收到的数据报保持不变。
在需要Internet层将ICMP错误消息传递到传输层的情况下,必须从原始头中提取IP协议号,并用于选择适当的传输协议实体来处理错误。
这说明了操作系统如何精确定位应更新MSS的TCP连接,因为这8个字节包括源端口和目标端口。
RFC 1122还规定,必须有一种机制,通过该机制,传输层可以学习可以为给定的{源,目的地,TOS}三元组发送的最大传输层消息大小。因此,我假设一旦收到ICMP Fragmentation needed and DF set
错误消息,MTU值就会以某种方式提供给可以使用它来更新其MSS值的TCP层。
此外,我认为实例化TCP连接并利用它的应用层也可以处理此类消息,并在更高级别对数据包进行分段。应用程序可能会打开一个需要ICMP消息的套接字,并在收到ICMP消息时采取相应的措但是,在应用层对数据包进行分段对TCP和TCP完全透明。 IP层。请注意,大多数应用程序将允许TCP& IP层可以自行处理这种情况。
但是,一旦主机收到ICMP Fragmentation needed and DF set
错误消息,其下层所指示的行为就不具有决定性。
RFC 5927, section 2.2指的是RFC 1122,第4.2.3.9节,其中指出TCP应该在从IP层传递ICMP Fragmentation needed and DF set
错误消息时中止连接,因为它表示硬错误情况。 RFC声明主机应该实现此行为,但它不是必须的(第4.2.5节)。此RFC还在3.2.2.1节中声明必须将接收到的目标无法到达消息报告给TCP层。当在该连接上收到ICMP Fragmentation needed and DF set
错误消息时,实现这两者将导致TCP连接的破坏,这没有任何意义,并且显然不是所期望的行为。
RFC 1191没有概述发送所需的特定行为 主机,因为不同的应用程序可能有不同的要求,并且 不同的实现架构可能有利于不同的策略[这 为这种方法留下了空间-OA]。
唯一需要的行为是主机必须尝试避免发送更多内容 在不久的将来具有相同PMTU值的消息。主持人也可以 停止在IP头中设置Don?t片段位(并允许 路由器碎片化的方式)或减少数据报大小。该 更好的策略是降低邮件大小,因为碎片化 将导致更多流量并消耗更多的互联网资源。
总而言之,我认为规范对于收到ICMP Fragmentation needed and DF set
错误消息时主机所需的行为并不确定。我的猜测是,两个层(IP和TCP)都会收到消息通知,以便更新他们的MTU&分别是MSS值,其中一个负责以较小的块重新传输有问题的数据包。
最后,关于您的实现,我认为为了完全符合RFC 1122,您应该更新ICMP消息以包含有问题的数据包的IP头,以及其接下来的8个字节(尽管您可能包含的不仅仅是前8个字节)。此外,您应该验证在ICMP消息所引用的数据包的相应ACK之前是否收到ICMP消息。事实上,为了安全起见,我会彻底废除那个ACK。
Here是如何构建ICMP消息的示例实现。如果发送ICMP消息作为对其中一个TCP数据包的响应失败,我建议你先尝试在收到与之相关的TCP数据包之前发送ICMP消息,以确保在ACK之前收到它。只有在失败的情况下,尝试完全取消ACK。
答案 1 :(得分:0)
我理解它的方式,主机收到"所需的ICMP碎片和DF设置" ,但消息可能来自路径中的中间设备(路由器),因此主机不能直接将icmp响应与当前会话匹配,icmp只包含目标ip和mtu限制。
主机然后在路由表中添加一个条目,用于记录路由的目标ip,以及10分钟到期的mtu。
这可以通过在执行跟踪触发icmp响应的跟踪路径或ping之后通过 ip route get x.x.x.x 询问特定路由来在linux上观察到。
$ ip route get 10.x.y.z
10.z.y.z via 10.a.b.1 dev eth0 src 10.a.b.100
cache expires 598sec mtu 1300