summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcp/pkt_filter_bpf.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dhcp/pkt_filter_bpf.h')
-rw-r--r--src/lib/dhcp/pkt_filter_bpf.h142
1 files changed, 142 insertions, 0 deletions
diff --git a/src/lib/dhcp/pkt_filter_bpf.h b/src/lib/dhcp/pkt_filter_bpf.h
new file mode 100644
index 0000000..9413848
--- /dev/null
+++ b/src/lib/dhcp/pkt_filter_bpf.h
@@ -0,0 +1,142 @@
+// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef PKT_FILTER_BPF_H
+#define PKT_FILTER_BPF_H
+
+#include <dhcp/pkt_filter.h>
+
+#include <util/buffer.h>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Packet handling class using Berkeley Packet Filtering (BPF)
+///
+/// The BPF is supported on the BSD-like operating systems. It allows for access
+/// to low level layers of the inbound and outbound packets. This is specifically
+/// useful when the DHCP server is allocating new address to the client.
+///
+/// The response being sent to the client must include the HW address in the
+/// datalink layer. When the regular datagram socket is used the kernel will
+/// determine the HW address of the destination using ARP. In the case when
+/// the DHCP server is allocating the new address for the client the ARP can't
+/// be used because it requires the destination to have the IP address.
+///
+/// The DHCP server utilizes HW address sent by the client in the DHCP message
+/// and stores it in the datalink layer of the outbound packet. The BPF provides
+/// the means for crafting the whole packet (including datalink and network
+/// layers) and injecting the hardware address of the client.
+///
+/// The DHCP server receiving the messages sent from the directly connected
+/// clients to the broadcast address must be able to determine the interface
+/// on which the message arrives. The Linux kernel provides the SO_BINDTODEVICE
+/// socket option which allows for binding the socket to the particular
+/// interface. This option is not implemented on the BSD-like operating
+/// systems. This implies that there may be only one datagram socket listening
+/// to broadcast messages and this socket would receive the traffic on all
+/// interfaces. This effectively precludes the server from identifying the
+/// interface on which the packet arrived. The BPF resolves this problem.
+/// The BPF device (socket) can be attached to the selected interface using
+/// the ioctl function.
+///
+/// In nutshell, the BPF device is created by opening the file /dev/bpf%d
+/// where %d is a number. The BPF device is configured by issuing ioctl
+/// commands listed here: http://www.freebsd.org/cgi/man.cgi?bpf(4).
+/// The specific configuration used by Kea DHCP server is described in
+/// documentation of @c PktFilterBPF::openSocket.
+///
+/// Use of BPF requires Kea to encode and decode the datalink and network
+/// layer headers. Currently Kea supports encoding and decoding ethernet
+/// frames on physical interfaces and pseudo headers received on local
+/// loopback interface.
+class PktFilterBPF : public PktFilter {
+public:
+
+ /// @brief Check if packet can be sent to the host without address directly.
+ ///
+ /// This class supports direct responses to the host without address.
+ ///
+ /// @return true always.
+ virtual bool isDirectResponseSupported() const {
+ return (true);
+ }
+
+ /// @brief Open primary and fallback socket.
+ ///
+ /// This method opens the BPF device and applies the following
+ /// configuration to it:
+ /// - attach the device to the specified interface
+ /// - set filter program to receive DHCP messages encapsulated in UDP
+ /// packets
+ /// - set immediate mode which causes the read function to return
+ /// immediately and do not wait for the whole read buffer to be filled
+ /// by the kernel (to avoid hangs)
+ ///
+ /// It also obtains the following configuration from the kernel:
+ /// - major and minor version of the BPF (and checks if it is valid)
+ /// - length of the buffer to be used to receive the data from the socket
+ ///
+ /// @param iface Interface descriptor. Note that the function (re)allocates
+ /// the socket read buffer according to the buffer size returned by the
+ /// kernel.
+ /// @param addr Address on the interface to be used to send packets.
+ /// @param port Port number.
+ /// @param receive_bcast Configure socket to receive broadcast messages
+ /// @param send_bcast Configure socket to send broadcast messages.
+ ///
+ /// @return A structure describing a primary and fallback socket.
+ virtual SocketInfo openSocket(Iface& iface,
+ const isc::asiolink::IOAddress& addr,
+ const uint16_t port,
+ const bool receive_bcast,
+ const bool send_bcast);
+
+ /// @brief Receive packet over specified socket.
+ ///
+ /// @param iface interface
+ /// @param socket_info structure holding socket information
+ ///
+ /// @return Received packet
+ virtual Pkt4Ptr receive(Iface& iface, const SocketInfo& socket_info);
+
+ /// @brief Send packet over specified socket.
+ ///
+ /// @param iface interface to be used to send packet
+ /// @param sockfd socket descriptor
+ /// @param pkt packet to be sent
+ ///
+ /// @return result of sending a packet. It is 0 if successful.
+ virtual int send(const Iface& iface, uint16_t sockfd,
+ const Pkt4Ptr& pkt);
+
+private:
+
+ /// @brief Writes pseudo header containing an address family into a buffer.
+ ///
+ /// BPF utilizes the pseudo headers to pass the ancillary data between the
+ /// kernel and the application. For example, when the packet is to be sent
+ /// over the local loopback interface the pseudo header must be added before
+ /// the network layer header to indicate the address family. Other link
+ /// layer header (e.g. ethernet) is not used for local loopback interface.
+ ///
+ /// The header written by this method consists of 4 bytes and contains the
+ /// address family value in host byte order. See sys/socket.h for the
+ /// address family values. Typically it will be AF_INET.
+ ///
+ /// This function doesn't throw.
+ ///
+ /// @param address_family Address family (e.g. AF_INET).
+ /// @param [out] out_buf buffer where a header is written.
+ void writeAFPseudoHeader(const uint32_t address_family,
+ util::OutputBuffer& out_buf);
+
+};
+
+} // namespace isc::dhcp
+} // namespace isc
+
+#endif // PKT_FILTER_BPF_H