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

Python使用原始套接字发送IP数据包的两类问题咨询

嘿,我来帮你搞定这两个RAW套接字的问题!咱们一个个来:

问题1:无法发送IP_PACKET变量

首先,RAW套接字发送数据包有几个容易踩坑的点,我帮你梳理常见原因和解决办法:

核心问题排查

  1. 缺少IP_HDRINCL选项设置
    当你使用IPPROTO_RAW创建套接字时,内核默认会自动替你生成IP头,覆盖你自定义的IP_PACKET里的IP头。必须通过套接字选项告诉内核:“我自己已经构造好完整IP头了,别改!”
    修正你的Create_SOCKET函数:

    def Create_SOCKET():
        global ST
        try:
            ST = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
            # 关键:开启IP_HDRINCL,让内核使用自定义IP头
            ST.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
        except socket.error as MSG:
            print "[ERROR] Socket creation error:\n", MSG
            sys.exit()
    
  2. IP_PACKET不完整
    你构造的IP_PACKET必须是完整的IP头 + 载荷数据,不能只有IP头。比如在IP_HEADER函数最后,要把你的业务数据(payload)拼接到IP头后面:

    # 示例:添加测试载荷
    payload = b"Test RAW socket data"
    IP_PACKET = ip_header + payload
    
  3. 权限不足
    RAW套接字需要特权权限才能使用,在Linux下必须用sudo运行脚本:

    sudo python your_script.py
    
  4. 发送参数错误
    使用sendto时,目标地址格式要正确,端口参数对RAW套接字无效,填0即可:

    # 发送示例
    ST.sendto(IP_PACKET, (Destination_IP, 0))
    

问题2:设置IP数据包的标志位

IP头里的标志位占3个比特,位于**IP标识字段后的2字节(标志+分片偏移)**中,高3位是标志位:

  • 位15(最高位):保留位,必须为0
  • 位14:DF(Don't Fragment,不分片),设为1表示禁止分片
  • 位13:MF(More Fragments,更多分片),设为1表示后面还有分片

具体实现步骤

  1. 定义标志位数值
    按网络字节序(大端)计算,常见的标志组合:

    • 无标志:0x0000
    • 开启DF(不分片):0x4000(因为2^14 = 16384 = 0x4000)
    • 开启MF(更多分片):0x2000(2^13 = 8192 = 0x2000)
    • 同时开启DF+MF:0x6000
  2. 打包到IP头中
    在构造IP头时,把标志位和分片偏移(一般设为0,除非你要分片)一起打包:

    def IP_HEADER(Source_IP, Destination_IP):
        global IP_PACKET
        IP_VER = 4
        IP_IHL = 5
        # 版本+IHL合并为1字节(4位版本+4位IHL)
        IP_VER_IHL = (IP_VER << 4) | IP_IHL
        IP_TOS = 0
        IP_ID = 0
        # 开启DF标志,分片偏移为0
        IP_FLAGS_OFFSET = 0x4000
        IP_TTL = 64
        # 协议类型,比如TCP(IPPROTO_TCP)或UDP(IPPROTO_UDP)
        IP_PROTOCOL = socket.IPPROTO_TCP
        IP_CHECKSUM = 0
    
        # 先打包IP头(总长度暂时填0,后面再修正)
        ip_header = struct.pack('!BBHHHBBH4s4s',
                                IP_VER_IHL,
                                IP_TOS,
                                0,  # 先占位总长度
                                IP_ID,
                                IP_FLAGS_OFFSET,
                                IP_TTL,
                                IP_PROTOCOL,
                                IP_CHECKSUM,
                                socket.inet_aton(Source_IP),
                                socket.inet_aton(Destination_IP))
        
        # (可选但推荐)计算IP头校验和
        def calculate_checksum(data):
            checksum = 0
            data_len = len(data)
            if data_len % 2 != 0:
                data += b'\x00'
                data_len += 1
            for i in range(0, data_len, 2):
                word = (data[i] << 8) + data[i+1]
                checksum += word
                checksum = (checksum & 0xffff) + (checksum >> 16)
            return ~checksum & 0xffff
    
        # 替换校验和
        ip_header = ip_header[:10] + struct.pack('!H', calculate_checksum(ip_header)) + ip_header[12:]
        
        # 添加载荷并修正总长度
        payload = b"Test payload for RAW IP packet"
        total_length = len(ip_header) + len(payload)
        ip_header = ip_header[:2] + struct.pack('!H', total_length) + ip_header[4:]
        
        # 组合成完整数据包
        IP_PACKET = ip_header + payload
    

小提示

  • 如果不需要分片,建议开启DF标志,避免数据包在传输中被分片导致问题
  • 校验和可以让内核自动计算,但手动计算能避免某些内核环境下的兼容性问题

内容的提问来源于stack exchange,提问作者D.H

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:27:31