Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ISC Open Source Projects
Kea
Commits
0b7cf4ce
Commit
0b7cf4ce
authored
Jul 03, 2014
by
Marcin Siodelski
Browse files
[2893] Created BPF packet filtering class.
parent
6582b6c2
Changes
5
Hide whitespace changes
Inline
Side-by-side
src/lib/dhcp/Makefile.am
View file @
0b7cf4ce
...
...
@@ -50,10 +50,16 @@ libkea_dhcp___la_SOURCES += pkt_filter6.h pkt_filter6.cc
libkea_dhcp___la_SOURCES
+=
pkt_filter_inet.cc pkt_filter_inet.h
libkea_dhcp___la_SOURCES
+=
pkt_filter_inet6.cc pkt_filter_inet6.h
# Utilize Linux Packet Filtering on Linux.
if
OS_LINUX
libkea_dhcp___la_SOURCES
+=
pkt_filter_lpf.cc pkt_filter_lpf.h
endif
# Utilize Berkeley Packet Filtering on BSD.
if
OS_BSD
libkea_dhcp___la_SOURCES
+=
pkt_filter_bpf.cc pkt_filter_bpf.h
endif
libkea_dhcp___la_SOURCES
+=
std_option_defs.h
libkea_dhcp___la_SOURCES
+=
docsis3_option_defs.h
...
...
src/lib/dhcp/pkt_filter_bpf.cc
0 → 100644
View file @
0b7cf4ce
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
#include <dhcp/dhcp4.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt_filter_bpf.h>
#include <dhcp/protocol_util.h>
#include <exceptions/exceptions.h>
#include <algorithm>
#include <net/bpf.h>
#include <net/ethernet.h>
namespace
{
using
namespace
isc
::
dhcp
;
/// @brief Maximum number of attempts to open BPF device.
const
unsigned
int
MAX_BPF_OPEN_ATTEMPTS
=
100
;
/// The following structure defines a Berkely Packet Filter program to perform
/// packet filtering. The program operates on Ethernet packets. To help with
/// interpretation of the program, for the types of Ethernet packets we are
/// interested in, the header layout is:
///
/// 6 bytes Destination Ethernet Address
/// 6 bytes Source Ethernet Address
/// 2 bytes Ethernet packet type
///
/// 20 bytes Fixed part of IP header
/// variable Variable part of IP header
///
/// 2 bytes UDP Source port
/// 2 bytes UDP destination port
/// 4 bytes Rest of UDP header
///
/// @todo We may want to extend the filter to receive packets sent
/// to the particular IP address assigned to the interface or
/// broadcast address.
struct
bpf_insn
dhcp_sock_filter
[]
=
{
// Make sure this is an IP packet: check the half-word (two bytes)
// at offset 12 in the packet (the Ethernet packet type). If it
// is, advance to the next instruction. If not, advance 8
// instructions (which takes execution to the last instruction in
// the sequence: "drop it").
BPF_STMT
(
BPF_LD
+
BPF_H
+
BPF_ABS
,
ETHERNET_PACKET_TYPE_OFFSET
),
BPF_JUMP
(
BPF_JMP
+
BPF_JEQ
+
BPF_K
,
ETHERTYPE_IP
,
0
,
8
),
// Make sure it's a UDP packet. The IP protocol is at offset
// 9 in the IP header so, adding the Ethernet packet header size
// of 14 bytes gives an absolute byte offset in the packet of 23.
BPF_STMT
(
BPF_LD
+
BPF_B
+
BPF_ABS
,
ETHERNET_HEADER_LEN
+
IP_PROTO_TYPE_OFFSET
),
BPF_JUMP
(
BPF_JMP
+
BPF_JEQ
+
BPF_K
,
IPPROTO_UDP
,
0
,
6
),
// Make sure this isn't a fragment by checking that the fragment
// offset field in the IP header is zero. This field is the
// least-significant 13 bits in the bytes at offsets 6 and 7 in
// the IP header, so the half-word at offset 20 (6 + size of
// Ethernet header) is loaded and an appropriate mask applied.
BPF_STMT
(
BPF_LD
+
BPF_H
+
BPF_ABS
,
ETHERNET_HEADER_LEN
+
IP_FLAGS_OFFSET
),
BPF_JUMP
(
BPF_JMP
+
BPF_JSET
+
BPF_K
,
0x1fff
,
4
,
0
),
// Get the IP header length. This is achieved by the following
// (special) instruction that, given the offset of the start
// of the IP header (offset 14) loads the IP header length.
BPF_STMT
(
BPF_LDX
+
BPF_B
+
BPF_MSH
,
ETHERNET_HEADER_LEN
),
// Make sure it's to the right port. The following instruction
// adds the previously extracted IP header length to the given
// offset to locate the correct byte. The given offset of 16
// comprises the length of the Ethernet header (14) plus the offset
// of the UDP destination port (2) within the UDP header.
BPF_STMT
(
BPF_LD
+
BPF_H
+
BPF_IND
,
ETHERNET_HEADER_LEN
+
UDP_DEST_PORT
),
// The following instruction tests against the default DHCP server port,
// but the action port is actually set in PktFilterBPF::openSocket().
// N.B. The code in that method assumes that this instruction is at
// offset 8 in the program. If this is changed, openSocket() must be
// updated.
BPF_JUMP
(
BPF_JMP
+
BPF_JEQ
+
BPF_K
,
DHCP4_SERVER_PORT
,
0
,
1
),
// If we passed all the tests, ask for the whole packet.
BPF_STMT
(
BPF_RET
+
BPF_K
,
(
u_int
)
-
1
),
// Otherwise, drop it.
BPF_STMT
(
BPF_RET
+
BPF_K
,
0
),
};
}
using
namespace
isc
::
util
;
namespace
isc
{
namespace
dhcp
{
SocketInfo
PktFilterBPF
::
openSocket
(
const
Iface
&
iface
,
const
isc
::
asiolink
::
IOAddress
&
addr
,
const
uint16_t
port
,
const
bool
,
const
bool
)
{
// Open fallback socket first. If it fails, it will give us an indication
// that there is another service (perhaps DHCP server) running.
// The function will throw an exception and effectivelly cease opening
// the BPF device below.
int
fallback
=
openFallbackSocket
(
addr
,
port
);
// Fallback has opened so, let's open the BPF device that we will be
// using for receiving and sending packets. The BPF device is opened
// by opening a file /dev/bpf%d where %d is a number. There may be
// devices already open so we will try them one by one and open the
// one that is not busy.
int
sock
=
-
1
;
for
(
unsigned
int
bpf_dev
=
0
;
bpf_dev
<
MAX_BPF_OPEN_ATTEMPTS
&&
(
sock
<
0
);
++
bpf_dev
)
{
std
::
ostringstream
s
;
s
<<
"/dev/bpf"
<<
bpf_dev
;
sock
=
open
(
s
.
str
().
c_str
(),
O_RDWR
,
0
);
if
(
sock
<
0
)
{
// If device busy, try another one.
if
(
errno
==
EBUSY
)
{
continue
;
}
// All other errors are fatal, so close the fallback socket
// and throw.
close
(
fallback
);
isc_throw
(
SocketConfigError
,
"Failed to open BPF device "
<<
s
);
}
}
// The BPF device is now open. Now it needs to be configured.
// Associate the device with the interface name.
struct
ifreq
iface_data
;
memset
(
&
iface_data
,
0
,
sizeof
(
iface_data
));
std
::
strncpy
(
iface_data
.
ifr_name
,
iface
.
getName
().
c_str
(),
std
::
min
(
static_cast
<
int
>
(
IFNAMSIZ
),
static_cast
<
int
>
(
iface
.
getName
().
length
())));
if
(
ioctl
(
sock
,
BIOCSETIF
,
&
iface_data
)
<
0
)
{
close
(
fallback
);
close
(
sock
);
isc_throw
(
SocketConfigError
,
"Failed to associate BPF device "
" with interface "
<<
iface
.
getName
());
}
// Get the BPF version supported by the kernel. Every application
// must check this version against the current version in use.
struct
bpf_version
ver
;
if
(
ioctl
(
sock
,
BIOCVERSION
,
&
ver
)
<
0
)
{
close
(
fallback
);
close
(
sock
);
isc_throw
(
SocketConfigError
,
"Failed to obtain the BPF version"
" number from the kernel"
);
}
// Major BPF version must match and the minor version that the kernel
// runs must be at least the current version in use.
if
((
ver
.
bv_major
!=
BPF_MAJOR_VERSION
)
||
(
ver
.
bv_minor
<
BPF_MINOR_VERSION
))
{
close
(
fallback
);
close
(
sock
);
isc_throw
(
SocketConfigError
,
"Invalid BPF version"
);
}
// Get the size of the read buffer for this device. We will need to
// allocate the buffer of this size for packet reads.
unsigned
int
buf_len
=
0
;
if
(
ioctl
(
sock
,
BIOCGBLEN
,
&
buf_len
)
<
0
)
{
close
(
fallback
);
close
(
sock
);
isc_throw
(
SocketConfigError
,
"Unable to obtain the required"
" buffer legth for reads from BPF device"
);
}
// Configure the BPF program to receive packets on the specified port.
dhcp_sock_filter
[
8
].
k
=
port
;
// Set the filter program so as we only get packets we are interested in.
struct
bpf_program
prog
;
prog
.
bf_insns
=
dhcp_sock_filter
;
prog
.
bf_len
=
sizeof
(
dhcp_sock_filter
)
/
sizeof
(
struct
bpf_insn
);
if
(
ioctl
(
sock
,
BIOCSETF
,
&
prog
)
<
0
)
{
close
(
fallback
);
close
(
sock
);
isc_throw
(
SocketConfigError
,
"Failed to install BPF filter"
" program"
);
}
// Everything is ok, return the socket (BPF device descriptor) to
// the caller.
return
(
SocketInfo
(
addr
,
port
,
sock
,
fallback
));
}
Pkt4Ptr
PktFilterBPF
::
receive
(
const
Iface
&
/* iface */
,
const
SocketInfo
&
/*socket_info*/
)
{
return
(
Pkt4Ptr
());
/* uint8_t raw_buf[IfaceMgr::RCVBUFSIZE];
// First let's get some data from the fallback socket. The data will be
// discarded but we don't want the socket buffer to bloat. We get the
// packets from the socket in loop but most of the time the loop will
// end after receiving one packet. The call to recv returns immediately
// when there is no data left on the socket because the socket is
// non-blocking.
// @todo In the normal conditions, both the primary socket and the fallback
// socket are in sync as they are set to receive packets on the same
// address and port. The reception of packets on the fallback socket
// shouldn't cause significant lags in packet reception. If we find in the
// future that it does, the sort of threshold could be set for the maximum
// bytes received on the fallback socket in a single round. Further
// optimizations would include an asynchronous read from the fallback socket
// when the DHCP server is idle.
int datalen;
do {
datalen = recv(socket_info.fallbackfd_, raw_buf, sizeof(raw_buf), 0);
} while (datalen > 0);
// Now that we finished getting data from the fallback socket, we
// have to get the data from the raw socket too.
int data_len = read(socket_info.sockfd_, raw_buf, sizeof(raw_buf));
// If negative value is returned by read(), it indicates that an
// error occured. If returned value is 0, no data was read from the
// socket. In both cases something has gone wrong, because we expect
// that a chunk of data is there. We signal the lack of data by
// returing an empty packet.
if (data_len <= 0) {
return Pkt4Ptr();
}
InputBuffer buf(raw_buf, data_len);
// @todo: This is awkward way to solve the chicken and egg problem
// whereby we don't know the offset where DHCP data start in the
// received buffer when we create the packet object. In general case,
// the IP header has variable length. The information about its length
// is stored in one of its fields. Therefore, we have to decode the
// packet to get the offset of the DHCP data. The dummy object is
// created so as we can pass it to the functions which decode IP stack
// and find actual offset of the DHCP data.
// Once we find the offset we can create another Pkt4 object from
// the reminder of the input buffer and set the IP addresses and
// ports from the dummy packet. We should consider doing it
// in some more elegant way.
Pkt4Ptr dummy_pkt = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 0));
// Decode ethernet, ip and udp headers.
decodeEthernetHeader(buf, dummy_pkt);
decodeIpUdpHeader(buf, dummy_pkt);
// Read the DHCP data.
std::vector<uint8_t> dhcp_buf;
buf.readVector(dhcp_buf, buf.getLength() - buf.getPosition());
// Decode DHCP data into the Pkt4 object.
Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(&dhcp_buf[0], dhcp_buf.size()));
// Set the appropriate packet members using data collected from
// the decoded headers.
pkt->setIndex(iface.getIndex());
pkt->setIface(iface.getName());
pkt->setLocalAddr(dummy_pkt->getLocalAddr());
pkt->setRemoteAddr(dummy_pkt->getRemoteAddr());
pkt->setLocalPort(dummy_pkt->getLocalPort());
pkt->setRemotePort(dummy_pkt->getRemotePort());
pkt->setLocalHWAddr(dummy_pkt->getLocalHWAddr());
pkt->setRemoteHWAddr(dummy_pkt->getRemoteHWAddr());
return (pkt); */
}
int
PktFilterBPF
::
send
(
const
Iface
&
/*iface*/
,
uint16_t
/*sockfd*/
,
const
Pkt4Ptr
&
/*pkt*/
)
{
return
0
;
/* OutputBuffer buf(14);
// Some interfaces may have no HW address - e.g. loopback interface.
// For these interfaces the HW address length is 0. If this is the case,
// then we will rely on the functions which construct the IP/UDP headers
// to provide a default HW addres. Otherwise, create the HW address
// object using the HW address of the interface.
if (iface.getMacLen() > 0) {
HWAddrPtr hwaddr(new HWAddr(iface.getMac(), iface.getMacLen(),
iface.getHWType()));
pkt->setLocalHWAddr(hwaddr);
}
// Ethernet frame header.
// Note that we don't validate whether HW addresses in 'pkt'
// are valid because they are checked by the function called.
writeEthernetHeader(pkt, buf);
// IP and UDP header
writeIpUdpHeader(pkt, buf);
// DHCPv4 message
buf.writeData(pkt->getBuffer().getData(), pkt->getBuffer().getLength());
sockaddr_ll sa;
sa.sll_family = AF_PACKET;
sa.sll_ifindex = iface.getIndex();
sa.sll_protocol = htons(ETH_P_IP);
sa.sll_halen = 6;
int result = sendto(sockfd, buf.getData(), buf.getLength(), 0,
reinterpret_cast<const struct sockaddr*>(&sa),
sizeof(sockaddr_ll));
if (result < 0) {
isc_throw(SocketWriteError, "failed to send DHCPv4 packet, errno="
<< errno << " (check errno.h)");
}
return (0);
*/
}
}
// end of isc::dhcp namespace
}
// end of isc namespace
src/lib/dhcp/pkt_filter_bpf.h
0 → 100644
View file @
0b7cf4ce
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#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
///
/// This class provides methods to send and recive DHCPv4 messages using raw
/// sockets and Berkeley Packet Filtering. It is used by @c isc::dhcp::IfaceMgr
/// to send DHCPv4 messages to the hosts which don't have an IPv4 address
/// assigned yet.
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.
///
/// @param iface Interface descriptor.
/// @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
(
const
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
(
const
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
);
};
}
// namespace isc::dhcp
}
// namespace isc
#endif // PKT_FILTER_BPF_H
src/lib/dhcp/tests/Makefile.am
View file @
0b7cf4ce
...
...
@@ -78,10 +78,16 @@ libdhcp___unittests_SOURCES += pkt_filter6_test_stub.cc pkt_filter_test_stub.h
libdhcp___unittests_SOURCES
+=
pkt_filter_test_utils.h pkt_filter_test_utils.cc
libdhcp___unittests_SOURCES
+=
pkt_filter6_test_utils.h pkt_filter6_test_utils.cc
# Utilize Linux Packet Filtering on Linux.
if
OS_LINUX
libdhcp___unittests_SOURCES
+=
pkt_filter_lpf_unittest.cc
endif
# Utilize Berkeley Packet Filtering on BSD.
if
OS_BSD
libdhcp___unittests_SOURCES
+=
pkt_filter_bpf_unittest.cc
endif
libdhcp___unittests_SOURCES
+=
protocol_util_unittest.cc
libdhcp___unittests_SOURCES
+=
duid_unittest.cc
...
...
src/lib/dhcp/tests/pkt_filter_bpf_unittest.cc
0 → 100644
View file @
0b7cf4ce
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
#include <asiolink/io_address.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt_filter_bpf.h>
#include <dhcp/protocol_util.h>
#include <dhcp/tests/pkt_filter_test_utils.h>
#include <util/buffer.h>
#include <gtest/gtest.h>
#include <sys/socket.h>
using
namespace
isc
::
asiolink
;
using
namespace
isc
::
dhcp
;
using
namespace
isc
::
util
;
namespace
{
/// Port number used by tests.
const
uint16_t
PORT
=
10067
;
/// Size of the buffer holding received packets.
const
size_t
RECV_BUF_SIZE
=
2048
;
// Test fixture class inherits from the class common for all packet
// filter tests.
class
PktFilterBPFTest
:
public
isc
::
dhcp
::
test
::
PktFilterTest
{
public:
PktFilterBPFTest
()
:
PktFilterTest
(
PORT
)
{
}
};
// This test verifies that the PktFilterBPF class reports its capability
// to send packets to the host having no IP address assigned.
TEST_F
(
PktFilterBPFTest
,
isDirectResponseSupported
)
{
// Create object under test.
PktFilterBPF
pkt_filter
;
// Must support direct responses.
EXPECT_TRUE
(
pkt_filter
.
isDirectResponseSupported
());
}
// All tests below require root privileges to execute successfully. If
// they are run as non-root user they will fail due to insufficient privileges
// to open raw network sockets. Therefore, they should remain disabled by default
// and "DISABLED_" tags should not be removed. If one is willing to run these
// tests please run "make check" as root and enable execution of disabled tests
// by setting GTEST_ALSO_RUN_DISABLED_TESTS to a value other than 0. In order
// to run tests from this particular file, set the GTEST_FILTER environmental
// variable to "PktFilterBPFTest.*" apart from GTEST_ALSO_RUN_DISABLED_TESTS
// setting.
// This test verifies that the raw AF_PACKET family socket can
// be opened and bound to the specific interface.
TEST_F
(
PktFilterBPFTest
,
DISABLED_openSocket
)
{
// Create object representing loopback interface.
Iface
iface
(
ifname_
,
ifindex_
);
// Set loopback address.
IOAddress
addr
(
"127.0.0.1"
);
// Try to open socket.
PktFilterBPF
pkt_filter
;
ASSERT_NO_THROW
(
sock_info_
=
pkt_filter
.
openSocket
(
iface
,
addr
,
PORT
,
false
,
false
);
);
// Check that the primary socket has been opened.
ASSERT_GE
(
sock_info_
.
sockfd_
,
0
);
// Check that the fallback socket has been opened too.
ASSERT_GE
(
sock_info_
.
fallbackfd_
,
0
);
/* // Verify that the socket belongs to AF_PACKET family.
sockaddr_ll sock_address;
socklen_t sock_address_len = sizeof(sock_address);
ASSERT_EQ(0, getsockname(sock_info_.sockfd_,
reinterpret_cast<sockaddr*>(&sock_address),
&sock_address_len));
EXPECT_EQ(AF_PACKET, sock_address.sll_family);
// Verify that the socket is bound to appropriate interface.
EXPECT_EQ(ifindex_, sock_address.sll_ifindex);
// Verify that the socket has SOCK_RAW type.
int sock_type;
socklen_t sock_type_len = sizeof(sock_type);
ASSERT_EQ(0, getsockopt(sock_info_.sockfd_, SOL_SOCKET, SO_TYPE,
&sock_type, &sock_type_len));
EXPECT_EQ(SOCK_RAW, sock_type); */
}
// This test verifies correctness of sending DHCP packet through the raw
// socket, whereby all IP stack headers are hand-crafted.
TEST_F
(
PktFilterBPFTest
,
DISABLED_send
)
{
/* // Packet will be sent over loopback interface.
Iface iface(ifname_, ifindex_);
IOAddress addr("127.0.0.1");
// Create an instance of the class which we are testing.
PktFilterBPF pkt_filter;
// Open socket. We don't check that the socket has appropriate
// options and family set because we have checked that in the
// openSocket test already.
sock_info_ = pkt_filter.openSocket(iface, addr, PORT, false, false);
ASSERT_GE(sock_info_.sockfd_, 0);
// Send the packet over the socket.
ASSERT_NO_THROW(pkt_filter.send(iface, sock_info_.sockfd_, test_message_));
// Read the data from socket.
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sock_info_.sockfd_, &readfds);
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
int result = select(sock_info_.sockfd_ + 1, &readfds, NULL, NULL, &timeout);
// We should receive some data from loopback interface.
ASSERT_GT(result, 0);
// Get the actual data.
uint8_t rcv_buf[RECV_BUF_SIZE];
result = recv(sock_info_.sockfd_, rcv_buf, RECV_BUF_SIZE, 0);
ASSERT_GT(result, 0);
Pkt4Ptr dummy_pkt = Pkt4Ptr(new Pkt4(DHCPDISCOVER, 0));
InputBuffer buf(rcv_buf, result);
// Decode ethernet, ip and udp headers.
decodeEthernetHeader(buf, dummy_pkt);
decodeIpUdpHeader(buf, dummy_pkt);
// Create the DHCPv4 packet from the received data.
std::vector<uint8_t> dhcp_buf;
buf.readVector(dhcp_buf, buf.getLength() - buf.getPosition());
Pkt4Ptr rcvd_pkt(new Pkt4(&dhcp_buf[0], dhcp_buf.size()));
ASSERT_TRUE(rcvd_pkt);
// Parse the packet.
ASSERT_NO_THROW(rcvd_pkt->unpack());
// Check if the received message is correct.
testRcvdMessage(rcvd_pkt); */
}
// This test verifies correctness of reception of the DHCP packet over
// raw socket, whereby all IP stack headers are hand-crafted.
TEST_F
(
PktFilterBPFTest
,
DISABLED_receive
)
{
// Packet will be received over loopback interface.
Iface
iface
(
ifname_
,
ifindex_
);
IOAddress
addr
(
"127.0.0.1"
);
// Create an instance of the class which we are testing.
PktFilterBPF
pkt_filter
;
// Open socket. We don't check that the socket has appropriate
// options and family set because we have checked that in the
// openSocket test already.
sock_info_
=
pkt_filter
.
openSocket
(
iface
,
addr
,
PORT
,
false
,
false
);
ASSERT_GE
(
sock_info_
.
sockfd_
,
0
);
// Send DHCPv4 message to the local loopback address and server's port.