Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Kea
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
Operations
Operations
Incidents
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Adam Osuchowski
Kea
Commits
6364a03c
Commit
6364a03c
authored
Mar 10, 2015
by
Marcin Siodelski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[3688] DHCPv4 server assignes reserved hostname to the clients.
parent
ac390543
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
549 additions
and
87 deletions
+549
-87
src/bin/dhcp4/dhcp4_srv.cc
src/bin/dhcp4/dhcp4_srv.cc
+215
-75
src/bin/dhcp4/dhcp4_srv.h
src/bin/dhcp4/dhcp4_srv.h
+1
-1
src/bin/dhcp4/tests/dhcp4_client.cc
src/bin/dhcp4/tests/dhcp4_client.cc
+32
-0
src/bin/dhcp4/tests/dhcp4_client.h
src/bin/dhcp4/tests/dhcp4_client.h
+29
-1
src/bin/dhcp4/tests/fqdn_unittest.cc
src/bin/dhcp4/tests/fqdn_unittest.cc
+265
-6
src/lib/dhcpsrv/alloc_engine.cc
src/lib/dhcpsrv/alloc_engine.cc
+1
-1
src/lib/dhcpsrv/alloc_engine.h
src/lib/dhcpsrv/alloc_engine.h
+5
-2
src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc
src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc
+1
-1
No files found.
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.
IfaceMgrTestConfig
iface_mgr_test_config_
;
// Bit Constants for turning on and off DDNS configuration options.