16#include <netinet/if_ether.h>
21using namespace boost::posix_time;
24const unsigned int MAX_BPF_OPEN_ATTEMPTS = 100;
28const unsigned int BPF_LOCAL_LOOPBACK_HEADER_LEN = 4;
52struct bpf_insn ethernet_ip_udp_filter [] = {
59 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ETHERNET_PACKET_TYPE_OFFSET),
61 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 11),
67 BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
68 ETHERNET_HEADER_LEN + IP_PROTO_TYPE_OFFSET),
70 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 9),
78 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ETHERNET_HEADER_LEN + IP_FLAGS_OFFSET),
80 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 7, 0),
90 BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
91 ETHERNET_HEADER_LEN + IP_DEST_ADDR_OFFSET),
94 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xffffffff, 1, 0),
98 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 4),
104 BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, ETHERNET_HEADER_LEN),
112 BPF_STMT(BPF_LD + BPF_H + BPF_IND, ETHERNET_HEADER_LEN + UDP_DEST_PORT),
119 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0, 1),
123 BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
127 BPF_STMT(BPF_RET + BPF_K, 0),
138struct bpf_insn loopback_ip_udp_filter [] = {
144 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 0),
146 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xFFFFFFFF, 0, 11),
152 BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
153 BPF_LOCAL_LOOPBACK_HEADER_LEN + IP_PROTO_TYPE_OFFSET),
155 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 9),
163 BPF_STMT(BPF_LD + BPF_H + BPF_ABS,
164 BPF_LOCAL_LOOPBACK_HEADER_LEN + IP_FLAGS_OFFSET),
166 BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 7, 0),
176 BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
177 BPF_LOCAL_LOOPBACK_HEADER_LEN + IP_DEST_ADDR_OFFSET),
180 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0xffffffff, 1, 0),
184 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 4),
190 BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, BPF_LOCAL_LOOPBACK_HEADER_LEN),
198 BPF_STMT(BPF_LD + BPF_H + BPF_IND,
199 BPF_LOCAL_LOOPBACK_HEADER_LEN + UDP_DEST_PORT),
206 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0, 1),
210 BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
214 BPF_STMT(BPF_RET + BPF_K, 0),
228 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));
327 if (iface.flag_loopback_) {
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) {
372 iface.resizeReadBuffer(buf_len);
380 return (
SocketInfo(addr, port, sock, fallback));
387 if (iface.getReadBufferSize() == 0) {
389 " for the interface: " << iface.getName());
408 datalen = recv(socket_info.fallbackfd_, iface.getReadBuffer(),
409 iface.getReadBufferSize(), 0);
410 }
while (datalen > 0);
412 datalen = read(socket_info.sockfd_, iface.getReadBuffer(),
413 iface.getReadBufferSize());
422 datalen = BPF_WORDALIGN(datalen);
434 while (offset < datalen) {
437 if (datalen - offset <
sizeof(bpf_hdr)) {
439 " interface " << iface.getName() <<
" has a truncated "
444 memcpy(
static_cast<void*
>(&bpfh),
445 static_cast<void*
>(iface.getReadBuffer()),
450 if (offset + bpfh.bh_hdrlen + bpfh.bh_caplen > datalen) {
452 <<
" attached to interface " << iface.getName()
457 if (bpfh.bh_caplen != bpfh.bh_datalen) {
459 offset = BPF_WORDALIGN(offset + bpfh.bh_hdrlen + bpfh.bh_caplen);
469 if (offset >= datalen) {
474 InputBuffer buf(iface.getReadBuffer() + offset + bpfh.bh_hdrlen,
475 datalen - bpfh.bh_hdrlen - offset);
497 if (iface.flag_loopback_) {
498 if (buf.getLength() < BPF_LOCAL_LOOPBACK_HEADER_LEN) {
500 " interface " << iface.getName() <<
" doesn't contain"
501 " the pseudo header with the address family type");
506 buf.setPosition(BPF_LOCAL_LOOPBACK_HEADER_LEN);
524 std::vector<uint8_t> dhcp_buf;
525 buf.readVector(dhcp_buf, buf.getLength() - buf.getPosition());
532 pkt->setIndex(iface.getIndex());
533 pkt->setIface(iface.getName());
534 pkt->setLocalAddr(dummy_pkt->getLocalAddr());
535 pkt->setRemoteAddr(dummy_pkt->getRemoteAddr());
536 pkt->setLocalPort(dummy_pkt->getLocalPort());
537 pkt->setRemotePort(dummy_pkt->getRemotePort());
538 pkt->setLocalHWAddr(dummy_pkt->getLocalHWAddr());
539 pkt->setRemoteHWAddr(dummy_pkt->getRemoteHWAddr());
542#if (defined(BPF_TIMEVAL)) && (BPF_TIMEVAL == timeval32)
545 time_t time_t_secs = bpfh.bh_tstamp.tv_sec;
546 ptime timestamp = from_time_t(time_t_secs);
547 time_duration usecs(0, 0, 0, bpfh.bh_tstamp.tv_usec);
570 if (iface.getMacLen() > 0) {
573 pkt->setLocalHWAddr(hwaddr);
581 if (iface.flag_loopback_) {
582 writeAFPseudoHeader(AF_INET, buf);
587 if (!iface.flag_loopback_) {
598 buf.writeData(pkt->getBuffer().getData(), pkt->getBuffer().getLength());
600 int result = write(sockfd, buf.getData(), buf.getLength());
611PktFilterBPF::writeAFPseudoHeader(
const uint32_t address_family,
616 memcpy(
static_cast<void*
>(af_buf),
617 static_cast<const void*
>(&address_family),
620 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.
Represents DHCPv4 packet.
static const std::string BUFFER_READ
Event that marks when a packet is read from the socket buffer by application.
static const std::string SOCKET_RECEIVED
Event that marks when a packet is placed in the socket buffer by the kernel.
static const std::string RESPONSE_SENT
Event that marks when a packet is been written to the socket by application.
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.
#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.