Как читать / писать из существующего интерфейса TAP в C - PullRequest
0 голосов
/ 21 марта 2019

У меня есть существующее устройство (tap0), которое я создал в командной строке.

# ip tuntap add dev tap0 mode tap

Я хочу прочитать любые данные, поступающие на этот интерфейс, используя программу на Си.Я проверил другие вопросы SO, но нашел код, который создает интерфейс, открыв /dev/net/tun.

Может ли кто-нибудь рассказать, как открыть и прочитать существующий интерфейс?Я не уверен, какой файл я должен открыть для tap0?

Ответы [ 2 ]

1 голос
/ 21 марта 2019

Вы можете реализовать как 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;
}
1 голос
/ 21 марта 2019

Откройте существующий интерфейс 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...