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
20f8fca7
Commit
20f8fca7
authored
Mar 05, 2015
by
Tomek Mrugalski
🛰
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[3705] RSOO support added, unit-tests implemented.
parent
33f7238e
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
251 additions
and
0 deletions
+251
-0
src/bin/dhcp6/dhcp6_srv.cc
src/bin/dhcp6/dhcp6_srv.cc
+58
-0
src/bin/dhcp6/dhcp6_srv.h
src/bin/dhcp6/dhcp6_srv.h
+10
-0
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+183
-0
No files found.
src/bin/dhcp6/dhcp6_srv.cc
View file @
20f8fca7
...
...
@@ -444,6 +444,19 @@ bool Dhcpv6Srv::run() {
}
if
(
rsp
)
{
// Process relay-supplied options. It is important to call this very
// late in the process, because we now have all the options the
// server wanted to send already set. This is important, because
// RFC6422, section 6 states:
//
// The server SHOULD discard any options that appear in the RSOO
// for which it already has one or more candidates.
//
// So we ignore any RSOO options if there's an option with the same
// code already present.
processRSOO
(
query
,
rsp
);
rsp
->
setRemoteAddr
(
query
->
getRemoteAddr
());
rsp
->
setLocalAddr
(
query
->
getLocalAddr
());
...
...
@@ -2718,5 +2731,50 @@ Daemon::getVersion(bool extended) {
return
(
tmp
.
str
());
}
void
Dhcpv6Srv
::
processRSOO
(
const
Pkt6Ptr
&
query
,
const
Pkt6Ptr
&
rsp
)
{
if
(
query
->
relay_info_
.
empty
())
{
// RSOO is inserted by relay agents, nothing to do here if it's
// a direct message.
return
;
}
// Get the global options info. We'll use it to check whether an
// option is RSOO-enabled or not.
ConstCfgOptionPtr
global_opts
=
CfgMgr
::
instance
().
getCurrentCfg
()
->
getCfgOption
();
// Let's get over all relays (encapsulation levels). We need to do
// it in the same order as the client packet traversed the relays.
for
(
int
i
=
query
->
relay_info_
.
size
();
i
>
0
;
--
i
)
{
OptionPtr
rsoo_container
=
query
->
getRelayOption
(
D6O_RSOO
,
i
-
1
);
if
(
!
rsoo_container
)
{
// No relay-supplied options by this relay? Ok, carry on.
continue
;
}
// There are RSOO options. Let's get through them one by one
// and if it's RSOO-enabled and there's no such option provided yet,
// copy it to the server's response
const
OptionCollection
&
rsoo
=
rsoo_container
->
getOptions
();
for
(
OptionCollection
::
const_iterator
opt
=
rsoo
.
begin
();
opt
!=
rsoo
.
end
();
++
opt
)
{
if
(
!
global_opts
->
isRSOOEnabled
(
opt
->
second
->
getType
()))
{
// We didn't copy this option, because it's not RSOO-enabled.
continue
;
}
if
(
rsp
->
getOption
(
opt
->
second
->
getType
()))
{
// There is such an option in the server's response already,
// we'll skip relay's option
continue
;
}
// All checks went ok, let's add this option.
rsp
->
addOption
(
opt
->
second
);
}
}
}
};
};
src/bin/dhcp6/dhcp6_srv.h
View file @
20f8fca7
...
...
@@ -606,6 +606,16 @@ protected:
/// @return HWaddr pointer (or NULL if configured methods fail)
static
HWAddrPtr
getMAC
(
const
Pkt6Ptr
&
pkt
);
/// @brief Processes Relay-supplied options, if present
///
/// This method implements RFC6422. It checks if there are any RSOO options
/// inserted by the relay agents in the query message. If there are, they
/// are copied over to the response if the met the following criteria:
/// - the option is marked as RSOO-enabled (see relay-supplied-options
/// configuration parameter)
/// - there is no such option provided by the server)
void
processRSOO
(
const
Pkt6Ptr
&
query
,
const
Pkt6Ptr
&
rsp
);
/// @brief this is a prefix added to the contend of vendor-class option
///
/// If incoming packet has a vendor class option, its content is
...
...
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
View file @
20f8fca7
...
...
@@ -40,6 +40,7 @@
#include <hooks/server_hooks.h>
#include <dhcp6/tests/dhcp6_test_utils.h>
#include <dhcp6/tests/dhcp6_client.h>
#include <dhcp/tests/pkt_captures.h>
#include <config/ccsession.h>
#include <boost/pointer_cast.hpp>
...
...
@@ -2094,6 +2095,188 @@ TEST_F(Dhcpv6SrvTest, relayOverrideAndClientClass) {
EXPECT_TRUE
(
subnet1
==
srv_
.
selectSubnet
(
sol
));
}
/// @brief Creates RSOO option with suboptions
///
/// Creates Relay-Supplied Options option that includes nested options. The
/// codes of those nested options are specified in codes parameter. Content of
/// the options is controlled with payload parameter. When it is zero, option
/// code will be used (e.g. option 100 will contain repeating bytes of value 100).
/// When non-zero is used, payload will used. Each suboption is always set to
/// arbitrary chosen value of 10.
///
/// @param codes a vector of option codes to be created
/// @param payload specified payload (0 = fill payload with repeating option code)
/// @return RSOO with nested options
OptionPtr
createRSOO
(
const
std
::
vector
<
uint16_t
>
codes
,
uint8_t
payload
=
0
)
{
OptionDefinitionPtr
def
=
LibDHCP
::
getOptionDef
(
Option
::
V6
,
D6O_RSOO
);
if
(
!
def
)
{
isc_throw
(
BadValue
,
"Can't find RSOO definition"
);
}
OptionPtr
rsoo_container
(
new
OptionCustom
(
*
def
,
Option
::
V6
));
for
(
int
i
=
0
;
i
<
codes
.
size
();
++
i
)
{
OptionBuffer
buf
(
10
,
payload
?
payload
:
codes
[
i
]);
// let's make the option 10 bytes long
rsoo_container
->
addOption
(
OptionPtr
(
new
Option
(
Option
::
V6
,
codes
[
i
],
buf
)));
}
return
(
rsoo_container
);
}
// Test that the server processes RSOO (Relay Supplied Options option) correctly,
// i.e. it includes in its response the options that are inserted by the relay.
// The server must do this only for options that are RSOO-enabled.
TEST_F
(
Dhcpv6SrvTest
,
rsoo
)
{
Dhcp6Client
client
;
string
config
=
"{"
"
\"
relay-supplied-options
\"
: [
\"
110
\"
,
\"
120
\"
,
\"
130
\"
],"
"
\"
preferred-lifetime
\"
: 3000,"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
subnet6
\"
: [ { "
"
\"
pools
\"
: [ {
\"
pool
\"
:
\"
2001:db8::/64
\"
} ],"
"
\"
subnet
\"
:
\"
2001:db8::/48
\"
"
" } ],"
"
\"
valid-lifetime
\"
: 4000"
"}"
;
EXPECT_NO_THROW
(
configure
(
config
,
*
client
.
getServer
()));
// Now pretend the packet came via one relay.
Pkt6
::
RelayInfo
relay
;
relay
.
msg_type_
=
DHCPV6_RELAY_FORW
;
relay
.
hop_count_
=
1
;
relay
.
linkaddr_
=
IOAddress
(
"2001:db8::1"
);
relay
.
peeraddr_
=
IOAddress
(
"fe80::1"
);
vector
<
uint16_t
>
rsoo1
;
rsoo1
.
push_back
(
109
);
rsoo1
.
push_back
(
110
);
rsoo1
.
push_back
(
111
);
// The relay will request echoing back 3 options: 109, 110, 111.
// The configuration allows echoing back only 110.
OptionPtr
opt
=
createRSOO
(
rsoo1
);
relay
.
options_
.
insert
(
make_pair
(
opt
->
getType
(),
opt
));
client
.
relay_info_
.
push_back
(
relay
);
client
.
doSARR
();
// Option 110 should be copied to the client
EXPECT_NE
(
client
.
config_
.
options_
.
find
(
110
),
client
.
config_
.
options_
.
end
());
// Options 109 and 111 should not be copied (they are not RSOO-enabled)
EXPECT_EQ
(
client
.
config_
.
options_
.
find
(
109
),
client
.
config_
.
options_
.
end
());
EXPECT_EQ
(
client
.
config_
.
options_
.
find
(
111
),
client
.
config_
.
options_
.
end
());
}
// Test that the server processes RSOO (Relay Supplied Options option) correctly
// when there are more relays. In particular, the following case is tested:
// if relay1 inserts option A and B, relay2 inserts option B and C, the response
// should include options A, B and C. The server must use instance of option B
// that comes from the first relay, not the second one.
TEST_F
(
Dhcpv6SrvTest
,
rsoo2relays
)
{
Dhcp6Client
client
;
string
config
=
"{"
"
\"
relay-supplied-options
\"
: [
\"
110
\"
,
\"
120
\"
,
\"
130
\"
],"
"
\"
preferred-lifetime
\"
: 3000,"
"
\"
rebind-timer
\"
: 2000, "
"
\"
renew-timer
\"
: 1000, "
"
\"
subnet6
\"
: [ { "
"
\"
pools
\"
: [ {
\"
pool
\"
:
\"
2001:db8::/64
\"
} ],"
"
\"
subnet
\"
:
\"
2001:db8::/48
\"
"
" } ],"
"
\"
valid-lifetime
\"
: 4000"
"}"
;
EXPECT_NO_THROW
(
configure
(
config
,
*
client
.
getServer
()));
// Now pretend the packet came via two relays.
// This situation reflects the following case:
// client----relay1----relay2----server
// Fabricate the first relay.
Pkt6
::
RelayInfo
relay1
;
relay1
.
msg_type_
=
DHCPV6_RELAY_FORW
;
relay1
.
hop_count_
=
1
;
relay1
.
linkaddr_
=
IOAddress
(
"2001:db8::1"
);
relay1
.
peeraddr_
=
IOAddress
(
"fe80::1"
);
vector
<
uint16_t
>
rsoo1
;
rsoo1
.
push_back
(
110
);
// The relay1 will send 2 options: 110, 120
rsoo1
.
push_back
(
120
);
OptionPtr
opt
=
createRSOO
(
rsoo1
,
1
);
// use 0x1 as payload
relay1
.
options_
.
insert
(
make_pair
(
opt
->
getType
(),
opt
));
// Now the second relay.
Pkt6
::
RelayInfo
relay2
;
relay2
.
msg_type_
=
DHCPV6_RELAY_FORW
;
relay2
.
hop_count_
=
1
;
relay2
.
linkaddr_
=
IOAddress
(
"2001:db8::1"
);
relay2
.
peeraddr_
=
IOAddress
(
"fe80::1"
);
vector
<
uint16_t
>
rsoo2
;
rsoo2
.
push_back
(
120
);
// The relay2 will send 2 options: 120, 130
rsoo2
.
push_back
(
130
);
opt
=
createRSOO
(
rsoo2
,
2
);
// use 0x2 as payload
relay2
.
options_
.
insert
(
make_pair
(
opt
->
getType
(),
opt
));
// The relays ecapsulate packet in this order: relay1, relay2, but the server
// decapsulates the packet in reverse order.
client
.
relay_info_
.
push_back
(
relay2
);
client
.
relay_info_
.
push_back
(
relay1
);
// There's a conflict here. Both relays want the server to echo back option
// 120. According to RFC6422, section 6:
//
// When such a conflict exists, the DHCP server MUST choose no more than
// one of these options to forward to the client. The DHCP server MUST
// NOT forward more than one of these options to the client.
//
// By default, the DHCP server MUST choose the innermost value -- the
// value supplied by the relay agent closest to the DHCP client -- to
// forward to the DHCP client.
// Let the client do his thing.
client
.
doSARR
();
int
count110
=
0
;
// Let's count how many times option 110 was echoed back
int
count120
=
0
;
// Let's count how many times option 120 was echoed back
int
count130
=
0
;
// Let's count how many times option 130 was echoed back
OptionPtr
opt120
;
for
(
OptionCollection
::
const_iterator
it
=
client
.
config_
.
options_
.
begin
();
it
!=
client
.
config_
.
options_
.
end
();
++
it
)
{
switch
(
it
->
second
->
getType
())
{
case
110
:
count110
++
;
break
;
case
120
:
count120
++
;
opt120
=
it
->
second
;
break
;
case
130
:
count130
++
;
break
;
default:
break
;
}
}
// We expect to have exactly one instance of each option code.
EXPECT_EQ
(
1
,
count110
);
EXPECT_EQ
(
1
,
count120
);
EXPECT_EQ
(
1
,
count130
);
// Now, let's check if the proper instance of option 120 was sent. It should
// match the content of what the first relay had sent.
ASSERT_TRUE
(
opt120
);
vector
<
uint8_t
>
expected
(
10
,
1
);
EXPECT_EQ
(
expected
,
opt120
->
getData
());
}
/// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
/// to call processX() methods.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a 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