token.h 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. // Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #ifndef TOKEN_H
  15. #define TOKEN_H
  16. #include <exceptions/exceptions.h>
  17. #include <dhcp/pkt.h>
  18. #include <stack>
  19. namespace isc {
  20. namespace dhcp {
  21. class Token;
  22. /// @brief Pointer to a single Token
  23. typedef boost::shared_ptr<Token> TokenPtr;
  24. /// This is a structure that holds an expression converted to RPN
  25. ///
  26. /// For example expression: option[123] == 'foo' will be converted to:
  27. /// [0] = option[123] (TokenOption object)
  28. /// [1] = 'foo' (TokenString object)
  29. /// [2] = == operator (TokenEqual object)
  30. typedef std::vector<TokenPtr> Expression;
  31. /// Evaluated values are stored as a stack of strings
  32. typedef std::stack<std::string> ValueStack;
  33. /// @brief EvalStackError is thrown when more or less parameters are on the
  34. /// stack than expected.
  35. class EvalBadStack : public Exception {
  36. public:
  37. EvalBadStack(const char* file, size_t line, const char* what) :
  38. isc::Exception(file, line, what) { };
  39. };
  40. /// @brief Base class for all tokens
  41. ///
  42. /// It provides an interface for all tokens and storage for string representation
  43. /// (all tokens evaluate to string).
  44. ///
  45. /// This class represents a single token. Examples of a token are:
  46. /// - "foo" (a constant string)
  47. /// - option[123] (a token that extracts value of option 123)
  48. /// - == (an operator that compares two other tokens)
  49. /// - substring(a,b,c) (an operator that takes three arguments: a string,
  50. /// first character and length)
  51. class Token {
  52. public:
  53. /// @brief This is a generic method for evaluating a packet.
  54. ///
  55. /// We need to pass the packet being evaluated and possibly previously
  56. /// evaluated values. Specific implementations may ignore the packet altogether
  57. /// and just put their own value on the stack (constant tokens), look at the
  58. /// packet and put some data extracted from it on the stack (option tokens),
  59. /// or pop arguments from the stack and put back the result (operators).
  60. ///
  61. /// The parameters passed will be:
  62. ///
  63. /// @param pkt - packet being classified
  64. /// @param values - stack of values with previously evaluated tokens
  65. virtual void evaluate(const Pkt& pkt, ValueStack& values) = 0;
  66. /// @brief Virtual destructor
  67. virtual ~Token() {}
  68. };
  69. /// @brief Token representing a constant string
  70. ///
  71. /// This token holds value of a constant string, e.g. it represents
  72. /// "MSFT" in expression option[vendor-class] == "MSFT"
  73. class TokenString : public Token {
  74. public:
  75. /// Value is set during token construction.
  76. ///
  77. /// @param str constant string to be represented.
  78. TokenString(const std::string& str)
  79. :value_(str){
  80. }
  81. /// @brief Token evaluation (puts value of the constant string on the stack)
  82. ///
  83. /// @param pkt (ignored)
  84. /// @param values (represented string will be pushed here)
  85. void evaluate(const Pkt& pkt, ValueStack& values);
  86. protected:
  87. std::string value_; ///< Constant value
  88. };
  89. /// @brief Token that represents a value of an option
  90. ///
  91. /// This represents a reference to a given option, e.g. in the expression
  92. /// option[vendor-class] == "MSFT", it represents option[vendor-class]
  93. ///
  94. /// During the evaluation it tries to extract the value of the specified
  95. /// option. If the option is not found, an empty string ("") is returned.
  96. class TokenOption : public Token {
  97. public:
  98. /// @brief Constructor that takes an option code as a parameter
  99. /// @param option_code code of the option
  100. ///
  101. /// Note: There is no constructor that takes option_name, as it would
  102. /// introduce complex dependency of the libkea-eval on libdhcpsrv.
  103. ///
  104. /// @param option_code code of the option to be represented.
  105. TokenOption(uint16_t option_code)
  106. :option_code_(option_code) {}
  107. /// @brief Evaluates the values of the option
  108. ///
  109. /// This token represents a value of the option, so this method attempts
  110. /// to extract the option from the packet and put its value on the stack.
  111. /// If the option is not there, an empty string ("") is put on the stack.
  112. ///
  113. /// @param pkt specified option will be extracted from this packet (if present)
  114. /// @param values value of the option will be pushed here (or "")
  115. void evaluate(const Pkt& pkt, ValueStack& values);
  116. private:
  117. uint16_t option_code_; ///< code of the option to be extracted
  118. };
  119. /// @brief Token that represents equality operator (compares two other tokens)
  120. ///
  121. /// For example in the expression option[vendor-class] == "MSFT" this token
  122. /// represents the equal (==) sign.
  123. class TokenEqual : public Token {
  124. public:
  125. /// @brief Constructor (does nothing)
  126. TokenEqual() {}
  127. /// @brief Compare two values.
  128. ///
  129. /// Evaluation does not use packet information, but rather consumes the last
  130. /// two parameters. It does a simple string comparison and sets the value to
  131. /// either "true" or "false". It requires at least two parameters to be
  132. /// present on stack.
  133. ///
  134. /// @throw EvalBadStack if there are less than 2 values on stack
  135. ///
  136. /// @param pkt (unused)
  137. /// @param values - stack of values (2 arguments will be popped, 1 result
  138. /// will be pushed)
  139. void evaluate(const Pkt& pkt, ValueStack& values);
  140. };
  141. /// @brief Token that represents the substring operator (returns a portion
  142. /// of the supplied string)
  143. ///
  144. /// This token represents substring(str, start, len) An operator that takes three
  145. /// arguments: a string, the first character and the length.
  146. class TokenSubstring : public Token {
  147. public:
  148. /// @brief Constructor (does nothing)
  149. TokenSubstring() {}
  150. /// @brief Extract a substring from a string
  151. ///
  152. /// Evaluation does not use packet information. It requires at least
  153. /// three values to be present on the stack. It will consume the top
  154. /// three values on the stack as parameters and push the resulting substring
  155. /// onto the stack. From the top it expects the values on the stack as:
  156. /// - len
  157. /// - start
  158. /// - str
  159. ///
  160. /// str is the string to extract a substring from. If it is empty, an empty
  161. /// string is pushed onto the value stack.
  162. ///
  163. /// start is the postion from which the code starts extracting the substring.
  164. /// 0 is the first character and a negative number starts from the end, with
  165. /// -1 being the last character. If the starting point is outside of the
  166. /// original string an empty string is pushed onto the value stack.
  167. ///
  168. /// length is the number of characters from the string to extract.
  169. /// "all" means all remaining characters from start to the end of string.
  170. /// A negative number means to go from start towards the beginning of
  171. /// the string, but doesn't include start.
  172. /// If length is longer than the remaining portion of string
  173. /// then the entire remaining portion is placed on the value stack.
  174. ///
  175. /// The following examples all use the base string "foobar", the first number
  176. /// is the starting position and the second is the length. Note that
  177. /// a negative length only selects which characters to extract it does not
  178. /// indicate an attempt to reverse the string.
  179. /// - 0, all => "foobar"
  180. /// - 0, 6 => "foobar"
  181. /// - 0, 4 => "foob"
  182. /// - 2, all => "obar"
  183. /// - 2, 6 => "obar"
  184. /// - -1, all => "r"
  185. /// - -1, -4 => "ooba"
  186. ///
  187. /// @throw EvalBadStack if there are less than 3 values on stack
  188. ///
  189. /// @param pkt (unused)
  190. /// @param values - stack of values (3 arguments will be popped, 1 result
  191. /// will be pushed)
  192. void evaluate(const Pkt& pkt, ValueStack& values);
  193. };
  194. }; // end of isc::dhcp namespace
  195. }; // end of isc namespace
  196. #endif