From 9ddfab5085cc3cf09a005aa371d369b1e6b1d86e Mon Sep 17 00:00:00 2001 From: "Nicholas J. Kain" Date: Fri, 1 Jul 2011 00:55:35 -0400 Subject: [PATCH] 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. --- ndhc/arp.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/ndhc/arp.c b/ndhc/arp.c index 096c55c..1cdf6a3 100644 --- a/ndhc/arp.c +++ b/ndhc/arp.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #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));