summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomek Mrugalski <tomasz@isc.org>2016-02-02 23:17:22 +0100
committerTomek Mrugalski <tomasz@isc.org>2016-02-02 23:17:22 +0100
commit6325cf1aefb95b862069dc4aaaf31184f70ee2ce (patch)
tree7dd67f0afd5f4ccdf6a3378758f2fa91a9915873
parent[master] version update (diff)
downloadkea-6325cf1aefb95b862069dc4aaaf31184f70ee2ce.tar.xz
kea-6325cf1aefb95b862069dc4aaaf31184f70ee2ce.zip
[4264] relay[123].hex token implemented.
-rw-r--r--doc/guide/classify.xml14
-rw-r--r--src/lib/eval/eval.dox2
-rw-r--r--src/lib/eval/eval_context.h7
-rw-r--r--src/lib/eval/lexer.ll1
-rw-r--r--src/lib/eval/parser.yy14
-rw-r--r--src/lib/eval/tests/context_unittest.cc39
-rw-r--r--src/lib/eval/tests/token_unittest.cc79
-rw-r--r--src/lib/eval/token.cc24
-rw-r--r--src/lib/eval/token.h42
9 files changed, 220 insertions, 2 deletions
diff --git a/doc/guide/classify.xml b/doc/guide/classify.xml
index 6dea8e5694..5bbbb9f803 100644
--- a/doc/guide/classify.xml
+++ b/doc/guide/classify.xml
@@ -164,6 +164,10 @@
<row><entry>Option Text</entry><entry>option[code].text</entry><entry>The value of the option with code "code" from the packet as text</entry></row>
-->
<row><entry>Option Hex</entry><entry>option[code].hex</entry><entry>The value of the option with code "code" from the packet as hex</entry></row>
+<row><entry>DHCPv4 Relay Agent
+sub-option</entry><entry>relay[code].hex</entry><entry>The value of
+sub-option with code "code" from the Relay Agent Information option
+(option 82)</entry></row>
</tbody>
</tgroup>
</table>
@@ -185,6 +189,16 @@
</para>
<para>
+ "relay[code].hex" attempts to extract value of the sub-option
+ "code" from the option inserted by the Relay Agent Information
+ (82) option. If the packet doesn't contain RAI option, or RAI
+ doesn't contain searched sub-option, the expression returns
+ empty string. The string is presented as a byte string of the
+ option payload without the type code or length fields. This
+ expression is allowed in DHCPv4 only.
+ </para>
+
+ <para>
<table frame="all" id="classification-expressions-list">
<title>List of Classification Expressions</title>
<tgroup cols='3'>
diff --git a/src/lib/eval/eval.dox b/src/lib/eval/eval.dox
index 590e15c9a0..b95b8ff03d 100644
--- a/src/lib/eval/eval.dox
+++ b/src/lib/eval/eval.dox
@@ -139,6 +139,8 @@ instantiated with the appropriate value and put onto the expression vector.
option[123].text;
- isc::dhcp::TokenEqual - represents equal (==) operator;
- isc::dhcp::TokenSubstring - represents substring(text, start, length) operator;
+ - isc::dhcp::TokenRelay4Option - represents a sub-option inserted by the
+ DHCPv4 relay, e.g. relay[123].text or relay[123].bin
More operators are expected to be implemented in upcoming releases.
diff --git a/src/lib/eval/eval_context.h b/src/lib/eval/eval_context.h
index cd86cad8c1..3007efc3d9 100644
--- a/src/lib/eval/eval_context.h
+++ b/src/lib/eval/eval_context.h
@@ -101,6 +101,13 @@ public:
uint16_t convertOptionName(const std::string& option_name,
const isc::eval::location& loc);
+ /// @brief Returns the universe (v4 or v6)
+ ///
+ /// @return universe
+ Option::Universe getUniverse() {
+ return (option_universe_);
+ }
+
private:
/// @brief Flag determining scanner debugging.
bool trace_scanning_;
diff --git a/src/lib/eval/lexer.ll b/src/lib/eval/lexer.ll
index b0419b6f36..3842b006b6 100644
--- a/src/lib/eval/lexer.ll
+++ b/src/lib/eval/lexer.ll
@@ -127,6 +127,7 @@ blank [ \t]
"text" return isc::eval::EvalParser::make_TEXT(loc);
"hex" return isc::eval::EvalParser::make_HEX(loc);
"substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
+"relay" return isc::eval::EvalParser::make_RELAY(loc);
"all" return isc::eval::EvalParser::make_ALL(loc);
"." return isc::eval::EvalParser::make_DOT(loc);
"(" return isc::eval::EvalParser::make_LPAREN(loc);
diff --git a/src/lib/eval/parser.yy b/src/lib/eval/parser.yy
index 2a84a2afc8..8716bc7bec 100644
--- a/src/lib/eval/parser.yy
+++ b/src/lib/eval/parser.yy
@@ -40,6 +40,7 @@ using namespace isc::eval;
OPTION "option"
SUBSTRING "substring"
TEXT "text"
+ RELAY "relay"
HEX "hex"
ALL "all"
DOT "."
@@ -93,6 +94,19 @@ string_expr : STRING
TokenPtr opt(new TokenOption($3, $6));
ctx.expression.push_back(opt);
}
+ | RELAY "[" option_code "]" "." option_repr_type
+ {
+ switch (ctx.getUniverse()) {
+ case Option::V4:
+ {
+ TokenPtr opt(new TokenRelay4Option($3, $6));
+ ctx.expression.push_back(opt);
+ break;
+ }
+ case Option::V6:
+ error(@1, "relay support for v6 is not implemented");
+ }
+ }
| SUBSTRING "(" string_expr "," start_expr "," length_expr ")"
{
TokenPtr sub(new TokenSubstring());
diff --git a/src/lib/eval/tests/context_unittest.cc b/src/lib/eval/tests/context_unittest.cc
index caca72ceb9..4e3e8a8696 100644
--- a/src/lib/eval/tests/context_unittest.cc
+++ b/src/lib/eval/tests/context_unittest.cc
@@ -89,6 +89,18 @@ public:
EXPECT_TRUE(sub);
}
+ /// @brief check if the given token is relay4 with the expected code
+ void checkTokenRelay4(const TokenPtr& token, uint16_t code) {
+ ASSERT_TRUE(token);
+ boost::shared_ptr<TokenRelay4Option> relay4 =
+ boost::dynamic_pointer_cast<TokenRelay4Option>(token);
+ EXPECT_TRUE(relay4);
+
+ if (relay4) {
+ EXPECT_EQ(code, relay4->getCode());
+ }
+ }
+
/// @brief checks if the given expression raises the expected message
/// when it is parsed.
void checkError(const string& expr, const string& msg) {
@@ -274,6 +286,33 @@ TEST_F(EvalContextTest, substring) {
checkTokenSubstring(tmp4);
}
+// This test checks that the relay[code].hex can be used in expressions.
+TEST_F(EvalContextTest, relay4Option) {
+
+ EvalContext eval(Option::V4);
+ EXPECT_NO_THROW(parsed_ =
+ eval.parseString("relay[13].hex == 'thirteen'"));
+ EXPECT_TRUE(parsed_);
+ ASSERT_EQ(3, eval.expression.size());
+
+ TokenPtr tmp1 = eval.expression.at(0);
+ TokenPtr tmp2 = eval.expression.at(1);
+ TokenPtr tmp3 = eval.expression.at(2);
+
+ checkTokenRelay4(tmp1, 13);
+ checkTokenString(tmp2, "thirteen");
+ checkTokenEq(tmp3);
+}
+
+// Verify that relay[13] is not usable in v6
+// There will be a separate relay accessor for v6.
+TEST_F(EvalContextTest, relay4Error) {
+ universe_ = Option::V6;
+
+ checkError("relay[13].hex == 'thirteen'",
+ "<string>:1.1-5: relay support for v6 is not implemented");
+}
+
// Test some scanner error cases
TEST_F(EvalContextTest, scanErrors) {
checkError("'", "<string>:1.1: Invalid character: '");
diff --git a/src/lib/eval/tests/token_unittest.cc b/src/lib/eval/tests/token_unittest.cc
index c55ded7473..5778bc5b1c 100644
--- a/src/lib/eval/tests/token_unittest.cc
+++ b/src/lib/eval/tests/token_unittest.cc
@@ -44,6 +44,24 @@ public:
pkt6_->addOption(option_str6_);
}
+ /// @brief Inserts RAI option with several suboptions
+ ///
+ /// The structure inserted is:
+ /// - RAI (option 82)
+ /// - option 1 (containing string "one")
+ /// - option 13 (containing string "thirteen")
+ void insertRelay4Option() {
+
+ // RAI (Relay Agent Information) option
+ OptionPtr rai(new Option(Option::V4, DHO_DHCP_AGENT_OPTIONS));
+ OptionPtr sub1(new OptionString(Option::V4, 1, "one"));
+ OptionPtr sub13(new OptionString(Option::V4, 13, "thirteen"));
+
+ rai->addOption(sub1);
+ rai->addOption(sub13);
+ pkt4_->addOption(rai);
+ }
+
TokenPtr t_; ///< Just a convenience pointer
ValueStack values_; ///< evaluated values will be stored here
@@ -574,3 +592,64 @@ TEST_F(TokenTest, substringEquals) {
EXPECT_EQ("false", values_.top());
}
+
+// This test checks that the existing relay option can be found.
+TEST_F(TokenTest, relayOption) {
+
+ // Insert relay option with sub-options 1 and 13
+ insertRelay4Option();
+
+ // Creating the token should be safe.
+ ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
+
+ // We should be able to evaluate it.
+ EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
+
+ // we should have one value on the stack
+ ASSERT_EQ(1, values_.size());
+
+ // The option should be found and relay[13] should evaluate to the
+ // content of that sub-option, i.e. "thirteen"
+ EXPECT_EQ("thirteen", values_.top());
+}
+
+// This test checks that the code properly handles cases when
+// there is RAI option, but there's no requested sub-option.
+TEST_F(TokenTest, relayOptionNoSuboption) {
+
+ // Insert relay option with sub-options 1 and 13
+ insertRelay4Option();
+
+ // Creating the token should be safe.
+ ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(15, TokenOption::TEXTUAL)));
+
+ // We should be able to evaluate it.
+ EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
+
+ // we should have one value on the stack
+ ASSERT_EQ(1, values_.size());
+
+ // The option should NOT be found (there is no sub-option 15),
+ // so the expression should evaluate to ""
+ EXPECT_EQ("", values_.top());
+}
+
+// This test checks that the code properly handles cases when
+// there's no RAI option at all.
+TEST_F(TokenTest, relayOptionNoRai) {
+
+ // We didn't call insertRelay4Option(), so there's no RAI option.
+
+ // Creating the token should be safe.
+ ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
+
+ // We should be able to evaluate it.
+ EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
+
+ // we should have one value on the stack
+ ASSERT_EQ(1, values_.size());
+
+ // The option should NOT be found (there is no sub-option 13),
+ // so the expression should evaluate to ""
+ EXPECT_EQ("", values_.top());
+}
diff --git a/src/lib/eval/token.cc b/src/lib/eval/token.cc
index b58b7610cf..b9e7c524de 100644
--- a/src/lib/eval/token.cc
+++ b/src/lib/eval/token.cc
@@ -54,9 +54,14 @@ TokenHexString::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
values.push(value_);
}
+OptionPtr
+TokenOption::getOption(const Pkt& pkt) {
+ return (pkt.getOption(option_code_));
+}
+
void
TokenOption::evaluate(const Pkt& pkt, ValueStack& values) {
- OptionPtr opt = pkt.getOption(option_code_);
+ OptionPtr opt = getOption(pkt);
std::string opt_str;
if (opt) {
if (representation_type_ == TEXTUAL) {
@@ -168,3 +173,20 @@ TokenSubstring::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
// and finally get the substring
values.push(string_str.substr(start_pos, length));
}
+
+TokenRelay4Option::TokenRelay4Option(const uint16_t option_code,
+ const RepresentationType& rep_type)
+ :TokenOption(option_code, rep_type) {
+}
+
+OptionPtr TokenRelay4Option::getOption(const Pkt& pkt) {
+
+ // Check if there is Relay Agent Option.
+ OptionPtr rai = pkt.getOption(DHO_DHCP_AGENT_OPTIONS);
+ if (!rai) {
+ return (OptionPtr());
+ }
+
+ // If there is, try to return its suboption
+ return (rai->getOption(option_code_));
+}
diff --git a/src/lib/eval/token.h b/src/lib/eval/token.h
index 12bde84895..e330b3f15f 100644
--- a/src/lib/eval/token.h
+++ b/src/lib/eval/token.h
@@ -183,7 +183,18 @@ public:
return (option_code_);
}
-private:
+protected:
+ /// @brief Attempts to retrieve an option
+ ///
+ /// For this class it simply attempts to retrieve the option from the packet,
+ /// but there may be derived classes that would attempt to extract it from
+ /// other places (e.g. relay option, or as a suboption of other specific option).
+ ///
+ ///
+ /// @param pkt the option will be retrieved from here
+ /// @return option instance (or NULL if not found)
+ virtual OptionPtr getOption(const Pkt& pkt);
+
uint16_t option_code_; ///< Code of the option to be extracted
RepresentationType representation_type_; ///< Representation type.
};
@@ -269,6 +280,35 @@ public:
void evaluate(const Pkt& pkt, ValueStack& values);
};
+/// @brief Represents a sub-option inserted by the DHCPv4 relay.
+///
+/// DHCPv4 relays insert sub-options in option 82. This token attempts to extract
+/// such sub-options. Note it is radically different than in DHCPv6 (possible
+/// many encapsulation levels), thus separate classes for v4 and v6.
+///
+/// This token can represent the following expressions:
+/// relay[13].text - Textual representation of sub-option 13 in RAI (option 82)
+/// relay[13].hex - Binary representation of sub-option 13 in RAI (option 82)
+/// relay[vendor-class].text - Text representation of sub-option X in RAI (option 82)
+/// relay[vendor-class].hex - Binary representation of sub-option X in RAI (option 82)
+class TokenRelay4Option : public TokenOption {
+public:
+
+ /// @brief Construtor for extracting sub-option from RAI (option 82)
+ ///
+ /// @param option_code code of the searched sub-option
+ /// @param rep_type code representation (currently .hex and .text are supported)
+ TokenRelay4Option(const uint16_t option_code,
+ const RepresentationType& rep_type);
+
+protected:
+ /// @brief Attempts to obtain specified sub-option of option 82 from the packet
+ /// @param pkt DHCPv4 packet (that hopefully contains option 82)
+ /// @return found sub-option from option 82
+ virtual OptionPtr getOption(const Pkt& pkt);
+};
+
+
}; // end of isc::dhcp namespace
}; // end of isc namespace