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));
 
  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) {
 
  380    return (
SocketInfo(addr, port, sock, fallback));
 
 
  389                  " for the interface: " << iface.
getName());
 
  410    } 
while (datalen > 0);
 
  422    datalen = BPF_WORDALIGN(datalen);
 
  434    while (offset < datalen) {
 
  437        if (datalen - offset < 
static_cast<int>(
sizeof(bpf_hdr))) {
 
  439                      " interface " << iface.
getName() << 
" has a truncated " 
  444        memcpy(
static_cast<void*
>(&bpfh),
 
  450        if (
static_cast<int>(bpfh.bh_hdrlen + bpfh.bh_caplen) > datalen - offset) {
 
  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) {
 
  475                    datalen - bpfh.bh_hdrlen - offset);
 
  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");
 
  524    std::vector<uint8_t> dhcp_buf;
 
  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);
 
 
  573        pkt->setLocalHWAddr(hwaddr);
 
  582        writeAFPseudoHeader(AF_INET, buf);
 
  598    buf.
writeData(pkt->getBuffer().getData(), pkt->getBuffer().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.
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.
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.
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
const uint8_t * getData() const
Return a pointer to the head of the data stored in the buffer.
size_t getLength() const
Return the length of data written 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.