Browse Source

[master] Merged trac4091 (hex strings)

Francis Dupont 9 years ago
parent
commit
b9898e9e1d

+ 1 - 1
src/lib/dhcpsrv/parsers/dhcp_parsers.cc

@@ -593,7 +593,7 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
             // The decodeHex function expects that the string contains an
             // even number of digits. If we don't meet this requirement,
             // we have to insert a leading 0.
-            if (!data_param.empty() && data_param.length() % 2) {
+            if (!data_param.empty() && ((data_param.length() % 2) != 0)) {
                 data_param = data_param.insert(0, "0");
             }
             util::encode::decodeHex(data_param, binary);

+ 1 - 1
src/lib/eval/tests/Makefile.am

@@ -26,7 +26,7 @@ if HAVE_GTEST
 
 TESTS += libeval_unittests
 
-libeval_unittests_SOURCES  = token_unittest.cc main.cc
+libeval_unittests_SOURCES  = token_unittest.cc run_unittests.cc
 libeval_unittests_CXXFLAGS = $(AM_CXXFLAGS)
 libeval_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 libeval_unittests_LDFLAGS  = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS)

src/lib/eval/tests/main.cc → src/lib/eval/tests/run_unittests.cc


+ 112 - 0
src/lib/eval/tests/token_unittest.cc

@@ -24,6 +24,8 @@
 #include <boost/scoped_ptr.hpp>
 #include <gtest/gtest.h>
 
+#include <arpa/inet.h>
+
 using namespace std;
 using namespace isc::dhcp;
 
@@ -127,6 +129,116 @@ TEST_F(TokenTest, string6) {
     EXPECT_EQ("foo", values_.top());
 }
 
+// This simple test checks that a TokenHexString, representing a constant
+// string coded in hexadecimal, can be used in Pkt4 evaluation.
+// (The actual packet is not used)
+TEST_F(TokenTest, hexstring4) {
+    TokenPtr empty;
+    TokenPtr bad;
+    TokenPtr nodigit;
+    TokenPtr baddigit;
+    TokenPtr bell;
+    TokenPtr foo;
+    TokenPtr cookie;
+
+    // Store constant empty hexstring "" ("") in the TokenHexString object.
+    ASSERT_NO_THROW(empty.reset(new TokenHexString("")));
+    // Store bad encoded hexstring "0abc" ("").
+    ASSERT_NO_THROW(bad.reset(new TokenHexString("0abc")));
+    // Store hexstring with no digits "0x" ("").
+    ASSERT_NO_THROW(nodigit.reset(new TokenHexString("0x")));
+    // Store hexstring with a bad hexdigit "0xxabc" ("").
+    ASSERT_NO_THROW(baddigit.reset(new TokenHexString("0xxabc")));
+    // Store hexstring with an odd number of hexdigits "0x7" ("\a").
+    ASSERT_NO_THROW(bell.reset(new TokenHexString("0x7")));
+    // Store constant hexstring "0x666f6f" ("foo").
+    ASSERT_NO_THROW(foo.reset(new TokenHexString("0x666f6f")));
+    // Store constant hexstring "0x63825363" (DHCP_OPTIONS_COOKIE).
+    ASSERT_NO_THROW(cookie.reset(new TokenHexString("0x63825363")));
+
+    // Make sure that tokens can be evaluated without exceptions.
+    ASSERT_NO_THROW(empty->evaluate(*pkt4_, values_));
+    ASSERT_NO_THROW(bad->evaluate(*pkt4_, values_));
+    ASSERT_NO_THROW(nodigit->evaluate(*pkt4_, values_));
+    ASSERT_NO_THROW(baddigit->evaluate(*pkt4_, values_));
+    ASSERT_NO_THROW(bell->evaluate(*pkt4_, values_));
+    ASSERT_NO_THROW(foo->evaluate(*pkt4_, values_));
+    ASSERT_NO_THROW(cookie->evaluate(*pkt4_, values_));
+
+    // Check that the evaluation put its value on the values stack.
+    ASSERT_EQ(7, values_.size());
+    uint32_t expected = htonl(DHCP_OPTIONS_COOKIE);
+    EXPECT_EQ(4, values_.top().size());
+    EXPECT_EQ(0, memcmp(&expected, &values_.top()[0], 4));
+    values_.pop();
+    EXPECT_EQ("foo", values_.top());
+    values_.pop();
+    EXPECT_EQ("\a", values_.top());
+    values_.pop();
+    EXPECT_EQ("", values_.top());
+    values_.pop();
+    EXPECT_EQ("", values_.top());
+    values_.pop();
+    EXPECT_EQ("", values_.top());
+    values_.pop();
+    EXPECT_EQ("", values_.top());
+}
+
+// This simple test checks that a TokenHexString, representing a constant
+// string coded in hexadecimal, can be used in Pkt6 evaluation.
+// (The actual packet is not used)
+TEST_F(TokenTest, hexstring6) {
+    TokenPtr empty;
+    TokenPtr bad;
+    TokenPtr nodigit;
+    TokenPtr baddigit;
+    TokenPtr bell;
+    TokenPtr foo;
+    TokenPtr cookie;
+
+    // Store constant empty hexstring "" ("") in the TokenHexString object.
+    ASSERT_NO_THROW(empty.reset(new TokenHexString("")));
+    // Store bad encoded hexstring "0abc" ("").
+    ASSERT_NO_THROW(bad.reset(new TokenHexString("0abc")));
+    // Store hexstring with no digits "0x" ("").
+    ASSERT_NO_THROW(nodigit.reset(new TokenHexString("0x")));
+    // Store hexstring with a bad hexdigit "0xxabc" ("").
+    ASSERT_NO_THROW(baddigit.reset(new TokenHexString("0xxabc")));
+    // Store hexstring with an odd number of hexdigits "0x7" ("\a").
+    ASSERT_NO_THROW(bell.reset(new TokenHexString("0x7")));
+    // Store constant hexstring "0x666f6f" ("foo").
+    ASSERT_NO_THROW(foo.reset(new TokenHexString("0x666f6f")));
+    // Store constant hexstring "0x63825363" (DHCP_OPTIONS_COOKIE).
+    ASSERT_NO_THROW(cookie.reset(new TokenHexString("0x63825363")));
+
+    // Make sure that tokens can be evaluated without exceptions.
+    ASSERT_NO_THROW(empty->evaluate(*pkt6_, values_));
+    ASSERT_NO_THROW(bad->evaluate(*pkt6_, values_));
+    ASSERT_NO_THROW(nodigit->evaluate(*pkt6_, values_));
+    ASSERT_NO_THROW(baddigit->evaluate(*pkt6_, values_));
+    ASSERT_NO_THROW(bell->evaluate(*pkt6_, values_));
+    ASSERT_NO_THROW(foo->evaluate(*pkt6_, values_));
+    ASSERT_NO_THROW(cookie->evaluate(*pkt6_, values_));
+
+    // Check that the evaluation put its value on the values stack.
+    ASSERT_EQ(7, values_.size());
+    uint32_t expected = htonl(DHCP_OPTIONS_COOKIE);
+    EXPECT_EQ(4, values_.top().size());
+    EXPECT_EQ(0, memcmp(&expected, &values_.top()[0], 4));
+    values_.pop();
+    EXPECT_EQ("foo", values_.top());
+    values_.pop();
+    EXPECT_EQ("\a", values_.top());
+    values_.pop();
+    EXPECT_EQ("", values_.top());
+    values_.pop();
+    EXPECT_EQ("", values_.top());
+    values_.pop();
+    EXPECT_EQ("", values_.top());
+    values_.pop();
+    EXPECT_EQ("", values_.top());
+}
+
 // This test checks if a token representing an option value is able to extract
 // the option from an IPv4 packet and properly store the option's value.
 TEST_F(TokenTest, optionString4) {

+ 36 - 0
src/lib/eval/token.cc

@@ -14,7 +14,9 @@
 
 #include <eval/token.h>
 #include <eval/eval_log.h>
+#include <util/encode/hex.h>
 #include <boost/lexical_cast.hpp>
+#include <cstring>
 #include <string>
 
 using namespace isc::dhcp;
@@ -26,6 +28,40 @@ TokenString::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
     values.push(value_);
 }
 
+TokenHexString::TokenHexString(const string& str) : value_("") {
+    // Check string starts "0x" or "0x" and has at least one additional character.
+    if ((str.size() < 3) ||
+        (str[0] != '0') ||
+        ((str[1] != 'x') && (str[1] != 'X'))) {
+        return;
+    }
+    string digits = str.substr(2);
+
+    // Transform string of hexadecimal digits into binary format
+    vector<uint8_t> binary;
+    try {
+        // The decodeHex function expects that the string contains an
+        // even number of digits. If we don't meet this requirement,
+        // we have to insert a leading 0.
+        if ((digits.length() % 2) != 0) {
+            digits = digits.insert(0, "0");
+        }
+        util::encode::decodeHex(digits, binary);
+    } catch (...) {
+        return;
+    }
+
+    // Convert to a string (note that binary.size() cannot be 0)
+    value_.resize(binary.size());
+    memmove(&value_[0], &binary[0], binary.size());
+}
+
+void
+TokenHexString::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
+    // Literals only push, nothing to pop
+    values.push(value_);
+}
+
 void
 TokenOption::evaluate(const Pkt& pkt, ValueStack& values) {
     OptionPtr opt = pkt.getOption(option_code_);

+ 25 - 0
src/lib/eval/token.h

@@ -101,6 +101,31 @@ protected:
     std::string value_; ///< Constant value
 };
 
+/// @brief Token representing a constant string in hexadecimal format
+///
+/// This token holds value of a constant string giving in an hexadecimal
+/// format, for instance 0x666f6f is "foo"
+class TokenHexString : public Token {
+public:
+    /// Value is set during token construction.
+    ///
+    /// @param str constant string to be represented
+    /// (must be "0x" or "0X" followed by a string of hexadecimal digits
+    /// or decoding will fail)
+    TokenHexString(const std::string& str);
+
+    /// @brief Token evaluation (puts value of the constant string on
+    /// the stack after decoding or an empty string if decoding fails
+    /// (note it should not if the parser is correct)
+    ///
+    /// @param pkt (ignored)
+    /// @param values (represented string will be pushed here)
+    void evaluate(const Pkt& pkt, ValueStack& values);
+
+protected:
+    std::string value_; ///< Constant value
+};
+
 /// @brief Token that represents a value of an option
 ///
 /// This represents a reference to a given option, e.g. in the expression