Reputation: 1072
Capturing packets using the following method with AF_PACKET and ring buffer (pseudo-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
...
As seen above, if sll_ifindex
is set to 0
, the socket will receive on all interfaces. Is there a way to either modify this method, or in some way glean the network interface on which the packet arrived?
Upvotes: 1
Views: 992
Reputation: 12337
Yes. Each frame placed into the ring buffer gets two structures inserted in front of it: first the tpacket_hdr
, then the sockaddr_ll
. The latter describes the interface on which the packet was received. There is padding between the structures so the code looks something like this:
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);
You can translate the interface index into a name with the SIOCGIFNAME
ioctl
.
Upvotes: 1