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
92758ecf
Commit
92758ecf
authored
Dec 12, 2012
by
Tomek Mrugalski
🛰
Browse files
[master] Merge branch 'master' into trac2325 (RENEW support in DHCPv6)
Conflicts: ChangeLog
parents
a56f7ff8
7f6c9d05
Changes
14
Hide whitespace changes
Inline
Side-by-side
ChangeLog
View file @
92758ecf
524. [func] tomek
b10-dhcp6 is now able to handle RENEW messages. Leases are
renewed and REPLY responses are sent back to clients.
(Trac #2325, git 7f6c9d057cc0a7a10f41ce7da9c8565b9ee85246)
523. [bug] muks
Fixed a problem in inmem NSEC3 lookup (for, instance when using a
zone with no non-apex names) which caused exceptions when the zone
...
...
src/bin/dhcp6/dhcp6_messages.mes
View file @
92758ecf
...
...
@@ -22,6 +22,11 @@ successfully established a session with the BIND 10 control channel.
This debug message is issued just before the IPv6 DHCP server attempts
to establish a session with the BIND 10 control channel.
% DHCP6_CLIENTID_MISSING mandatory client-id option is missing, message from %1 dropped
This error message indicates that the received message is being dropped
because it does not include the mandatory client-id option necessary for
address assignment. The most likely cause is a problem with the client.
% DHCP6_COMMAND_RECEIVED received command %1, arguments: %2
A debug message listing the command (and possible arguments) received
from the BIND 10 control system by the IPv6 DHCP server.
...
...
@@ -81,6 +86,13 @@ This message indicates that the server failed to grant (in response to
received REQUEST) a lease for a given client. There may be many reasons for
such failure. Each specific failure is logged in a separate log entry.
% DHCP6_REQUIRED_OPTIONS_CHECK_FAIL %1 message received from %2 failed the following check: %3
This message indicates that received DHCPv6 packet is invalid. This may be due
to a number of reasons, e.g. the mandatory client-id option is missing,
the server-id forbidden in that particular type of message is present,
there is more than one instance of client-id or server-id present,
etc. The exact reason for rejecting the packet is included in the message.
% DHCP6_NOT_RUNNING IPv6 DHCP server is not running
A warning message is issued when an attempt is made to shut down the
IPv6 DHCP server but it is not running.
...
...
@@ -189,3 +201,18 @@ which the DHCPv6 server has not been configured. The cause is most likely due
to a misconfiguration of the server. The packet processing will continue, but
the response will only contain generic configuration parameters and no
addresses or prefixes.
% DHCP6_UNKNOWN_RENEW received RENEW from client (duid=%1, iaid=%2) in subnet %3
This warning message is printed when client attempts to renew a lease,
but no such lease is known by the server. It typically means that
client has attempted to use its lease past its lifetime: causes of this
include a adjustment of the clients date/time setting or poor support
for sleep/recovery. A properly implemented client will recover from such
a situation by restarting the lease allocation process after receiving
a negative reply from the server.
An alternative cause could be that the server has lost its database
recently and does not recognize its well-behaving clients. This is more
probable if you see many such messages. Clients will recover from this,
but they will most likely get a different IP addresses and experience
a brief service interruption.
src/bin/dhcp6/dhcp6_srv.cc
View file @
92758ecf
...
...
@@ -127,50 +127,57 @@ bool Dhcpv6Srv::run() {
continue
;
}
LOG_DEBUG
(
dhcp6_logger
,
DBG_DHCP6_DETAIL
,
DHCP6_PACKET_RECEIVED
)
.
arg
(
serverReceivedPacketName
(
query
->
get
Typ
e
())
)
;
.
arg
(
query
->
get
Nam
e
());
LOG_DEBUG
(
dhcp6_logger
,
DBG_DHCP6_DETAIL_DATA
,
DHCP6_QUERY_DATA
)
.
arg
(
static_cast
<
int
>
(
query
->
getType
()))
.
arg
(
query
->
getBuffer
().
getLength
())
.
arg
(
query
->
toText
());
switch
(
query
->
getType
())
{
case
DHCPV6_SOLICIT
:
rsp
=
processSolicit
(
query
);
break
;
try
{
switch
(
query
->
getType
())
{
case
DHCPV6_SOLICIT
:
rsp
=
processSolicit
(
query
);
break
;
case
DHCPV6_REQUEST
:
rsp
=
processRequest
(
query
);
break
;
case
DHCPV6_REQUEST
:
rsp
=
processRequest
(
query
);
break
;
case
DHCPV6_RENEW
:
rsp
=
processRenew
(
query
);
break
;
case
DHCPV6_RENEW
:
rsp
=
processRenew
(
query
);
break
;
case
DHCPV6_REBIND
:
rsp
=
processRebind
(
query
);
break
;
case
DHCPV6_REBIND
:
rsp
=
processRebind
(
query
);
break
;
case
DHCPV6_CONFIRM
:
rsp
=
processConfirm
(
query
);
break
;
case
DHCPV6_CONFIRM
:
rsp
=
processConfirm
(
query
);
break
;
case
DHCPV6_RELEASE
:
case
DHCPV6_RELEASE
:
rsp
=
processRelease
(
query
);
break
;
case
DHCPV6_DECLINE
:
rsp
=
processDecline
(
query
);
break
;
case
DHCPV6_DECLINE
:
rsp
=
processDecline
(
query
);
break
;
case
DHCPV6_INFORMATION_REQUEST
:
rsp
=
processInfRequest
(
query
);
break
;
case
DHCPV6_INFORMATION_REQUEST
:
rsp
=
processInfRequest
(
query
);
break
;
default:
// Only action is to output a message if debug is enabled,
// and that will be covered by the debug statement before
// the "switch" statement.
;
default:
// Only action is to output a message if debug is enabled,
// and that will be covered by the debug statement before
// the "switch" statement.
;
}
}
catch
(
const
RFCViolation
&
e
)
{
LOG_DEBUG
(
dhcp6_logger
,
DBG_DHCP6_BASIC
,
DHCP6_REQUIRED_OPTIONS_CHECK_FAIL
)
.
arg
(
query
->
getName
())
.
arg
(
query
->
getRemoteAddr
())
.
arg
(
e
.
what
());
}
if
(
rsp
)
{
...
...
@@ -196,9 +203,6 @@ bool Dhcpv6Srv::run() {
}
}
}
// TODO add support for config session (see src/bin/auth/main.cc)
// so this daemon can be controlled from bob
}
return
(
true
);
...
...
@@ -374,6 +378,54 @@ OptionPtr Dhcpv6Srv::createStatusCode(uint16_t code, const std::string& text) {
return
(
option_status
);
}
void
Dhcpv6Srv
::
sanityCheck
(
const
Pkt6Ptr
&
pkt
,
RequirementLevel
clientid
,
RequirementLevel
serverid
)
{
Option
::
OptionCollection
client_ids
=
pkt
->
getOptions
(
D6O_CLIENTID
);
switch
(
clientid
)
{
case
MANDATORY
:
if
(
client_ids
.
size
()
!=
1
)
{
isc_throw
(
RFCViolation
,
"Exactly 1 client-id option expected in "
<<
pkt
->
getName
()
<<
", but "
<<
client_ids
.
size
()
<<
" received"
);
}
break
;
case
OPTIONAL
:
if
(
client_ids
.
size
()
>
1
)
{
isc_throw
(
RFCViolation
,
"Too many ("
<<
client_ids
.
size
()
<<
") client-id options received in "
<<
pkt
->
getName
());
}
break
;
case
FORBIDDEN
:
// doesn't make sense - client-id is always allowed
break
;
}
Option
::
OptionCollection
server_ids
=
pkt
->
getOptions
(
D6O_SERVERID
);
switch
(
serverid
)
{
case
FORBIDDEN
:
if
(
server_ids
.
size
()
>
0
)
{
isc_throw
(
RFCViolation
,
"Exactly 1 server-id option expected, but "
<<
server_ids
.
size
()
<<
" received in "
<<
pkt
->
getName
());
}
break
;
case
MANDATORY
:
if
(
server_ids
.
size
()
!=
1
)
{
isc_throw
(
RFCViolation
,
"Invalid number of server-id options received ("
<<
server_ids
.
size
()
<<
"), exactly 1 expected in message "
<<
pkt
->
getName
());
}
break
;
case
OPTIONAL
:
if
(
server_ids
.
size
()
>
1
)
{
isc_throw
(
RFCViolation
,
"Too many ("
<<
server_ids
.
size
()
<<
") server-id options received in "
<<
pkt
->
getName
());
}
}
}
Subnet6Ptr
Dhcpv6Srv
::
selectSubnet
(
const
Pkt6Ptr
&
question
)
{
Subnet6Ptr
subnet
=
CfgMgr
::
instance
().
getSubnet6
(
question
->
getRemoteAddr
());
...
...
@@ -387,7 +439,7 @@ void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
// We need to select a subnet the client is connected in.
Subnet6Ptr
subnet
=
selectSubnet
(
question
);
if
(
subnet
)
{
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
// misconfiguration of the server (or some relays). We will continue to
...
...
@@ -395,12 +447,13 @@ void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
// addresses or prefixes, no subnet specific configuration etc. The only
// thing this client can get is some global information (like DNS
// servers).
LOG_DEBUG
(
dhcp6_logger
,
DBG_DHCP6_DETAIL_DATA
,
DHCP6_SUBNET_SELECTED
)
.
arg
(
subnet
->
toText
());
}
else
{
// perhaps this should be logged on some higher level? This is most likely
// configuration bug.
LOG_DEBUG
(
dhcp6_logger
,
DBG_DHCP6_BASIC
,
DHCP6_SUBNET_SELECTION_FAILED
);
LOG_ERROR
(
dhcp6_logger
,
DHCP6_SUBNET_SELECTION_FAILED
);
}
else
{
LOG_DEBUG
(
dhcp6_logger
,
DBG_DHCP6_DETAIL_DATA
,
DHCP6_SUBNET_SELECTED
)
.
arg
(
subnet
->
toText
());
}
// @todo: We should implement Option6Duid some day, but we can do without it
...
...
@@ -414,6 +467,10 @@ void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
OptionPtr
opt_duid
=
question
->
getOption
(
D6O_CLIENTID
);
if
(
opt_duid
)
{
duid
=
DuidPtr
(
new
DUID
(
opt_duid
->
getData
()));
}
else
{
LOG_DEBUG
(
dhcp6_logger
,
DBG_DHCP6_BASIC
,
DHCP6_CLIENTID_MISSING
);
// Let's drop the message. This client is not sane.
isc_throw
(
RFCViolation
,
"Mandatory client-id is missing in received message"
);
}
// Now that we have all information about the client, let's iterate over all
...
...
@@ -426,7 +483,7 @@ void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
opt
!=
question
->
options_
.
end
();
++
opt
)
{
switch
(
opt
->
second
->
getType
())
{
case
D6O_IA_NA
:
{
OptionPtr
answer_opt
=
handle
IA_NA
(
subnet
,
duid
,
question
,
OptionPtr
answer_opt
=
assign
IA_NA
(
subnet
,
duid
,
question
,
boost
::
dynamic_pointer_cast
<
Option6IA
>
(
opt
->
second
));
if
(
answer_opt
)
{
answer
->
addOption
(
answer_opt
);
...
...
@@ -439,8 +496,8 @@ void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
}
}
OptionPtr
Dhcpv6Srv
::
handle
IA_NA
(
const
Subnet6Ptr
&
subnet
,
const
DuidPtr
&
duid
,
Pkt6Ptr
question
,
boost
::
shared_ptr
<
Option6IA
>
ia
)
{
OptionPtr
Dhcpv6Srv
::
assign
IA_NA
(
const
Subnet6Ptr
&
subnet
,
const
DuidPtr
&
duid
,
Pkt6Ptr
question
,
boost
::
shared_ptr
<
Option6IA
>
ia
)
{
// If there is no subnet selected for handling this IA_NA, the only thing to do left is
// to say that we are sorry, but the user won't get an address. As a convenience, we
// use a different status text to indicate that (compare to the same status code,
...
...
@@ -535,8 +592,111 @@ OptionPtr Dhcpv6Srv::handleIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
return
(
ia_rsp
);
}
OptionPtr
Dhcpv6Srv
::
renewIA_NA
(
const
Subnet6Ptr
&
subnet
,
const
DuidPtr
&
duid
,
Pkt6Ptr
question
,
boost
::
shared_ptr
<
Option6IA
>
ia
)
{
Lease6Ptr
lease
=
LeaseMgrFactory
::
instance
().
getLease6
(
*
duid
,
ia
->
getIAID
(),
subnet
->
getID
());
if
(
!
lease
)
{
// client renewing a lease that we don't know about.
// Create empty IA_NA option with IAID matching the request.
boost
::
shared_ptr
<
Option6IA
>
ia_rsp
(
new
Option6IA
(
D6O_IA_NA
,
ia
->
getIAID
()));
// Insert status code NoAddrsAvail.
ia_rsp
->
addOption
(
createStatusCode
(
STATUS_NoAddrsAvail
,
"Sorry, no known leases for this duid/iaid."
));
LOG_DEBUG
(
dhcp6_logger
,
DBG_DHCP6_DETAIL
,
DHCP6_UNKNOWN_RENEW
)
.
arg
(
duid
->
toText
())
.
arg
(
ia
->
getIAID
())
.
arg
(
subnet
->
toText
());
return
(
ia_rsp
);
}
lease
->
preferred_lft_
=
subnet
->
getPreferred
();
lease
->
valid_lft_
=
subnet
->
getValid
();
lease
->
t1_
=
subnet
->
getT1
();
lease
->
t2_
=
subnet
->
getT2
();
lease
->
cltt_
=
time
(
NULL
);
LeaseMgrFactory
::
instance
().
updateLease6
(
lease
);
// Create empty IA_NA option with IAID matching the request.
boost
::
shared_ptr
<
Option6IA
>
ia_rsp
(
new
Option6IA
(
D6O_IA_NA
,
ia
->
getIAID
()));
ia_rsp
->
setT1
(
subnet
->
getT1
());
ia_rsp
->
setT2
(
subnet
->
getT2
());
boost
::
shared_ptr
<
Option6IAAddr
>
addr
(
new
Option6IAAddr
(
D6O_IAADDR
,
lease
->
addr_
,
lease
->
preferred_lft_
,
lease
->
valid_lft_
));
ia_rsp
->
addOption
(
addr
);
return
(
ia_rsp
);
}
void
Dhcpv6Srv
::
renewLeases
(
const
Pkt6Ptr
&
renew
,
Pkt6Ptr
&
reply
)
{
// We need to renew addresses for all IA_NA options in the client's
// RENEW message.
// We need to select a subnet the client is connected in.
Subnet6Ptr
subnet
=
selectSubnet
(
renew
);
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
// misconfiguration of the server (or some relays). We will continue to
// process this message, but our response will be almost useless: no
// addresses or prefixes, no subnet specific configuration etc. The only
// thing this client can get is some global information (like DNS
// servers).
// perhaps this should be logged on some higher level? This is most likely
// configuration bug.
LOG_ERROR
(
dhcp6_logger
,
DHCP6_SUBNET_SELECTION_FAILED
);
}
else
{
LOG_DEBUG
(
dhcp6_logger
,
DBG_DHCP6_DETAIL_DATA
,
DHCP6_SUBNET_SELECTED
)
.
arg
(
subnet
->
toText
());
}
// Let's find client's DUID. Client is supposed to include its client-id
// option almost all the time (the only exception is an anonymous inf-request,
// but that is mostly a theoretical case). Our allocation engine needs DUID
// and will refuse to allocate anything to anonymous clients.
OptionPtr
opt_duid
=
renew
->
getOption
(
D6O_CLIENTID
);
if
(
!
opt_duid
)
{
// This should not happen. We have checked this before.
reply
->
addOption
(
createStatusCode
(
STATUS_UnspecFail
,
"You did not include mandatory client-id"
));
return
;
}
DuidPtr
duid
(
new
DUID
(
opt_duid
->
getData
()));
for
(
Option
::
OptionCollection
::
iterator
opt
=
renew
->
options_
.
begin
();
opt
!=
renew
->
options_
.
end
();
++
opt
)
{
switch
(
opt
->
second
->
getType
())
{
case
D6O_IA_NA
:
{
OptionPtr
answer_opt
=
renewIA_NA
(
subnet
,
duid
,
renew
,
boost
::
dynamic_pointer_cast
<
Option6IA
>
(
opt
->
second
));
if
(
answer_opt
)
{
reply
->
addOption
(
answer_opt
);
}
break
;
}
default:
break
;
}
}
}
Pkt6Ptr
Dhcpv6Srv
::
processSolicit
(
const
Pkt6Ptr
&
solicit
)
{
sanityCheck
(
solicit
,
MANDATORY
,
FORBIDDEN
);
Pkt6Ptr
advertise
(
new
Pkt6
(
DHCPV6_ADVERTISE
,
solicit
->
getTransid
()));
copyDefaultOptions
(
solicit
,
advertise
);
...
...
@@ -549,6 +709,9 @@ Pkt6Ptr Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
}
Pkt6Ptr
Dhcpv6Srv
::
processRequest
(
const
Pkt6Ptr
&
request
)
{
sanityCheck
(
request
,
MANDATORY
,
MANDATORY
);
Pkt6Ptr
reply
(
new
Pkt6
(
DHCPV6_REPLY
,
request
->
getTransid
()));
copyDefaultOptions
(
request
,
reply
);
...
...
@@ -561,8 +724,17 @@ Pkt6Ptr Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
}
Pkt6Ptr
Dhcpv6Srv
::
processRenew
(
const
Pkt6Ptr
&
renew
)
{
/// @todo: Implement this
sanityCheck
(
renew
,
MANDATORY
,
MANDATORY
);
Pkt6Ptr
reply
(
new
Pkt6
(
DHCPV6_REPLY
,
renew
->
getTransid
()));
copyDefaultOptions
(
renew
,
reply
);
appendDefaultOptions
(
renew
,
reply
);
appendRequestedOptions
(
renew
,
reply
);
renewLeases
(
renew
,
reply
);
return
reply
;
}
...
...
@@ -596,48 +768,5 @@ Pkt6Ptr Dhcpv6Srv::processInfRequest(const Pkt6Ptr& infRequest) {
return
reply
;
}
const
char
*
Dhcpv6Srv
::
serverReceivedPacketName
(
uint8_t
type
)
{
static
const
char
*
CONFIRM
=
"CONFIRM"
;
static
const
char
*
DECLINE
=
"DECLINE"
;
static
const
char
*
INFORMATION_REQUEST
=
"INFORMATION_REQUEST"
;
static
const
char
*
REBIND
=
"REBIND"
;
static
const
char
*
RELEASE
=
"RELEASE"
;
static
const
char
*
RENEW
=
"RENEW"
;
static
const
char
*
REQUEST
=
"REQUEST"
;
static
const
char
*
SOLICIT
=
"SOLICIT"
;
static
const
char
*
UNKNOWN
=
"UNKNOWN"
;
switch
(
type
)
{
case
DHCPV6_CONFIRM
:
return
(
CONFIRM
);
case
DHCPV6_DECLINE
:
return
(
DECLINE
);
case
DHCPV6_INFORMATION_REQUEST
:
return
(
INFORMATION_REQUEST
);
case
DHCPV6_REBIND
:
return
(
REBIND
);
case
DHCPV6_RELEASE
:
return
(
RELEASE
);
case
DHCPV6_RENEW
:
return
(
RENEW
);
case
DHCPV6_REQUEST
:
return
(
REQUEST
);
case
DHCPV6_SOLICIT
:
return
(
SOLICIT
);
default:
;
}
return
(
UNKNOWN
);
}
};
};
src/bin/dhcp6/dhcp6_srv.h
View file @
92758ecf
...
...
@@ -30,6 +30,23 @@
namespace
isc
{
namespace
dhcp
{
/// An exception that is thrown if a DHCPv6 protocol violation occurs while
/// processing a message (e.g. a mandatory option is missing)
class
RFCViolation
:
public
isc
::
Exception
{
public:
/// @brief constructor
///
/// @param file name of the file, where exception occurred
/// @param line line of the file, where exception occurred
/// @param what text description of the issue that caused exception
RFCViolation
(
const
char
*
file
,
size_t
line
,
const
char
*
what
)
:
isc
::
Exception
(
file
,
line
,
what
)
{}
};
/// @brief DHCPv6 server service.
///
/// This class represents DHCPv6 server. It contains all
...
...
@@ -45,6 +62,12 @@ namespace dhcp {
class
Dhcpv6Srv
:
public
boost
::
noncopyable
{
public:
/// @brief defines if certain option may, must or must not appear
typedef
enum
{
FORBIDDEN
,
MANDATORY
,
OPTIONAL
}
RequirementLevel
;
/// @brief Minimum length of a MAC address to be used in DUID generation.
static
const
size_t
MIN_MAC_LEN
=
6
;
...
...
@@ -83,24 +106,20 @@ public:
/// @brief Instructs the server to shut down.
void
shutdown
();
/// @brief Return textual type of packet received by server.
///
/// Returns the name of valid packet received by the server (e.g. SOLICIT).
/// If the packet is unknown - or if it is a valid DHCP packet but not one
/// expected to be received by the server (such as an ADVERTISE), the string
/// "UNKNOWN" is returned. This method is used in debug messages.
///
/// As the operation of the method does not depend on any server state, it
/// is declared static.
protected:
/// @brief verifies if specified packet meets RFC requirements
///
/// @param type DHCPv4 packet type
/// Checks if mandatory option is really there, that forbidden option
/// is not there, and that client-id or server-id appears only once.
///
/// @return Pointer to "const" string containing the packet name.
/// Note that this string is statically allocated and MUST NOT
/// be freed by the caller.
static
const
char
*
serverReceivedPacketName
(
uint8_t
type
);
/// @param pkt packet to be checked
/// @param clientid expectation regarding client-id option
/// @param serverid expectation regarding server-id option
/// @throw RFCViolation if any issues are detected
void
sanityCheck
(
const
Pkt6Ptr
&
pkt
,
RequirementLevel
clientid
,
RequirementLevel
serverid
);
protected:
/// @brief Processes incoming SOLICIT and returns response.
///
/// Processes received SOLICIT message and verifies that its sender
...
...
@@ -186,11 +205,24 @@ protected:
/// @param question client's message (typically SOLICIT or REQUEST)
/// @param ia pointer to client's IA_NA option (client's request)
/// @return IA_NA option (server's response)
OptionPtr
handle
IA_NA
(
const
isc
::
dhcp
::
Subnet6Ptr
&
subnet
,
OptionPtr
assign
IA_NA
(
const
isc
::
dhcp
::
Subnet6Ptr
&
subnet
,
const
isc
::
dhcp
::
DuidPtr
&
duid
,
isc
::
dhcp
::
Pkt6Ptr
question
,
boost
::
shared_ptr
<
Option6IA
>
ia
);
/// @brief Renews specific IA_NA option
///
/// Generates response to IA_NA. This typically includes finding a lease that
/// corresponds to the received address. If no such lease is found, an IA_NA
/// response is generated with an appropriate status code.
///
/// @param subnet subnet the sender belongs to
/// @param duid client's duid
/// @param question client's message
/// @param ia IA_NA option that is being renewed
OptionPtr
renewIA_NA
(
const
Subnet6Ptr
&
subnet
,
const
DuidPtr
&
duid
,
Pkt6Ptr
question
,
boost
::
shared_ptr
<
Option6IA
>
ia
);
/// @brief Copies required options from client message to server answer.
///
/// Copies options that must appear in any server response (ADVERTISE, REPLY)
...
...
@@ -221,14 +253,24 @@ protected:
/// @brief Assigns leases.
///
///
TODO: This method is currently a stub. It just appends one
///
hardcoded lease. It supports addresses (IA_NA) only. It does NOT
///
support temporary addresses (IA_TA) nor prefixes (IA_PD).
///
It supports addresses (IA_NA) only. It does NOT support temporary
///
addresses (IA_TA) nor prefixes (IA_PD).
///
@todo: Extend this method once TA and PD becomes supported
///
/// @param question client's message (with requested IA_NA)
/// @param answer server's message (IA_NA options will be added here)
void
assignLeases
(
const
Pkt6Ptr
&
question
,
Pkt6Ptr
&
answer
);
/// @brief Attempts to renew received addresses
///
/// It iterates through received IA_NA options and attempts to renew
/// received addresses. If no such leases are found, proper status
/// code is added to reply message. Renewed addresses are added
/// as IA_NA/IAADDR to reply packet.
/// @param renew client's message asking for renew
/// @param reply server's response
void
renewLeases
(
const
Pkt6Ptr
&
renew
,
Pkt6Ptr
&
reply
);
/// @brief Sets server-identifier.
///
/// This method attempts to set server-identifier DUID. It loads it
...
...
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
View file @
92758ecf
...
...
@@ -19,6 +19,7 @@
#include <dhcp/dhcp6.h>
#include <dhcp/duid.h>
#include <dhcp/option.h>
#include <dhcp/option_custom.h>
#include <dhcp/option6_addrlst.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
...
...
@@ -57,8 +58,10 @@ public:
using
Dhcpv6Srv
::
processSolicit
;
using
Dhcpv6Srv
::
processRequest
;
using
Dhcpv6Srv
::
processRenew
;
using
Dhcpv6Srv
::
createStatusCode
;
using
Dhcpv6Srv
::
selectSubnet
;
using
Dhcpv6Srv
::
sanityCheck
;
};
class
Dhcpv6SrvTest
:
public
::
testing
::
Test
{
...
...
@@ -139,6 +142,33 @@ public:
return
(
addr
);
}
// Checks that server rejected IA_NA, i.e. that it has no addresses and
// that expected status code really appears there.
// Status code indicates type of error encountered (in theory it can also
// indicate success, but servers typically don't send success status
// as this is the default result and it saves bandwidth)
void
checkRejectedIA_NA
(
const
boost
::
shared_ptr
<
Option6IA
>&
ia
,
uint16_t
expected_status_code
)
{
// Make sure there is no address assigned.
EXPECT_FALSE
(
ia
->
getOption
(
D6O_IAADDR
));
// T1, T2 should be zeroed
EXPECT_EQ
(
0
,
ia
->
getT1
());
EXPECT_EQ
(
0
,
ia
->
getT2
());
boost
::
shared_ptr
<
OptionCustom
>
status
=
boost
::
dynamic_pointer_cast
<
OptionCustom
>
(
ia
->
getOption
(
D6O_STATUS_CODE
));
EXPECT_TRUE
(
status
);
if
(
status
)
{
// We don't have dedicated class for status code, so let's just interpret
// first 2 bytes as status. Remainder of the status code option content is
// just a text explanation what went wrong.
EXPECT_EQ
(
static_cast
<
uint16_t
>
(
expected_status_code
),
status
->
readInteger
<
uint16_t
>
(
0
));
}
}
// Check that generated IAADDR option contains expected address.