0

不要对我谈论 L2TP 感到困惑。虽然我的问题与 L2TP 有关,但它本身并不是 L2TP 问题。这更像是一个网络问题。

背景

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

实际问题

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

尽管我的应用程序是用 GO 而不是 C 编写的,但 C 中的解决方案就足够了。Tbh 在这一点上,我对任何以编程方式解决此问题的方法感到高兴。:)

非常感谢提前

4

1 回答 1

0

I just found a tutorial which answers my own question. It was actually really easy using AF_PACKET sockets.

There is a lovely tutorial on microhowto.info, which explains how AF_PACKET sockets work, better than I ever could. It even includes a section "Capture only from a particular network interface".


Here is a minimal example, which worked for my use case:

#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);
于 2021-07-12T10:16:54.683 回答