Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sebastian Schrader
Kea
Commits
5eede0e0
Commit
5eede0e0
authored
Oct 11, 2013
by
Tomek Mrugalski
🛰
Browse files
[master] Merge branch 'trac3184' (RAI option echoed back in DHCPv4)
Conflicts: ChangeLog src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
parents
b080f05c
287389c0
Changes
7
Expand all
Show whitespace changes
Inline
Side-by-side
ChangeLog
View file @
5eede0e0
690. [bug] tomek
b10-dhcp4: Relay Agent Info option is now echoed back in
DHCPv4 responses.
(Trac #3184, git 287389c049518bff66bdf6a5a49bb8768be02d8e)
689. [func]* marcin
b10-dhcp4 and b10-dhcp6 install callback functions which parse options
in the received DHCP packets.
...
...
src/bin/dhcp4/dhcp4_srv.cc
View file @
5eede0e0
...
...
@@ -584,6 +584,12 @@ Dhcpv4Srv::copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer) {
if
(
dst_hw_addr
)
{
answer
->
setRemoteHWAddr
(
dst_hw_addr
);
}
// If this packet is relayed, we want to copy Relay Agent Info option
OptionPtr
rai
=
question
->
getOption
(
DHO_DHCP_AGENT_OPTIONS
);
if
(
rai
)
{
answer
->
addOption
(
rai
);
}
}
void
...
...
src/bin/dhcp4/tests/Makefile.am
View file @
5eede0e0
...
...
@@ -77,6 +77,8 @@ dhcp4_unittests_SOURCES += ../dhcp4_log.h ../dhcp4_log.cc
dhcp4_unittests_SOURCES
+=
../config_parser.cc ../config_parser.h
dhcp4_unittests_SOURCES
+=
dhcp4_unittests.cc
dhcp4_unittests_SOURCES
+=
dhcp4_srv_unittest.cc
dhcp4_unittests_SOURCES
+=
dhcp4_test_utils.cc dhcp4_test_utils.h
dhcp4_unittests_SOURCES
+=
wireshark.cc
dhcp4_unittests_SOURCES
+=
ctrl_dhcp4_srv_unittest.cc
dhcp4_unittests_SOURCES
+=
config_parser_unittest.cc
dhcp4_unittests_SOURCES
+=
marker_file.cc
...
...
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
View file @
5eede0e0
This diff is collapsed.
Click to expand it.
src/bin/dhcp4/tests/dhcp4_test_utils.cc
0 → 100644
View file @
5eede0e0
// 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 <config/ccsession.h>
#include <dhcp4/tests/dhcp4_test_utils.h>
#include <dhcp/option4_addrlst.h>
#include <dhcp/option_int_array.h>
#include <dhcp/option_custom.h>
#include <dhcp/iface_mgr.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/lease_mgr.h>
#include <dhcpsrv/lease_mgr_factory.h>
using
namespace
std
;
using
namespace
isc
::
asiolink
;
namespace
isc
{
namespace
dhcp
{
namespace
test
{
/// dummy server-id file location
static
const
char
*
SRVID_FILE
=
"server-id-test.txt"
;
Dhcpv4SrvTest
::
Dhcpv4SrvTest
()
:
rcode_
(
-
1
)
{
subnet_
=
Subnet4Ptr
(
new
Subnet4
(
IOAddress
(
"192.0.2.0"
),
24
,
1000
,
2000
,
3000
));
pool_
=
Pool4Ptr
(
new
Pool4
(
IOAddress
(
"192.0.2.100"
),
IOAddress
(
"192.0.2.110"
)));
subnet_
->
addPool
(
pool_
);
CfgMgr
::
instance
().
deleteSubnets4
();
CfgMgr
::
instance
().
addSubnet4
(
subnet_
);
// Add Router option.
Option4AddrLstPtr
opt_routers
(
new
Option4AddrLst
(
DHO_ROUTERS
));
opt_routers
->
setAddress
(
IOAddress
(
"192.0.2.2"
));
subnet_
->
addOption
(
opt_routers
,
false
,
"dhcp4"
);
// it's ok if that fails. There should not be such a file anyway
unlink
(
SRVID_FILE
);
const
IfaceMgr
::
IfaceCollection
&
ifaces
=
IfaceMgr
::
instance
().
getIfaces
();
// There must be some interface detected
if
(
ifaces
.
empty
())
{
// We can't use ASSERT in constructor
ADD_FAILURE
()
<<
"No interfaces detected."
;
}
valid_iface_
=
ifaces
.
begin
()
->
getName
();
}
void
Dhcpv4SrvTest
::
addPrlOption
(
Pkt4Ptr
&
pkt
)
{
OptionUint8ArrayPtr
option_prl
=
OptionUint8ArrayPtr
(
new
OptionUint8Array
(
Option
::
V4
,
DHO_DHCP_PARAMETER_REQUEST_LIST
));
// Let's request options that have been configured for the subnet.
option_prl
->
addValue
(
DHO_DOMAIN_NAME_SERVERS
);
option_prl
->
addValue
(
DHO_DOMAIN_NAME
);
option_prl
->
addValue
(
DHO_LOG_SERVERS
);
option_prl
->
addValue
(
DHO_COOKIE_SERVERS
);
// Let's also request the option that hasn't been configured. In such
// case server should ignore request for this particular option.
option_prl
->
addValue
(
DHO_LPR_SERVERS
);
// And add 'Parameter Request List' option into the DISCOVER packet.
pkt
->
addOption
(
option_prl
);
}
void
Dhcpv4SrvTest
::
configureRequestedOptions
()
{
// dns-servers
Option4AddrLstPtr
option_dns_servers
(
new
Option4AddrLst
(
DHO_DOMAIN_NAME_SERVERS
));
option_dns_servers
->
addAddress
(
IOAddress
(
"192.0.2.1"
));
option_dns_servers
->
addAddress
(
IOAddress
(
"192.0.2.100"
));
ASSERT_NO_THROW
(
subnet_
->
addOption
(
option_dns_servers
,
false
,
"dhcp4"
));
// domain-name
OptionDefinition
def
(
"domain-name"
,
DHO_DOMAIN_NAME
,
OPT_FQDN_TYPE
);
OptionCustomPtr
option_domain_name
(
new
OptionCustom
(
def
,
Option
::
V4
));
option_domain_name
->
writeFqdn
(
"example.com"
);
subnet_
->
addOption
(
option_domain_name
,
false
,
"dhcp4"
);
// log-servers
Option4AddrLstPtr
option_log_servers
(
new
Option4AddrLst
(
DHO_LOG_SERVERS
));
option_log_servers
->
addAddress
(
IOAddress
(
"192.0.2.2"
));
option_log_servers
->
addAddress
(
IOAddress
(
"192.0.2.10"
));
ASSERT_NO_THROW
(
subnet_
->
addOption
(
option_log_servers
,
false
,
"dhcp4"
));
// cookie-servers
Option4AddrLstPtr
option_cookie_servers
(
new
Option4AddrLst
(
DHO_COOKIE_SERVERS
));
option_cookie_servers
->
addAddress
(
IOAddress
(
"192.0.2.1"
));
ASSERT_NO_THROW
(
subnet_
->
addOption
(
option_cookie_servers
,
false
,
"dhcp4"
));
}
void
Dhcpv4SrvTest
::
messageCheck
(
const
Pkt4Ptr
&
q
,
const
Pkt4Ptr
&
a
)
{
ASSERT_TRUE
(
q
);
ASSERT_TRUE
(
a
);
EXPECT_EQ
(
q
->
getHops
(),
a
->
getHops
());
EXPECT_EQ
(
q
->
getIface
(),
a
->
getIface
());
EXPECT_EQ
(
q
->
getIndex
(),
a
->
getIndex
());
EXPECT_EQ
(
q
->
getGiaddr
(),
a
->
getGiaddr
());
// When processing an incoming packet the remote address
// is copied as a src address, and the source address is
// copied as a remote address to the response.
EXPECT_TRUE
(
q
->
getLocalHWAddr
()
==
a
->
getLocalHWAddr
());
EXPECT_TRUE
(
q
->
getRemoteHWAddr
()
==
a
->
getRemoteHWAddr
());
// Check that bare minimum of required options are there.
// We don't check options requested by a client. Those
// are checked elsewhere.
EXPECT_TRUE
(
a
->
getOption
(
DHO_SUBNET_MASK
));
EXPECT_TRUE
(
a
->
getOption
(
DHO_ROUTERS
));
EXPECT_TRUE
(
a
->
getOption
(
DHO_DHCP_SERVER_IDENTIFIER
));
EXPECT_TRUE
(
a
->
getOption
(
DHO_DHCP_LEASE_TIME
));
EXPECT_TRUE
(
a
->
getOption
(
DHO_SUBNET_MASK
));
EXPECT_TRUE
(
a
->
getOption
(
DHO_DOMAIN_NAME
));
EXPECT_TRUE
(
a
->
getOption
(
DHO_DOMAIN_NAME_SERVERS
));
// Check that something is offered
EXPECT_TRUE
(
a
->
getYiaddr
().
toText
()
!=
"0.0.0.0"
);
}
void
Dhcpv4SrvTest
::
optionsCheck
(
const
Pkt4Ptr
&
pkt
)
{
// Check that the requested and configured options are returned
// in the ACK message.
EXPECT_TRUE
(
pkt
->
getOption
(
DHO_DOMAIN_NAME
))
<<
"domain-name not present in the response"
;
EXPECT_TRUE
(
pkt
->
getOption
(
DHO_DOMAIN_NAME_SERVERS
))
<<
"dns-servers not present in the response"
;
EXPECT_TRUE
(
pkt
->
getOption
(
DHO_LOG_SERVERS
))
<<
"log-servers not present in the response"
;
EXPECT_TRUE
(
pkt
->
getOption
(
DHO_COOKIE_SERVERS
))
<<
"cookie-servers not present in the response"
;
// Check that the requested but not configured options are not
// returned in the ACK message.
EXPECT_FALSE
(
pkt
->
getOption
(
DHO_LPR_SERVERS
))
<<
"domain-name present in the response but it is"
<<
" expected not to be present"
;
}
OptionPtr
Dhcpv4SrvTest
::
generateClientId
(
size_t
size
/*= 4*/
)
{
OptionBuffer
clnt_id
(
size
);
for
(
int
i
=
0
;
i
<
size
;
i
++
)
{
clnt_id
[
i
]
=
100
+
i
;
}
client_id_
=
ClientIdPtr
(
new
ClientId
(
clnt_id
));
return
(
OptionPtr
(
new
Option
(
Option
::
V4
,
DHO_DHCP_CLIENT_IDENTIFIER
,
clnt_id
.
begin
(),
clnt_id
.
begin
()
+
size
)));
}
HWAddrPtr
Dhcpv4SrvTest
::
generateHWAddr
(
size_t
size
/*= 6*/
)
{
const
uint8_t
hw_type
=
123
;
// Just a fake number (typically 6=HTYPE_ETHER, see dhcp4.h)
OptionBuffer
mac
(
size
);
for
(
int
i
=
0
;
i
<
size
;
++
i
)
{
mac
[
i
]
=
50
+
i
;
}
return
(
HWAddrPtr
(
new
HWAddr
(
mac
,
hw_type
)));
}
void
Dhcpv4SrvTest
::
checkAddressParams
(
const
Pkt4Ptr
&
rsp
,
const
SubnetPtr
subnet
,
bool
t1_mandatory
/*= false*/
,
bool
t2_mandatory
/*= false*/
)
{
// Technically inPool implies inRange, but let's be on the safe
// side and check both.
EXPECT_TRUE
(
subnet
->
inRange
(
rsp
->
getYiaddr
()));
EXPECT_TRUE
(
subnet
->
inPool
(
Lease
::
TYPE_V4
,
rsp
->
getYiaddr
()));
// Check lease time
OptionPtr
opt
=
rsp
->
getOption
(
DHO_DHCP_LEASE_TIME
);
if
(
!
opt
)
{
ADD_FAILURE
()
<<
"Lease time option missing in response"
;
}
else
{
EXPECT_EQ
(
opt
->
getUint32
(),
subnet
->
getValid
());
}
// Check T1 timer
opt
=
rsp
->
getOption
(
DHO_DHCP_RENEWAL_TIME
);
if
(
opt
)
{
EXPECT_EQ
(
opt
->
getUint32
(),
subnet
->
getT1
());
}
else
{
if
(
t1_mandatory
)
{
ADD_FAILURE
()
<<
"Required T1 option missing"
;
}
}
// Check T2 timer
opt
=
rsp
->
getOption
(
DHO_DHCP_REBINDING_TIME
);
if
(
opt
)
{
EXPECT_EQ
(
opt
->
getUint32
(),
subnet
->
getT2
());
}
else
{
if
(
t2_mandatory
)
{
ADD_FAILURE
()
<<
"Required T2 option missing"
;
}
}
}
void
Dhcpv4SrvTest
::
checkResponse
(
const
Pkt4Ptr
&
rsp
,
uint8_t
expected_message_type
,
uint32_t
expected_transid
)
{
ASSERT_TRUE
(
rsp
);
EXPECT_EQ
(
expected_message_type
,
rsp
->
getType
());
EXPECT_EQ
(
expected_transid
,
rsp
->
getTransid
());
}
Lease4Ptr
Dhcpv4SrvTest
::
checkLease
(
const
Pkt4Ptr
&
rsp
,
const
OptionPtr
&
client_id
,
const
HWAddrPtr
&
,
const
IOAddress
&
expected_addr
)
{
ClientIdPtr
id
;
if
(
client_id
)
{
OptionBuffer
data
=
client_id
->
getData
();
id
.
reset
(
new
ClientId
(
data
));
}
Lease4Ptr
lease
=
LeaseMgrFactory
::
instance
().
getLease4
(
expected_addr
);
if
(
!
lease
)
{
cout
<<
"Lease for "
<<
expected_addr
.
toText
()
<<
" not found in the database backend."
;
return
(
Lease4Ptr
());
}
EXPECT_EQ
(
rsp
->
getYiaddr
().
toText
(),
expected_addr
.
toText
());
EXPECT_EQ
(
expected_addr
.
toText
(),
lease
->
addr_
.
toText
());
if
(
client_id
)
{
EXPECT_TRUE
(
*
lease
->
client_id_
==
*
id
);
}
EXPECT_EQ
(
subnet_
->
getID
(),
lease
->
subnet_id_
);
return
(
lease
);
}
/// @brief Checks if server response (OFFER, ACK, NAK) includes proper server-id
/// @param rsp response packet to be validated
/// @param expected_srvid expected value of server-id
void
Dhcpv4SrvTest
::
checkServerId
(
const
Pkt4Ptr
&
rsp
,
const
OptionPtr
&
expected_srvid
)
{
// Check that server included its server-id
OptionPtr
opt
=
rsp
->
getOption
(
DHO_DHCP_SERVER_IDENTIFIER
);
ASSERT_TRUE
(
opt
);
EXPECT_EQ
(
opt
->
getType
(),
expected_srvid
->
getType
()
);
EXPECT_EQ
(
opt
->
len
(),
expected_srvid
->
len
()
);
EXPECT_TRUE
(
opt
->
getData
()
==
expected_srvid
->
getData
());
}
void
Dhcpv4SrvTest
::
checkClientId
(
const
Pkt4Ptr
&
rsp
,
const
OptionPtr
&
expected_clientid
)
{
// check that server included our own client-id
OptionPtr
opt
=
rsp
->
getOption
(
DHO_DHCP_CLIENT_IDENTIFIER
);
ASSERT_TRUE
(
opt
);
EXPECT_EQ
(
expected_clientid
->
getType
(),
opt
->
getType
());
EXPECT_EQ
(
expected_clientid
->
len
(),
opt
->
len
());
EXPECT_TRUE
(
expected_clientid
->
getData
()
==
opt
->
getData
());
}
void
Dhcpv4SrvTest
::
testDiscoverRequest
(
const
uint8_t
msg_type
)
{
// Create an instance of the tested class.
boost
::
scoped_ptr
<
NakedDhcpv4Srv
>
srv
(
new
NakedDhcpv4Srv
(
0
));
// Initialize the source HW address.
vector
<
uint8_t
>
mac
(
6
);
for
(
int
i
=
0
;
i
<
6
;
++
i
)
{
mac
[
i
]
=
i
*
10
;
}
// Initialized the destination HW address.
vector
<
uint8_t
>
dst_mac
(
6
);
for
(
int
i
=
0
;
i
<
6
;
++
i
)
{
dst_mac
[
i
]
=
i
*
20
;
}
// Create a DHCP message. It will be used to simulate the
// incoming message.
boost
::
shared_ptr
<
Pkt4
>
req
(
new
Pkt4
(
msg_type
,
1234
));
// Create a response message. It will hold a reponse packet.
// Initially, set it to NULL.
boost
::
shared_ptr
<
Pkt4
>
rsp
;
// Set the name of the interface on which packet is received.
req
->
setIface
(
"eth0"
);
// Set the interface index. It is just a dummy value and will
// not be interpreted.
req
->
setIndex
(
17
);
// Set the target HW address. This value is normally used to
// construct the data link layer header.
req
->
setRemoteHWAddr
(
1
,
6
,
dst_mac
);
// Set the HW address. This value is set on DHCP level (in chaddr).
req
->
setHWAddr
(
1
,
6
,
mac
);
// Set local HW address. It is used to construct the data link layer
// header.
req
->
setLocalHWAddr
(
1
,
6
,
mac
);
// Set target IP address.
req
->
setRemoteAddr
(
IOAddress
(
"192.0.2.55"
));
// Set relay address.
req
->
setGiaddr
(
IOAddress
(
"192.0.2.10"
));
// We are going to test that certain options are returned
// in the response message when requested using 'Parameter
// Request List' option. Let's configure those options that
// are returned when requested.
configureRequestedOptions
();
if
(
msg_type
==
DHCPDISCOVER
)
{
ASSERT_NO_THROW
(
rsp
=
srv
->
processDiscover
(
req
);
);
// Should return OFFER
ASSERT_TRUE
(
rsp
);
EXPECT_EQ
(
DHCPOFFER
,
rsp
->
getType
());
}
else
{
ASSERT_NO_THROW
(
rsp
=
srv
->
processRequest
(
req
););
// Should return ACK
ASSERT_TRUE
(
rsp
);
EXPECT_EQ
(
DHCPACK
,
rsp
->
getType
());
}
messageCheck
(
req
,
rsp
);
// We did not request any options so these should not be present
// in the RSP.
EXPECT_FALSE
(
rsp
->
getOption
(
DHO_LOG_SERVERS
));
EXPECT_FALSE
(
rsp
->
getOption
(
DHO_COOKIE_SERVERS
));
EXPECT_FALSE
(
rsp
->
getOption
(
DHO_LPR_SERVERS
));
// Repeat the test but request some options.
// Add 'Parameter Request List' option.
addPrlOption
(
req
);
if
(
msg_type
==
DHCPDISCOVER
)
{
ASSERT_NO_THROW
(
rsp
=
srv
->
processDiscover
(
req
););
// Should return non-NULL packet.
ASSERT_TRUE
(
rsp
);
EXPECT_EQ
(
DHCPOFFER
,
rsp
->
getType
());
}
else
{
ASSERT_NO_THROW
(
rsp
=
srv
->
processRequest
(
req
););
// Should return non-NULL packet.
ASSERT_TRUE
(
rsp
);
EXPECT_EQ
(
DHCPACK
,
rsp
->
getType
());
}
// Check that the requested options are returned.
optionsCheck
(
rsp
);
}
/// @brief This function cleans up after the test.
void
Dhcpv4SrvTest
::
TearDown
()
{
CfgMgr
::
instance
().
deleteSubnets4
();
// Let's clean up if there is such a file.
unlink
(
SRVID_FILE
);
// Close all open sockets.
IfaceMgr
::
instance
().
closeSockets
();
// Some unit tests override the default packet filtering class, used
// by the IfaceMgr. The dummy class, called PktFilterTest, reports the
// capability to directly respond to the clients without IP address
// assigned. This capability is not supported by the default packet
// filtering class: PktFilterInet. Therefore setting the dummy class
// allows to test scenarios, when server responds to the broadcast address
// on client's request, despite having support for direct response.
// The following call restores the use of original packet filtering class
// after the test.
try
{
IfaceMgr
::
instance
().
setPacketFilter
(
PktFilterPtr
(
new
PktFilterInet
()));
}
catch
(
const
Exception
&
ex
)
{
FAIL
()
<<
"Failed to restore the default (PktFilterInet) packet filtering"
<<
" class after the test. Exception has been caught: "
<<
ex
.
what
();
}
}
};
// end of isc::dhcp::test namespace
};
// end of isc::dhcp namespace
};
// end of isc namespace
src/bin/dhcp4/tests/dhcp4_test_utils.h
0 → 100644
View file @
5eede0e0
// 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.
/// @file dhcp4_test_utils.h
///
/// @brief This file contains utility classes used for DHCPv4 server testing
#ifndef DHCP4_TEST_UTILS_H
#define DHCP4_TEST_UTILS_H
#include <gtest/gtest.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt_filter.h>
#include <dhcp/pkt_filter_inet.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/lease.h>
#include <dhcp4/dhcp4_srv.h>
#include <asiolink/io_address.h>
#include <config/ccsession.h>
#include <list>
namespace
isc
{
namespace
dhcp
{
namespace
test
{
/// @brief Dummy Packet Filtering class.
///
/// This class reports capability to respond directly to the client which
/// doesn't have address configured yet.
///
/// All packet and socket handling functions do nothing because they are not
/// used in unit tests.
class
PktFilterTest
:
public
PktFilter
{
public:
/// @brief Reports 'direct response' capability.
///
/// @return always true.
virtual
bool
isDirectResponseSupported
()
const
{
return
(
true
);
}
/// Does nothing.
virtual
int
openSocket
(
const
Iface
&
,
const
isc
::
asiolink
::
IOAddress
&
,
const
uint16_t
,
const
bool
,
const
bool
)
{
return
(
0
);
}
/// Does nothing.
virtual
Pkt4Ptr
receive
(
const
Iface
&
,
const
SocketInfo
&
)
{
return
Pkt4Ptr
();
}
/// Does nothing.
virtual
int
send
(
const
Iface
&
,
uint16_t
,
const
Pkt4Ptr
&
)
{
return
(
0
);
}
};
class
Dhcpv4SrvTest
:
public
::
testing
::
Test
{
public:
/// @brief Constructor
///
/// Initializes common objects used in many tests.
/// Also sets up initial configuration in CfgMgr.
Dhcpv4SrvTest
();
/// @brief destructor
virtual
~
Dhcpv4SrvTest
()
{
}
/// @brief Add 'Parameter Request List' option to the packet.
///
/// This function adds PRL option comprising the following option codes:
/// - 5 - Name Server
/// - 15 - Domain Name
/// - 7 - Log Server
/// - 8 - Quotes Server
/// - 9 - LPR Server
///
/// @param pkt packet to add PRL option to.
void
addPrlOption
(
Pkt4Ptr
&
pkt
);
/// @brief Configures options being requested in the PRL option.
///
/// The lpr-servers option is NOT configured here although it is
/// added to the 'Parameter Request List' option in the
/// \ref addPrlOption. When requested option is not configured
/// the server should not return it in its response. The goal
/// of not configuring the requested option is to verify that
/// the server will not return it.
void
configureRequestedOptions
();
/// @brief checks that the response matches request
/// @param q query (client's message)
/// @param a answer (server's message)
void
messageCheck
(
const
Pkt4Ptr
&
q
,
const
Pkt4Ptr
&
a
);
/// @brief Check that requested options are present.
///
/// @param pkt packet to be checked.
void
optionsCheck
(
const
Pkt4Ptr
&
pkt
);
/// @brief generates client-id option
///
/// Generate client-id option of specified length
/// Ids with different lengths are sufficent to generate
/// unique ids. If more fine grained control is required,
/// tests generate client-ids on their own.
/// Sets client_id_ field.
/// @param size size of the client-id to be generated
OptionPtr
generateClientId
(
size_t
size
=
4
);
/// @brief generate hardware address
///
/// @param size size of the generated MAC address
/// @param pointer to Hardware Address object
HWAddrPtr
generateHWAddr
(
size_t
size
=
6
);
/// Check that address was returned from proper range, that its lease
/// lifetime is correct, that T1 and T2 are returned properly
/// @param rsp response to be checked
/// @param subnet subnet that should be used to verify assigned address
/// and options
/// @param t1_mandatory is T1 mandatory?
/// @param t2_mandatory is T2 mandatory?
void
checkAddressParams
(
const
Pkt4Ptr
&
rsp
,
const
SubnetPtr
subnet
,
bool
t1_mandatory
=
false
,
bool
t2_mandatory
=
false
);
/// @brief Basic checks for generated response (message type and trans-id).
///
/// @param rsp response packet to be validated
/// @param expected_message_type expected message type
/// @param expected_transid expected transaction-id
void
checkResponse
(
const
Pkt4Ptr
&
rsp
,
uint8_t
expected_message_type
,
uint32_t
expected_transid
);
/// @brief Checks if the lease sent to client is present in the database
///
/// @param rsp response packet to be validated
/// @param client_id expected client-identifier (or NULL)
/// @param HWAddr expected hardware address (not used now)
/// @param expected_addr expected address
Lease4Ptr
checkLease
(
const
Pkt4Ptr
&
rsp
,
const
OptionPtr
&
client_id
,
const
HWAddrPtr
&
,
const
isc
::
asiolink
::
IOAddress
&
expected_addr
);
/// @brief Checks if server response (OFFER, ACK, NAK) includes proper server-id
/// @param rsp response packet to be validated
/// @param expected_srvid expected value of server-id
void
checkServerId
(
const
Pkt4Ptr
&
rsp
,
const
OptionPtr
&
expected_srvid
);
/// @brief Checks if server response (OFFER, ACK, NAK) includes proper client-id
/// @param rsp response packet to be validated
/// @param expected_clientid expected value of client-id
void
checkClientId
(
const
Pkt4Ptr
&
rsp
,
const
OptionPtr
&
expected_clientid
);
/// @brief sets default fields in a captured packet
///