You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux系统中如何让监听UDP的recvmsg调用返回小于0的失败值

如何让监听UDP的recvmsg返回小于0的失败值

约束条件

  • 无法在目标系统上运行代码,仅能向该系统发送UDP/IP数据包。

已尝试的方案及结果

此前参考@Ben Voigt提出的方案,尝试发送ICMP Port Unreachable报文触发ECONNRESET/ECONNREFUSED错误,分两步测试:

  1. 首先发送普通UDP报文触发目标系统调用recvmsg,测试代码如下:
from scapy.all import *
send(IP(dst=dst_ip)/UDP(sport=src_port,dport=dst_port))

运行后recvmsg被正常调用,未返回-1错误值。
2. 随后直接向目标端口发送构造的ICMP Port Unreachable报文,期望触发recvmsg调用失败,代码如下:

from scapy.all import *
send(IP(dst=dst_ip)/ICMP(type=3,code=3)/IP(dst=dst_ip)/UDP(sport=src_port,dport=dst_port))

测试后该操作未触发recvmsg被调用。

失败原因分析

测试未生效有两个核心原因:

  1. 构造的ICMP报文不符合内核匹配规则
    ICMP端口不可达报文需要严格匹配协议规范才会被内核关联到对应UDP socket,当前构造的报文存在明显错误:
    • 嵌套IP头地址方向错误:ICMP错误会路由给原始报文的发送方,因此嵌套的IP头源地址必须是目标主机IP,目的地址为原始报文的接收地址,当前代码中嵌套IP头目的地址写为目标主机自身IP,完全不符合格式要求。
    • 嵌套UDP头的校验和、长度字段未按规范计算,内核校验失败后会直接丢弃报文,不会向上层递交。
  2. 目标UDP socket默认不接收异步ICMP错误
    仅执行bind()后调用recvmsg()的UDP监听socket,默认不会处理任何异步ICMP错误。只有满足以下两个条件之一,匹配的ICMP错误才会触发recvmsg返回-1:
    • 该socket主动调用过connect()绑定了固定对端地址
    • 该socket开启了IP_RECVERR套接字选项
      如果目标程序未做上述配置,无论发送何种ICMP报文,都不会触发recvmsg返回错误。

可行方案说明

如果确认目标UDP socket已经调用过connect()绑定对端,可按以下规则构造ICMP报文触发错误:

  • 外层IP头:源地址填写socket绑定的对端IP,目的地址填写目标主机IP
  • ICMP头:type=3(目的不可达)、code=3(端口不可达),正确计算校验和
  • 嵌套IP头:完全匹配目标socket发往对端的报文特征:源IP为目标主机IP、目的IP为对端IP、协议号为17(UDP)
  • 嵌套UDP头:源端口为目标监听端口、目的端口为对端端口,长度、校验和与原始发出的UDP报文前8字节一致
    如果目标socket既未调用connect()也未开启IP_RECVERR,仅靠外部发包无法让recvmsg返回-1:所有畸形UDP包(校验和错误、长度非法、重叠分片、带非法IP选项)都会被内核协议栈直接丢弃,不会触发socket层错误;而socket本身的运行错误(接收超时、缓冲区异常、socket被关闭等)都需要本地权限操作才能触发,外部发包无法干预。

内容的提问来源于stack exchange,提问作者Kokomelom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 11:24:40