16 #include <netinet/if_ether.h>
23 const unsigned int MAX_BPF_OPEN_ATTEMPTS = 100;
27 const unsigned int BPF_LOCAL_LOOPBACK_HEADER_LEN = 4;
51 struct 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),
137 struct 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),
225 PktFilterBPF::openSocket(
Iface& iface,
227 const uint16_t port,
const bool,
234 int fallback = openFallbackSocket(addr, port);
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");
505 buf.setPosition(BPF_LOCAL_LOOPBACK_HEADER_LEN);
523 std::vector<uint8_t> dhcp_buf;
524 buf.readVector(dhcp_buf, buf.getLength() - buf.getPosition());
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());
544 PktFilterBPF::send(
const Iface& iface, uint16_t sockfd,
const Pkt4Ptr& pkt) {
556 pkt->setLocalHWAddr(hwaddr);
563 #if !defined (OS_OSX)
565 writeAFPseudoHeader(AF_INET, buf);
581 buf.
writeData(pkt->getBuffer().getData(), pkt->getBuffer().getLength());
593 PktFilterBPF::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));
uint32_t toUint32() const
Converts IPv4 address to uint32_t.
void writeEthernetHeader(const Pkt4Ptr &pkt, OutputBuffer &out_buf)
Writes ethernet frame header into a buffer.
IfaceMgr exception thrown thrown when socket opening or configuration failed.
const void * getData() const
Return a pointer to the head of the data stored in the buffer.
int fallbackfd_
Fallback socket descriptor.
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
bool flag_loopback_
Specifies if selected interface is loopback.
uint32_t getIndex() const
Returns interface index.
size_t getMacLen() const
Returns MAC length.
Represents a single network interface.
uint16_t getHWType() const
Returns hardware type of the interface.
void decodeEthernetHeader(InputBuffer &buf, Pkt4Ptr &pkt)
Decode the Ethernet header.
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
void writeIpUdpHeader(const Pkt4Ptr &pkt, util::OutputBuffer &out_buf)
Writes both IP and UDP header into output buffer.
boost::shared_ptr< Pkt4 > Pkt4Ptr
A pointer to Pkt4 object.
IfaceMgr exception thrown thrown when error occurred during reading data from socket.
const uint8_t * getMac() const
Returns pointer to MAC address.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
std::string getName() const
Returns interface name.
Defines the logger used by the top-level component of kea-dhcp-ddns.
Represents DHCPv4 packet.
void resizeReadBuffer(const size_t new_size)
Reallocates the socket read buffer.
Hardware type that represents information from DHCPv4 packet.
The IOAddress class represents an IP addresses (version agnostic)
uint8_t * getReadBuffer()
Returns the pointer to the buffer used for data reading.
size_t getLength() const
Return the length of data written in the buffer.
IfaceMgr exception thrown thrown when error occurred during sending data through socket.
Holds information about socket.
void decodeIpUdpHeader(InputBuffer &buf, Pkt4Ptr &pkt)
Decode IP and UDP header.
size_t getReadBufferSize() const
Returns the current size of the socket read buffer.