【问题标题】:Opening TUN interface throws either io.UnsupportedOperation or FileNotFoundError打开 TUN 接口会引发 io.UnsupportedOperation 或 FileNotFoundError
【发布时间】:2022-04-09 01:50:36
【问题描述】:

不太熟悉 tun 接口的工作原理。我不确定我是否应该在我的本地机器上实际做一些事情(即创建一个 tun 接口,安装一个驱动程序或其他东西)来让它工作或自动处理它。理想情况下,我想让它在 Mac 上运行,但 Linux 也可以。

所以基本上这就是我所拥有的:

在 MacOS 中,当__init_osx() 从下面的 sn-p 调用时(取自 openthread 项目):

import os
import sys
import struct
import logging
import threading
import traceback
import subprocess

if sys.platform == "linux" or sys.platform == "linux2":
    import fcntl

from select import select

import spinel.util as util
import spinel.config as CONFIG

IFF_TUN = 0x0001
IFF_TAP = 0x0002
IFF_NO_PI = 0x1000
IFF_TUNSETIFF = 0x400454ca
IFF_TUNSETOWNER = IFF_TUNSETIFF + 2


class TunInterface(object):
    """ Utility class for creating a TUN network interface. """

    def __init__(self, identifier):
        self.identifier = identifier
        self.ifname = "tun" + str(self.identifier)
        self.tun = None
        self.fd = None

        platform = sys.platform
        if platform == "linux" or platform == "linux2":
            self.__init_linux()
        elif platform == "darwin":
            self.__init_osx()
        else:
            raise RuntimeError(
                "Platform \"{}\" is not supported.".format(platform))

        self.ifconfig("up")
        #self.ifconfig("inet6 add fd00::1/64")
        self.__start_tun_thread()

    def __init_osx(self):
        CONFIG.LOGGER.info("TUN: Starting osx " + self.ifname)
        filename = "/dev/" + self.ifname
        self.tun = os.open(filename, os.O_RDWR)
        self.fd = self.tun
        # trick osx to auto-assign a link local address
        self.addr_add("fe80::1")
        self.addr_del("fe80::1")



    def __init_linux(self):
        CONFIG.LOGGER.info("TUN: Starting linux " + self.ifname)
        self.tun = open("/dev/net/tun", "r+b")
        self.fd = self.tun.fileno()

        ifr = struct.pack("16sH", self.ifname, IFF_TUN | IFF_NO_PI)
        fcntl.ioctl(self.tun, IFF_TUNSETIFF, ifr)  # Name interface tun#
        fcntl.ioctl(self.tun, IFF_TUNSETOWNER, 1000)  # Allow non-sudo access


    def close(self):
        """ Close this tunnel interface. """
        if self.tun:
            os.close(self.fd)
            self.fd = None
            self.tun = None

    @classmethod
    def command(cls, cmd):
        """ Utility to make a system call. """
        subprocess.check_call(cmd, shell=True)

    def ifconfig(self, args):
        """ Bring interface up and/or assign addresses. """
        self.command('ifconfig ' + self.ifname + ' ' + args)


    def __run_tun_thread(self):
        while self.fd:
            try:
                ready_fd = select([self.fd], [], [])[0][0]
                if ready_fd == self.fd:
                    packet = os.read(self.fd, 4000)
                    if CONFIG.DEBUG_TUN:
                        CONFIG.LOGGER.debug("\nTUN: RX (" + str(len(packet)) +
                                            ") " + util.hexify_str(packet))
                    self.write(packet)
            except:
                traceback.print_exc()
                break

        CONFIG.LOGGER.info("TUN: exiting")
        if self.fd:
            os.close(self.fd)
            self.fd = None

    def __start_tun_thread(self):
        """Start reader thread"""
        self._reader_alive = True
        self.receiver_thread = threading.Thread(target=self.__run_tun_thread)
        self.receiver_thread.setDaemon(True)
        self.receiver_thread.start()

它在 Mac 上抛出以下错误:

TUN: Starting osx tun1
Traceback (most recent call last):
  File "spinel-cli.py", line 2484, in <module>
    main()
  File "spinel-cli.py", line 2475, in main
    shell.cmdloop()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/cmd.py", line 138, in cmdloop
    stop = self.onecmd(line)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/cmd.py", line 217, in onecmd
    return func(arg)
  File "spinel-cli.py", line 2319, in do_ncptun
    self.tun_if = TunInterface(self.nodeid)
  File "/Users/nick/project/pyspinel/spinel/tun.py", line 55, in __init__
    self.__init_osx()
  File "/Users/nick/project/pyspinel/spinel/tun.py", line 68, in __init_osx
    self.tun = os.open(filename, os.O_RDWR)
FileNotFoundError: [Errno 2] No such file or directory: '/dev/tun1'

而在Linux中调用__init_linux()时,会抛出如下错误:

TUN: Starting linux tun1
Traceback (most recent call last):
  File "spinel-cli.py", line 2483, in <module>
    main()
  File "spinel-cli.py", line 2474, in main
    shell.cmdloop()
  File "/usr/lib/python3.6/cmd.py", line 138, in cmdloop
    stop = self.onecmd(line)
  File "/usr/lib/python3.6/cmd.py", line 217, in onecmd
    return func(arg)
  File "spinel-cli.py", line 2318, in do_ncptun
    self.tun_if = TunInterface(self.nodeid)
  File "/home/nick/project/pyspinel/spinel/tun.py", line 53, in __init__
    self.__init_linux()
  File "/home/nick/project/pyspinel/spinel/tun.py", line 75, in __init_linux
    self.tun = open("/dev/net/tun", "r+b")
io.UnsupportedOperation: File or stream is not seekable.

Mac 环境:

  • Python 3.7.4
  • MacOS Catalina 10.15.7

Linux 环境:

  • Python 3.6.9
  • Ubuntu 18.04.6 在虚拟机中运行

【问题讨论】:

    标签: python python-3.x linux macos tun


    【解决方案1】:

    这个问题在 linux 中通过以下方式解决:

    1. 使用os.open方法打开界面并传入os.O_RDWR选项。
    2. 接口名称也需要作为具有指定限制的字节传入。

    这里是更新的 linux 初始化方法:

    def __init_linux(self):
        CONFIG.LOGGER.info("TUN: Starting linux " + self.ifname)
        self.tun = os.open("/dev/net/tun", os.O_RDWR)
        self.fd = self.tun.fileno()
    
        ifr = struct.pack("16sH", bytes(self.ifname[:IFF_TUN_NAMELIMIT], 'utf-8'), IFF_TUN | IFF_NO_PI)
        fcntl.ioctl(self.tun, IFF_TUNSETIFF, ifr)  # Name interface tun#
        fcntl.ioctl(self.tun, IFF_TUNSETOWNER, 1000)  # Allow non-sudo access
    

    在哪里IFF_TUN_NAMELIMIT = 15

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-07
      • 1970-01-01
      • 2015-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多