16#include <netinet/if_ether.h>
23const unsigned int MAX_BPF_OPEN_ATTEMPTS = 100;
27const unsigned int BPF_LOCAL_LOOPBACK_HEADER_LEN = 4;
51struct bpf_insn ethernet_ip_udp_filter [] = {
58 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ETHERNET_PACKET_TYPE_OFFSET),
60 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 11),
66 BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
67 ETHERNET_HEADER_LEN + IP_PROTO_TYPE_OFFSET),
69 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 9),
77 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ETHERNET_HEADER_LEN + IP_FLAGS_OFFSET),
79 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 7, 0),
89 BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
90 ETHERNET_HEADER_LEN + IP_DEST_ADDR_OFFSET),
93 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xffffffff, 1, 0),
97 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 4),
103 BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, ETHERNET_HEADER_LEN),
111 BPF_STMT(BPF_LD + BPF_H + BPF_IND, ETHERNET_HEADER_LEN + UDP_DEST_PORT),
118 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0, 1),
122 BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
126 BPF_STMT(BPF_RET + BPF_K, 0),
137struct bpf_insn loopback_ip_udp_filter [] = {
143 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 0),
145 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xFFFFFFFF, 0, 11),
151 BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
152 BPF_LOCAL_LOOPBACK_HEADER_LEN + IP_PROTO_TYPE_OFFSET),
154 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 9),
162 BPF_STMT(BPF_LD + BPF_H + BPF_ABS,
163 BPF_LOCAL_LOOPBACK_HEADER_LEN + IP_FLAGS_OFFSET),
165 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 7, 0),
175 BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
176 BPF_LOCAL_LOOPBACK_HEADER_LEN + IP_DEST_ADDR_OFFSET),
179 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xffffffff, 1, 0),
183 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 4),
189 BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, BPF_LOCAL_LOOPBACK_HEADER_LEN),
197 BPF_STMT(BPF_LD + BPF_H + BPF_IND,
198 BPF_LOCAL_LOOPBACK_HEADER_LEN + UDP_DEST_PORT),
205 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0, 1),
209 BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
213 BPF_STMT(BPF_RET + BPF_K, 0),
227 const uint16_t port,
const bool,
242 for (
unsigned int bpf_dev = 0;
243 bpf_dev < MAX_BPF_OPEN_ATTEMPTS && (sock < 0);
245 std::ostringstream s;
246 s <<
"/dev/bpf" << bpf_dev;
247 sock = open(s.str().c_str(), O_RDWR, 0);
250 if (errno == EBUSY) {
257 "Failed to open BPF device " << s.str());
262 if (fcntl(sock, F_SETFD, FD_CLOEXEC) < 0) {
266 <<
" on BPF device with interface " << iface.
getName());
272 struct ifreq iface_data;
273 memset(&iface_data, 0,
sizeof(iface_data));
274 std::strncpy(iface_data.ifr_name, iface.
getName().c_str(),
275 std::min(
static_cast<int>(IFNAMSIZ),
276 static_cast<int>(iface.
getName().length())));
277 if (ioctl(sock, BIOCSETIF, &iface_data) < 0) {
281 " with interface " << iface.
getName());
286 struct bpf_version ver;
287 if (ioctl(sock, BIOCVERSION, &ver) < 0) {
291 " number from the kernel");
295 if ((ver.bv_major != BPF_MAJOR_VERSION) ||
296 (ver.bv_minor < BPF_MINOR_VERSION)) {
300 << ver.bv_major <<
"." << ver.bv_minor
301 <<
" Expected at least version:"
302 << BPF_MAJOR_VERSION <<
"."
303 << BPF_MINOR_VERSION);
308 unsigned int buf_len = 0;
309 if (ioctl(sock, BIOCGBLEN, &buf_len) < 0) {
313 " buffer length for reads from BPF device");
316 if (buf_len <
sizeof(bpf_hdr)) {
318 " kernel for the BPF device associated with the interface"
319 << iface.
getName() <<
" is lower than the BPF header"
320 " length: this condition is impossible unless the"
321 " operating system is really broken!");
325 struct bpf_program prog;
326 memset(&prog, 0,
sizeof(bpf_program));
328 prog.bf_insns = loopback_ip_udp_filter;
329 prog.bf_len =
sizeof(loopback_ip_udp_filter) /
sizeof(
struct bpf_insn);
334 prog.bf_insns[1].k = htonl(AF_INET);
337 prog.bf_insns = ethernet_ip_udp_filter;
338 prog.bf_len =
sizeof(ethernet_ip_udp_filter) /
sizeof(
struct bpf_insn);
344 prog.bf_insns[8].k = addr.
toUint32();
347 prog.bf_insns[11].k = port;
350 if (ioctl(sock, BIOCSETF, &prog) < 0) {
362 if (ioctl(sock, BIOCIMMEDIATE, &flag) < 0) {
379 return (
SocketInfo(addr, port, sock, fallback));
388 " for the interface: " << iface.
getName());
409 }
while (datalen > 0);
421 datalen = BPF_WORDALIGN(datalen);
433 while (offset < datalen) {
436 if (datalen - offset <
sizeof(bpf_hdr)) {
438 " interface " << iface.
getName() <<
" has a truncated "
443 memcpy(
static_cast<void*
>(&bpfh),
449 if (offset + bpfh.bh_hdrlen + bpfh.bh_caplen > datalen) {
451 <<
" attached to interface " << iface.
getName()
456 if (bpfh.bh_caplen != bpfh.bh_datalen) {
458 offset = BPF_WORDALIGN(offset + bpfh.bh_hdrlen + bpfh.bh_caplen);
468 if (offset >= datalen) {
474 datalen - bpfh.bh_hdrlen - offset);
497 if (buf.
getLength() < BPF_LOCAL_LOOPBACK_HEADER_LEN) {
499 " interface " << iface.
getName() <<
" doesn't contain"
500 " the pseudo header with the address family type");
523 std::vector<uint8_t> dhcp_buf;
532 pkt->setIface(iface.
getName());
533 pkt->setLocalAddr(dummy_pkt->getLocalAddr());
534 pkt->setRemoteAddr(dummy_pkt->getRemoteAddr());
535 pkt->setLocalPort(dummy_pkt->getLocalPort());
536 pkt->setRemotePort(dummy_pkt->getRemotePort());
537 pkt->setLocalHWAddr(dummy_pkt->getLocalHWAddr());
538 pkt->setRemoteHWAddr(dummy_pkt->getRemoteHWAddr());
556 pkt->setLocalHWAddr(hwaddr);
565 writeAFPseudoHeader(AF_INET, buf);
581 buf.
writeData(pkt->getBuffer().getData(), pkt->getBuffer().getLength());
593PktFilterBPF::writeAFPseudoHeader(
const uint32_t address_family,
598 memcpy(
static_cast<void*
>(af_buf),
599 static_cast<const void*
>(&address_family),
602 out_buf.
writeData(af_buf,
sizeof(af_buf));
The IOAddress class represents an IP addresses (version agnostic)
uint32_t toUint32() const
Converts IPv4 address to uint32_t.
Represents a single network interface.
size_t getReadBufferSize() const
Returns the current size of the socket read buffer.
size_t getMacLen() const
Returns MAC length.
uint8_t * getReadBuffer()
Returns the pointer to the buffer used for data reading.
std::string getName() const
Returns interface name.
uint16_t getHWType() const
Returns hardware type of the interface.
unsigned int getIndex() const
Returns interface index.
void resizeReadBuffer(const size_t new_size)
Reallocates the socket read buffer.
bool flag_loopback_
Specifies if selected interface is loopback.
const uint8_t * getMac() const
Returns pointer to MAC address.
Represents DHCPv4 packet.
virtual Pkt4Ptr receive(Iface &iface, const SocketInfo &socket_info)
Receive packet over specified socket.
virtual SocketInfo openSocket(Iface &iface, const isc::asiolink::IOAddress &addr, const uint16_t port, const bool receive_bcast, const bool send_bcast)
Open primary and fallback socket.
virtual int send(const Iface &iface, uint16_t sockfd, const Pkt4Ptr &pkt)
Send packet over specified socket.
virtual int openFallbackSocket(const isc::asiolink::IOAddress &addr, const uint16_t port)
Default implementation to open a fallback socket.
IfaceMgr exception thrown thrown when socket opening or configuration failed.
IfaceMgr exception thrown thrown when error occurred during reading data from socket.
IfaceMgr exception thrown thrown when error occurred during sending data through socket.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
size_t getLength() const
Return the length of data written in the buffer.
const void * getData() const
Return a pointer to the head of the data stored in the buffer.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
void decodeEthernetHeader(InputBuffer &buf, Pkt4Ptr &pkt)
Decode the Ethernet header.
void writeEthernetHeader(const Pkt4Ptr &pkt, OutputBuffer &out_buf)
Writes ethernet frame header into a buffer.
void decodeIpUdpHeader(InputBuffer &buf, Pkt4Ptr &pkt)
Decode IP and UDP header.
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
void writeIpUdpHeader(const Pkt4Ptr &pkt, util::OutputBuffer &out_buf)
Writes both IP and UDP header into output buffer.
Defines the logger used by the top-level component of kea-lfc.
Hardware type that represents information from DHCPv4 packet.
Holds information about socket.
int fallbackfd_
Fallback socket descriptor.