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);