打开TUN接口抛出io.UnsupportedOperation或FileNotFoundError问题咨询
TUN接口报错问题排查及解决方案
TUN接口在不同操作系统的创建逻辑存在差异,你使用的代码原生没有适配自动创建设备的逻辑,两个平台的报错分别由不同的配置、代码问题导致。
macOS 端问题
成因
MacOS 默认不会自动生成 /dev/tunN 格式的TUN设备节点,代码中__init_osx方法直接尝试打开固定路径/dev/tun1,路径不存在就会触发FileNotFoundError。且MacOS原生utun接口的创建逻辑和代码现有实现不兼容。
解决方案
- 前置依赖安装:安装第三方TUN/TAP驱动
tuntaposx,Catalina 10.15版本需要在「系统偏好设置-安全性与隐私」中放行内核扩展权限,安装完成后系统会自动生成/dev/tun0到/dev/tun15的设备节点。 - 代码适配:
- 补全代码中缺失的
addr_add、addr_del方法:
def addr_add(self, ip): self.ifconfig(f"inet6 add {ip}/64") def addr_del(self, ip): self.ifconfig(f"inet6 delete {ip}/64")- 如果不想安装第三方驱动,可以替换原有逻辑改用系统原生支持的utun接口创建逻辑。
- 补全代码中缺失的
- 操作验证:运行代码前可先手动执行
sudo ifconfig tun1 create创建设备节点,再运行代码验证路径问题是否解决。 - 权限要求:运行代码必须加
sudo前缀,操作网络设备需要root权限。
Linux 端问题
成因
Linux下/dev/net/tun是字符设备,不属于可寻址的普通文件,用Python内置open()函数以二进制模式打开时,默认会触发seek操作,而字符设备不支持seek,因此抛出io.UnsupportedOperation: File or stream is not seekable错误。
解决方案
修改__init_linux方法的打开逻辑,改用os.open()直接获取文件描述符,不需要用Python文件对象包装,修改后代码如下:
def __init_linux(self): CONFIG.LOGGER.info("TUN: Starting linux " + self.ifname) # 替换原open调用,用os.open直接获取文件描述符 self.fd = os.open("/dev/net/tun", os.O_RDWR) # 后续ioctl直接传文件描述符即可,注意ifname要转成bytes格式 ifr = struct.pack("16sH", self.ifname.encode('utf-8'), IFF_TUN | IFF_NO_PI) fcntl.ioctl(self.fd, IFF_TUNSETIFF, ifr) fcntl.ioctl(self.fd, IFF_TUNSETOWNER, 1000)
额外配置检查:
- 确认内核已加载TUN模块,执行
lsmod | grep tun检查,无输出的话先执行sudo modprobe tun加载模块。 - 运行代码需要加
sudo前缀,或者提前给当前用户放开/dev/net/tun的操作权限。
内容的提问来源于stack exchange,提问作者12435432nm
相关产品推荐
相关产品推荐

