Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Adam Osuchowski
Kea
Commits
ae0620ed
Commit
ae0620ed
authored
Apr 25, 2013
by
Marcin Siodelski
Browse files
[2902] Unit tests for linux packet filtering.
parent
757a5b14
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/lib/dhcp/tests/Makefile.am
View file @
ae0620ed
...
...
@@ -44,6 +44,7 @@ libdhcp___unittests_SOURCES += option_space_unittest.cc
libdhcp___unittests_SOURCES
+=
pkt4_unittest.cc
libdhcp___unittests_SOURCES
+=
pkt6_unittest.cc
libdhcp___unittests_SOURCES
+=
pkt_filter_inet_unittest.cc
libdhcp___unittests_SOURCES
+=
pkt_filter_lpf_unittest.cc
libdhcp___unittests_SOURCES
+=
protocol_util_unittest.cc
libdhcp___unittests_SOURCES
+=
duid_unittest.cc
...
...
src/lib/dhcp/tests/pkt_filter_lpf_unittest.cc
0 → 100644
View file @
ae0620ed
// Copyright (C) 2013 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_lpf.h>
#include
<dhcp/protocol_util.h>
#include
<util/buffer.h>
#include
<gtest/gtest.h>
#include
<linux/if_packet.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
;
/// This class handles has simple algorithm checking
/// presence of loopback interface and initializing
/// its index.
class
PktFilterLPFTest
:
public
::
testing
::
Test
{
public:
PktFilterLPFTest
()
{
// Initialize ifname_ and ifindex_.
loInit
();
}
~
PktFilterLPFTest
()
{
// Cleanup after each test. This guarantees
// that the socket does not hang after a test.
close
(
socket_
);
}
/// @brief Detect loopback interface.
///
/// @todo this function will be removed once cross-OS interface
/// detection is implemented
void
loInit
()
{
if
(
if_nametoindex
(
"lo"
)
>
0
)
{
ifname_
=
"lo"
;
ifindex_
=
if_nametoindex
(
"lo"
);
}
else
if
(
if_nametoindex
(
"lo0"
)
>
0
)
{
ifname_
=
"lo0"
;
ifindex_
=
if_nametoindex
(
"lo0"
);
}
else
{
std
::
cout
<<
"Failed to detect loopback interface. Neither "
<<
"lo nor lo0 worked. Giving up."
<<
std
::
endl
;
FAIL
();
}
}
std
::
string
ifname_
;
///< Loopback interface name
uint16_t
ifindex_
;
///< Loopback interface index.
int
socket_
;
///< Socket descriptor.
};
// 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 "PktFilterLPFTest.*" 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
(
PktFilterLPFTest
,
DISABLED_openSocket
)
{
// Create object representing loopback interface.
Iface
iface
(
ifname_
,
ifindex_
);
// Set loopback address.
IOAddress
addr
(
"127.0.0.1"
);
// Try to open socket.
PktFilterLPF
pkt_filter
;
socket_
=
pkt_filter
.
openSocket
(
iface
,
addr
,
PORT
,
false
,
false
);
// Check that socket has been opened.
ASSERT_GE
(
socket_
,
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
(
socket_
,
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
(
socket_
,
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
(
PktFilterLPFTest
,
DISABLED_send
)
{
// Let's create a DHCPv4 packet.
Pkt4Ptr
pkt
(
new
Pkt4
(
DHCPOFFER
,
0
));
ASSERT_TRUE
(
pkt
);
// Set required fields.
pkt
->
setLocalAddr
(
IOAddress
(
"127.0.0.1"
));
pkt
->
setRemotePort
(
PORT
);
pkt
->
setLocalPort
(
PORT
+
1
);
pkt
->
setIndex
(
ifindex_
);
pkt
->
setIface
(
ifname_
);
pkt
->
setHops
(
6
);
pkt
->
setSecs
(
42
);
pkt
->
setCiaddr
(
IOAddress
(
"192.0.2.1"
));
pkt
->
setSiaddr
(
IOAddress
(
"192.0.2.2"
));
pkt
->
setYiaddr
(
IOAddress
(
"192.0.2.3"
));
pkt
->
setGiaddr
(
IOAddress
(
"192.0.2.4"
));
// Create the on-wire data.
ASSERT_NO_THROW
(
pkt
->
pack
());
// 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.
PktFilterLPF
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.
socket_
=
pkt_filter
.
openSocket
(
iface
,
addr
,
PORT
,
false
,
false
);
ASSERT_GE
(
socket_
,
0
);
// Send the packet over the socket.
ASSERT_NO_THROW
(
pkt_filter
.
send
(
iface
,
socket_
,
pkt
));
// Read the data from socket.
fd_set
readfds
;
FD_ZERO
(
&
readfds
);
FD_SET
(
socket_
,
&
readfds
);
struct
timeval
timeout
;
timeout
.
tv_sec
=
5
;
timeout
.
tv_usec
=
0
;
int
result
=
select
(
socket_
+
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
(
socket_
,
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
());
// Verify that the received packet matches sent packet.
EXPECT_EQ
(
pkt
->
getHops
(),
rcvd_pkt
->
getHops
());
EXPECT_EQ
(
pkt
->
getOp
(),
rcvd_pkt
->
getOp
());
EXPECT_EQ
(
pkt
->
getSecs
(),
rcvd_pkt
->
getSecs
());
EXPECT_EQ
(
pkt
->
getFlags
(),
rcvd_pkt
->
getFlags
());
EXPECT_EQ
(
pkt
->
getCiaddr
(),
rcvd_pkt
->
getCiaddr
());
EXPECT_EQ
(
pkt
->
getSiaddr
(),
rcvd_pkt
->
getSiaddr
());
EXPECT_EQ
(
pkt
->
getYiaddr
(),
rcvd_pkt
->
getYiaddr
());
EXPECT_EQ
(
pkt
->
getGiaddr
(),
rcvd_pkt
->
getGiaddr
());
EXPECT_EQ
(
pkt
->
getTransid
(),
rcvd_pkt
->
getTransid
());
EXPECT_TRUE
(
pkt
->
getSname
()
==
rcvd_pkt
->
getSname
());
EXPECT_TRUE
(
pkt
->
getFile
()
==
rcvd_pkt
->
getFile
());
EXPECT_EQ
(
pkt
->
getHtype
(),
rcvd_pkt
->
getHtype
());
EXPECT_EQ
(
pkt
->
getHlen
(),
rcvd_pkt
->
getHlen
());
}
// This test verifies correctness of reception of the DHCP packet over
// raw socket, whereby all IP stack headers are hand-crafted.
TEST_F
(
PktFilterLPFTest
,
DISABLED_receive
)
{
// Let's create a DHCPv4 packet.
Pkt4Ptr
pkt
(
new
Pkt4
(
DHCPOFFER
,
0
));
ASSERT_TRUE
(
pkt
);
// Set required fields.
pkt
->
setLocalAddr
(
IOAddress
(
"127.0.0.1"
));
pkt
->
setRemotePort
(
PORT
);
pkt
->
setLocalPort
(
PORT
+
1
);
pkt
->
setIndex
(
ifindex_
);
pkt
->
setIface
(
ifname_
);
pkt
->
setHops
(
6
);
pkt
->
setSecs
(
42
);
pkt
->
setCiaddr
(
IOAddress
(
"192.0.2.1"
));
pkt
->
setSiaddr
(
IOAddress
(
"192.0.2.2"
));
pkt
->
setYiaddr
(
IOAddress
(
"192.0.2.3"
));
pkt
->
setGiaddr
(
IOAddress
(
"192.0.2.4"
));
// Create the on-wire data.
ASSERT_NO_THROW
(
pkt
->
pack
());
// 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.
PktFilterLPF
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.
socket_
=
pkt_filter
.
openSocket
(
iface
,
addr
,
PORT
,
false
,
false
);
ASSERT_GE
(
socket_
,
0
);
// Send the packet over the socket.
ASSERT_NO_THROW
(
pkt_filter
.
send
(
iface
,
socket_
,
pkt
));
// Receive the packet.
SocketInfo
socket_info
(
socket_
,
IOAddress
(
"127.0.0.1"
),
PORT
);
Pkt4Ptr
rcvd_pkt
=
pkt_filter
.
receive
(
iface
,
socket_info
);
// Check that the packet has been correctly received.
ASSERT_TRUE
(
rcvd_pkt
);
// Parse the packet.
ASSERT_NO_THROW
(
rcvd_pkt
->
unpack
());
// Verify that the received packet matches sent packet.
EXPECT_EQ
(
pkt
->
getHops
(),
rcvd_pkt
->
getHops
());
EXPECT_EQ
(
pkt
->
getOp
(),
rcvd_pkt
->
getOp
());
EXPECT_EQ
(
pkt
->
getSecs
(),
rcvd_pkt
->
getSecs
());
EXPECT_EQ
(
pkt
->
getFlags
(),
rcvd_pkt
->
getFlags
());
EXPECT_EQ
(
pkt
->
getCiaddr
(),
rcvd_pkt
->
getCiaddr
());
EXPECT_EQ
(
pkt
->
getSiaddr
(),
rcvd_pkt
->
getSiaddr
());
EXPECT_EQ
(
pkt
->
getYiaddr
(),
rcvd_pkt
->
getYiaddr
());
EXPECT_EQ
(
pkt
->
getGiaddr
(),
rcvd_pkt
->
getGiaddr
());
EXPECT_EQ
(
pkt
->
getTransid
(),
rcvd_pkt
->
getTransid
());
EXPECT_TRUE
(
pkt
->
getSname
()
==
rcvd_pkt
->
getSname
());
EXPECT_TRUE
(
pkt
->
getFile
()
==
rcvd_pkt
->
getFile
());
EXPECT_EQ
(
pkt
->
getHtype
(),
rcvd_pkt
->
getHtype
());
EXPECT_EQ
(
pkt
->
getHlen
(),
rcvd_pkt
->
getHlen
());
}
}
// anonymous namespace
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment