监听虚拟网络接口

Listening to virtual network interface

不要被我谈论的 L2TP 搞糊涂了。虽然我的问题与 L2TP 有关,但它本身并不是 L2TP 问题。这更像是一个网络问题。

背景

我正在编写一个使用 L2TP 的应用程序。这是我第一次使用 L2TP 和 linux L2TP 子系统,所以我希望我做对了。 创建 L2TP 以太网会话时,子系统会自动创建一个虚拟网络接口。
启动界面后,我可以使用 Wireshark 检查,确实所需的数据已发送到界面。这是没有任何包装的。它不在以太网帧或任何东西中,而只是包含在 L2TP 数据包中的数据字节。
我无法控制实际创建设备,但我可以查询它的名称以及它的索引等,到目前为止一切顺利。

实际问题

我的问题实际上很简单:如何将发送到虚拟接口的数据导入我的用户空间应用程序?
我在 unix 上没有太多网络经验,但我的期望是这是一个相当简单的问题,可以通过获取我可以使用的文件描述符来解决 read / recv 或者以某种方式将套接字绑定到该网络接口。
我找不到任何 (gen-)netlink / ioctl API(或其他任何东西)来执行此操作或类似的操作。

尽管我的应用程序是用 GO 而不是 C 编写的,但 C 中的解决方案就完全足够了。说实话,在这一点上,我很乐意以编程方式解决此问题的任何方法。 :)

非常感谢

我刚刚找到了一个教程来回答我自己的问题。使用 AF_PACKET 套接字实际上非常容易。

有一个 lovely tutorial on microhowto.info,它解释了 AF_PACKET 套接字的工作原理,比我以前能做的更好。 它甚至包括一个部分 “仅从特定网络接口捕获”


这是一个最小的例子,适用于我的用例:

#include <stdlib.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <net/ethernet.h>
#include <linux/if_packet.h>
#include <sys/socket.h>

// [...]

// Create socket
int fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (fd == -1) {
    perror("ERROR socket");
    exit(1);
}

// Interface index (i.e. obtainable via ioctl SIOCGIFINDEX)
int ifindex = 1337;

// create link layer socket address
struct sockaddr_ll addr = {0};
addr.sll_family = AF_PACKET;
addr.sll_ifindex = ifindex;
addr.sll_protocol = htons(ETH_P_ALL)

if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
    perror("ERROR bind");
    exit(1);
}

char buffer[65535];
ssize_t len;    
do { 
    len = recv(fd, buffer, sizeof(buffer) -1, 0);
    if (len < 0) {
        perror("ERROR recvfrom");
        exit(1);
    }
    printf("recived data (length: %i)\n", (int) len);
} while (len > 0);