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
445
Issues
445
List
Boards
Labels
Service Desk
Milestones
Merge Requests
71
Merge Requests
71
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
ISC Open Source Projects
Kea
Commits
4f43c309
Commit
4f43c309
authored
Jul 24, 2014
by
Marcin Siodelski
Browse files
Options
Browse Files
Download
Plain Diff
[master] Merge branch 'trac3269'
parents
acdbb45c
080ee7ee
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
774 additions
and
98 deletions
+774
-98
doc/guide/dhcp6-srv.xml
doc/guide/dhcp6-srv.xml
+4
-4
src/bin/dhcp6/dhcp6_srv.cc
src/bin/dhcp6/dhcp6_srv.cc
+74
-2
src/bin/dhcp6/dhcp6_srv.h
src/bin/dhcp6/dhcp6_srv.h
+22
-2
src/bin/dhcp6/tests/Makefile.am
src/bin/dhcp6/tests/Makefile.am
+2
-0
src/bin/dhcp6/tests/confirm_unittest.cc
src/bin/dhcp6/tests/confirm_unittest.cc
+329
-0
src/bin/dhcp6/tests/dhcp6_client.cc
src/bin/dhcp6/tests/dhcp6_client.cc
+87
-26
src/bin/dhcp6/tests/dhcp6_client.h
src/bin/dhcp6/tests/dhcp6_client.h
+68
-2
src/bin/dhcp6/tests/dhcp6_message_test.cc
src/bin/dhcp6/tests/dhcp6_message_test.cc
+78
-0
src/bin/dhcp6/tests/dhcp6_message_test.h
src/bin/dhcp6/tests/dhcp6_message_test.h
+92
-0
src/bin/dhcp6/tests/rebind_unittest.cc
src/bin/dhcp6/tests/rebind_unittest.cc
+18
-62
No files found.
doc/guide/dhcp6-srv.xml
View file @
4f43c309
...
...
@@ -1442,7 +1442,7 @@ Dhcp6/dhcp-ddns/qualifying-suffix "example.com" string
<itemizedlist>
<listitem>
<simpara><ulink
url=
"http://tools.ietf.org/html/rfc3315"
>
RFC 3315
</ulink>
: Supported messages are SOLICIT,
ADVERTISE, REQUEST, RELEASE, RENEW, REBIND and REPLY.
</simpara>
ADVERTISE, REQUEST, RELEASE, RENEW, REBIND
, CONFIRM
and REPLY.
</simpara>
</listitem>
<listitem>
<simpara><ulink
url=
"http://tools.ietf.org/html/rfc3633"
>
RFC 3633
</ulink>
: Supported options are IA_PD and
...
...
@@ -1510,9 +1510,9 @@ Dhcp6/renew-timer 1000 integer (default)
</listitem>
<listitem>
<simpara>
Confirmation (CONFIRM), duplication report (DECLINE),
stateless configuration (INFORMATION-REQUEST) and client
reconfiguration (RECONFIGURE) are
not yet supported.
Duplication report (DECLINE), stateless configuration
(INFORMATION-REQUEST) and client reconfiguration (RECONFIGURE) are
not yet supported.
</simpara>
</listitem>
<listitem>
...
...
src/bin/dhcp6/dhcp6_srv.cc
View file @
4f43c309
...
...
@@ -2314,9 +2314,81 @@ Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind) {
Pkt6Ptr
Dhcpv6Srv
::
processConfirm
(
const
Pkt6Ptr
&
confirm
)
{
/// @todo: Implement this
// Get IA_NAs from the Confirm. If there are none, the message is
// invalid and must be discarded. There is nothing more to do.
OptionCollection
ias
=
confirm
->
getOptions
(
D6O_IA_NA
);
if
(
ias
.
empty
())
{
return
(
Pkt6Ptr
());
}
// The server sends Reply message in response to Confirm.
Pkt6Ptr
reply
(
new
Pkt6
(
DHCPV6_REPLY
,
confirm
->
getTransid
()));
return
reply
;
// Make sure that the necessary options are included.
copyDefaultOptions
(
confirm
,
reply
);
appendDefaultOptions
(
confirm
,
reply
);
// Indicates if at least one address has been verified. If no addresses
// are verified it means that the client has sent no IA_NA options
// or no IAAddr options and that client's message has to be discarded.
bool
verified
=
false
;
// Check if subnet can be selected for the message. If no subnet
// has been selected, the client is not on link.
SubnetPtr
subnet
=
selectSubnet
(
confirm
);
// Regardless if the subnet has been selected or not, we will iterate
// over the IA_NA options to check if they hold any addresses. If there
// are no, the Confirm is discarded.
// Check addresses in IA_NA options and make sure they are appropriate.
for
(
OptionCollection
::
const_iterator
ia
=
ias
.
begin
();
ia
!=
ias
.
end
();
++
ia
)
{
const
OptionCollection
&
opts
=
ia
->
second
->
getOptions
();
for
(
OptionCollection
::
const_iterator
opt
=
opts
.
begin
();
opt
!=
opts
.
end
();
++
opt
)
{
// Ignore options other than IAAddr.
if
(
opt
->
second
->
getType
()
==
D6O_IAADDR
)
{
// Check that the address is in range in the subnet selected.
Option6IAAddrPtr
iaaddr
=
boost
::
dynamic_pointer_cast
<
Option6IAAddr
>
(
opt
->
second
);
// If there is subnet selected and the address has been included
// in IA_NA, mark it verified and verify that it belongs to the
// subnet.
if
(
iaaddr
)
{
// If at least one address is not in range, then return
// the NotOnLink status code.
if
(
subnet
&&
!
subnet
->
inRange
(
iaaddr
->
getAddress
()))
{
std
::
ostringstream
status_msg
;
status_msg
<<
"Address "
<<
iaaddr
->
getAddress
()
<<
" is not on link."
;
reply
->
addOption
(
createStatusCode
(
STATUS_NotOnLink
,
status_msg
.
str
()));
return
(
reply
);
}
verified
=
true
;
}
else
{
isc_throw
(
Unexpected
,
"failed to cast the IA Address option"
" to the Option6IAAddrPtr. This is programming"
" error and should be reported"
);
}
}
}
}
// It seems that the client hasn't included any addresses in which case
// the Confirm must be discarded.
if
(
!
verified
)
{
return
(
Pkt6Ptr
());
}
// If there is a subnet, there were addresses in IA_NA options and the
// addresses where consistent with the subnet then the client is on link.
if
(
subnet
)
{
// All addresses in range, so return success.
reply
->
addOption
(
createStatusCode
(
STATUS_Success
,
"All addresses are on-link"
));
}
else
{
reply
->
addOption
(
createStatusCode
(
STATUS_NotOnLink
,
"No subnet selected"
));
}
return
(
reply
);
}
Pkt6Ptr
...
...
src/bin/dhcp6/dhcp6_srv.h
View file @
4f43c309
...
...
@@ -221,9 +221,29 @@ protected:
/// @param rebind message received from client
Pkt6Ptr
processRebind
(
const
Pkt6Ptr
&
rebind
);
/// @brief
Stub function that will handle incoming CONFIRM messages
.
/// @brief
Processes incoming Confirm message and returns Reply
.
///
/// @param confirm message received from client
/// This function processes Confirm message from the client according
/// to section 18.2.2. of RFC3315. It discards the Confirm message if
/// the message sent by the client contains no addresses, i.e. it has
/// no IA_NA options or all IA_NA options contain no IAAddr options.
///
/// If the Confirm message contains addresses this function will perform
/// the following checks:
/// - check if there is appropriate subnet configured for the client
/// (e.g. subnet from which addresses are assigned for requests
/// received on the particular interface).
/// - check if all addresses sent in the Confirm message belong to the
/// selected subnet.
///
/// If any of the checks above fails, the Reply message with the status
/// code NotOnLink is returned. Otherwise, the Reply message with the
/// status code Success is returned.
///
/// @param confirm Confirm message sent by a client.
///
/// @return Reply message from the server al NULL pointer if Confirm
/// message should be discarded by the server.
Pkt6Ptr
processConfirm
(
const
Pkt6Ptr
&
confirm
);
/// @brief Stub function that will handle incoming RELEASE messages.
...
...
src/bin/dhcp6/tests/Makefile.am
View file @
4f43c309
...
...
@@ -88,6 +88,8 @@ dhcp6_unittests_SOURCES += rebind_unittest.cc
dhcp6_unittests_SOURCES
+=
sarr_unittest.cc
dhcp6_unittests_SOURCES
+=
../json_config_parser.cc ../json_config_parser.h
dhcp6_unittests_SOURCES
+=
config_parser_unittest.cc
dhcp6_unittests_SOURCES
+=
confirm_unittest.cc
dhcp6_unittests_SOURCES
+=
dhcp6_message_test.cc dhcp6_message_test.h
if
CONFIG_BACKEND_BUNDY
# For Bundy backend, we only need to run the usual tests. There are no
...
...
src/bin/dhcp6/tests/confirm_unittest.cc
0 → 100644
View file @
4f43c309
// 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 <config.h>
#include <asiolink/io_address.h>
#include <cc/data.h>
#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcp6/json_config_parser.h>
#include <dhcp6/tests/dhcp6_message_test.h>
using
namespace
isc
;
using
namespace
isc
::
asiolink
;
using
namespace
isc
::
data
;
using
namespace
isc
::
dhcp
;
using
namespace
isc
::
dhcp
::
test
;
using
namespace
isc
::
test
;
namespace
{
/// @brief Set of JSON configurations used throughout the Confirm tests.
///
/// - Configuration 0:
/// - only addresses (no prefixes)
/// - 2 subnets with 2001:db8:1::/64 and 2001:db8:2::/64
/// - 1 subnet for eth0 and 1 subnet for eth1
///
/// - Configuration 1:
/// - similar to Configuration 0
/// - pools configured: 3000:1::/64 and 3000:2::/64
/// - this specific configuration is used by tests using relays
///
const
char
*
CONFIRM_CONFIGS
[]
=
{
// Configuration 0
"{
\"
interfaces
\"
: [
\"
all
\"
],"
"
\"
preferred-lifetime
\"
: 3000,"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
subnet6
\"
: [ { "
"
\"
pool
\"
: [
\"
2001:db8:1::/64
\"
],"
"
\"
subnet
\"
:
\"
2001:db8:1::/48
\"
, "
"
\"
interface-id
\"
:
\"\"
,"
"
\"
interface
\"
:
\"
eth0
\"
"
" },"
" {"
"
\"
pool
\"
: [
\"
2001:db8:2::/64
\"
],"
"
\"
subnet
\"
:
\"
2001:db8:2::/48
\"
, "
"
\"
interface-id
\"
:
\"\"
,"
"
\"
interface
\"
:
\"
eth1
\"
"
" } ],"
"
\"
valid-lifetime
\"
: 4000 }"
,
// Configuration 1
"{
\"
interfaces
\"
: [
\"
all
\"
],"
"
\"
preferred-lifetime
\"
: 3000,"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
subnet6
\"
: [ { "
"
\"
pool
\"
: [
\"
3000:1::/64
\"
],"
"
\"
subnet
\"
:
\"
3000:1::/48
\"
, "
"
\"
interface-id
\"
:
\"\"
,"
"
\"
interface
\"
:
\"
eth0
\"
"
" },"
" {"
"
\"
pool
\"
: [
\"
3000:2::/64
\"
],"
"
\"
subnet
\"
:
\"
3000:2::/48
\"
, "
"
\"
interface-id
\"
:
\"\"
,"
"
\"
interface
\"
:
\"
eth1
\"
"
" } ],"
"
\"
valid-lifetime
\"
: 4000 }"
};
/// @brief Test fixture class for testing Confirm..
class
ConfirmTest
:
public
isc
::
dhcp
::
test
::
Dhcpv6MessageTest
{
public:
/// @brief Constructor.
///
/// Sets up fake interfaces.
ConfirmTest
()
:
Dhcpv6MessageTest
()
{
}
};
// Test that directly connected client's Confirm message is processed and Reply
// message is sent back. In this test case, the client sends Confirm for two
// addresses that belong to the same IAID and are sent within the same IA_NA
// option (RFC3315, section 18.2.2).
TEST_F
(
ConfirmTest
,
directClientSameIAID
)
{
Dhcp6Client
client
;
// Configure client to request IA_NA.
client
.
useNA
();
// Make 4-way exchange to get the lease.
ASSERT_NO_FATAL_FAILURE
(
requestLease
(
CONFIRM_CONFIGS
[
0
],
2
,
client
));
// Keep the client's lease for future reference.
Lease6
lease_client1
=
client
.
getLease
(
0
);
// Clone the lease and modify its address so as it is still in the range
// of the subnet to which the first lease belongs. When the client sends
// the Confirm it should include both addresses and the server should
// send Success because both of these addresses are on-link, regardless
// what the server has in the lease database.
Lease6
lease_client2
=
lease_client1
;
lease_client2
.
addr_
=
bumpAddress
(
lease_client2
.
addr_
);
client
.
createLease
(
lease_client2
);
ASSERT_EQ
(
2
,
client
.
getLeaseNum
());
// Send Confirm message to the server.
ASSERT_NO_THROW
(
client
.
doConfirm
());
// Client should have received a status code option and this option should
// indicate the success.
ASSERT_TRUE
(
client
.
receivedStatusCode
());
ASSERT_EQ
(
STATUS_Success
,
client
.
getStatusCode
());
ASSERT_EQ
(
2
,
client
.
getLeaseNum
());
lease_client2
=
client
.
getLease
(
1
);
lease_client2
.
addr_
=
bumpSubnet
(
lease_client2
.
addr_
);
client
.
createLease
(
lease_client2
);
// Send confirm to the server. This time, one of the leases contains the
// address which doesn't belong to the configured subnet and the server
// should respond with STATUS_NotOnLink.
ASSERT_NO_THROW
(
client
.
doConfirm
());
ASSERT_TRUE
(
client
.
receivedStatusCode
());
ASSERT_EQ
(
STATUS_NotOnLink
,
client
.
getStatusCode
());
// Make sure that the server id has been included.
EXPECT_TRUE
(
client
.
getContext
().
response_
->
getOption
(
D6O_SERVERID
));
}
// Test that directly connected client's Confirm message is processed and Reply
// message is sent back. In this test case, the client sends Confirm for two
// addresses that belong to different IAIDs and are sent within the different
// IA_NA options (RFC3315, section 18.2.2).
TEST_F
(
ConfirmTest
,
directClientDifferentIAID
)
{
Dhcp6Client
client
;
// Configure client to request IA_NA.
client
.
useNA
();
// Make 4-way exchange to get the lease.
ASSERT_NO_FATAL_FAILURE
(
requestLease
(
CONFIRM_CONFIGS
[
0
],
2
,
client
));
// Keep the client's lease for future reference.
Lease6
lease_client1
=
client
.
getLease
(
0
);
// Clone the lease and modify its address so as it is still in the range
// of the subnet to which the first lease belongs. When the client sends
// the Confirm it should include both addresses and the server should
// send Success because both of these addresses are on-link, regardless
// what the server has in the lease database.
Lease6
lease_client2
=
lease_client1
;
++
lease_client2
.
iaid_
;
lease_client2
.
addr_
=
bumpAddress
(
lease_client2
.
addr_
);
client
.
createLease
(
lease_client2
);
ASSERT_EQ
(
2
,
client
.
getLeaseNum
());
// Send Confirm message to the server.
ASSERT_NO_THROW
(
client
.
doConfirm
());
// Client should have received a status code option and this option should
// indicate the success.
ASSERT_TRUE
(
client
.
receivedStatusCode
());
ASSERT_EQ
(
STATUS_Success
,
client
.
getStatusCode
());
// Make sure that the server id and client id have been included.
EXPECT_TRUE
(
client
.
getContext
().
response_
->
getOption
(
D6O_SERVERID
));
EXPECT_TRUE
(
client
.
getContext
().
response_
->
getOption
(
D6O_CLIENTID
));
ASSERT_EQ
(
2
,
client
.
getLeaseNum
());
lease_client2
=
client
.
getLease
(
1
);
lease_client2
.
addr_
=
bumpSubnet
(
lease_client2
.
addr_
);
client
.
createLease
(
lease_client2
);
// Send confirm to the server. This time, one of the leases contains the
// address which doesn't belong to the configured subnet and the server
// should respond with STATUS_NotOnLink.
ASSERT_NO_THROW
(
client
.
doConfirm
());
ASSERT_TRUE
(
client
.
receivedStatusCode
());
ASSERT_EQ
(
STATUS_NotOnLink
,
client
.
getStatusCode
());
// Make sure that the server id have been included.
EXPECT_TRUE
(
client
.
getContext
().
response_
->
getOption
(
D6O_SERVERID
));
EXPECT_TRUE
(
client
.
getContext
().
response_
->
getOption
(
D6O_CLIENTID
));
}
// Test that relayed client's Confirm message is processed and Reply message
// is sent back (RFC3315, section 18.2.2).
TEST_F
(
ConfirmTest
,
relayedClient
)
{
Dhcp6Client
client
;
// Client to send relayed message.
client
.
useRelay
();
// Configure client to request IA_NA.
client
.
useNA
();
// Make 4-way exchange to get the lease.
ASSERT_NO_FATAL_FAILURE
(
requestLease
(
CONFIRM_CONFIGS
[
1
],
2
,
client
));
// Keep the client's lease for future reference.
Lease6
lease_client1
=
client
.
getLease
(
0
);
// Clone the lease and modify its address so as it is still in the range
// of the subnet to which the first lease belongs. When the client sends
// the Confirm it should include both addresses and the server should
// send Success because both of these addresses are on-link, regardless
// what the server has in the lease database.
Lease6
lease_client2
=
lease_client1
;
lease_client2
.
addr_
=
bumpAddress
(
lease_client2
.
addr_
);
++
lease_client2
.
iaid_
;
client
.
createLease
(
lease_client2
);
// Send Confirm message to the server.
ASSERT_NO_THROW
(
client
.
doConfirm
());
// Client should have received a status code option and this option should
// indicate the success.
ASSERT_TRUE
(
client
.
receivedStatusCode
());
ASSERT_EQ
(
STATUS_Success
,
client
.
getStatusCode
());
lease_client2
=
client
.
getLease
(
1
);
lease_client2
.
addr_
=
bumpSubnet
(
lease_client2
.
addr_
);
client
.
createLease
(
lease_client2
);
// Send confirm to the server. This time, one of the leases contains the
// address which doesn't belong to the configured subnet and the server
// should respond with STATUS_NotOnLink.
ASSERT_NO_THROW
(
client
.
doConfirm
());
ASSERT_TRUE
(
client
.
receivedStatusCode
());
ASSERT_EQ
(
STATUS_NotOnLink
,
client
.
getStatusCode
());
// Make sure that the server id and client id have been included.
EXPECT_TRUE
(
client
.
getContext
().
response_
->
getOption
(
D6O_SERVERID
));
EXPECT_TRUE
(
client
.
getContext
().
response_
->
getOption
(
D6O_CLIENTID
));
}
// Test that the Confirm message without any addresses is discarded
// (RFC3315, section 18.2.2).
TEST_F
(
ConfirmTest
,
relayedClientNoAddress
)
{
Dhcp6Client
client
;
// Configure the server.
configure
(
CONFIRM_CONFIGS
[
1
],
*
client
.
getServer
());
// Make sure we ended-up having expected number of subnets configured.
const
Subnet6Collection
*
subnets
=
CfgMgr
::
instance
().
getSubnets6
();
ASSERT_EQ
(
2
,
subnets
->
size
());
// Client to send relayed message.
client
.
useRelay
();
// Send Confirm message to the server. This message will contain no
// addresses because client has no leases.
ASSERT_NO_THROW
(
client
.
doConfirm
());
EXPECT_FALSE
(
client
.
getContext
().
response_
);
}
// This test checks that the server processes Confirm message correctly if
// the subnet can't be selected for the client (RFC3315, section 18.2.2).
TEST_F
(
ConfirmTest
,
relayedClientNoSubnet
)
{
Dhcp6Client
client
;
// Client to send relayed message.
client
.
useRelay
();
// Configure client to request IA_NA.
client
.
useNA
();
// Make 4-way exchange to get the lease.
ASSERT_NO_FATAL_FAILURE
(
requestLease
(
CONFIRM_CONFIGS
[
1
],
2
,
client
));
// Now that the client has a lease, let's remove any subnets to check
// how the server would respond to the Confirm.
ASSERT_NO_THROW
(
CfgMgr
::
instance
().
deleteSubnets6
());
// Send Confirm message to the server.
ASSERT_NO_THROW
(
client
.
doConfirm
());
// Client should have received a status code option and this option should
// indicate that the client is NotOnLink becuase subnet could not be
// selected.
ASSERT_TRUE
(
client
.
receivedStatusCode
());
ASSERT_EQ
(
STATUS_NotOnLink
,
client
.
getStatusCode
());
// Let's test another case that the client sends no addresses in the Confirm
// message. The subnet can't be selected for that client as in the previous
// case but this time the server must discard the client's message because
// it contains no addresses (is invalid).
// Set lifetimes to 0 so as the Confirm will ignore the specific address
// and send an empty IA_NA.
client
.
config_
.
leases_
[
0
].
lease_
.
preferred_lft_
=
0
;
client
.
config_
.
leases_
[
0
].
lease_
.
valid_lft_
=
0
;
ASSERT_NO_THROW
(
client
.
doConfirm
());
EXPECT_FALSE
(
client
.
getContext
().
response_
);
// Do similar test but this time remove the lease so as no IA_NA option
// is sent.
client
.
config_
.
clear
();
ASSERT_NO_THROW
(
client
.
doConfirm
());
EXPECT_FALSE
(
client
.
getContext
().
response_
);
}
// This test checks that the relayed Confirm messsage is processed by the server
// when sent to unicast address RFC3315, section 18.2.8).
TEST_F
(
ConfirmTest
,
relayedUnicast
)
{
Dhcp6Client
client
;
// Client to send relayed message.
client
.
useRelay
();
// Configure client to request IA_NA.
client
.
useNA
();
// Make 4-way exchange to get the lease.
ASSERT_NO_FATAL_FAILURE
(
requestLease
(
CONFIRM_CONFIGS
[
1
],
2
,
client
));
// Make sure we have got the lease.
ASSERT_GT
(
client
.
getLeaseNum
(),
0
);
client
.
setDestAddress
(
IOAddress
(
"2001:db8:1::1"
));
// Send Confirm message to the server.
ASSERT_NO_THROW
(
client
.
doConfirm
());
// Client should have received a response.
ASSERT_TRUE
(
client
.
getContext
().
response_
);
// Client should have received a status code option and this option should
// indicate the success.
ASSERT_TRUE
(
client
.
receivedStatusCode
());
ASSERT_EQ
(
STATUS_Success
,
client
.
getStatusCode
());
// Make sure that the server id and client id have been included.
EXPECT_TRUE
(
client
.
getContext
().
response_
->
getOption
(
D6O_SERVERID
));
EXPECT_TRUE
(
client
.
getContext
().
response_
->
getOption
(
D6O_CLIENTID
));
}
// This test checks that the Confirm message is discarded by the server if it
// has been sent to unicast address (RFC3315, section 15).
TEST_F
(
ConfirmTest
,
unicast
)
{
Dhcp6Client
client
;
// Configure client to request IA_NA.
client
.
useNA
();
// Make 4-way exchange to get the lease.
ASSERT_NO_FATAL_FAILURE
(
requestLease
(
CONFIRM_CONFIGS
[
0
],
2
,
client
));
// Make sure the client has got the lease.
ASSERT_GT
(
client
.
getLeaseNum
(),
0
);
// Send Confirm message to the server to the unicast address.
client
.
setDestAddress
(
IOAddress
(
"2001:db8:1::1"
));
ASSERT_NO_THROW
(
client
.
doConfirm
());
// Mak sure that the server discarded client's Confirm message.
EXPECT_FALSE
(
client
.
getContext
().
response_
);
}
}
// end of anonymous namespace
src/bin/dhcp6/tests/dhcp6_client.cc
View file @
4f43c309
...
...
@@ -58,8 +58,11 @@ Dhcp6Client::Dhcp6Client(boost::shared_ptr<NakedDhcpv6Srv>& srv) :
void
Dhcp6Client
::
applyRcvdConfiguration
(
const
Pkt6Ptr
&
reply
)
{
typedef
OptionCollection
Opts
;
// Get all options in the reply message and pick IA_NA and IA_PD.
// Get all options in the reply message and pick IA_NA, IA_PD and
// Status code.
Opts
opts
=
reply
->
options_
;
// Set the global status code to default: success and not received.
config_
.
resetGlobalStatusCode
();
for
(
Opts
::
const_iterator
opt
=
opts
.
begin
();
opt
!=
opts
.
end
();
++
opt
)
{
Option6IAPtr
ia
=
boost
::
dynamic_pointer_cast
<
Option6IA
>
(
opt
->
second
);
if
(
!
ia
)
{
...
...
@@ -137,6 +140,16 @@ Dhcp6Client::applyRcvdConfiguration(const Pkt6Ptr& reply) {
applyLease
(
lease_info
);
}
}
// Get the global status code.
OptionCustomPtr
status_code
=
boost
::
dynamic_pointer_cast
<
OptionCustom
>
(
reply
->
getOption
(
D6O_STATUS_CODE
));
// If status code has been sent, we override the default status code:
// Success and record that we have received the status code.
if
(
status_code
)
{
config_
.
received_status_code_
=
true
;
config_
.
status_code_
=
status_code
->
readInteger
<
uint16_t
>
(
0
);
}
}
void
...
...
@@ -150,7 +163,8 @@ Dhcp6Client::applyLease(const LeaseInfo& lease_info) {
// lease assignment so we keep what we have.
if
((
existing_lease
.
iaid_
==
lease_info
.
lease_
.
iaid_
)
&&
(
existing_lease
.
type_
==
lease_info
.
lease_
.
type_
)
&&
(
lease_info
.
lease_
.
addr_
!=
asiolink
::
IOAddress
(
"::"
)))
{
&&
(
lease_info
.
lease_
.
addr_
!=
asiolink
::
IOAddress
(
"::"
))
&&
(
existing_lease
.
addr_
==
lease_info
.
lease_
.
addr_
))
{
config_
.
leases_
[
i
]
=
lease_info
;
return
;
...
...
@@ -164,7 +178,6 @@ Dhcp6Client::applyLease(const LeaseInfo& lease_info) {
config_
.
leases_
.
push_back
(
lease_info
);
}
void
Dhcp6Client
::
copyIAs
(
const
Pkt6Ptr
&
source
,
const
Pkt6Ptr
&
dest
)
{
typedef
OptionCollection
Opts
;
...
...
@@ -184,33 +197,44 @@ void
Dhcp6Client
::
copyIAsFromLeases
(
const
Pkt6Ptr
&
dest
)
const
{
// Go over leases and create IA_NA and IA_PD options from them.
// Create one IA per lease.
for
(
std
::
vector
<
LeaseInfo
>::
const_iterator
info
=
config_
.
leases_
.
begin
();
info
!=
config_
.
leases_
.
end
();
++
info
)
{
Lease6
lease
=
info
->
lease_
;
if
(
lease
.
type_
==
Lease
::
TYPE_NA
)
{
Option6IAPtr
opt
(
new
Option6IA
(
D6O_IA_NA
,
lease
.
iaid_
));
opt
->
setT1
(
lease
.
t1_
);
opt
->
setT2
(
lease
.
t1_
);
opt
->
addOption
(
Option6IAAddrPtr
(
new
Option6IAAddr
(
D6O_IAADDR
,
lease
.
addr_
,
lease
.
preferred_lft_
,
lease
.
valid_lft_
)));
dest
->
addOption
(
opt
);
}
else
if
(
lease
.
type_
==
Lease
::
TYPE_PD
)
{
Option6IAPtr
opt
(
new
Option6IA
(
D6O_IA_PD
,
lease
.
iaid_
));
opt
->
setT1
(
lease
.
t1_
);
opt
->
setT2
(
lease
.
t1_
);
opt
->
addOption
(
Option6IAPrefixPtr
(
new
Option6IAPrefix
(
D6O_IAPREFIX
,
lease
.
addr_
,
lease
.
prefixlen_
,
lease
.
preferred_lft_
,
lease
.
valid_lft_
)));
dest
->
addOption
(
opt
);
std
::
set
<
uint32_t
>
iaids
=
getIAIDs
();
for
(
std
::
set
<
uint32_t
>::
const_iterator
iaid
=
iaids
.
begin
();
iaid
!=
iaids
.
end
();
++
iaid
)
{
std
::
vector
<
Lease6
>
leases
=
getLeasesByIAID
(
*
iaid
);
Option6IAPtr
opt
(
new
Option6IA
(
leases
[
0
].
type_
==
Lease
::
TYPE_NA
?
D6O_IA_NA
:
D6O_IA_PD
,
*
iaid
));
opt
->
setT1
(
leases
[
0
].
t1_
);
opt
->
setT2
(
leases
[
0
].
t2_
);
for
(
std
::
vector
<
Lease6
>::
const_iterator
lease
=
leases
.
begin
();
lease
!=
leases
.
end
();
++
lease
)
{
if
((
lease
->
preferred_lft_
!=
0
)
&&
(
lease
->
valid_lft_
!=
0
))
{
if
(
lease
->
type_
==
Lease
::
TYPE_NA
)
{
opt
->
addOption
(
Option6IAAddrPtr
(
new
Option6IAAddr
(
D6O_IAADDR
,
lease
->
addr_
,
lease
->
preferred_lft_
,
lease
->
valid_lft_
)));
}
else
if
(
lease
->
type_
==
Lease
::
TYPE_PD
)
{
opt
->
addOption
(
Option6IAAddrPtr
(
new
Option6IAPrefix
(
D6O_IAPREFIX
,
lease
->
addr_
,
lease
->
prefixlen_
,
lease
->
preferred_lft_
,
lease
->
valid_lft_
)));
}
}
}
dest
->
addOption
(
opt
);
}
}
void
Dhcp6Client
::
createLease
(
const
Lease6
&
lease
)
{
LeaseInfo
info
;
info
.
lease_
=
lease
;
applyLease
(
info
);
}
Pkt6Ptr
Dhcp6Client
::
createMsg
(
const
uint8_t
msg_type
)
{
Pkt6Ptr
msg
(
new
Pkt6
(
msg_type
,
curr_transid_
++
));
...
...
@@ -277,6 +301,19 @@ Dhcp6Client::doRebind() {
}
}
void
Dhcp6Client
::
doConfirm
()
{
context_
.
query_
=
createMsg
(
DHCPV6_CONFIRM
);
copyIAsFromLeases
(
context_
.
query_
);
sendMsg
(
context_
.
query_
);
context_
.
response_
=
receiveOneMsg
();
// Set the global status code to default: success and not received.
config_
.
resetGlobalStatusCode
();
if
(
context_
.
response_
)
{
applyRcvdConfiguration
(
context_
.
response_
);
}