使用以下方法使用AF_PACKET和环形缓冲区(伪C)捕获数据包:
// Set up socket
fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))
// Set socket bind options
struct sockaddr_ll sll;
sll.sll_family = AF_PACKET
sll.sll_protocol = htons(ETH_P_ALL)
sll.sll_ifindex = 0 // Bind to all interfaces
// Bind socket to all interfaces
bind(fd, (struct sockaddr *) &sll, socklen_t(sizeof(sll)))
// Set tpacket options in tp
setsockopt(fd, SOL_PACKET, PACKET_RX_RING, &tp, socklen_t(sizeof(tp)))
// Map the ring buffer
mmap(NULL, ring_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)
// Read from ring using offsets
...
如上所示,如果sll_ifindex
设置为0
,套接字将在所有接口上接收。有没有办法修改此方法,或以某种方式收集数据包到达的网络接口?
答案 0 :(得分:1)
是。放入环形缓冲区的每个帧都会在其前面插入两个结构:首先是tpacket_hdr
,然后是sockaddr_ll
。后者描述了接收数据包的接口。结构之间有填充,因此代码看起来像这样:
struct tpacket_hdr *tp = <Next frame in ring buffer>;
<wait for packet to arrive>
struct sockaddr_ll *sll = (struct sockaddr_ll*)((char *)tp + TPACKET_ALIGN(sizeof(*tp)));
printf("Frame received on IF index %u", sll->sll_ifindex);
您可以将界面索引翻译为SIOCGIFNAME
ioctl
。