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

Python使用raw socket构造TCP SYN包发送时报WinError 10022错误

问题现象

使用Raw Socket构造TCP SYN数据包时,执行发送操作触发如下错误:

报错位置:server.sendto(packet, (dst_ip, 0))
错误信息:OSError: [WinError 10022] An invalid argument was supplied(提供了无效参数)

错误原因
  • Windows平台对AF_INET类型、SOCK_RAW类型、IPPROTO_TCP协议的原始套接字有强制约束:必须手动构造完整的IP头+TCP头,且提前通过setsockopt开启IP_HDRINCL选项告知系统用户自行填充IP头,否则系统直接判定传入参数无效。原代码未开启该选项,且仅构造了TCP头、缺失IP头。
  • TCP头数据偏移字段(doff)取值错误:该字段单位为4字节,标准20字节TCP头对应的取值为5(5*4=20字节),原代码赋值为80,完全不符合协议规范,导致头结构解析异常。
  • 发送时目标端口参数错误:原代码sendto传入的目标端口为0,属于无效端口值,目标端口应为构造TCP头时指定的80端口。
  • 校验和计算逻辑错误:原代码构造TCP校验和伪头部时使用的结构体格式串与字段定义不匹配,计算出的校验和为无效值,即使绕过参数校验,数据包也会被协议栈直接丢弃。
  • 运行权限不足:Windows下原始套接字操作需要管理员权限,普通权限启动Python进程也会触发参数类报错。
修正后代码
import socket
import struct


def checksum_calculator(data):
    checksum = 0
    data_len = len(data)
    index = 0
    # 按2字节为单位累加计算
    while data_len > 1:
        checksum += (data[index] << 8) + data[index + 1]
        checksum = (checksum & 0xffff) + (checksum >> 16)
        index += 2
        data_len -= 2
    # 处理奇数长度剩余字节
    if data_len:
        checksum += data[index] << 8
        checksum = (checksum & 0xffff) + (checksum >> 16)
    return (~checksum) & 0xffff


# 创建原始TCP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
# 关键配置:开启IP头自定义选项,Windows平台必须设置
sock.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)

# 基础地址配置
src_ip = socket.gethostbyname(socket.gethostname())
dst_ip = socket.gethostbyname('www.google.com')

# IP头字段配置
ip_version = 4
ip_ihl = 5  # IP头长度,单位4字节,标准20字节头对应值5
ip_tos = 0
ip_total_length = 40  # 20字节IP头 + 20字节TCP头
ip_id = 54321
ip_frag_offset = 0
ip_ttl = 64
ip_protocol = socket.IPPROTO_TCP
ip_checksum = 0  # 先填0,计算完成后回填

# TCP头字段配置
src_port = 4790
dst_port = 80
tcp_seq = 0
tcp_ack_seq = 0
tcp_doff = 5  # TCP头长度,单位4字节,标准20字节头对应值5
# TCP标志位
tcp_fin = 0
tcp_syn = 1
tcp_rst = 0
tcp_psh = 0
tcp_ack = 0
tcp_urg = 0
tcp_window = socket.htons(5840)
tcp_checksum = 0
tcp_urg_ptr = 0

# 组装临时IP头计算校验和
ip_ihl_ver = (ip_version << 4) + ip_ihl
tmp_ip_header = struct.pack(
    '!BBHHHBBH4s4s',
    ip_ihl_ver,
    ip_tos,
    ip_total_length,
    ip_id,
    ip_frag_offset,
    ip_ttl,
    ip_protocol,
    ip_checksum,
    socket.inet_aton(src_ip),
    socket.inet_aton(dst_ip)
)
ip_checksum = checksum_calculator(tmp_ip_header)
# 回填正确校验和,生成最终IP头
ip_header = struct.pack(
    '!BBHHHBBH4s4s',
    ip_ihl_ver,
    ip_tos,
    ip_total_length,
    ip_id,
    ip_frag_offset,
    ip_ttl,
    ip_protocol,
    ip_checksum,
    socket.inet_aton(src_ip),
    socket.inet_aton(dst_ip)
)

# 构造TCP伪头部用于计算TCP校验和
tcp_placeholder = 0
tcp_total_length = tcp_doff * 4
tcp_pseudo_header = struct.pack(
    '!4s4sBBH',
    socket.inet_aton(src_ip),
    socket.inet_aton(dst_ip),
    tcp_placeholder,
    ip_protocol,
    tcp_total_length
)
tcp_flags = tcp_fin + (tcp_syn << 1) + (tcp_rst << 2) + (tcp_psh << 3) + (tcp_ack << 4) + (tcp_urg << 5)
# 组装临时TCP头计算校验和
tmp_tcp_header = struct.pack(
    '!HHLLBBHHH',
    src_port,
    dst_port,
    tcp_seq,
    tcp_ack_seq,
    (tcp_doff << 4),  # 数据偏移存放在高4位,低4位为保留位填0
    tcp_flags,
    tcp_window,
    tcp_checksum,
    tcp_urg_ptr
)
tcp_checksum = checksum_calculator(tcp_pseudo_header + tmp_tcp_header)
# 回填正确校验和,生成最终TCP头
tcp_header = struct.pack(
    '!HHLLBBHHH',
    src_port,
    dst_port,
    tcp_seq,
    tcp_ack_seq,
    (tcp_doff << 4),
    tcp_flags,
    tcp_window,
    tcp_checksum,
    tcp_urg_ptr
)

# 构造完整IP数据包:IP头 + TCP头
full_packet = ip_header + tcp_header
# 发送数据包,目标端口填写实际的80端口
sock.sendto(full_packet, (dst_ip, dst_port))
运行注意事项
  • 必须以管理员权限启动命令行/Python进程,否则原始套接字调用会被系统拦截。
  • 本地防火墙、安全软件可能拦截自定义原始数据包,测试时可临时添加对应放行规则。
  • 若处于NAT网络环境(如家用路由器共享上网、公司内网),自定义构造的TCP SYN包可能被网关、运营商设备丢弃,无法收到目标响应属于正常网络限制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 05:15:42