Browse Source

[4272a] Ported previous attempt

Francis Dupont 9 years ago
parent
commit
d480426005

+ 27 - 3
doc/guide/classify.xml

@@ -217,25 +217,49 @@
             <row>
             <row>
               <entry>DHCPv6 Relay Options</entry>
               <entry>DHCPv6 Relay Options</entry>
               <entry>relay6[nest].option[code].hex</entry>
               <entry>relay6[nest].option[code].hex</entry>
-              <!--  <entry>Value of the option</entry> -->
+              <entry>(value of the option)</entry>
               <entry>The value of the option with code "code" from the
               <entry>The value of the option with code "code" from the
               relay encapsulation "nest"</entry>
               relay encapsulation "nest"</entry>
             </row>
             </row>
             <row>
             <row>
               <entry>DHCPv6 Relay Peer Address</entry>
               <entry>DHCPv6 Relay Peer Address</entry>
               <entry>relay6[nest].peeraddr</entry>
               <entry>relay6[nest].peeraddr</entry>
-              <!-- <entry>2001:DB8::1</entry> -->n
+              <entry>2001:DB8::1</entry>
               <entry>The value of the peer address field from the
               <entry>The value of the peer address field from the
               relay encapsulation "nest"</entry>
               relay encapsulation "nest"</entry>
             </row>
             </row>
             <row>
             <row>
               <entry>DHCPv6 Relay Link Address</entry>
               <entry>DHCPv6 Relay Link Address</entry>
               <entry>relay6[nest].linkaddr</entry>
               <entry>relay6[nest].linkaddr</entry>
-              <!-- <entry>2001:DB8::1</entry> -->n
+              <entry>2001:DB8::1</entry>
               <entry>The value of the link address field from the
               <entry>The value of the link address field from the
               relay encapsulation "nest"</entry>
               relay encapsulation "nest"</entry>
             </row>
             </row>
             <row>
             <row>
+              <entry>Interface name of packet</entry>
+              <entry>pkt.iface</entry>
+              <entry>eth0</entry>
+              <entry>The name of the incoming interface of a DHCP packet.</entry>
+            </row>
+            <row>
+              <entry>Source address of packet</entry>
+              <entry>pkt.src</entry>
+              <entry>10.1.2.3</entry>
+              <entry>The IP source address of a DHCP packet.</entry>
+            </row>
+            <row>
+              <entry>Destination address of packet</entry>
+              <entry>pkt.dst</entry>
+              <entry>10.1.2.3</entry>
+              <entry>The IP destination address of a DHCP packet.</entry>
+            </row>
+            <row>
+              <entry>Length of packet</entry>
+              <entry>pkt.len</entry>
+              <entry>0x00000100</entry>
+              <entry>The length of a DHCP packet (UDP header field) padded to 4 bytes.</entry>
+            </row>
+            <row>
               <entry>Hardware address in DHCPv4 packet</entry>
               <entry>Hardware address in DHCPv4 packet</entry>
               <entry>pkt4.mac</entry>
               <entry>pkt4.mac</entry>
               <entry>0x010203040506</entry>
               <entry>0x010203040506</entry>

+ 8 - 2
src/lib/eval/eval_messages.mes

@@ -60,16 +60,22 @@ the value stack.  Then are then combined via logical or and
 the result is pushed onto the value stack. The string is displayed
 the result is pushed onto the value stack. The string is displayed
 in text.
 in text.
 
 
+# For use with TokenPkt
+% EVAL_DEBUG_PKT Pushing PKT meta data %1 with value %2
+This debug message indicates that the given binary string representing
+the value of the requested meta data is being pushed onto the value stack.
+The string is displayed in hex at the exception of interface name.
+
 # For use with TokenPkt4
 # For use with TokenPkt4
 % EVAL_DEBUG_PKT4 Pushing PKT4 field %1 with value %2
 % EVAL_DEBUG_PKT4 Pushing PKT4 field %1 with value %2
 This debug message indicates that the given binary string representing
 This debug message indicates that the given binary string representing
-the value of the requested fied is being pushed onto the value stack.
+the value of the requested field is being pushed onto the value stack.
 The string is displayed in hex.
 The string is displayed in hex.
 
 
 # For use with TokenPkt6
 # For use with TokenPkt6
 % EVAL_DEBUG_PKT6 Pushing PKT6 field %1 with value %2
 % EVAL_DEBUG_PKT6 Pushing PKT6 field %1 with value %2
 This debug message indicates that the given binary string representing
 This debug message indicates that the given binary string representing
-the value of the requested fied is being pushed onto the value stack.
+the value of the requested field is being pushed onto the value stack.
 The string is displayed in hex.
 The string is displayed in hex.
 
 
 # For use with TokenRelay6Field
 # For use with TokenRelay6Field

+ 5 - 0
src/lib/eval/lexer.ll

@@ -147,6 +147,11 @@ addr6 [0-9a-fA-F]*\:[0-9a-fA-F]*\:[0-9a-fA-F:.]*
 "text"      return isc::eval::EvalParser::make_TEXT(loc);
 "text"      return isc::eval::EvalParser::make_TEXT(loc);
 "hex"       return isc::eval::EvalParser::make_HEX(loc);
 "hex"       return isc::eval::EvalParser::make_HEX(loc);
 "exists"    return isc::eval::EvalParser::make_EXISTS(loc);
 "exists"    return isc::eval::EvalParser::make_EXISTS(loc);
+"pkt"       return isc::eval::EvalParser::make_PKT(loc);
+"iface"     return isc::eval::EvalParser::make_IFACE(loc);
+"src"       return isc::eval::EvalParser::make_SRC(loc);
+"dst"       return isc::eval::EvalParser::make_DST(loc);
+"len"       return isc::eval::EvalParser::make_LEN(loc);
 "pkt4"      return isc::eval::EvalParser::make_PKT4(loc);
 "pkt4"      return isc::eval::EvalParser::make_PKT4(loc);
 "mac"       return isc::eval::EvalParser::make_CHADDR(loc);
 "mac"       return isc::eval::EvalParser::make_CHADDR(loc);
 "hlen"      return isc::eval::EvalParser::make_HLEN(loc);
 "hlen"      return isc::eval::EvalParser::make_HLEN(loc);

+ 51 - 4
src/lib/eval/parser.yy

@@ -52,6 +52,11 @@ using namespace isc::eval;
   TEXT "text"
   TEXT "text"
   HEX "hex"
   HEX "hex"
   EXISTS "exists"
   EXISTS "exists"
+  PKT "pkt"
+  IFACE "iface"
+  SRC "src"
+  DST "dst"
+  LEN "len"
   PKT4 "pkt4"
   PKT4 "pkt4"
   CHADDR "mac"
   CHADDR "mac"
   HLEN "hlen"
   HLEN "hlen"
@@ -81,6 +86,7 @@ using namespace isc::eval;
 %type <TokenOption::RepresentationType> option_repr_type
 %type <TokenOption::RepresentationType> option_repr_type
 %type <TokenRelay6Field::FieldType> relay6_field
 %type <TokenRelay6Field::FieldType> relay6_field
 %type <uint8_t> nest_level
 %type <uint8_t> nest_level
+%type <TokenPkt::MetadataType> pkt_metadata
 %type <TokenPkt4::FieldType> pkt4_field
 %type <TokenPkt4::FieldType> pkt4_field
 %type <TokenPkt6::FieldType> pkt6_field
 %type <TokenPkt6::FieldType> pkt6_field
 
 
@@ -218,15 +224,38 @@ string_expr : STRING
                      }
                      }
                   }
                   }
 
 
+            | PKT "." pkt_metadata
+                  {
+                      TokenPtr pkt_metadata(new TokenPkt($3));
+                      ctx.expression.push_back(pkt_metadata);
+                  }
             | PKT4 "." pkt4_field
             | PKT4 "." pkt4_field
                   {
                   {
-                      TokenPtr pkt4_field(new TokenPkt4($3));
-                      ctx.expression.push_back(pkt4_field);
+                     switch (ctx.getUniverse()) {
+                     case Option::V4:
+                     {
+                         TokenPtr pkt4_field(new TokenPkt4($3));
+                         ctx.expression.push_back(pkt4_field);
+                         break;
+                     }
+                     case Option::V6:
+                         // For now we only use pkt4 in DHCPv4.
+                         error(@1, "pkt4 can only be used in DHCPv4.");
+                     }
                   }
                   }
             | PKT6 "." pkt6_field
             | PKT6 "." pkt6_field
                   {
                   {
-                      TokenPtr pkt6_field(new TokenPkt6($3));
-                      ctx.expression.push_back(pkt6_field);
+                     switch (ctx.getUniverse()) {
+                     case Option::V6:
+                     {
+                         TokenPtr pkt6_field(new TokenPkt6($3));
+                         ctx.expression.push_back(pkt6_field);
+                         break;
+                     }
+                     case Option::V4:
+                         // For now we only use pkt6 in DHCPv6.
+                         error(@1, "pkt6 can only be used in DHCPv6.");
+                     }
                   }
                   }
             | RELAY6 "[" nest_level "]" "." relay6_field
             | RELAY6 "[" nest_level "]" "." relay6_field
                   {
                   {
@@ -284,6 +313,24 @@ nest_level : INTEGER
                  // an option or field.
                  // an option or field.
            ;
            ;
 
 
+pkt_metadata : IFACE
+                  {
+                      $$ = TokenPkt::IFACE;
+                  }
+             | SRC
+                  {
+                      $$ = TokenPkt::SRC;
+                  }
+             | DST
+                  {
+                      $$ = TokenPkt::DST;
+                  }
+             | LEN
+                  {
+                      $$ = TokenPkt::LEN;
+                  }
+             ;
+
 pkt4_field : CHADDR
 pkt4_field : CHADDR
                 {
                 {
                     $$ = TokenPkt4::CHADDR;
                     $$ = TokenPkt4::CHADDR;

+ 65 - 0
src/lib/eval/tests/context_unittest.cc

@@ -188,6 +188,51 @@ public:
         checkTokenRelay6Option(eval.expression.at(0), exp_level, exp_code, exp_repr);
         checkTokenRelay6Option(eval.expression.at(0), exp_level, exp_code, exp_repr);
     }
     }
 
 
+    /// @brief check if the given token is a Pkt of specified type
+    /// @param token token to be checked
+    /// @param type expected type of the Pkt metadata
+    void checkTokenPkt(const TokenPtr& token, TokenPkt::MetadataType type) {
+        ASSERT_TRUE(token);
+        boost::shared_ptr<TokenPkt> pkt =
+            boost::dynamic_pointer_cast<TokenPkt>(token);
+        ASSERT_TRUE(pkt);
+
+        EXPECT_EQ(type, pkt->getType());
+    }
+
+    /// @brief Test that verifies access to the DHCP packet metadatas.
+    ///
+    /// This test attempts to parse the expression, will check if the number
+    /// of tokens is exactly as expected and then will try to verify if the
+    /// first token represents the expected metadata in DHCP packet.
+    ///
+    /// @param expr expression to be parsed
+    /// @param exp_type expected metadata type to be parsed
+    /// @param exp_tokens expected number of tokens
+    void testPktMetadata(std::string expr,
+                         TokenPkt::MetadataType exp_type,
+                         int exp_tokens) {
+        EvalContext eval(Option::V6);
+
+        // Parse the expression.
+        try {
+            parsed_ = eval.parseString(expr);
+        }
+        catch (const EvalParseError& ex) {
+            FAIL() << "Exception thrown: " << ex.what();
+            return;
+        }
+
+        // Parsing should succeed and return a token.
+        EXPECT_TRUE(parsed_);
+
+        // There should be exactly the expected number of tokens.
+        ASSERT_EQ(exp_tokens, eval.expression.size());
+
+        // Check that the first token is TokenPkt instance and has correct type.
+        checkTokenPkt(eval.expression.at(0), exp_type);
+    }
+
     /// @brief checks if the given token is Pkt4 of specified type
     /// @brief checks if the given token is Pkt4 of specified type
     /// @param token token to be checked
     /// @param token token to be checked
     /// @param type expected type of the Pkt4 field
     /// @param type expected type of the Pkt4 field
@@ -654,6 +699,26 @@ TEST_F(EvalContextTest, relay6OptionHex) {
                      2, 85, TokenOption::HEXADECIMAL, 3);
                      2, 85, TokenOption::HEXADECIMAL, 3);
 }
 }
 
 
+// Tests whether iface metadata in DHCP can be accessed.
+TEST_F(EvalContextTest, pktMetadataIface) {
+    testPktMetadata("pkt.iface == 'eth0'", TokenPkt::IFACE, 3);
+}
+
+// Tests whether src metadata in DHCP can be accessed.
+TEST_F(EvalContextTest, pktMetadataSrc) {
+    testPktMetadata("pkt.src == fe80::1", TokenPkt::SRC, 3);
+}
+
+// Tests whether dst metadata in DHCP can be accessed.
+TEST_F(EvalContextTest, pktMetadataDst) {
+    testPktMetadata("pkt.dst == fe80::2", TokenPkt::DST, 3);
+}
+
+// Tests whether len metadata in DHCP can be accessed.
+TEST_F(EvalContextTest, pktMetadataLen) {
+    testPktMetadata("pkt.len == 0x00000100", TokenPkt::LEN, 3);
+}
+
 // Tests whether chaddr field in DHCPv4 can be accessed.
 // Tests whether chaddr field in DHCPv4 can be accessed.
 TEST_F(EvalContextTest, pkt4FieldChaddr) {
 TEST_F(EvalContextTest, pkt4FieldChaddr) {
     testPkt4Field("pkt4.mac == 0x000102030405", TokenPkt4::CHADDR, 3);
     testPkt4Field("pkt4.mac == 0x000102030405", TokenPkt4::CHADDR, 3);

+ 88 - 1
src/lib/eval/tests/token_unittest.cc

@@ -39,7 +39,7 @@ namespace {
 class TokenTest : public LogContentTest {
 class TokenTest : public LogContentTest {
 public:
 public:
 
 
-    /// @brief Initializes Pkt4,Pkt6 and options that can be useful for
+    /// @brief Initializes Pkt4, Pkt6 and options that can be useful for
     ///        evaluation tests.
     ///        evaluation tests.
     TokenTest() {
     TokenTest() {
         pkt4_.reset(new Pkt4(DHCPDISCOVER, 12345));
         pkt4_.reset(new Pkt4(DHCPDISCOVER, 12345));
@@ -885,6 +885,93 @@ TEST_F(TokenTest, relay6Option) {
     EXPECT_TRUE(checkFile());
     EXPECT_TRUE(checkFile());
 }
 }
 
 
+// Verifies that DHCPv4 packet metadata can be extracted.
+TEST_F(TokenTest, pkt4MetaData) {
+    pkt4_->setIface("eth0");
+    pkt4_->setLocalAddr(IOAddress("10.0.0.1"));
+    pkt4_->setRemoteAddr(IOAddress("10.0.0.2"));
+
+    // Check interface (expect eth0)
+    ASSERT_NO_THROW(t_.reset(new TokenPkt(TokenPkt::IFACE)));
+    EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
+    ASSERT_EQ(1, values_.size());
+    ASSERT_EQ("eth0", values_.top());
+
+    // Check source (expect 10.0.0.2)
+    clearStack();
+    ASSERT_NO_THROW(t_.reset(new TokenPkt(TokenPkt::SRC)));
+    EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
+    ASSERT_EQ(1, values_.size());
+    ASSERT_EQ(4, values_.top().size());
+    EXPECT_EQ(10, values_.top()[0]);
+    EXPECT_EQ(0, values_.top()[1]);
+    EXPECT_EQ(0, values_.top()[2]);
+    EXPECT_EQ(2, values_.top()[3]);
+
+    // Check destination (expect 10.0.0.1)
+    clearStack();
+    ASSERT_NO_THROW(t_.reset(new TokenPkt(TokenPkt::DST)));
+    EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
+    ASSERT_EQ(1, values_.size());
+    vector<uint8_t> a1 = IOAddress("10.0.0.1").toBytes();
+    ASSERT_EQ(a1.size(), values_.top().size());
+    EXPECT_EQ(0, memcmp(&a1[0], &values_.top()[0], a1.size()));
+
+    // Check length (expect 249)
+    clearStack();
+    ASSERT_NO_THROW(t_.reset(new TokenPkt(TokenPkt::LEN)));
+    EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
+    ASSERT_EQ(1, values_.size());
+    uint32_t length = htonl(static_cast<uint32_t>(pkt4_->len()));
+    ASSERT_EQ(4, values_.top().size());
+    EXPECT_EQ(0, memcmp(&length, &values_.top()[0], 4));
+}
+
+// Verifies that DHCPv6 packet metadata can be extracted.
+TEST_F(TokenTest, pkt6MetaData) {
+    pkt6_->setIface("eth0");
+    pkt6_->setLocalAddr(IOAddress("ff02::1:2"));
+    pkt6_->setRemoteAddr(IOAddress("fe80::1234"));
+
+    // Check interface (expect eth0)
+    ASSERT_NO_THROW(t_.reset(new TokenPkt(TokenPkt::IFACE)));
+    EXPECT_NO_THROW(t_->evaluate(*pkt6_, values_));
+    ASSERT_EQ(1, values_.size());
+    ASSERT_EQ("eth0", values_.top());
+
+    // Check source (expect fe80::1234)
+    clearStack();
+    ASSERT_NO_THROW(t_.reset(new TokenPkt(TokenPkt::SRC)));
+    EXPECT_NO_THROW(t_->evaluate(*pkt6_, values_));
+    ASSERT_EQ(1, values_.size());
+    ASSERT_EQ(16, values_.top().size());
+    EXPECT_EQ(0xfe, static_cast<uint8_t>(values_.top()[0]));
+    EXPECT_EQ(0x80, static_cast<uint8_t>(values_.top()[1]));
+    for (unsigned i = 2; i < 14; ++i) {
+        EXPECT_EQ(0, values_.top()[i]);
+    }
+    EXPECT_EQ(0x12, values_.top()[14]);
+    EXPECT_EQ(0x34, values_.top()[15]);
+
+    // Check destination (expect ff02::1:2)
+    clearStack();
+    ASSERT_NO_THROW(t_.reset(new TokenPkt(TokenPkt::DST)));
+    EXPECT_NO_THROW(t_->evaluate(*pkt6_, values_));
+    ASSERT_EQ(1, values_.size());
+    vector<uint8_t> ma = IOAddress("ff02::1:2").toBytes();
+    ASSERT_EQ(ma.size(), values_.top().size());
+    EXPECT_EQ(0, memcmp(&ma[0], &values_.top()[0], ma.size()));
+
+    // Check length (expect 16)
+    clearStack();
+    ASSERT_NO_THROW(t_.reset(new TokenPkt(TokenPkt::LEN)));
+    EXPECT_NO_THROW(t_->evaluate(*pkt6_, values_));
+    ASSERT_EQ(1, values_.size());
+    uint32_t length = htonl(static_cast<uint32_t>(pkt6_->len()));
+    ASSERT_EQ(4, values_.top().size());
+    EXPECT_EQ(0, memcmp(&length, &values_.top()[0], 4));
+}
+
 // Verifies if the DHCPv4 packet fields can be extracted.
 // Verifies if the DHCPv4 packet fields can be extracted.
 TEST_F(TokenTest, pkt4Fields) {
 TEST_F(TokenTest, pkt4Fields) {
     pkt4_->setGiaddr(IOAddress("192.0.2.1"));
     pkt4_->setGiaddr(IOAddress("192.0.2.1"));

+ 87 - 28
src/lib/eval/token.cc

@@ -17,6 +17,19 @@
 using namespace isc::dhcp;
 using namespace isc::dhcp;
 using namespace std;
 using namespace std;
 
 
+namespace {
+
+/// @brief encode in hexadecimal
+///
+/// @param value the value to encode
+/// @return 0x followed by the value encoded in hexa
+inline string toHex(string value) {
+    vector<uint8_t> bin(value.begin(), value.end());
+    return ("0x" + isc::util::encode::encodeHex(bin));
+}
+
+}; // end of anonymous namespace
+
 void
 void
 TokenString::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
 TokenString::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
     // Literals only push, nothing to pop
     // Literals only push, nothing to pop
@@ -62,8 +75,7 @@ TokenHexString::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
 
 
     // Log what we pushed
     // Log what we pushed
     LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_HEXSTRING)
     LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_HEXSTRING)
-        .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(value_.begin(),
-								 value_.end())));
+        .arg(toHex(value_));
 }
 }
 
 
 TokenIpAddress::TokenIpAddress(const string& addr) : value_("") {
 TokenIpAddress::TokenIpAddress(const string& addr) : value_("") {
@@ -88,8 +100,7 @@ TokenIpAddress::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
 
 
     // Log what we pushed
     // Log what we pushed
     LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_IPADDRESS)
     LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_IPADDRESS)
-        .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(value_.begin(),
-								 value_.end())));
+        .arg(toHex(value_));
 }
 }
 
 
 OptionPtr
 OptionPtr
@@ -127,8 +138,7 @@ TokenOption::evaluate(const Pkt& pkt, ValueStack& values) {
     if (representation_type_ == HEXADECIMAL) {
     if (representation_type_ == HEXADECIMAL) {
         LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_OPTION)
         LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_OPTION)
             .arg(option_code_)
             .arg(option_code_)
-            .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(opt_str.begin(),
-                                                                     opt_str.end())));
+            .arg(toHex(opt_str));
     } else {
     } else {
         LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_OPTION)
         LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_OPTION)
             .arg(option_code_)
             .arg(option_code_)
@@ -180,6 +190,66 @@ OptionPtr TokenRelay6Option::getOption(const Pkt& pkt) {
 }
 }
 
 
 void
 void
+TokenPkt::evaluate(const Pkt& pkt, ValueStack& values) {
+
+    string value;
+    vector<uint8_t> binary;
+    string type_str;
+    uint32_t len;
+    bool is_binary = true;
+    switch (type_) {
+    case IFACE:
+        is_binary = false;
+        value = pkt.getIface();
+        type_str = "iface";
+        break;
+    case SRC:
+        binary = pkt.getRemoteAddr().toBytes();
+        type_str = "src";
+        break;
+    case DST:
+        binary = pkt.getLocalAddr().toBytes();
+        type_str = "dst";
+        break;
+    case LEN:
+        // len() returns a size_t but in fact it can't be very large
+        // (with UDP transport it fits in 16 bits)
+        // the len() method is not const because of DHCPv6 relays.
+        // We assume here it has no bad side effects...
+        len = static_cast<uint32_t>(const_cast<Pkt&>(pkt).len());
+        binary.push_back(len >> 24);
+        binary.push_back((len >> 16) & 0xFF);
+        binary.push_back((len >> 8) & 0xFF);
+        binary.push_back(len & 0xFF);
+        type_str = "len";
+        break;
+
+    default:
+        isc_throw(EvalTypeError, "Bad meta data specified: "
+                  << static_cast<int>(type_) );
+    }
+
+    if (is_binary) {
+        value.resize(binary.size());
+        if (!binary.empty()) {
+            memmove(&value[0], &binary[0], binary.size());
+        }
+    }
+    values.push(value);
+
+    // Log what we pushed
+    if (is_binary) {
+        LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_PKT)
+            .arg(type_str)
+            .arg(toHex(value));
+    } else {
+        LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_PKT)
+            .arg(type_str)
+            .arg(value);
+    }
+}
+
+void
 TokenPkt4::evaluate(const Pkt& pkt, ValueStack& values) {
 TokenPkt4::evaluate(const Pkt& pkt, ValueStack& values) {
 
 
     vector<uint8_t> binary;
     vector<uint8_t> binary;
@@ -260,8 +330,7 @@ TokenPkt4::evaluate(const Pkt& pkt, ValueStack& values) {
     // Log what we pushed
     // Log what we pushed
     LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_PKT4)
     LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_PKT4)
         .arg(type_str)
         .arg(type_str)
-        .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(value.begin(),
-                                                                 value.end())));
+        .arg(toHex(value));
 }
 }
 
 
 void
 void
@@ -312,8 +381,7 @@ TokenPkt6::evaluate(const Pkt& pkt, ValueStack& values) {
     // Log what we pushed
     // Log what we pushed
     LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_PKT6)
     LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_PKT6)
         .arg(type_str)
         .arg(type_str)
-        .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(value.begin(),
-                                                                 value.end())));
+        .arg(toHex(value));
 }
 }
 
 
 void
 void
@@ -365,8 +433,7 @@ TokenRelay6Field::evaluate(const Pkt& pkt, ValueStack& values) {
     LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_RELAY6)
     LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_RELAY6)
         .arg(type_str)
         .arg(type_str)
         .arg(unsigned(nest_level_))
         .arg(unsigned(nest_level_))
-        .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(value.begin(),
-                                                                 value.end())));
+        .arg(toHex(value));
 }
 }
 
 
 void
 void
@@ -389,10 +456,8 @@ TokenEqual::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
 
 
     // Log what we popped and pushed
     // Log what we popped and pushed
     LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_EQUAL)
     LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_EQUAL)
-        .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(op1.begin(),
-                                                                 op1.end())))
-        .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(op2.begin(),
-                                                                 op2.end())))
+        .arg(toHex(op1))
+        .arg(toHex(op2))
         .arg('\'' + values.top() + '\'');
         .arg('\'' + values.top() + '\'');
 }
 }
 
 
@@ -459,8 +524,7 @@ TokenSubstring::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
         LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUBSTRING_RANGE)
         LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUBSTRING_RANGE)
             .arg(len_str)
             .arg(len_str)
             .arg(start_str)
             .arg(start_str)
-            .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(string_str.begin(),
-                                                                     string_str.end())))
+            .arg(toHex(string_str))
             .arg("0x");
             .arg("0x");
         return;
         return;
     }
     }
@@ -489,10 +553,8 @@ TokenSubstring::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
     LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUBSTRING)
     LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUBSTRING)
         .arg(len_str)
         .arg(len_str)
         .arg(start_str)
         .arg(start_str)
-        .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(string_str.begin(),
-                                                                 string_str.end())))
-        .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(values.top().begin(),
-                                                                 values.top().end())));
+        .arg(toHex(string_str))
+        .arg(toHex(values.top()));
 }
 }
 
 
 void
 void
@@ -513,12 +575,9 @@ TokenConcat::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
 
 
     // Log what we popped and pushed
     // Log what we popped and pushed
     LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_CONCAT)
     LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_CONCAT)
-        .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(op1.begin(),
-                                                                 op1.end())))
-        .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(op2.begin(),
-                                                                 op2.end())))
-        .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(values.top().begin(),
-                                                                 values.top().end())));
+        .arg(toHex(op1))
+        .arg(toHex(op2))
+        .arg(toHex(values.top()));
 }
 }
 
 
 void
 void

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

@@ -334,6 +334,53 @@ protected:
     uint8_t nest_level_; ///< nesting level of the relay block to use
     uint8_t nest_level_; ///< nesting level of the relay block to use
 };
 };
 
 
+/// @brief Token that represents meta data of a DHCP packet.
+///
+/// For example in the expression pkt.iface == 'eth0'
+/// this token represents the pkt.iface expression.
+///
+/// Currently supported meta datas are:
+/// - iface (incoming/outgoinginterface name)
+/// - src   (source IP address, 4 or 16 octets)
+/// - dst   (destination IP address, 4 octets)
+/// - len   (length field in the UDP header, padded to 4 octets)
+class TokenPkt : public Token {
+public:
+
+    /// @brief enum value that determines the field.
+    enum MetadataType {
+        IFACE, ///< interface name (string)
+        SRC,   ///< source (IP address)
+        DST,   ///< destination (IP address)
+        LEN    ///< length (4 octets)
+    };
+
+    /// @brief Constructor (does nothing)
+    TokenPkt(const MetadataType type)
+        : type_(type) {}
+
+    /// @brief Gets a value from the specified packet.
+    ///
+    /// Evaluation uses metadatas available in the packet. It does not
+    /// require any values to be present on the stack.
+    ///
+    /// @param pkt - metadatas will be extracted from here
+    /// @param values - stack of values (1 result will be pushed)
+    void evaluate(const Pkt& pkt, ValueStack& values);
+
+    /// @brief Returns metadata type
+    ///
+    /// This method is used only in tests.
+    /// @return type of the metadata.
+    MetadataType getType() {
+        return (type_);
+    }
+
+private:
+    /// @brief Specifies metadata of the DHCP packet
+    MetadataType type_;
+};
+
 /// @brief Token that represents fields of a DHCPv4 packet.
 /// @brief Token that represents fields of a DHCPv4 packet.
 ///
 ///
 /// For example in the expression pkt4.chaddr == 0x0102030405
 /// For example in the expression pkt4.chaddr == 0x0102030405