如何获取使用“ip tuntap add mode tap”创建的接口名称

如何获取使用“ip tuntap add mode tap”创建的接口名称

我想使用 sudo 创建一个 Tap,然后将用户空间程序 (ssh) 附加到它。

我不想对接口名称进行硬编码,因为多个用户将使用它,所以我希望动态生成接口名称。

所以我像这样创建水龙头:

sudo ip tuntap add mode tap user $USER

如何让 ip 命令返回创建的接口的名称,以便我可以使用它传递给 ssh?

答案1

tuntap设备的 Linux 编程接口记录在此处(带有示例代码):tuntap.rst。可以询问接口名称,然后使用初始调用传递的结构来检索接口名称ioctl(fd, TUNSETIFF, ...)。由于ip tuntap不显示该名称,因此仅此命令无法提供信息。

有两种方法可以做到这一点。

库包装器

可以添加一个 libc 包装器ioctl()对于这个特定目标,可以在运行时使用LD_PRELOAD从而无需修改原始工具。这是相应用途的包装器ioctl(),将打印到标准输出刚刚创建的接口的名称。考虑到 OP 的ip tuntap示例仅使用了 3 次ioctl()轻敲接口,这是相当安全的,尽管ioctl()其所有用途并不总是具有相同数量的参数(这里假设有 3 个参数)。

wraptuntap.c:

#define _GNU_SOURCE
#include <dlfcn.h>

#include <linux/if.h>
#include <linux/if_tun.h>

#define ioctl ioctl_diverted
#include <sys/ioctl.h>
#undef ioctl

#include <stdio.h>

int ioctl(int fd, unsigned long request, void *p) {
        int ret;

        int (*orig_ioctl)(int, unsigned long, void *)=dlsym(RTLD_NEXT,"ioctl");
        if ((ret=orig_ioctl(fd, request, p)) != -1 )
                if (request == TUNSETIFF)
                        printf("%s\n",((struct ifreq *)p)->ifr_name);
        return ret;
}

评论:

  • <sys/ioctl.h>需要TUNSETIFF正确定义,但同时我们不能ioctl()定义,否则包装器的定义会发生冲突。它的初始定义被转移为这个SO Q/A的方法
  • ifr_name保证是自内核 4.13 起以 null 终止否则……好吧,这是一个脆弱的包装纸。

例如要编译为:

gcc -shared -fPIC -o /tmp/wraptuntap.so wraptuntap.c -ldl

然后像这样使用:

# LD_PRELOAD=/tmp/wraptuntap.so ip tuntap add mode tap user 1000
tap0
# LD_PRELOAD=/tmp/wraptuntap.so ip tuntap add mode tap user 1000
tap1
# LD_PRELOAD=/tmp/wraptuntap.so ip tuntap add mode tap user 1000 name foo%d
foo0
# LD_PRELOAD=/tmp/wraptuntap.so ip tuntap add mode tap user 1000 name foo%d
foo1

或更有用的:

# mytun=$(LD_PRELOAD=/tmp/wraptuntap.so ip tuntap add mode tap user 1000 name foo%d)
# ip link show dev "$mytun"
11: foo2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether ae:99:4a:2b:1f:6b brd ff:ff:ff:ff:ff:ff

由于创建这样的界面并不是很困难,因此对于生产用途,应该优先创建一个专用的工具,或者使用其他可以显示此类界面名称的工具。

年长的tunctl(仅限于轻敲接口):

随 UML 实用程序一起提供的较旧的(因此通常已弃用的)tunctl工具会显示一个带有所使用的接口名称的句子,但只会创建模式轻敲(第 2 层)接口(这正是 OP 正在寻找的)而不是(第 3 层)接口。

例子:

# tunctl -u 1000 -t foo%d
Set 'foo3' persistent and owned by uid 1000
# tunctl -u 1000 -t foo%d | sed -E "s/^Set '([^']+)' .*\$/\1/"
foo4
# ip -d link show dev foo4 # this is a "type tap" interface
13: foo4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether c2:05:de:78:16:a3 brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 68 maxmtu 65521 
    tun type tap pi off vnet_hdr off persist on user 1000 addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 tso_max_size 65536 tso_max_segs 65535 gro_max_size 65536 

相关内容