【问题标题】:How to read/write from existing TAP interface in C如何从 C 中现有的 TAP 接口读取/写入
【发布时间】:2019-03-21 05:27:39
【问题描述】:

我有一个在命令行上创建的现有 Tap 设备 (tap0)。

# ip tuntap add dev tap0 mode tap

我想使用 C 程序读取从该接口传入的任何数据。我检查了其他 SO 问题,但找到了通过打开 /dev/net/tun 创建界面的代码。

谁能提供一些关于如何打开和阅读现有界面的指导?我不确定应该为tap0 打开哪个文件?

【问题讨论】:

  • 您能在自己创建设备之前找到有关访问现有设备的教程吗?
  • 在实际测试中,其他人会为我创建接口。所以我只需要知道名字就可以打开和阅读界面。
  • 您仍然可以使用访问现有设备的教程。但是您写的内容值得通过editing 它添加到问题中。

标签: c linux networking


【解决方案1】:

打开现有的 tun/tap 界面与创建新界面类似。 使用 ioctl(TUNSETIFF) 时只需为接口命名:

const int fd = open("/dev/net/tun", O_RDWR);
if (fd != -1)
{
    struct ifreq ifr;

    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = IFF_TUN | IFF_NO_PI;

    strncpy(ifr.ifr_name, "tun0", IFNAMSIZ);  // <<<<=== THIS WAY

    if (ioctl(fd, TUNSETIFF, &ifr) != -1)
    {

没有strncpy 行,代码会创建一个带有一些空闲号码的新接口。 使用该行,它会尝试打开 tun0。注意:如果 tun0 已被其他进程打开,则会失败。

以上是用 IFF_TUN 测试的。我还没有尝试过IFF_TAP。

可以使用文件描述符(fd)进行读写:

tun 示例:

char buffer[0x1000];

const int len = read(fd, buffer, sizeof(buffer));
if (len > 0)
{
    static const char IPV6_VER_MASK = 0x60;

    if ((buffer[0] & IPV6_VER_MASK) == IPV6_VER_MASK)
    {
        handle_ipv6_packet((const struct ip6_hdr*)buffer, len);
    }
}

【讨论】:

    【解决方案2】:

    您可以像 tcpdump 一样实现捕获数据包,可以使用 libpcap 或 使用套接字 RAW_SOCKET

    sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)
    

    当然你也可以添加bpf过滤器

    setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, ... 
    

    简单示例:

    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #include <arpa/inet.h>
    #include <net/if.h>
    #include <netinet/ether.h>
    #include <linux/if_packet.h>
    #include <sys/ioctl.h>
    
    int main(int argc, char **argv)
    {
        int n;
        int ret = 0;
        int sock;
        char buf[2048];
        struct ifreq ifreq;
        struct sockaddr_ll saddr;
    
        // create socket
        if((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
            ret = errno;
            goto error_exit;
        }
    
        // bind tap0
        snprintf(ifreq.ifr_name, sizeof(ifreq.ifr_name), "tap0");
        if (ioctl(sock, SIOCGIFINDEX, &ifreq)) {
            ret = errno;
            goto error_exit;
        }
    
        memset(&saddr, 0, sizeof(saddr));
        saddr.sll_family = AF_PACKET;
        saddr.sll_protocol = htons(ETH_P_ALL);
        saddr.sll_ifindex = ifreq.ifr_ifindex;
        saddr.sll_pkttype = PACKET_HOST;
    
        if(bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) {
            ret = errno;
            goto error_exit;
        }
    
        // recv data
        while(1) {
            n = recvfrom(sock, buf, sizeof(buf), 0, NULL, NULL);
            printf("%d bytes recieved\n", n);
        }
    
    error_exit:
        if (ret) {
            printf("error: %s (%d)\n", strerror(ret), ret);
        }
        close(sock);
        return ret;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多