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
6364a03c
Commit
6364a03c
authored
Mar 10, 2015
by
Marcin Siodelski
Browse files
[3688] DHCPv4 server assignes reserved hostname to the clients.
parent
ac390543
Changes
8
Hide whitespace changes
Inline
Side-by-side
src/bin/dhcp4/dhcp4_srv.cc
View file @
6364a03c
...
...
@@ -43,6 +43,7 @@
#include
<asio.hpp>
#include
<boost/bind.hpp>
#include
<boost/foreach.hpp>
#include
<boost/shared_ptr.hpp>
#include
<iomanip>
...
...
@@ -80,6 +81,152 @@ struct Dhcp4Hooks {
// module is called.
Dhcp4Hooks
Hooks
;
namespace
{
/// @brief DHCPv4 message exchange.
///
/// This class represents the DHCPv4 message exchange. The message exchange
/// consists of the single client message, server response to this message
/// and the mechanisms to generate the server's response. The server creates
/// the instance of the @c DHCPv4Exchange for each inbound message that it
/// accepts for processing.
///
/// The use of the @c DHCPv4Exchange object as a central repository of
/// information about the message exchange simplifies the API of the
/// @c Dhcpv4Srv class.
///
/// Another benefit of using this class is that different methods of the
/// @c Dhcpv4Srv may share information. For example, the constructor of this
/// class selects the subnet and multiple methods of @c Dhcpv4Srv use this
/// subnet, without the need to select it again.
///
/// @todo This is the initial version of this class. In the future a lot of
/// code from the @c Dhcpv4Srv class will be migrated here.
class
DHCPv4Exchange
{
public:
/// @brief Constructor.
///
/// The constructor selects the subnet for the query and checks for the
/// static host reservations for the client which has sent the message.
/// The information about the reservations is stored in the
/// @c AllocEngine::ClientContext4 object, which can be obtained by
/// calling the @c getContext.
///
/// @param alloc_engine Pointer to the instance of the Allocation Engine
/// used by the server.
/// @param query Pointer to the client message.
DHCPv4Exchange
(
const
AllocEnginePtr
&
alloc_engine
,
const
Pkt4Ptr
&
query
);
/// @brief Selects the subnet for the message processing.
///
/// The pointer to the selected subnet is stored in the @c ClientContext4
/// structure.
void
selectSubnet
();
/// @brief Selects the subnet for the message processing.
///
/// @todo This variant of the @c selectSubnet method is static and public so
/// as it may be invoked by the @c Dhcpv4Srv object. This is temporary solution
/// and the function will go away once the server code fully supports the use
/// of this class and it obtains the subnet from the context returned by the
/// @c getContext method.
///
/// @param query Pointer to the client's message.
/// @return Pointer to the selected subnet or NULL if no suitable subnet
/// has been found.
static
Subnet4Ptr
selectSubnet
(
const
Pkt4Ptr
&
query
);
/// @brief Returns the copy of the context for the Allocation engine.
AllocEngine
::
ClientContext4
getContext
()
const
{
return
(
context_
);
}
private:
/// @brief Pointer to the allocation engine used by the server.
AllocEnginePtr
alloc_engine_
;
/// @brief Pointer to the DHCPv4 message sent by the client.
Pkt4Ptr
query_
;
/// @brief Context for use with allocation engine.
AllocEngine
::
ClientContext4
context_
;
};
/// @brief Type representing the pointer to the @c DHCPv4Exchange.
typedef
boost
::
shared_ptr
<
DHCPv4Exchange
>
DHCPv4ExchangePtr
;
DHCPv4Exchange
::
DHCPv4Exchange
(
const
AllocEnginePtr
&
alloc_engine
,
const
Pkt4Ptr
&
query
)
:
alloc_engine_
(
alloc_engine
),
query_
(
query
),
context_
()
{
selectSubnet
();
// Hardware address.
context_
.
hwaddr_
=
query
->
getHWAddr
();
// Client Identifier
OptionPtr
opt_clientid
=
query
->
getOption
(
DHO_DHCP_CLIENT_IDENTIFIER
);
if
(
opt_clientid
)
{
context_
.
clientid_
.
reset
(
new
ClientId
(
opt_clientid
->
getData
()));
}
// Check for static reservations.
alloc_engine
->
findReservation
(
context_
);
};
void
DHCPv4Exchange
::
selectSubnet
()
{
context_
.
subnet_
=
selectSubnet
(
query_
);
}
Subnet4Ptr
DHCPv4Exchange
::
selectSubnet
(
const
Pkt4Ptr
&
query
)
{
Subnet4Ptr
subnet
;
SubnetSelector
selector
;
selector
.
ciaddr_
=
query
->
getCiaddr
();
selector
.
giaddr_
=
query
->
getGiaddr
();
selector
.
local_address_
=
query
->
getLocalAddr
();
selector
.
remote_address_
=
query
->
getRemoteAddr
();
selector
.
client_classes_
=
query
->
classes_
;
selector
.
iface_name_
=
query
->
getIface
();
CfgMgr
&
cfgmgr
=
CfgMgr
::
instance
();
subnet
=
cfgmgr
.
getCurrentCfg
()
->
getCfgSubnets4
()
->
selectSubnet
(
selector
);
// Let's execute all callouts registered for subnet4_select
if
(
HooksManager
::
calloutsPresent
(
Hooks
.
hook_index_subnet4_select_
))
{
CalloutHandlePtr
callout_handle
=
getCalloutHandle
(
query
);
// We're reusing callout_handle from previous calls
callout_handle
->
deleteAllArguments
();
// Set new arguments
callout_handle
->
setArgument
(
"query4"
,
query
);
callout_handle
->
setArgument
(
"subnet4"
,
subnet
);
callout_handle
->
setArgument
(
"subnet4collection"
,
cfgmgr
.
getCurrentCfg
()
->
getCfgSubnets4
()
->
getAll
());
// Call user (and server-side) callouts
HooksManager
::
callCallouts
(
Hooks
.
hook_index_subnet4_select_
,
*
callout_handle
);
// Callouts decided to skip this step. This means that no subnet
// will be selected. Packet processing will continue, but it will
// be severely limited (i.e. only global options will be assigned)
if
(
callout_handle
->
getSkip
())
{
LOG_DEBUG
(
dhcp4_logger
,
DBG_DHCP4_HOOKS
,
DHCP4_HOOK_SUBNET4_SELECT_SKIP
);
return
(
Subnet4Ptr
());
}
// Use whatever subnet was specified by the callout
callout_handle
->
getArgument
(
"subnet4"
,
subnet
);
}
return
(
subnet
);
}
DHCPv4ExchangePtr
exchange
;
};
namespace
isc
{
namespace
dhcp
{
...
...
@@ -137,6 +284,11 @@ Dhcpv4Srv::shutdown() {
shutdown_
=
true
;
}
isc
::
dhcp
::
Subnet4Ptr
Dhcpv4Srv
::
selectSubnet
(
const
Pkt4Ptr
&
question
)
{
return
(
DHCPv4Exchange
::
selectSubnet
(
question
));
}
Pkt4Ptr
Dhcpv4Srv
::
receivePacket
(
int
timeout
)
{
return
(
IfaceMgr
::
instance
().
receive4
(
timeout
));
...
...
@@ -150,6 +302,9 @@ Dhcpv4Srv::sendPacket(const Pkt4Ptr& packet) {
bool
Dhcpv4Srv
::
run
()
{
while
(
!
shutdown_
)
{
// Reset pointer to the current exchange.
exchange
.
reset
();
// client's message and server's response
Pkt4Ptr
query
;
Pkt4Ptr
rsp
;
...
...
@@ -592,7 +747,7 @@ Dhcpv4Srv::appendRequestedOptions(const Pkt4Ptr& question, Pkt4Ptr& msg) {
// Get the subnet relevant for the client. We will need it
// to get the options associated with it.
Subnet4Ptr
subnet
=
selectSubnet
(
question
);
Subnet4Ptr
subnet
=
DHCPv4Exchange
::
selectSubnet
(
question
);
// If we can't find the subnet for the client there is no way
// to get the options to be sent to a client. We don't log an
// error because it will be logged by the assignLease method
...
...
@@ -629,7 +784,7 @@ Dhcpv4Srv::appendRequestedOptions(const Pkt4Ptr& question, Pkt4Ptr& msg) {
void
Dhcpv4Srv
::
appendRequestedVendorOptions
(
const
Pkt4Ptr
&
question
,
Pkt4Ptr
&
answer
)
{
// Get the configured subnet suitable for the incoming packet.
Subnet4Ptr
subnet
=
selectSubnet
(
question
);
Subnet4Ptr
subnet
=
DHCPv4Exchange
::
selectSubnet
(
question
);
// Leave if there is no subnet matching the incoming packet.
// There is no need to log the error message here because
// it will be logged in the assignLease() when it fails to
...
...
@@ -696,7 +851,7 @@ Dhcpv4Srv::appendBasicOptions(const Pkt4Ptr& question, Pkt4Ptr& msg) {
sizeof
(
required_options
)
/
sizeof
(
required_options
[
0
]);
// Get the subnet.
Subnet4Ptr
subnet
=
selectSubnet
(
question
);
Subnet4Ptr
subnet
=
DHCPv4Exchange
::
selectSubnet
(
question
);
if
(
!
subnet
)
{
return
;
}
...
...
@@ -764,10 +919,16 @@ Dhcpv4Srv::processClientFqdnOption(const Option4ClientFqdnPtr& fqdn,
fqdn_resp
->
setFlag
(
Option4ClientFqdn
::
FLAG_E
,
fqdn
->
getFlag
(
Option4ClientFqdn
::
FLAG_E
));
if
(
exchange
&&
exchange
->
getContext
().
host_
&&
!
exchange
->
getContext
().
host_
->
getHostname
().
empty
())
{
fqdn_resp
->
setDomainName
(
exchange
->
getContext
().
host_
->
getHostname
(),
Option4ClientFqdn
::
FULL
);
// Adjust the domain name based on domain name value and type sent by the
// client and current configuration.
d2_mgr
.
adjustDomainName
<
Option4ClientFqdn
>
(
*
fqdn
,
*
fqdn_resp
);
}
else
{
// Adjust the domain name based on domain name value and type sent by the
// client and current configuration.
d2_mgr
.
adjustDomainName
<
Option4ClientFqdn
>
(
*
fqdn
,
*
fqdn_resp
);
}
// Add FQDN option to the response message. Note that, there may be some
// cases when server may choose not to include the FQDN option in a
...
...
@@ -818,17 +979,23 @@ Dhcpv4Srv::processHostnameOption(const OptionStringPtr& opt_hostname,
// By checking the number of labels present in the hostname we may infer
// whether client has sent the fully qualified or unqualified hostname.
/// @todo We may want to reconsider whether it is appropriate for the
/// client to send a root domain name as a Hostname. There are
/// also extensions to the auto generation of the client's name,
/// e.g. conversion to the puny code which may be considered at some point.
/// For now, we just remain liberal and expect that the DNS will handle
/// conversion if needed and possible.
if
((
d2_mgr
.
getD2ClientConfig
()
->
getReplaceClientName
())
||
(
label_count
<
2
))
{
// If there is a hostname reservation for this client, use it.
if
(
exchange
&&
exchange
->
getContext
().
host_
&&
!
exchange
->
getContext
().
host_
->
getHostname
().
empty
())
{
opt_hostname_resp
->
setValue
(
exchange
->
getContext
().
host_
->
getHostname
());
}
else
if
((
d2_mgr
.
getD2ClientConfig
()
->
getReplaceClientName
())
||
(
label_count
<
2
))
{
// Set to root domain to signal later on that we should replace it.
// DHO_HOST_NAME is a string option which cannot be empty.
/// @todo We may want to reconsider whether it is appropriate for the
/// client to send a root domain name as a Hostname. There are
/// also extensions to the auto generation of the client's name,
/// e.g. conversion to the puny code which may be considered at some point.
/// For now, we just remain liberal and expect that the DNS will handle
/// conversion if needed and possible.
opt_hostname_resp
->
setValue
(
"."
);
}
else
if
(
label_count
==
2
)
{
// If there are two labels, it means that the client has specified
// the unqualified name. We have to concatenate the unqualified name
...
...
@@ -933,7 +1100,7 @@ void
Dhcpv4Srv
::
assignLease
(
const
Pkt4Ptr
&
question
,
Pkt4Ptr
&
answer
)
{
// We need to select a subnet the client is connected in.
Subnet4Ptr
subnet
=
selectSubnet
(
question
);
Subnet4Ptr
subnet
=
DHCPv4Exchange
::
selectSubnet
(
question
);
if
(
!
subnet
)
{
// This particular client is out of luck today. We do not have
// information about the subnet he is connected to. This likely means
...
...
@@ -1072,13 +1239,18 @@ Dhcpv4Srv::assignLease(const Pkt4Ptr& question, Pkt4Ptr& answer) {
}
}
// Use allocation engine to pick a lease for this client. Allocation engine
// will try to honour the hint, but it is just a hint - some other address
// may be used instead. If fake_allocation is set to false, the lease will
// be inserted into the LeaseMgr as well.
/// @todo pass the actual FQDN data.
AllocEngine
::
ClientContext4
ctx
(
subnet
,
client_id
,
hwaddr
,
hint
,
fqdn_fwd
,
fqdn_rev
,
hostname
,
fake_allocation
);
AllocEngine
::
ClientContext4
ctx
;
if
(
exchange
)
{
ctx
=
exchange
->
getContext
();
}
ctx
.
subnet_
=
subnet
;
ctx
.
clientid_
=
client_id
;
ctx
.
hwaddr_
=
hwaddr
;
ctx
.
requested_address_
=
hint
;
ctx
.
fwd_dns_update_
=
fqdn_fwd
;
ctx
.
rev_dns_update_
=
fqdn_rev
;
ctx
.
hostname_
=
hostname
;
ctx
.
fake_allocation_
=
fake_allocation
;
ctx
.
callout_handle_
=
callout_handle
;
Lease4Ptr
lease
=
alloc_engine_
->
allocateLease4
(
ctx
);
...
...
@@ -1342,6 +1514,9 @@ Dhcpv4Srv::getNetmaskOption(const Subnet4Ptr& subnet) {
Pkt4Ptr
Dhcpv4Srv
::
processDiscover
(
Pkt4Ptr
&
discover
)
{
/// @todo Move this call to run() once we reorgnize some unit tests
/// which directly call this method.
exchange
.
reset
(
new
DHCPv4Exchange
(
alloc_engine_
,
discover
));
sanityCheck
(
discover
,
FORBIDDEN
);
...
...
@@ -1390,6 +1565,9 @@ Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) {
Pkt4Ptr
Dhcpv4Srv
::
processRequest
(
Pkt4Ptr
&
request
)
{
/// @todo Move this call to run() once we reorgnize some unit tests
/// which directly call this method.
exchange
.
reset
(
new
DHCPv4Exchange
(
alloc_engine_
,
request
));
/// @todo Uncomment this (see ticket #3116)
/// sanityCheck(request, MANDATORY);
...
...
@@ -1437,6 +1615,9 @@ Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
void
Dhcpv4Srv
::
processRelease
(
Pkt4Ptr
&
release
)
{
/// @todo Move this call to run() once we reorgnize some unit tests
/// which directly call this method.
exchange
.
reset
(
new
DHCPv4Exchange
(
alloc_engine_
,
release
));
/// @todo Uncomment this (see ticket #3116)
/// sanityCheck(release, MANDATORY);
...
...
@@ -1548,12 +1729,20 @@ Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
}
void
Dhcpv4Srv
::
processDecline
(
Pkt4Ptr
&
/* decline */
)
{
Dhcpv4Srv
::
processDecline
(
Pkt4Ptr
&
decline
)
{
/// @todo Move this call to run() once we reorgnize some unit tests
/// which directly call this method.
exchange
.
reset
(
new
DHCPv4Exchange
(
alloc_engine_
,
decline
));
/// @todo Implement this (also see ticket #3116)
}
Pkt4Ptr
Dhcpv4Srv
::
processInform
(
Pkt4Ptr
&
inform
)
{
/// @todo Move this call to run() once we reorgnize some unit tests
/// which directly call this method.
exchange
.
reset
(
new
DHCPv4Exchange
(
alloc_engine_
,
inform
));
// DHCPINFORM MUST not include server identifier.
sanityCheck
(
inform
,
FORBIDDEN
);
...
...
@@ -1611,56 +1800,6 @@ Dhcpv4Srv::serverReceivedPacketName(uint8_t type) {
return
(
UNKNOWN
);
}
Subnet4Ptr
Dhcpv4Srv
::
selectSubnet
(
const
Pkt4Ptr
&
question
)
const
{
Subnet4Ptr
subnet
;
SubnetSelector
selector
;
selector
.
ciaddr_
=
question
->
getCiaddr
();
selector
.
giaddr_
=
question
->
getGiaddr
();
selector
.
local_address_
=
question
->
getLocalAddr
();
selector
.
remote_address_
=
question
->
getRemoteAddr
();
selector
.
client_classes_
=
question
->
classes_
;
selector
.
iface_name_
=
question
->
getIface
();
CfgMgr
&
cfgmgr
=
CfgMgr
::
instance
();
subnet
=
cfgmgr
.
getCurrentCfg
()
->
getCfgSubnets4
()
->
selectSubnet
(
selector
);
// Let's execute all callouts registered for subnet4_select
if
(
HooksManager
::
calloutsPresent
(
hook_index_subnet4_select_
))
{
CalloutHandlePtr
callout_handle
=
getCalloutHandle
(
question
);
// We're reusing callout_handle from previous calls
callout_handle
->
deleteAllArguments
();
// Set new arguments
callout_handle
->
setArgument
(
"query4"
,
question
);
callout_handle
->
setArgument
(
"subnet4"
,
subnet
);
callout_handle
->
setArgument
(
"subnet4collection"
,
cfgmgr
.
getCurrentCfg
()
->
getCfgSubnets4
()
->
getAll
());
// Call user (and server-side) callouts
HooksManager
::
callCallouts
(
hook_index_subnet4_select_
,
*
callout_handle
);
// Callouts decided to skip this step. This means that no subnet
// will be selected. Packet processing will continue, but it will
// be severely limited (i.e. only global options will be assigned)
if
(
callout_handle
->
getSkip
())
{
LOG_DEBUG
(
dhcp4_logger
,
DBG_DHCP4_HOOKS
,
DHCP4_HOOK_SUBNET4_SELECT_SKIP
);
return
(
Subnet4Ptr
());
}
// Use whatever subnet was specified by the callout
callout_handle
->
getArgument
(
"subnet4"
,
subnet
);
}
return
(
subnet
);
}
bool
Dhcpv4Srv
::
accept
(
const
Pkt4Ptr
&
query
)
const
{
// Check that the message type is accepted by the server. We rely on the
...
...
@@ -1725,7 +1864,8 @@ Dhcpv4Srv::acceptDirectRequest(const Pkt4Ptr& pkt) const {
// we validate the message type prior to calling this function.
return
(
false
);
}
return
((
pkt
->
getLocalAddr
()
!=
IOAddress
::
IPV4_BCAST_ADDRESS
()
||
selectSubnet
(
pkt
)));
return
((
pkt
->
getLocalAddr
()
!=
IOAddress
::
IPV4_BCAST_ADDRESS
()
||
DHCPv4Exchange
::
selectSubnet
(
pkt
)));
}
bool
...
...
@@ -2012,7 +2152,7 @@ void Dhcpv4Srv::classifyPacket(const Pkt4Ptr& pkt) {
bool
Dhcpv4Srv
::
classSpecificProcessing
(
const
Pkt4Ptr
&
query
,
const
Pkt4Ptr
&
rsp
)
{
Subnet4Ptr
subnet
=
selectSubnet
(
query
);
Subnet4Ptr
subnet
=
DHCPv4Exchange
::
selectSubnet
(
query
);
if
(
!
subnet
)
{
return
(
true
);
}
...
...
src/bin/dhcp4/dhcp4_srv.h
View file @
6364a03c
...
...
@@ -619,7 +619,7 @@ protected:
///
/// @param question client's message
/// @return selected subnet (or NULL if no suitable subnet was found)
isc
::
dhcp
::
Subnet4Ptr
selectSubnet
(
const
Pkt4Ptr
&
question
)
const
;
static
isc
::
dhcp
::
Subnet4Ptr
selectSubnet
(
const
Pkt4Ptr
&
question
);
/// indicates if shutdown is in progress. Setting it to true will
/// initiate server shutdown procedure.
...
...
src/bin/dhcp4/tests/dhcp4_client.cc
View file @
6364a03c
...
...
@@ -64,6 +64,7 @@ Dhcp4Client::Dhcp4Client(boost::shared_ptr<NakedDhcpv4Srv> srv,
ciaddr_
(
IOAddress
(
"0.0.0.0"
)),
curr_transid_
(
0
),
dest_addr_
(
"255.255.255.255"
),
fqdn_
(),
hwaddr_
(
generateHWAddr
()),
iface_name_
(
"eth0"
),
relay_addr_
(
"192.0.2.2"
),
...
...
@@ -150,6 +151,8 @@ Dhcp4Client::doDiscover(const boost::shared_ptr<IOAddress>& requested_addr) {
context_
.
query_
=
createMsg
(
DHCPDISCOVER
);
// Request options if any.
includePRL
();
// Include FQDN or Hostname.
includeName
();
if
(
requested_addr
)
{
addRequestedAddress
(
*
requested_addr
);
}
...
...
@@ -239,6 +242,8 @@ Dhcp4Client::doRequest() {
// Request options if any.
includePRL
();
// Include FQDN or Hostname.
includeName
();
// Send the message to the server.
sendMsg
(
context_
.
query_
);
// Expect response.
...
...
@@ -249,6 +254,33 @@ Dhcp4Client::doRequest() {
}
}
void
Dhcp4Client
::
includeFQDN
(
const
uint8_t
flags
,
const
std
::
string
&
fqdn_name
,
Option4ClientFqdn
::
DomainNameType
fqdn_type
)
{
fqdn_
.
reset
(
new
Option4ClientFqdn
(
flags
,
Option4ClientFqdn
::
RCODE_CLIENT
(),
fqdn_name
,
fqdn_type
));
}
void
Dhcp4Client
::
includeHostname
(
const
std
::
string
&
name
)
{
hostname_
.
reset
(
new
OptionString
(
Option
::
V4
,
DHO_HOST_NAME
,
name
));
}
void
Dhcp4Client
::
includeName
()
{
if
(
!
context_
.
query_
)
{
isc_throw
(
Dhcp4ClientError
,
"pointer to the query must not be NULL"
" when adding FQDN or Hostname option"
);
}
if
(
fqdn_
)
{
context_
.
query_
->
addOption
(
fqdn_
);
}
else
if
(
hostname_
)
{
context_
.
query_
->
addOption
(
hostname_
);
}
}
void
Dhcp4Client
::
includePRL
()
{
if
(
!
context_
.
query_
)
{
...
...
src/bin/dhcp4/tests/dhcp4_client.h
View file @
6364a03c
...
...
@@ -217,6 +217,21 @@ public:
return
(
srv_
);
}
/// @brief Creates an instance of the Client FQDN option to be included
/// in the client's message.
///
/// @param flags Flags.
/// @param fqdn_name Name in the textual format.
/// @param fqdn_type Type of the name (fully qualified or partial).
void
includeFQDN
(
const
uint8_t
flags
,
const
std
::
string
&
fqdn_name
,
Option4ClientFqdn
::
DomainNameType
fqdn_type
);
/// @brief Creates an instance of the Hostname option to be included
/// in the client's message.
///
/// @param name Name to be stored in the option.
void
includeHostname
(
const
std
::
string
&
name
);
/// @brief Modifies the client's HW address (adds one to it).
///
/// The HW address should be modified to test negative scenarios when the
...
...
@@ -345,6 +360,13 @@ private:
/// @return An instance of the message created.
Pkt4Ptr
createMsg
(
const
uint8_t
msg_type
);
/// @brief Includes FQDN or Hostname option in the client's message.
///
/// This method checks if @c fqdn_ or @c hostname_ is specified and
/// includes it in the client's message. If both are specified, the
/// @c fqdn_ will be used.
void
includeName
();
/// @brief Include PRL Option in the query message.
///
/// This function creates the instance of the PRL (Parameter Request List)
...
...
@@ -376,6 +398,12 @@ private:
/// @brief Currently used destination address.
asiolink
::
IOAddress
dest_addr_
;
/// @brief FQDN requested by the client.
Option4ClientFqdnPtr
fqdn_
;
/// @brief Hostname requested by the client.
OptionStringPtr
hostname_
;
/// @brief Current hardware address of the client.
HWAddrPtr
hwaddr_
;
...
...
@@ -406,4 +434,4 @@ private:
}
// end of namespace isc::dhcp
}
// end of namespace isc
#endif // DHCP4_CLIENT
#endif // DHCP4_CLIENT
_H
src/bin/dhcp4/tests/fqdn_unittest.cc
View file @
6364a03c
...
...
@@ -17,9 +17,12 @@
#include
<dhcp/option4_client_fqdn.h>
#include
<dhcp/option_int_array.h>
#include
<dhcp/tests/iface_mgr_test_config.h>
#include
<dhcp4/tests/dhcp4_client.h>
#include
<dhcp4/tests/dhcp4_test_utils.h>
#include
<dhcp_ddns/ncr_msg.h>
#include
<dhcpsrv/cfgmgr.h>
#include
<dhcpsrv/lease_mgr.h>
#include
<dhcpsrv/lease_mgr_factory.h>
#include
<gtest/gtest.h>
#include
<boost/scoped_ptr.hpp>
...
...
@@ -32,20 +35,91 @@ using namespace isc::dhcp_ddns;
namespace
{
/// @brief Set of JSON configurations used by the FQDN tests.
const
char
*
CONFIGS
[]
=
{
"{
\"
interfaces-config
\"
: {"
"
\"
interfaces
\"
: [
\"
*
\"
]"
"},"
"
\"
valid-lifetime
\"
: 3000,"
"
\"
subnet4
\"
: [ { "
"
\"
subnet
\"
:
\"
10.0.0.0/24
\"
, "
"
\"
id
\"
: 1,"
"
\"
pools
\"
: [ {
\"
pool
\"
:
\"
10.0.0.10-10.0.0.100
\"
} ],"
"
\"
option-data
\"
: [ {"
"
\"
name
\"
:
\"
routers
\"
,"
"
\"
code
\"
: 3,"
"
\"
data
\"
:
\"
10.0.0.200,10.0.0.201
\"
,"
"
\"
csv-format
\"
: true,"
"
\"
space
\"
:
\"
dhcp4
\"
"
" } ],"
"
\"
reservations
\"
: ["
" {"
"
\"
hw-address
\"
:
\"
aa:bb:cc:dd:ee:ff
\"
,"
"
\"
ip-address
\"
:
\"
10.0.0.5
\"
,"
"
\"
hostname
\"
:
\"
unique-host.example.org
\"
"
" }"
" ]"
" }],"
"
\"
dhcp-ddns
\"
: {"
"
\"
enable-updates
\"
: true,"
"
\"
qualifying-suffix
\"
:
\"
fake-suffix.isc.org.
\"
"
"}"
"}"
,
"{
\"
interfaces-config
\"
: {"
"
\"
interfaces
\"
: [
\"
*
\"
]"
"},"
"
\"
valid-lifetime
\"
: 3000,"
"
\"
subnet4
\"
: [ { "
"
\"
subnet
\"
:
\"
10.0.0.0/24
\"
, "
"
\"
id
\"
: 1,"
"
\"
pools
\"
: [ {
\"
pool
\"
:
\"
10.0.0.10-10.0.0.100
\"
} ],"
"
\"
option-data
\"
: [ {"
"
\"
name
\"
:
\"
routers
\"
,"
"
\"
code
\"
: 3,"
"
\"
data
\"
:
\"
10.0.0.200,10.0.0.201
\"
,"
"
\"
csv-format
\"
: true,"
"
\"
space
\"
:
\"
dhcp4
\"
"
" } ],"
"
\"
reservations
\"
: ["
" {"
"
\"
hw-address
\"
:
\"
aa:bb:cc:dd:ee:ff
\"
,"
"
\"
ip-address
\"
:
\"
10.0.0.5
\"
,"
"
\"
hostname
\"
:
\"
foobar.org
\"
"
" }"
" ]"
" }],"
"
\"
dhcp-ddns
\"
: {"
"
\"
enable-updates
\"
: true,"
"
\"
qualifying-suffix
\"
:
\"
fake-suffix.isc.org.
\"
"
"}"
"}"
};
class
NameDhcpv4SrvTest
:
public
Dhcpv4SrvTest
{
public:
// Reference to D2ClientMgr singleton
D2ClientMgr
&
d2_mgr_
;
/// @brief Pointer to the DHCP server instance.
NakedDhcpv4Srv
*
srv_
;
/// @brief Interface Manager's fake configuration control.