Lars
Lars

Reputation: 1072

Getting interface name from packet with af_packet

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

Answers (1)

Gil Hamilton
Gil Hamilton

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

Related Questions