diff options
author | Tomek Mrugalski <tomasz@isc.org> | 2016-02-02 23:17:22 +0100 |
---|---|---|
committer | Tomek Mrugalski <tomasz@isc.org> | 2016-02-02 23:17:22 +0100 |
commit | 6325cf1aefb95b862069dc4aaaf31184f70ee2ce (patch) | |
tree | 7dd67f0afd5f4ccdf6a3378758f2fa91a9915873 | |
parent | [master] version update (diff) | |
download | kea-6325cf1aefb95b862069dc4aaaf31184f70ee2ce.tar.xz kea-6325cf1aefb95b862069dc4aaaf31184f70ee2ce.zip |
[4264] relay[123].hex token implemented.
-rw-r--r-- | doc/guide/classify.xml | 14 | ||||
-rw-r--r-- | src/lib/eval/eval.dox | 2 | ||||
-rw-r--r-- | src/lib/eval/eval_context.h | 7 | ||||
-rw-r--r-- | src/lib/eval/lexer.ll | 1 | ||||
-rw-r--r-- | src/lib/eval/parser.yy | 14 | ||||
-rw-r--r-- | src/lib/eval/tests/context_unittest.cc | 39 | ||||
-rw-r--r-- | src/lib/eval/tests/token_unittest.cc | 79 | ||||
-rw-r--r-- | src/lib/eval/token.cc | 24 | ||||
-rw-r--r-- | src/lib/eval/token.h | 42 |
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 |