Commit bb00d9d2 authored by Shawn Routhier's avatar Shawn Routhier

Merge branch 'trac4265' Access to options and constants from DHCP6 relay encapsulations

parents 3b34ad14 0e4e33ca
1102. [func] sar
Added access to the peer address, link address and option
information added by relays in a DHCPv6 message.
(Trac $4269, git tbd)
1101. [bug] stephen
Made DHCPSRV_MEMFILE_LFC_UNREGISTER_TIMER_FAILED a debug message as the
condition leading to it (trying to unregister a timer that is not
......
......@@ -170,6 +170,24 @@
sub-option</entry><entry>relay4[code].hex</entry><entry>The value of
sub-option with code "code" from the DHCPv4 Relay Agent Information option
(option 82)</entry></row>
<row>
<entry>DHCPv6 Relay Options</entry>
<entry>relay6[nest].option[code].hex</entry>
<!-- <entry>Value of the option</entry> -->
<entry>The value of the option with code "code" from the relay encapsulation "nest"</entry>
</row>
<row>
<entry>DHCPv6 Relay Peer Address</entry>
<entry>relay6[nest].peeraddr</entry>
<!-- <entry>2001:DB8::1</entry> -->n
<entry>The value of the peer address field from the relay encapsulation "nest"</entry>
</row>
<row>
<entry>DHCPv6 Relay Link Address</entry>
<entry>relay6[nest].linkaddr</entry>
<!-- <entry>2001:DB8::1</entry> -->n
<entry>The value of the link address field from the relay encapsulation "nest"</entry>
</row>
</tbody>
</tgroup>
</table>
......@@ -211,10 +229,24 @@ sub-option with code "code" from the DHCPv4 Relay Agent Information option
</para>
<para>
"relay4" shares the same representation types than "option", for
"relay4" shares the same representation types as "option", for
instance "relay4[code].exists" is supported.
</para>
<para>
"relay6[nest]" allows access to the encapsulations used by any DHCPv6
relays that forwarded the packet. The "nest" level specifies the relay
from which to extract the information, with a value of 0 indicating
the relay closest to the DHCPv6 server. If the requested encapsulation
doesn't exist an empty string "" is returned. This expression is
allowed in DHCPv6 only.
</para>
<para>
"relay6[nest].option[code]" shares the same representation types as
"option", for instance "relay6[nest].option[code].exists" is supported.
</para>
<para>
<table frame="all" id="classification-expressions-list">
<title>List of Classification Expressions</title>
......
// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -112,22 +112,40 @@ OptionPtr Pkt6::getAnyRelayOption(uint16_t opt_type, RelaySearchOrder order) {
return (OptionPtr());
}
OptionPtr Pkt6::getRelayOption(uint16_t opt_type, uint8_t relay_level) {
OptionPtr Pkt6::getRelayOption(uint16_t opt_type, uint8_t relay_level) const {
if (relay_level >= relay_info_.size()) {
isc_throw(OutOfRange, "This message was relayed " << relay_info_.size() << " time(s)."
<< " There is no info about " << relay_level + 1 << " relay.");
}
for (OptionCollection::iterator it = relay_info_[relay_level].options_.begin();
it != relay_info_[relay_level].options_.end(); ++it) {
if ((*it).second->getType() == opt_type) {
return (it->second);
}
}
OptionCollection::const_iterator x = relay_info_[relay_level].options_.find(opt_type);
if (x != relay_info_[relay_level].options_.end()) {
return (*x).second;
}
return (OptionPtr());
}
const isc::asiolink::IOAddress&
Pkt6::getRelay6LinkAddress(uint8_t relay_level) const {
if (relay_level >= relay_info_.size()) {
isc_throw(OutOfRange, "This message was relayed " << relay_info_.size() << " time(s)."
<< " There is no info about " << relay_level + 1 << " relay.");
}
return (relay_info_[relay_level].linkaddr_);
}
const isc::asiolink::IOAddress&
Pkt6::getRelay6PeerAddress(uint8_t relay_level) const {
if (relay_level >= relay_info_.size()) {
isc_throw(OutOfRange, "This message was relayed " << relay_info_.size() << " time(s)."
<< " There is no info about " << relay_level + 1 << " relay.");
}
return (relay_info_[relay_level].peeraddr_);
}
uint16_t Pkt6::getRelayOverhead(const RelayInfo& relay) const {
uint16_t len = DHCPV6_RELAY_HDR_LEN // fixed header
+ Option::OPTION6_HDR_LEN; // header of the relay-msg option
......@@ -429,7 +447,7 @@ Pkt6::unpackRelayMsg() {
void
Pkt6::addRelayInfo(const RelayInfo& relay) {
if (relay_info_.size() > 32) {
if (relay_info_.size() > HOP_COUNT_LIMIT) {
isc_throw(BadValue, "Massage cannot be encapsulated more than 32 times");
}
......
// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -239,7 +239,7 @@ public:
/// @param nesting_level see description above
///
/// @return pointer to the option (or NULL if there is no such option)
OptionPtr getRelayOption(uint16_t option_code, uint8_t nesting_level);
OptionPtr getRelayOption(uint16_t option_code, uint8_t nesting_level) const;
/// @brief Return first instance of a specified option
///
......@@ -253,6 +253,39 @@ public:
/// @return option pointer (or NULL if no option matches specified criteria)
OptionPtr getAnyRelayOption(uint16_t option_code, RelaySearchOrder order);
/// @brief return the link address field from a relay option
///
/// As with @c Pkt6::getRelayOption this returns information from the
/// specified relay scope. The relay_level specifies which relay
/// scope is to be used. 0 is the outermost encapsulation (relay closest
/// to the server). pkt->relay_info_.size() -1 is the innermost encapsulation
/// (relay closest to the client).
///
/// @throw isc::OutOfRange if relay level has an invalid value.
///
/// @param relay_level see description above
///
/// @return pointer to the link address field
const isc::asiolink::IOAddress&
getRelay6LinkAddress(uint8_t relay_level) const;
/// @brief return the peer address field from a relay option
///
/// As with @c Pkt6::getRelayOption this returns information from the
/// specified relay scope. The relay_level specifies which relay
/// scope is to be used. 0 is the outermost encapsulation (relay closest
/// to the server). pkt->relay_info_.size() -1 is the innermost encapsulation
/// (relay closest to the client).
///
/// @throw isc::OutOfRange if relay level has an invalid value.
///
/// @param relay_level see description above
///
/// @return pointer to the peer address field
const isc::asiolink::IOAddress&
getRelay6PeerAddress(uint8_t relay_level) const;
///
/// @brief Returns all instances of specified type.
///
/// Returns all instances of options of the specified type. DHCPv6 protocol
......@@ -279,13 +312,13 @@ public:
/// @param type DHCPv6 message type which name should be returned.
///
/// @return Pointer to "const" string containing the message name. If
/// the message type is unknnown the "UNKNOWN" is returned. The caller
/// the message type is unknown the "UNKNOWN" is returned. The caller
/// must not release the returned pointer.
static const char* getName(const uint8_t type);
/// @brief Returns name of the DHCPv6 message.
///
/// This method requires an object. There is also static version, which
/// This method requires an object. There is also a static version, which
/// requires one parameter (type).
///
/// @return Pointer to "const" string containing the message name. If
......
// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -763,7 +763,7 @@ TEST_F(Pkt6Test, relayPack) {
Pkt6::RelayInfo relay1;
relay1.msg_type_ = DHCPV6_RELAY_REPL;
relay1.hop_count_ = 17; // not very miningful, but useful for testing
relay1.hop_count_ = 17; // not very meaningful, but useful for testing
relay1.linkaddr_ = IOAddress("2001:db8::1");
relay1.peeraddr_ = IOAddress("fe80::abcd");
......@@ -830,6 +830,16 @@ TEST_F(Pkt6Test, relayPack) {
OptionBuffer data = opt->getData();
ASSERT_EQ(data.size(), sizeof(relay_opt_data));
EXPECT_EQ(0, memcmp(&data[0], relay_opt_data, sizeof(relay_opt_data)));
// As we have a nicely built relay packet we can check
// that the functions to get the peer and link addreses work
EXPECT_EQ("2001:db8::1", clone->getRelay6LinkAddress(0).toText());
EXPECT_EQ("fe80::abcd", clone->getRelay6PeerAddress(0).toText());
vector<uint8_t>binary = clone->getRelay6LinkAddress(0).toBytes();
uint8_t expected0[] = {0x20, 1, 0x0d, 0xb8, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1};
EXPECT_EQ(0, memcmp(expected0, &binary[0], 16));
}
......
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <dhcp/dhcp6.h>
#include <dhcp/option.h>
#include <dhcp/option_definition.h>
#include <dhcp/libdhcp++.h>
......@@ -92,6 +93,29 @@ EvalContext::convertOptionName(const std::string& option_name,
return (option_def->getCode());
}
uint8_t
EvalContext::convertNestLevelNumber(const std::string& nest_level,
const isc::eval::location& loc)
{
int n = 0;
try {
n = boost::lexical_cast<int>(nest_level);
} catch (const boost::bad_lexical_cast &) {
error(loc, "Nest level has invalid value in " + nest_level);
}
if (option_universe_ == Option::V6) {
if (n < 0 || n >= HOP_COUNT_LIMIT) {
error(loc, "Nest level has invalid value in "
+ nest_level + ". Allowed range: 0..31");
}
} else {
error(loc, "Nest level invalid for DHCPv4 packets");
}
return (static_cast<uint8_t>(n));
}
void
EvalContext::fatal (const std::string& what)
{
......
......@@ -82,12 +82,12 @@ public:
/// This is for should not happen but fatal errors
static void fatal(const std::string& what);
/// @brief Option code convertion
/// @brief Option code conversion
///
/// @param option_code a string representing the integer code
/// @param loc the location of the token
/// @result the option code
/// @throw calls the syntax error function if the value is no in
/// @throw calls the syntax error function if the value is not in
/// the range 0..255 or 0..65535
uint16_t convertOptionCode(const std::string& option_code,
const isc::eval::location& loc);
......@@ -101,6 +101,16 @@ public:
uint16_t convertOptionName(const std::string& option_name,
const isc::eval::location& loc);
/// @brief Nest level conversion
///
/// @param nest_level a string representing the integer nesting level
/// @param loc the location of the token
/// @result the nesting level
/// @throw calls the syntax error function if the value is not in
/// the range 0..31
uint8_t convertNestLevelNumber(const std::string& nest_level,
const isc::eval::location& loc);
/// @brief Returns the universe (v4 or v6)
///
/// @return universe
......
This diff is collapsed.
......@@ -143,6 +143,9 @@ addr6 [0-9a-fA-F]*\:[0-9a-fA-F]*\:[0-9a-fA-F:.]*
"==" return isc::eval::EvalParser::make_EQUAL(loc);
"option" return isc::eval::EvalParser::make_OPTION(loc);
"relay4" return isc::eval::EvalParser::make_RELAY4(loc);
"relay6" return isc::eval::EvalParser::make_RELAY6(loc);
"peeraddr" return isc::eval::EvalParser::make_PEERADDR(loc);
"linkaddr" return isc::eval::EvalParser::make_LINKADDR(loc);
"text" return isc::eval::EvalParser::make_TEXT(loc);
"hex" return isc::eval::EvalParser::make_HEX(loc);
"exists" return isc::eval::EvalParser::make_EXISTS(loc);
......
This diff is collapsed.
......@@ -298,15 +298,21 @@ namespace isc { namespace eval {
// option_repr_type
char dummy1[sizeof(TokenOption::RepresentationType)];
// relay6_field
char dummy2[sizeof(TokenRelay6Field::FieldType)];
// "constant string"
// "integer"
// "constant hexstring"
// "option name"
// "ip address"
char dummy2[sizeof(std::string)];
char dummy3[sizeof(std::string)];
// option_code
char dummy3[sizeof(uint16_t)];
char dummy4[sizeof(uint16_t)];
// nest_level
char dummy5[sizeof(uint8_t)];
};
/// Symbol semantic values.
......@@ -338,21 +344,24 @@ namespace isc { namespace eval {
TOKEN_EQUAL = 263,
TOKEN_OPTION = 264,
TOKEN_RELAY4 = 265,
TOKEN_LBRACKET = 266,
TOKEN_RBRACKET = 267,
TOKEN_DOT = 268,
TOKEN_TEXT = 269,
TOKEN_HEX = 270,
TOKEN_EXISTS = 271,
TOKEN_SUBSTRING = 272,
TOKEN_ALL = 273,
TOKEN_COMA = 274,
TOKEN_CONCAT = 275,
TOKEN_STRING = 276,
TOKEN_INTEGER = 277,
TOKEN_HEXSTRING = 278,
TOKEN_OPTION_NAME = 279,
TOKEN_IP_ADDRESS = 280
TOKEN_RELAY6 = 266,
TOKEN_PEERADDR = 267,
TOKEN_LINKADDR = 268,
TOKEN_LBRACKET = 269,
TOKEN_RBRACKET = 270,
TOKEN_DOT = 271,
TOKEN_TEXT = 272,
TOKEN_HEX = 273,
TOKEN_EXISTS = 274,
TOKEN_SUBSTRING = 275,
TOKEN_ALL = 276,
TOKEN_COMA = 277,
TOKEN_CONCAT = 278,
TOKEN_STRING = 279,
TOKEN_INTEGER = 280,
TOKEN_HEXSTRING = 281,
TOKEN_OPTION_NAME = 282,
TOKEN_IP_ADDRESS = 283
};
};
......@@ -392,10 +401,14 @@ namespace isc { namespace eval {
basic_symbol (typename Base::kind_type t, const TokenOption::RepresentationType v, const location_type& l);
basic_symbol (typename Base::kind_type t, const TokenRelay6Field::FieldType v, const location_type& l);
basic_symbol (typename Base::kind_type t, const std::string v, const location_type& l);
basic_symbol (typename Base::kind_type t, const uint16_t v, const location_type& l);
basic_symbol (typename Base::kind_type t, const uint8_t v, const location_type& l);
/// Constructor for symbols with semantic value.
basic_symbol (typename Base::kind_type t,
......@@ -499,6 +512,18 @@ namespace isc { namespace eval {
symbol_type
make_RELAY4 (const location_type& l);
static inline
symbol_type
make_RELAY6 (const location_type& l);
static inline
symbol_type
make_PEERADDR (const location_type& l);
static inline
symbol_type
make_LINKADDR (const location_type& l);
static inline
symbol_type
make_LBRACKET (const location_type& l);
......@@ -665,7 +690,7 @@ namespace isc { namespace eval {
static const char* const yytname_[];
#if YYDEBUG
// YYRLINE[YYN] -- Source line where rule number YYN was defined.
static const unsigned char yyrline_[];
static const unsigned short int yyrline_[];
/// Report on the debug stream that the rule \a r is going to be reduced.
virtual void yy_reduce_print_ (int r);
/// Print the state stack on the debug stream.
......@@ -764,12 +789,12 @@ namespace isc { namespace eval {
enum
{
yyeof_ = 0,
yylast_ = 69, ///< Last index in yytable_.
yynnts_ = 8, ///< Number of nonterminal symbols.
yyfinal_ = 19, ///< Termination state number.
yylast_ = 98, ///< Last index in yytable_.
yynnts_ = 10, ///< Number of nonterminal symbols.
yyfinal_ = 21, ///< Termination state number.
yyterror_ = 1,
yyerrcode_ = 256,
yyntokens_ = 26 ///< Number of tokens.
yyntokens_ = 29 ///< Number of tokens.
};
......@@ -814,9 +839,9 @@ namespace isc { namespace eval {
2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25
25, 26, 27, 28
};
const unsigned int user_token_number_max_ = 280;
const unsigned int user_token_number_max_ = 283;
const token_number_type undef_token_ = 2;
if (static_cast<int>(t) <= yyeof_)
......@@ -849,22 +874,30 @@ namespace isc { namespace eval {
{
switch (other.type_get ())
{
case 31: // option_repr_type
case 34: // option_repr_type
value.copy< TokenOption::RepresentationType > (other.value);
break;
case 21: // "constant string"
case 22: // "integer"
case 23: // "constant hexstring"
case 24: // "option name"
case 25: // "ip address"
case 37: // relay6_field
value.copy< TokenRelay6Field::FieldType > (other.value);
break;
case 24: // "constant string"
case 25: // "integer"
case 26: // "constant hexstring"
case 27: // "option name"
case 28: // "ip address"
value.copy< std::string > (other.value);
break;
case 30: // option_code
case 33: // option_code
value.copy< uint16_t > (other.value);
break;
case 38: // nest_level
value.copy< uint8_t > (other.value);
break;
default:
break;
}
......@@ -882,22 +915,30 @@ namespace isc { namespace eval {
(void) v;
switch (this->type_get ())
{
case 31: // option_repr_type
case 34: // option_repr_type
value.copy< TokenOption::RepresentationType > (v);
break;
case 21: // "constant string"
case 22: // "integer"
case 23: // "constant hexstring"
case 24: // "option name"
case 25: // "ip address"
case 37: // relay6_field
value.copy< TokenRelay6Field::FieldType > (v);
break;
case 24: // "constant string"
case 25: // "integer"
case 26: // "constant hexstring"
case 27: // "option name"
case 28: // "ip address"
value.copy< std::string > (v);
break;
case 30: // option_code
case 33: // option_code
value.copy< uint16_t > (v);
break;
case 38: // nest_level
value.copy< uint8_t > (v);
break;
default:
break;
}
......@@ -920,6 +961,13 @@ namespace isc { namespace eval {
, location (l)
{}
template <typename Base>
EvalParser::basic_symbol<Base>::basic_symbol (typename Base::kind_type t, const TokenRelay6Field::FieldType v, const location_type& l)
: Base (t)
, value (v)
, location (l)
{}
template <typename Base>
EvalParser::basic_symbol<Base>::basic_symbol (typename Base::kind_type t, const std::string v, const location_type& l)
: Base (t)
......@@ -934,6 +982,13 @@ namespace isc { namespace eval {
, location (l)
{}
template <typename Base>
EvalParser::basic_symbol<Base>::basic_symbol (typename Base::kind_type t, const uint8_t v, const location_type& l)
: Base (t)
, value (v)
, location (l)
{}
template <typename Base>
inline
......@@ -960,22 +1015,30 @@ namespace isc { namespace eval {
// Type destructor.
switch (yytype)
{
case 31: // option_repr_type
case 34: // option_repr_type
value.template destroy< TokenOption::RepresentationType > ();
break;
case 21: // "constant string"
case 22: // "integer"
case 23: // "constant hexstring"
case 24: // "option name"
case 25: // "ip address"
case 37: // relay6_field
value.template destroy< TokenRelay6Field::FieldType > ();
break;
case 24: // "constant string"
case 25: // "integer"
case 26: // "constant hexstring"
case 27: // "option name"
case 28: // "ip address"
value.template destroy< std::string > ();
break;
case 30: // option_code
case 33: // option_code
value.template destroy< uint16_t > ();
break;
case 38: // nest_level
value.template destroy< uint8_t > ();
break;
default:
break;
}
......@@ -999,22 +1062,30 @@ namespace isc { namespace eval {
super_type::move(s);
switch (this->type_get ())
{
case 31: // option_repr_type
case 34: // option_repr_type
value.move< TokenOption::RepresentationType > (s.value);
break;
case 21: // "constant string"
case 22: // "integer"
case 23: // "constant hexstring"
case 24: // "option name"
case 25: // "ip address"
case 37: // relay6_field
value.move< TokenRelay6Field::FieldType > (s.value);
break;
case 24: // "constant string"
case 25: // "integer"
case 26: // "constant hexstring"
case 27: // "option name"
case 28: // "ip address"
value.move< std::string > (s.value);
break;
case 30: // option_code
case 33: // option_code
value.move< uint16_t > (s.value);
break;
case 38: // nest_level
value.move< uint8_t > (s.value);
break;
default:
break;
}
......@@ -1072,7 +1143,7 @@ namespace isc { namespace eval {
{
0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
275, 276, 277, 278, 279, 280
275, 276, 277, 278, 279, 280, 281, 282, 283
};
return static_cast<token_type> (yytoken_number_[type]);
}
......@@ -1131,6 +1202,24 @@ namespace isc { namespace eval {
return symbol_type (token::TOKEN_RELAY4, l);
}
EvalParser::symbol_type
EvalParser::make_RELAY6 (const location_type& l)
{
return symbol_type (token::TOKEN_RELAY6, l);
}
EvalParser::symbol_type
EvalParser::make_PEERADDR (const location_type& l)
{
return symbol_type (token::TOKEN_PEERADDR, l);
}
EvalParser::symbol_type
EvalParser::make_LINKADDR (const location_type& l)
{
return symbol_type (token::TOKEN_LINKADDR, l);