macOS下Python用socket.sendto()发送手工数据包遇Errno22求助
macOS下Raw Socket发送数据包报错OSError: [Errno 22] Invalid Argument的原因与解决方法
核心原因分析
macOS对RAW套接字的限制和Linux存在显著差异,触发该错误的常见原因包括:
- IP头字段校验严格:使用
IPPROTO_RAW创建的套接字要求构造的IP头完全符合系统规范,哪怕微小错误(如校验和、总长度计算错误)都会触发参数无效 - 端口参数隐性要求:
sendto中传入的端口设为0可能不符合macOS套接字实现的隐性规则 - IP_HDRINCL行为差异:开启
IP_HDRINCL后,系统不会自动修正IP头的错误,只会严格校验并拒绝不符合要求的数据包
具体解决步骤
严格校验IP头关键字段
确保IP头的以下字段完全正确:- 版本号(version):必须为4(IPv4)
- 头部长度(IHL):以32位字为单位计算,20字节标准IP头对应IHL=5
- 总长度(total_length):等于IP头长度+传输层数据总字节数
- 校验和(checksum):必须准确计算,不能留空或使用错误值
可使用以下代码计算IP头校验和:
def calculate_ip_checksum(ip_header): checksum = 0 # 按16位分组求和 for i in range(0, len(ip_header), 2): word = (ip_header[i] << 8) + (ip_header[i+1] if i+1 < len(ip_header) else 0) checksum += word # 折叠进位并取反 checksum = (checksum >> 16) + (checksum & 0xffff) checksum += checksum >> 16 return ~checksum & 0xffff调整sendto的端口参数
将sendto中的端口从0改为合法传输层端口(与构造的TCP/UDP头目标端口一致即可):sent_bytes = sock_send.sendto(packet.tobytes(), (Destination_Address, 80))替换协议族标识(可选)
macOS中PF_INET是协议族的标准标识,替换AF_INET可能解决隐性兼容问题:sock_send = socket.socket(socket.PF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)以root权限运行程序
RAW套接字需要管理员权限,执行脚本时添加sudo:sudo python3 your_script.py
额外验证建议
用Wireshark抓取本地发送的数据包,对比IP头字段与系统规范的一致性,重点排查校验和、总长度等容易出错的字段。
内容的提问来源于stack exchange,提问作者Daniel Muntean
相关产品推荐
相关产品推荐

