如何从tap接口读取数据?

如何从tap接口读取数据?

我的网桥和 tun/tap 设备有问题。

实际上,主要问题是我试图在编译之前创建一个网桥和一个tap接口。在编译时我的代码需要使用该接口。在我的项目代码中,the Contikihttps://github.com/contiki-os/contiki)代码被编译并用于创建tap接口和通信。

如果我使用sudo命令运行源代码,一切都很好,但正如我所说,我需要之前创建点击界面,并且我应该在没有命令的情况下运行代码sudo

因此,如果我的代码使用命令运行sudoifconfig tap0则响应如下所示;

tap0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fc00::231  prefixlen 7  scopeid 0x0<global>
        inet6 fe80::cc9f:ddff:fe50:7d9a  prefixlen 64  scopeid 0x20<link>
        ether ce:9f:dd:50:7d:9a  txqueuelen 1000  (Ethernet)
        RX packets 50  bytes 12195 (12.1 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 52  bytes 7869 (7.8 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

而在这种状态下,我的项目运行得很好。

但我正在尝试使用以下命令创建点击界面;

sudo ip tuntap add mode tap tap0 user myusername
sudo ifconfig tap0 up
sudo ip link set tap0 up
sudo ip -6 address add fc00::231/7 dev tap0
sudo ip address add dev tap0 scope link fe80::cc9f:ddff:fe50:7d9a

然后是ifconfig tap0响应;

tap0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet6 fe80::cc9f:ddff:fe50:7d9a  prefixlen 128  scopeid 0x20<link>
        inet6 fc00::231  prefixlen 7  scopeid 0x0<global>
        ether 06:ea:8d:0e:66:74  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

因此,在我的 Contiki 代码修改之后,尝试读取 tap0 接口

ret = read(fd, uip_buf, UIP_BUFSIZE);

但 ret 值为 -1。(当它与 sudo 一起运行时,它返回一个 int 值)我想如果我能够更改 tap0 接口的状态,也许RUNNING我可以获得 ret 值,但我不知道该怎么做。

有谁知道我该怎么办?

注意:tapdev6.c 修改

void
tapdev_init(void)
{
  printf("INIT TAP DEV!!!!!!!!!!!!!!!!! \n");
  net_fd = open(DEVTAP, O_RDWR);
  if(net_fd == -1) {
    perror("tapdev: tapdev_init: open");
    return;
  }

#ifdef __linux
  {
    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
    printf("INIT0 net_fd %d \n", net_fd);
    if (ioctl(/*net_fd*/4, TUNSETIFF, (void *) &ifr) < 0) {
        printf("INIT FAIL \n");
      perror("Unable to init tunnel interface\n");
      //exit(1);
    }
    printf("INIT1 net_fd %d \n", net_fd);
    ioctl(/*net_fd*/4, SIOCGIFHWADDR, &ifr);
    printf("INIT2 net_fd %d \n", net_fd);
  }
  /* Linux (ubuntu) */
char buf[256];
     snprintf(buf, sizeof(buf), "ip link set tap0 up");
     system(buf);
     PRINTF("%s\n", buf);
     snprintf(buf, sizeof(buf), "ip -6 address add fc00::231/7 dev tap0");
     system(buf);
     PRINTF("%s\n", buf);
     snprintf(buf, sizeof(buf), "ip -6 route add fc00::0/7 dev tap0");
     system(buf);
     PRINTF("%s\n", buf);

  /* freebsd */

    //try to set hw address
     // 12:bc:34:76:c9:2f
    ifr.ifr_hwaddr.sa_data[0] = 0x12;
    ifr.ifr_hwaddr.sa_data[1] = 0xbc;
    ifr.ifr_hwaddr.sa_data[2] = 0x34;
    ifr.ifr_hwaddr.sa_data[3] = 0x76;
    ifr.ifr_hwaddr.sa_data[4] = 0xc9;
    ifr.ifr_hwaddr.sa_data[5] = 0x2f;
  printf("Lan device %s\n", ifr.ifr_name);
  printf("LAN HW addr %02X:%02X:%02X:%02X:%02X:%02X\n",
          (unsigned char)ifr.ifr_hwaddr.sa_data[0],
          (unsigned char)ifr.ifr_hwaddr.sa_data[1],
          (unsigned char)ifr.ifr_hwaddr.sa_data[2],
          (unsigned char)ifr.ifr_hwaddr.sa_data[3],
          (unsigned char)ifr.ifr_hwaddr.sa_data[4],
          (unsigned char)ifr.ifr_hwaddr.sa_data[5]);
#endif /* Linux */

  lasttime = 0;

}

答案1

-ESUDO

说真的,你应该设置点击界面的所有者。尝试以下操作:

ip tuntap add tap0 mode tap user USER

USER将读取和写入通过打开的句柄的用户在哪里/dev/net/tun。我怀疑不仅仅是读取失败,还有ioctl(TUNSETIFF),但你没有费心去检查返回值。

这是一个简单的opentap(ifname)函数,应该打开一个指向 Tap 接口的 fd 句柄,前提是运行它的用户具有正确的权限:

#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int opentap(char *ifn)
{
    int fd;
    struct ifreq ifr = { 0 };
    if (snprintf(ifr.ifr_name, sizeof ifr.ifr_name, "%s", ifn)
            >= sizeof ifr.ifr_name) {
        errno = ENAMETOOLONG; return -1;
    }
    if ((fd = open("/dev/net/tun", O_RDWR)) == -1) return -1;
    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
    if (ioctl(fd, TUNSETIFF, &ifr) == -1) {
        int e = errno; close(fd); errno = e; return -1;
    }
    return fd;
}

相关内容