Define a BPF for ARP-listening raw sockets that discriminates by ethernet
frame protocol type field, ARP hardware type field, ARP protocol type field, ARP hardware address length field, and ARP protocol address length field.
This commit is contained in:
parent
3e3ecc816f
commit
9ddfab5085
35
ndhc/arp.c
35
ndhc/arp.c
@ -27,6 +27,7 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/time.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/filter.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include "arp.h"
|
||||
@ -48,6 +49,35 @@ static int arp_packet_num;
|
||||
|
||||
static int arp_open_fd(struct client_state_t *cs)
|
||||
{
|
||||
struct sock_filter sf_arp[] = {
|
||||
// Verify that the frame has ethernet protocol type of ARP.
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, htons(ETH_P_ARP), 1, 0),
|
||||
BPF_STMT(BPF_RET + BPF_K, 0),
|
||||
// Verify that the ARP hardware type field indicates Ethernet.
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 14),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, htons(ARPHRD_ETHER), 1, 0),
|
||||
BPF_STMT(BPF_RET + BPF_K, 0),
|
||||
// Verify that the ARP protocol type field indicates IP.
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 16),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, htons(ETH_P_IP), 1, 0),
|
||||
BPF_STMT(BPF_RET + BPF_K, 0),
|
||||
// Verify that the ARP hardware address length field is 6.
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 18),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 6, 1, 0),
|
||||
BPF_STMT(BPF_RET + BPF_K, 0),
|
||||
// Verify that the ARP protocol address length field is 4.
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 19),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 4, 1, 0),
|
||||
BPF_STMT(BPF_RET + BPF_K, 0),
|
||||
// Sanity tests passed, so send all possible data.
|
||||
BPF_STMT(BPF_RET + BPF_K, 0x0fffffff),
|
||||
};
|
||||
struct sock_fprog sfp_arp = {
|
||||
.len = sizeof sf_arp / sizeof sf_arp[0],
|
||||
.filter = (struct sock_filter *)sf_arp,
|
||||
};
|
||||
|
||||
if (cs->arpFd != -1)
|
||||
return 0;
|
||||
|
||||
@ -57,6 +87,11 @@ static int arp_open_fd(struct client_state_t *cs)
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Ignoring error since kernel may lack support for BPF.
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &sfp_arp,
|
||||
sizeof sfp_arp) >= 0)
|
||||
log_line("Attached filter to raw ARP socket fd %d", fd);
|
||||
|
||||
int opt = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof opt) == -1) {
|
||||
log_error("arp: failed to set broadcast: %s", strerror(errno));
|
||||
|
Loading…
Reference in New Issue
Block a user