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
ISC Open Source Projects
Kea
Commits
b966ebcc
Commit
b966ebcc
authored
Nov 05, 2012
by
Marcin Siodelski
Browse files
[2417] Append configured DHCPv6 options to server's response.
parent
38ebe09e
Changes
6
Hide whitespace changes
Inline
Side-by-side
src/bin/dhcp6/config_parser.cc
View file @
b966ebcc
...
...
@@ -602,7 +602,7 @@ private:
<<
" be equal to zero. Option code '0' is reserved in"
<<
" DHCPv6."
);
}
else
if
(
option_code
>
std
::
numeric_limits
<
uint16_t
>::
max
())
{
isc_throw
(
Dhcp6ConfigError
,
"Parser error: value of 'code' must not"
ciwtezcowy
isc_throw
(
Dhcp6ConfigError
,
"Parser error: value of 'code' must not"
<<
" exceed "
<<
std
::
numeric_limits
<
uint16_t
>::
max
());
}
// Check the option name has been specified, is non-empty and does not
...
...
src/bin/dhcp6/dhcp6_messages.mes
View file @
b966ebcc
...
...
@@ -110,6 +110,10 @@ This is a debug message issued during the IPv6 DHCP server startup.
It lists some information about the parameters with which the server
is running.
% DHCP6_NO_SUBNET_FOR_ADDRESS fail to find subnet for address: %1
This warning message indicates that server does not support subnet
that received DHCPv6 packet comes from.
% DHCP6_CONFIG_LOAD_FAIL failed to load configuration: %1
This critical error message indicates that the initial DHCPv6
configuration has failed. The server will start, but nothing will be
...
...
src/bin/dhcp6/dhcp6_srv.cc
View file @
b966ebcc
...
...
@@ -24,11 +24,16 @@
#include
<dhcp/option6_addrlst.h>
#include
<dhcp/option6_iaaddr.h>
#include
<dhcp/option6_ia.h>
#include
<dhcp/option6_int_array.h>
#include
<dhcp/pkt6.h>
#include
<dhcp/subnet.h>
#include
<dhcp/cfgmgr.h>
#include
<exceptions/exceptions.h>
#include
<util/io_utilities.h>
#include
<util/range_utilities.h>
#include
<boost/foreach.hpp>
using
namespace
isc
;
using
namespace
isc
::
asiolink
;
using
namespace
isc
::
dhcp
;
...
...
@@ -289,23 +294,63 @@ void Dhcpv6Srv::copyDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
// TODO: Should throw if there is no client-id (except anonymous INF-REQUEST)
}
void
Dhcpv6Srv
::
appendDefaultOptions
(
const
Pkt6Ptr
&
/*question*/
,
Pkt6Ptr
&
answer
)
{
// TODO: question is currently unused, but we need it at least to know
// message type we are answering
void
Dhcpv6Srv
::
appendDefaultOptions
(
const
Pkt6Ptr
&
question
,
Pkt6Ptr
&
answer
)
{
// add server-id
answer
->
addOption
(
getServerID
());
}
// Get the subnet object. It holds options to be sent to the client
// that belongs to the particular subnet.
Subnet6Ptr
subnet
=
CfgMgr
::
instance
().
getSubnet6
(
question
->
getRemoteAddr
());
// Warn if subnet is not supported and quit.
if
(
!
subnet
)
{
LOG_WARN
(
dhcp6_logger
,
DHCP6_NO_SUBNET_FOR_ADDRESS
)
.
arg
(
question
->
getRemoteAddr
().
toText
());
return
;
}
// Add DNS_SERVERS option. It should have been configured.
const
Subnet
::
OptionContainer
&
options
=
subnet
->
getOptions
();
const
Subnet
::
OptionContainerTypeIndex
&
idx
=
options
.
get
<
1
>
();
const
Subnet
::
OptionContainerTypeRange
range
=
idx
.
equal_range
(
D6O_NAME_SERVERS
);
// In theory we may have multiple options with the same
// option code. They are not differentiated right now
// until support for option spaces is implemented.
// Until that's the case, simply add the first found option.
if
(
std
::
distance
(
range
.
first
,
range
.
second
)
>
0
)
{
answer
->
addOption
(
range
.
first
->
option
);
}
}
void
Dhcpv6Srv
::
appendRequestedOptions
(
const
Pkt6Ptr
&
/*question*/
,
Pkt6Ptr
&
answer
)
{
// TODO: question is currently unused, but we need to extract ORO from it
// and act on its content. Now we just send DNS-SERVERS option.
void
Dhcpv6Srv
::
appendRequestedOptions
(
const
Pkt6Ptr
&
question
,
Pkt6Ptr
&
answer
)
{
// Get the subnet for a particular address.
Subnet6Ptr
subnet
=
CfgMgr
::
instance
().
getSubnet6
(
question
->
getRemoteAddr
());
if
(
!
subnet
)
{
LOG_WARN
(
dhcp6_logger
,
DHCP6_NO_SUBNET_FOR_ADDRESS
)
.
arg
(
question
->
getRemoteAddr
().
toText
());
return
;
}
// add dns-servers option
boost
::
shared_ptr
<
Option
>
dnsservers
(
new
Option6AddrLst
(
D6O_NAME_SERVERS
,
IOAddress
(
HARDCODED_DNS_SERVER
)));
answer
->
addOption
(
dnsservers
);
// Client requests some options using ORO option. Try to
// get this option from client's message.
boost
::
shared_ptr
<
Option6IntArray
<
uint16_t
>
>
option_oro
=
boost
::
dynamic_pointer_cast
<
Option6IntArray
<
uint16_t
>
>
(
question
->
getOption
(
D6O_ORO
));
// Option ORO not found. Don't do anything then.
if
(
!
option_oro
)
{
return
;
}
// Get the list of options that client requested.
const
std
::
vector
<
uint16_t
>&
requested_opts
=
option_oro
->
getValues
();
// Get the list of options configured for a subnet.
const
Subnet
::
OptionContainer
&
options
=
subnet
->
getOptions
();
const
Subnet
::
OptionContainerTypeIndex
&
idx
=
options
.
get
<
1
>
();
// Try to match requested options with those configured for a subnet.
// If match is found, append configured option to the answer message.
BOOST_FOREACH
(
uint16_t
opt
,
requested_opts
)
{
const
Subnet
::
OptionContainerTypeRange
&
range
=
idx
.
equal_range
(
opt
);
BOOST_FOREACH
(
Subnet
::
OptionDescriptor
desc
,
range
)
{
answer
->
addOption
(
desc
.
option
);
}
}
}
void
Dhcpv6Srv
::
assignLeases
(
const
Pkt6Ptr
&
question
,
Pkt6Ptr
&
answer
)
{
...
...
src/bin/dhcp6/dhcp6_srv.h
View file @
b966ebcc
...
...
@@ -171,8 +171,6 @@ protected:
/// @brief Appends requested options to server's answer.
///
/// Appends options requested by client to the server's answer.
/// TODO: This method is currently a stub. It just appends DNS-SERVERS
/// option.
///
/// @param question client's message
/// @param answer server's message (options will be added here)
...
...
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
View file @
b966ebcc
...
...
@@ -20,9 +20,13 @@
#include
<arpa/inet.h>
#include
<gtest/gtest.h>
#include
<dhcp6/config_parser.h>
#include
<dhcp6/dhcp6_srv.h>
#include
<dhcp/dhcp6.h>
#include
<dhcp/option6_ia.h>
#include
<dhcp6/dhcp6_srv.h>
#include
<dhcp/option6_addrlst.h>
#include
<dhcp/option6_int_array.h>
#include
<config/ccsession.h>
#include
<util/buffer.h>
#include
<util/range_utilities.h>
#include
<boost/scoped_ptr.hpp>
...
...
@@ -31,6 +35,9 @@ using namespace std;
using
namespace
isc
;
using
namespace
isc
::
dhcp
;
using
namespace
isc
::
util
;
using
namespace
isc
::
data
;
using
namespace
isc
::
config
;
using
namespace
isc
::
asiolink
;
// namespace has to be named, because friends are defined in Dhcpv6Srv class
// Maybe it should be isc::test?
...
...
@@ -53,11 +60,14 @@ public:
class
Dhcpv6SrvTest
:
public
::
testing
::
Test
{
public:
// these are empty for now, but let's keep them around
Dhcpv6SrvTest
(
)
{
Dhcpv6SrvTest
()
:
rcode_
(
-
1
)
{
}
~
Dhcpv6SrvTest
()
{
};
int
rcode_
;
ConstElementPtr
comment_
;
};
TEST_F
(
Dhcpv6SrvTest
,
basic
)
{
...
...
@@ -150,10 +160,40 @@ TEST_F(Dhcpv6SrvTest, DUID) {
}
}
TEST_F
(
Dhcpv6SrvTest
,
Solicit_basic
)
{
TEST_F
(
Dhcpv6SrvTest
,
solicitBasic
)
{
ConstElementPtr
x
;
string
config
=
"{
\"
interface
\"
: [
\"
all
\"
],"
"
\"
preferred-lifetime
\"
: 3000,"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
subnet6
\"
: [ { "
"
\"
pool
\"
: [
\"
2001:db8:1234::/80
\"
],"
"
\"
subnet
\"
:
\"
2001:db8:1234::/64
\"
, "
"
\"
option-data
\"
: [ {"
"
\"
name
\"
:
\"
OPTION_DNS_SERVERS
\"
,"
"
\"
code
\"
: 23,"
"
\"
data
\"
:
\"
2001 0DB8 1234 FFFF 0000 0000 0000 0001"
"2001 0DB8 1234 FFFF 0000 0000 0000 0002
\"
"
" },"
" {"
"
\"
name
\"
:
\"
OPTION_FOO
\"
,"
"
\"
code
\"
: 1000,"
"
\"
data
\"
:
\"
1234
\"
"
" } ]"
" } ],"
"
\"
valid-lifetime
\"
: 4000 }"
;
ElementPtr
json
=
Element
::
fromJSON
(
config
);
boost
::
scoped_ptr
<
NakedDhcpv6Srv
>
srv
;
ASSERT_NO_THROW
(
srv
.
reset
(
new
NakedDhcpv6Srv
())
);
EXPECT_NO_THROW
(
x
=
configureDhcp6Server
(
*
srv
,
json
));
ASSERT_TRUE
(
x
);
comment_
=
parseAnswer
(
rcode_
,
x
);
ASSERT_EQ
(
0
,
rcode_
);
// a dummy content for client-id
OptionBuffer
clntDuid
(
32
);
for
(
int
i
=
0
;
i
<
32
;
i
++
)
{
...
...
@@ -169,10 +209,10 @@ TEST_F(Dhcpv6SrvTest, Solicit_basic) {
sol
->
addOption
(
ia
);
// Let's not send address in solicit yet
/
/
boost::shared_ptr<Option6IAAddr>
addr(new Option6IAAddr(D6O_IAADDR,
//
IOAddress("2001:db8:1234:ffff::ffff"), 5001, 7001));
//
ia->addOption(addr);
//
sol->addOption(ia);
/
*
boost::shared_ptr<Option6IAAddr>
addr(new Option6IAAddr(D6O_IAADDR,
IOAddress("2001:db8:1234:ffff::ffff"), 5001, 7001));
ia->addOption(addr);
sol->addOption(ia);
*/
// constructed very simple SOLICIT message with:
// - client-id option (mandatory)
...
...
@@ -191,15 +231,38 @@ TEST_F(Dhcpv6SrvTest, Solicit_basic) {
boost
::
shared_ptr
<
Pkt6
>
reply
=
srv
->
processSolicit
(
sol
);
// check if we get response at all
ASSERT_TRUE
(
reply
!=
boost
::
shared_ptr
<
Pkt6
>
()
);
ASSERT_TRUE
(
reply
);
EXPECT_EQ
(
DHCPV6_ADVERTISE
,
reply
->
getType
()
);
EXPECT_EQ
(
1234
,
reply
->
getTransid
()
);
// We have not requested option with code 1000 so it should not
// be included in the response.
ASSERT_FALSE
(
reply
->
getOption
(
1000
));
// Let's now request option with code 1000.
// We expect that server will include this option in its reply.
boost
::
shared_ptr
<
Option6IntArray
<
uint16_t
>
>
option_oro
(
new
Option6IntArray
<
uint16_t
>
(
D6O_ORO
));
// Create vector with one code equal to 1000.
std
::
vector
<
uint16_t
>
codes
(
1
,
1000
);
// Pass this code to option.
option_oro
->
setValues
(
codes
);
// Append ORO to SOLICIT message.
sol
->
addOption
(
option_oro
);
// Need to process SOLICIT again after requesting new option.
reply
=
srv
->
processSolicit
(
sol
);
ASSERT_TRUE
(
reply
);
EXPECT_EQ
(
DHCPV6_ADVERTISE
,
reply
->
getType
());
OptionPtr
tmp
=
reply
->
getOption
(
D6O_IA_NA
);
ASSERT_TRUE
(
tmp
);
Option6IA
*
reply_ia
=
dynamic_cast
<
Option6IA
*>
(
tmp
.
get
());
boost
::
shared_ptr
<
Option6IA
>
reply_ia
=
boost
::
dynamic_pointer_cast
<
Option6IA
>
(
tmp
);
ASSERT_TRUE
(
reply_ia
);
EXPECT_EQ
(
234
,
reply_ia
->
getIAID
()
);
// check that there's an address included
...
...
@@ -219,6 +282,32 @@ TEST_F(Dhcpv6SrvTest, Solicit_basic) {
ASSERT_EQ
(
tmp
->
len
(),
srv
->
getServerID
()
->
len
()
);
EXPECT_TRUE
(
tmp
->
getData
()
==
srv
->
getServerID
()
->
getData
());
tmp
=
reply
->
getOption
(
D6O_NAME_SERVERS
);
ASSERT_TRUE
(
tmp
);
boost
::
shared_ptr
<
Option6AddrLst
>
reply_nameservers
=
boost
::
dynamic_pointer_cast
<
Option6AddrLst
>
(
tmp
);
ASSERT_TRUE
(
reply_nameservers
);
Option6AddrLst
::
AddressContainer
addrs
=
reply_nameservers
->
getAddresses
();
ASSERT_EQ
(
2
,
addrs
.
size
());
EXPECT_TRUE
(
addrs
[
0
]
==
IOAddress
(
"2001:db8:1234:FFFF::1"
));
EXPECT_TRUE
(
addrs
[
1
]
==
IOAddress
(
"2001:db8:1234:FFFF::2"
));
// There is a dummy option with code 1000 we requested from a server.
// Expect that this option is in server's response.
tmp
=
reply
->
getOption
(
1000
);
ASSERT_TRUE
(
tmp
);
// Check that the option contains valid data (from configuration).
std
::
vector
<
uint8_t
>
data
=
tmp
->
getData
();
ASSERT_EQ
(
2
,
data
.
size
());
const
uint8_t
foo_expected
[]
=
{
0x12
,
0x34
};
EXPECT_EQ
(
0
,
memcmp
(
&
data
[
0
],
foo_expected
,
2
));
// more checks to be implemented
}
...
...
src/lib/dhcp/libdhcp++.cc
View file @
b966ebcc
...
...
@@ -106,6 +106,11 @@ size_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
buf
.
begin
()
+
offset
,
buf
.
begin
()
+
offset
+
opt_len
));
break
;
case
D6O_ORO
:
opt
=
OptionPtr
(
new
Option6IntArray
<
uint16_t
>
(
opt_type
,
buf
.
begin
()
+
offset
,
buf
.
begin
()
+
offset
+
opt_len
));
break
;
default:
opt
=
OptionPtr
(
new
Option
(
Option
::
V6
,
opt_type
,
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment