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
Sebastian Schrader
Kea
Commits
77f8577b
Commit
77f8577b
authored
Jul 18, 2014
by
Marcin Siodelski
Browse files
[master] Merge branch 'trac3390'
parents
aec605bd
cc0fc02c
Changes
12
Hide whitespace changes
Inline
Side-by-side
doc/guide/dhcp4-srv.xml
View file @
77f8577b
...
...
@@ -1058,6 +1058,67 @@ temporarily override a list of interface names and listen on all interfaces.
</para>
</section>
<section
id=
"dhcp4-stateless-configuration"
>
<title>
Stateless Configuration of DHCPv4 clients
</title>
<para>
The DHCPv4 server supports the stateless client configuration whereby the
client has an IP address configured (e.g. using manual configuration) and only
contacts the server to obtain other configuration parameters, e.g. DNS servers' addresses.
In order to obtain the stateless configuration parameters the client sends the
DHCPINFORM message to the server with the "ciaddr" set to the address that the
client is currently using. The server unicasts the DHCPACK message to the
client that includes the stateless configuration ("yiaddr" not set).
</para>
<para>
The server will respond to the DHCPINFORM when the client is associated
with the particular subnet defined in the server's configuration. The example
subnet configuration will look like this:
<screen>
"Dhcp4": {
"subnet4": [
{
"subnet": "192.0.2.0/24"
"option-data": [ {"
"name": "domain-name-servers",
"code": 6,
"data": "192.0.2.200,192.0.2.201",
"csv-format": true,
"space": "dhcp4"
} ]
}
]
}
</screen>
</para>
<para>
This subnet specifies the single option which will be included in
the DHCPACK message to the client in response to DHCPINFORM. Note that
the subnet definition does not require the address pool configuration
if it will be used solely for the stateless configuration.
</para>
<para>
This server will associate the subnet with the client if one of
the following conditions is met:
<itemizedlist>
<listitem>
<simpara>
The DHCPINFORM is relayed and the giaddr matches the
configured subnet.
</simpara>
</listitem>
<listitem>
<simpara>
The DHCPINFORM is unicast from the client and the ciaddr
matches the configured subnet.
</simpara>
</listitem>
<listitem>
<simpara>
The DHCPINFORM is unicast from the client, the ciaddr is
not set but the source address of the IP packet matches the
configured subnet.
</simpara>
</listitem>
<listitem>
<simpara>
The DHCPINFORM is not relayed and the IP address on the
interface on which the message is received matches the configured
subnet.
</simpara>
</listitem>
</itemizedlist>
</para>
</section>
<section
id=
"dhcp4-client-classifier"
>
<title>
Client Classification in DHCPv4
</title>
<note>
...
...
@@ -1699,8 +1760,8 @@ temporarily override a list of interface names and listen on all interfaces.
<para>
The following standards and draft standards are currently supported:
</para>
<itemizedlist>
<listitem>
<simpara><ulink
url=
"http://tools.ietf.org/html/rfc2131"
>
RFC 2131
</ulink>
: Supported messages are DISCOVER, OFFER,
REQUEST, RELEASE, ACK, and NAK.
</simpara>
<simpara><ulink
url=
"http://tools.ietf.org/html/rfc2131"
>
RFC 2131
</ulink>
: Supported messages are DISCOVER
(1)
, OFFER
(2)
,
REQUEST
(3)
, RELEASE
(7), INFORM (8)
, ACK
(5)
, and NAK
(6)
.
</simpara>
</listitem>
<listitem>
<simpara><ulink
url=
"http://tools.ietf.org/html/rfc2132"
>
RFC 2132
</ulink>
:
...
...
src/bin/dhcp4/dhcp4_srv.cc
View file @
77f8577b
...
...
@@ -299,7 +299,7 @@ Dhcpv4Srv::run() {
break
;
case
DHCPINFORM
:
processInform
(
query
);
rsp
=
processInform
(
query
);
break
;
default:
...
...
@@ -1133,8 +1133,48 @@ Dhcpv4Srv::adjustRemoteAddr(const Pkt4Ptr& question, const Pkt4Ptr& response) {
static
const
IOAddress
zero_addr
(
"0.0.0.0"
);
static
const
IOAddress
bcast_addr
(
"255.255.255.255"
);
// The DHCPINFORM is slightly different than other messages in a sense
// that the server should always unicast the response to the ciaddr.
// It appears however that some clients don't set the ciaddr. We still
// want to provision these clients and we do what we can't to send the
// packet to the address where client can receive it.
if
(
question
->
getType
()
==
DHCPINFORM
)
{
// If client adheres to RFC2131 it will set the ciaddr and in this
// case we always unicast our response to this address.
if
(
question
->
getCiaddr
()
!=
zero_addr
)
{
response
->
setRemoteAddr
(
question
->
getCiaddr
());
// If we received DHCPINFOM via relay and the ciaddr is not set we
// will try to send the response via relay. The caveat is that the
// relay will not have any idea where to forward the packet because
// the yiaddr is likely not set. So, the broadcast flag is set so
// as the response may be broadcast.
}
else
if
(
question
->
isRelayed
())
{
response
->
setRemoteAddr
(
question
->
getGiaddr
());
response
->
setFlags
(
response
->
getFlags
()
|
BOOTP_BROADCAST
);
// If there is no ciaddr and no giaddr the only thing we can do is
// to use the source address of the packet.
}
else
{
response
->
setRemoteAddr
(
question
->
getRemoteAddr
());
}
// Remote addres is now set so return.
return
;
}
// If received relayed message, server responds to the relay address.
if
(
question
->
isRelayed
())
{
// The client should set the ciaddr when sending the DHCPINFORM
// but in case he didn't, the relay may not be able to determine the
// address of the client, because yiaddr is not set when responding
// to Confirm and the only address available was the source address
// of the client. The source address is however not used here because
// the message is relayed. Therefore, we set the BROADCAST flag so
// as the relay can broadcast the packet.
if
((
question
->
getType
()
==
DHCPINFORM
)
&&
(
question
->
getCiaddr
()
==
zero_addr
))
{
response
->
setFlags
(
BOOTP_BROADCAST
);
}
response
->
setRemoteAddr
(
question
->
getGiaddr
());
// If giaddr is 0 but client set ciaddr, server should unicast the
...
...
@@ -1385,9 +1425,30 @@ Dhcpv4Srv::processDecline(Pkt4Ptr& /* decline */) {
Pkt4Ptr
Dhcpv4Srv
::
processInform
(
Pkt4Ptr
&
inform
)
{
/// @todo Implement this for real. (also see ticket #3116)
return
(
inform
);
// DHCPINFORM MUST not include server identifier.
sanityCheck
(
inform
,
FORBIDDEN
);
Pkt4Ptr
ack
=
Pkt4Ptr
(
new
Pkt4
(
DHCPACK
,
inform
->
getTransid
()));
copyDefaultFields
(
inform
,
ack
);
appendRequestedOptions
(
inform
,
ack
);
appendRequestedVendorOptions
(
inform
,
ack
);
appendBasicOptions
(
inform
,
ack
);
adjustIfaceData
(
inform
,
ack
);
// There are cases for the DHCPINFORM that the server receives it via
// relay but will send the response to the client's unicast address
// carried in the ciaddr. In this case, the giaddr and hops field should
// be cleared (these fields were copied by the copyDefaultFields function).
// Also Relay Agent Options should be removed if present.
if
(
ack
->
getRemoteAddr
()
!=
inform
->
getGiaddr
())
{
ack
->
setHops
(
0
);
ack
->
setGiaddr
(
IOAddress
(
"0.0.0.0"
));
ack
->
delOption
(
DHO_DHCP_AGENT_OPTIONS
);
}
// The DHCPACK must contain server id.
appendServerID
(
ack
);
return
(
ack
);
}
const
char
*
...
...
@@ -1449,6 +1510,15 @@ Dhcpv4Srv::selectSubnet(const Pkt4Ptr& question) const {
subnet
=
CfgMgr
::
instance
().
getSubnet4
(
question
->
getCiaddr
(),
question
->
classes_
);
// Either renewing client or the client that sends DHCPINFORM
// must set the ciaddr. But apparently some clients don't do it,
// so if the client didn't include ciaddr we will use the source
// address.
}
else
if
((
question
->
getLocalAddr
()
!=
bcast
)
&&
(
question
->
getRemoteAddr
()
!=
notset
))
{
subnet
=
CfgMgr
::
instance
().
getSubnet4
(
question
->
getRemoteAddr
(),
question
->
classes_
);
// The message has been received from a directly connected client
// and this client appears to have no address. The IPv4 address
// assigned to the interface on which this message has been received,
...
...
@@ -1493,6 +1563,11 @@ Dhcpv4Srv::selectSubnet(const Pkt4Ptr& question) const {
bool
Dhcpv4Srv
::
accept
(
const
Pkt4Ptr
&
query
)
const
{
// Check that the message type is accepted by the server. We rely on the
// function called to log a message if needed.
if
(
!
acceptMessageType
(
query
))
{
return
(
false
);
}
// Check if the message from directly connected client (if directly
// connected) should be dropped or processed.
if
(
!
acceptDirectRequest
(
query
))
{
...
...
@@ -1511,12 +1586,6 @@ Dhcpv4Srv::accept(const Pkt4Ptr& query) const {
return
(
false
);
}
// Check that the message type is accepted by the server. We rely on the
// function called to log a message if needed.
if
(
!
acceptMessageType
(
query
))
{
return
(
false
);
}
return
(
true
);
}
...
...
@@ -1529,6 +1598,23 @@ Dhcpv4Srv::acceptDirectRequest(const Pkt4Ptr& pkt) const {
}
catch
(
const
Exception
&
ex
)
{
return
(
false
);
}
// The source address must not be zero for the DHCPINFORM message from
// the directly connected client because the server will not know where
// to respond if the ciaddr was not present.
static
const
IOAddress
zero_addr
(
"0.0.0.0"
);
try
{
if
(
pkt
->
getType
()
==
DHCPINFORM
)
{
if
((
pkt
->
getRemoteAddr
()
==
zero_addr
)
&&
(
pkt
->
getCiaddr
()
==
zero_addr
))
{
return
(
false
);
}
}
}
catch
(...)
{
// If we got here, it is probably because the message type hasn't
// been set. But, this should not really happen assuming that
// we validate the message type prior to calling this function.
return
(
false
);
}
static
const
IOAddress
bcast
(
"255.255.255.255"
);
return
((
pkt
->
getLocalAddr
()
!=
bcast
||
selectSubnet
(
pkt
)));
}
...
...
src/bin/dhcp4/dhcp4_srv.h
View file @
77f8577b
...
...
@@ -239,8 +239,9 @@ protected:
/// This function accepts the following messages:
/// - all valid relayed messages,
/// - all unicast messages,
/// - all broadcast messages received on the interface for which the
/// suitable subnet exists (is configured).
/// - all broadcast messages except DHCPINFORM received on the interface
/// for which the suitable subnet exists (is configured).
/// - all DHCPINFORM messages with source address or ciaddr set.
///
/// @param query Message sent by a client.
///
...
...
src/bin/dhcp4/tests/Makefile.am
View file @
77f8577b
...
...
@@ -88,6 +88,8 @@ dhcp4_unittests_SOURCES += ctrl_dhcp4_srv_unittest.cc
dhcp4_unittests_SOURCES
+=
config_parser_unittest.cc
dhcp4_unittests_SOURCES
+=
fqdn_unittest.cc
dhcp4_unittests_SOURCES
+=
marker_file.cc
dhcp4_unittests_SOURCES
+=
dhcp4_client.cc dhcp4_client.h
dhcp4_unittests_SOURCES
+=
inform_unittest.cc
if
CONFIG_BACKEND_BUNDY
# For Bundy backend, we only need to run the usual tests. There are no
...
...
src/bin/dhcp4/tests/dhcp4_client.cc
0 → 100644
View file @
77f8577b
// 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
<dhcp/dhcp4.h>
#include
<dhcp/option.h>
#include
<dhcp/option_int_array.h>
#include
<dhcpsrv/lease.h>
#include
<dhcp4/tests/dhcp4_client.h>
#include
<util/range_utilities.h>
#include
<boost/pointer_cast.hpp>
#include
<cstdlib>
namespace
isc
{
namespace
dhcp
{
namespace
test
{
Dhcp4Client
::
Configuration
::
Configuration
()
:
routers_
(),
dns_servers_
(),
log_servers_
(),
quotes_servers_
(),
serverid_
(
"0.0.0.0"
)
{
reset
();
}
void
Dhcp4Client
::
Configuration
::
reset
()
{
routers_
.
clear
();
dns_servers_
.
clear
();
log_servers_
.
clear
();
quotes_servers_
.
clear
();
serverid_
=
asiolink
::
IOAddress
(
"0.0.0.0"
);
}
Dhcp4Client
::
Dhcp4Client
()
:
config_
(),
curr_transid_
(
0
),
dest_addr_
(
"255.255.255.255"
),
hwaddr_
(
generateHWAddr
()),
relay_addr_
(
"192.0.2.2"
),
requested_options_
(),
server_facing_relay_addr_
(
"10.0.0.2"
),
srv_
(
boost
::
shared_ptr
<
NakedDhcpv4Srv
>
(
new
NakedDhcpv4Srv
(
0
))),
use_relay_
(
false
)
{
}
Dhcp4Client
::
Dhcp4Client
(
boost
::
shared_ptr
<
NakedDhcpv4Srv
>&
srv
)
:
config_
(),
curr_transid_
(
0
),
dest_addr_
(
"255.255.255.255"
),
hwaddr_
(
generateHWAddr
()),
relay_addr_
(
"192.0.2.2"
),
requested_options_
(),
server_facing_relay_addr_
(
"10.0.0.2"
),
srv_
(
srv
),
use_relay_
(
false
)
{
}
void
Dhcp4Client
::
applyConfiguration
()
{
Pkt4Ptr
resp
=
context_
.
response_
;
if
(
!
resp
)
{
return
;
}
config_
.
reset
();
// Routers
Option4AddrLstPtr
opt_routers
=
boost
::
dynamic_pointer_cast
<
Option4AddrLst
>
(
resp
->
getOption
(
DHO_ROUTERS
));
if
(
opt_routers
)
{
config_
.
routers_
=
opt_routers
->
getAddresses
();
}
// DNS Servers
Option4AddrLstPtr
opt_dns_servers
=
boost
::
dynamic_pointer_cast
<
Option4AddrLst
>
(
resp
->
getOption
(
DHO_DOMAIN_NAME_SERVERS
));
if
(
opt_dns_servers
)
{
config_
.
dns_servers_
=
opt_dns_servers
->
getAddresses
();
}
// Log Servers
Option4AddrLstPtr
opt_log_servers
=
boost
::
dynamic_pointer_cast
<
Option4AddrLst
>
(
resp
->
getOption
(
DHO_LOG_SERVERS
));
if
(
opt_log_servers
)
{
config_
.
log_servers_
=
opt_routers
->
getAddresses
();
}
// Quotes Servers
Option4AddrLstPtr
opt_quotes_servers
=
boost
::
dynamic_pointer_cast
<
Option4AddrLst
>
(
resp
->
getOption
(
DHO_COOKIE_SERVERS
));
if
(
opt_quotes_servers
)
{
config_
.
quotes_servers_
=
opt_dns_servers
->
getAddresses
();
}
// Server Identifier
OptionCustomPtr
opt_serverid
=
boost
::
dynamic_pointer_cast
<
OptionCustom
>
(
resp
->
getOption
(
DHO_DHCP_SERVER_IDENTIFIER
));
if
(
opt_serverid
)
{
config_
.
serverid_
=
opt_serverid
->
readAddress
();
}
/// @todo Other possible configuration, e.g. lease.
}
void
Dhcp4Client
::
createLease
(
const
asiolink
::
IOAddress
&
addr
,
const
uint32_t
valid_lft
)
{
Lease4
lease
(
addr
,
&
hwaddr_
->
hwaddr_
[
0
],
hwaddr_
->
hwaddr_
.
size
(),
0
,
0
,
valid_lft
,
valid_lft
/
2
,
valid_lft
,
time
(
NULL
),
false
,
false
,
""
);
config_
.
lease_
=
lease
;
}
Pkt4Ptr
Dhcp4Client
::
createMsg
(
const
uint8_t
msg_type
)
{
Pkt4Ptr
msg
(
new
Pkt4
(
msg_type
,
curr_transid_
++
));
msg
->
setHWAddr
(
hwaddr_
);
return
(
msg
);
}
void
Dhcp4Client
::
doInform
(
const
bool
set_ciaddr
)
{
context_
.
query_
=
createMsg
(
DHCPINFORM
);
// Request options if any.
if
(
!
requested_options_
.
empty
())
{
// Include Parameter Request List if at least one option code
// has been specified to be requested.
OptionUint8ArrayPtr
prl
(
new
OptionUint8Array
(
Option
::
V4
,
DHO_DHCP_PARAMETER_REQUEST_LIST
));
for
(
std
::
set
<
uint8_t
>::
const_iterator
opt
=
requested_options_
.
begin
();
opt
!=
requested_options_
.
end
();
++
opt
)
{
prl
->
addValue
(
*
opt
);
}
context_
.
query_
->
addOption
(
prl
);
}
// The client sending a DHCPINFORM message has an IP address obtained
// by some other means, e.g. static configuration. The lease which we
// are using here is most likely set by the createLease method.
if
(
set_ciaddr
)
{
context_
.
query_
->
setCiaddr
(
config_
.
lease_
.
addr_
);
}
context_
.
query_
->
setLocalAddr
(
config_
.
lease_
.
addr_
);
// Send the message to the server.
sendMsg
(
context_
.
query_
);
// Expect response. If there is no response, return.
context_
.
response_
=
receiveOneMsg
();
if
(
!
context_
.
response_
)
{
return
;
}
// If DHCPACK has been returned by the server, use the returned
// configuration.
if
(
context_
.
response_
->
getType
()
==
DHCPACK
)
{
applyConfiguration
();
}
}
HWAddrPtr
Dhcp4Client
::
generateHWAddr
(
const
uint8_t
htype
)
const
{
if
(
htype
!=
HTYPE_ETHER
)
{
isc_throw
(
isc
::
NotImplemented
,
"The harware address type "
<<
static_cast
<
int
>
(
htype
)
<<
" is currently not supported"
);
}
std
::
vector
<
uint8_t
>
hwaddr
(
HWAddr
::
ETHERNET_HWADDR_LEN
);
// Generate ethernet hardware address by assigning random byte values.
isc
::
util
::
fillRandom
(
hwaddr
.
begin
(),
hwaddr
.
end
());
return
(
HWAddrPtr
(
new
HWAddr
(
hwaddr
,
htype
)));
}
void
Dhcp4Client
::
modifyHWAddr
()
{
if
(
!
hwaddr_
)
{
hwaddr_
=
generateHWAddr
();
return
;
}
// Modify the HW address by adding 1 to its last byte.
++
hwaddr_
->
hwaddr_
[
hwaddr_
->
hwaddr_
.
size
()
-
1
];
}
void
Dhcp4Client
::
requestOption
(
const
uint8_t
option
)
{
if
(
option
!=
0
)
{
requested_options_
.
insert
(
option
);
}
}
void
Dhcp4Client
::
requestOptions
(
const
uint8_t
option1
,
const
uint8_t
option2
,
const
uint8_t
option3
)
{
requested_options_
.
clear
();
requestOption
(
option1
);
requestOption
(
option2
);
requestOption
(
option3
);
}
Pkt4Ptr
Dhcp4Client
::
receiveOneMsg
()
{
// Return empty pointer if server hasn't responded.
if
(
srv_
->
fake_sent_
.
empty
())
{
return
(
Pkt4Ptr
());
}
Pkt4Ptr
msg
=
srv_
->
fake_sent_
.
front
();
srv_
->
fake_sent_
.
pop_front
();
// Copy the original message to simulate reception over the wire.
msg
->
pack
();
Pkt4Ptr
msg_copy
(
new
Pkt4
(
static_cast
<
const
uint8_t
*>
(
msg
->
getBuffer
().
getData
()),
msg
->
getBuffer
().
getLength
()));
msg_copy
->
setRemoteAddr
(
msg
->
getLocalAddr
());
msg_copy
->
setLocalAddr
(
msg
->
getRemoteAddr
());
msg_copy
->
setIface
(
msg
->
getIface
());
msg_copy
->
unpack
();
return
(
msg_copy
);
}
void
Dhcp4Client
::
sendMsg
(
const
Pkt4Ptr
&
msg
)
{
srv_
->
shutdown_
=
false
;
if
(
use_relay_
)
{
msg
->
setHops
(
1
);
msg
->
setGiaddr
(
relay_addr_
);
msg
->
setLocalAddr
(
server_facing_relay_addr_
);
}
// Repack the message to simulate wire-data parsing.
msg
->
pack
();
Pkt4Ptr
msg_copy
(
new
Pkt4
(
static_cast
<
const
uint8_t
*>
(
msg
->
getBuffer
().
getData
()),
msg
->
getBuffer
().
getLength
()));
msg_copy
->
setRemoteAddr
(
msg
->
getLocalAddr
());
msg_copy
->
setLocalAddr
(
dest_addr_
);
msg_copy
->
setIface
(
"eth0"
);
srv_
->
fakeReceive
(
msg_copy
);
srv_
->
run
();
}
}
// end of namespace isc::dhcp::test
}
// end of namespace isc::dhcp
}
// end of namespace isc
src/bin/dhcp4/tests/dhcp4_client.h
0 → 100644
View file @
77f8577b
// 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 DHCP4_CLIENT_H
#define DHCP4_CLIENT_H
#include
<asiolink/io_address.h>
#include
<dhcp/hwaddr.h>
#include
<dhcp/pkt4.h>
#include
<dhcp4/tests/dhcp4_test_utils.h>
#include
<boost/noncopyable.hpp>
#include
<boost/shared_ptr.hpp>
#include
<set>
namespace
isc
{
namespace
dhcp
{
namespace
test
{
/// @brief DHCPv4 client used for unit testing.
///
/// This class implements a DHCPv4 "client" which interoperates with the
/// @c NakedDhcpv4Srv class. It calls @c NakedDhcpv4Srv::fakeReceive to
/// deliver client messages to the server for processing. The server places
/// the response in the @c NakedDhcpv4Srv::fake_sent_ container. The client
/// pops messages from this container which simulates reception of the
/// response from the server.
///
/// The client maintains the leases it acquired from the server.
///
/// The client exposes a set of functions which simulate different exchange
/// types between the client and the server. It also provides the access to
/// the objects encapsulating responses from the server so as it is possible
/// to verify from the unit test that the server's response is correct.
class
Dhcp4Client
:
public
boost
::
noncopyable
{
public:
/// @brief Holds the DHCPv4 messages taking part in transaction between
/// the client and the server.
struct
Context
{
/// @brief Holds the last sent message from the client to the server.
Pkt4Ptr
query_
;
/// @brief Holds the last sent message by the server to the client.
Pkt4Ptr
response_
;
};
/// @brief Holds the configuration of the client received from the
/// DHCP server.
struct
Configuration
{
/// @brief Holds IP addresses received in the Routers option.
Option4AddrLst
::
AddressContainer
routers_
;
/// @brief Holds IP addresses received in the DNS Servers option.
Option4AddrLst
::
AddressContainer
dns_servers_
;
/// @brief Holds IP addresses received in the Log Servers option.
Option4AddrLst
::
AddressContainer
log_servers_
;
/// @brief Holds IP addresses received in the Quotes Servers option.
Option4AddrLst
::
AddressContainer
quotes_servers_
;
/// @brief Holds a lease obtained by the client.
Lease4
lease_
;
/// @brief Holds server id of the server which responded to the client's
/// request.
asiolink
::
IOAddress
serverid_
;
/// @brief Constructor.
Configuration
();
/// @brief Sets configuration values to defaults.
void
reset
();
};
/// @brief Creates a new client.
Dhcp4Client
();
/// @brief Creates a new client that communicates with a specified server.
///
/// @param srv An instance of the DHCPv4 server to be used.
Dhcp4Client
(
boost
::
shared_ptr
<
NakedDhcpv4Srv
>&
srv
);
/// @brief Creates a lease for the client using the specified address
/// and valid lifetime.
///
/// This method creates the lease using the specified address and
/// valid lease lifetime. The client will use this lease in any
/// future communication with the DHCP server. One of the use cases
/// for this method is to pre-configure the client with the explicitly
/// given address before it sends the DHCPINFORM to the DHCP server.
/// The client will inject the leased address into the ciaddr field
/// of the DHCPINFORM message.
///
/// @param addr Lease address.
/// @param valid_lft Valid lifetime.
void
createLease
(
const
asiolink
::
IOAddress
&
addr
,
const
uint32_t
valid_lft
);
/// @brief Sends DHCPINFORM message to the server and receives response.
///
/// This function simulates sending the DHCPINFORM message to the server
/// and receiving server's response (if any). The server's response and the
/// message sent to the server is stored in the context structure and can
/// be accessed using @c getContext function.
///
/// The configuration returned by the server is stored in the
/// @c config_ public member and can be accessed directly.
///
/// @param set_ciaddr Indicates if the ciaddr should be set for an