Python使用原始套接字发TCP SYN包报WinError 10022无效参数如何解决
问题根因
Windows平台的原始套接字机制和Linux存在差异,你遇到的WinError 10022报错由以下几个常见原因触发:
- 权限不足:Windows要求所有操作原始套接字的程序必须以管理员身份运行,普通用户权限执行会直接抛出参数无效错误。
- 源IP不符合限制:Windows会默认拦截源IP不属于本机已配置网卡IP的出站原始TCP包,如果你构造TCP包时传入了伪造的源IP,会被系统直接拦截触发报错。
- 套接字选项配置错误:如果你自己构造了完整的IP头+TCP段数据包,没有提前开启
IP_HDRINCL套接字选项,系统会误将你传入的IP头当成TCP payload处理,导致参数校验失败。 - 端口占用:你构造TCP包时使用的源端口已经被本机其他进程占用,也会触发参数错误。
解决方案
按以下步骤逐一排查修复即可:
- 右键点击终端/IDE,选择「以管理员身份运行」,再执行你的Python脚本,确认权限问题是否解决。
- 替换
TCPPacket初始化时的src_host参数为你本机网卡的实际IP(可以通过ipconfig命令查看,不能用127.0.0.1除非你发送环回测试包),不要使用伪造的源IP。 - 确认你的数据包结构:
- 如果只构造了TCP段(也就是你现在的TCPPacket类生成的内容),不需要加
IP_HDRINCL选项,系统会自动为你填充IP头; - 如果你自行构造了完整的IP头+TCP段结构,需要在套接字创建后添加配置:
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) - 如果只构造了TCP段(也就是你现在的TCPPacket类生成的内容),不需要加
- 更换未被占用的源端口再测试,避免端口占用问题。
- 临时关闭本机第三方防火墙、安全软件再测试,部分安全软件会拦截原始套接字操作触发报错。
可用参考代码
import socket import struct import array def chksum(packet: bytes) -> int: if len(packet) % 2 != 0: packet += b'\0' res = sum(array.array("H", packet)) res = (res >> 16) + (res & 0xffff) res += res >> 16 return (~res) & 0xffff class TCPPacket: def __init__(self, src_host: str, src_port: int, dst_host: str, dst_port: int, flags: int = 0): self.src_host = src_host self.src_port = src_port self.dst_host = dst_host self.dst_port = dst_port self.flags = flags def build(self) -> bytes: packet = struct.pack( '!HHIIBBHHH', self.src_port, # Source Port self.dst_port, # Destination Port 0, # Sequence Number 0, # Acknoledgement Number 5 << 4, # Data Offset self.flags, # Flags 8192, # Window 0, # Checksum (initial value) 0 # Urgent pointer ) pseudo_hdr = struct.pack( '!4s4sHH', socket.inet_aton(self.src_host), # Source Address socket.inet_aton(self.dst_host), # Destination Address socket.IPPROTO_TCP, # PTCL len(packet) # TCP Length ) checksum = chksum(pseudo_hdr + packet) packet = packet[:16] + struct.pack('H', checksum) + packet[18:] return packet if __name__ == '__main__': # 替换为你本机实际网卡IP SRC_IP = "192.168.1.100" DST_IP = "8.8.8.8" SRC_PORT = 12345 DST_PORT = 80 # 构造SYN包,标志位2对应SYN syn_packet = TCPPacket(SRC_IP, SRC_PORT, DST_IP, DST_PORT, flags=2).build() s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP) s.sendto(syn_packet, (DST_IP, DST_PORT)) s.close()
内容的提问来源于stack exchange,提问作者Lima Victor
相关产品推荐
相关产品推荐

