token.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  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/option.h>
  18. #include <dhcp/pkt.h>
  19. #include <stack>
  20. #include <string>
  21. namespace isc {
  22. namespace dhcp {
  23. class Token;
  24. /// @brief Pointer to a single Token
  25. typedef boost::shared_ptr<Token> TokenPtr;
  26. /// This is a structure that holds an expression converted to RPN
  27. ///
  28. /// For example expression: option[123].text == 'foo' will be converted to:
  29. /// [0] = option[123].text (TokenOption object)
  30. /// [1] = 'foo' (TokenString object)
  31. /// [2] = == operator (TokenEqual object)
  32. typedef std::vector<TokenPtr> Expression;
  33. typedef boost::shared_ptr<Expression> ExpressionPtr;
  34. /// Evaluated values are stored as a stack of strings
  35. typedef std::stack<std::string> ValueStack;
  36. /// @brief EvalBadStack is thrown when more or less parameters are on the
  37. /// stack than expected.
  38. class EvalBadStack : public Exception {
  39. public:
  40. EvalBadStack(const char* file, size_t line, const char* what) :
  41. isc::Exception(file, line, what) { };
  42. };
  43. /// @brief EvalTypeError is thrown when a value on the stack has a content
  44. /// with an unexpected type.
  45. class EvalTypeError : public Exception {
  46. public:
  47. EvalTypeError(const char* file, size_t line, const char* what) :
  48. isc::Exception(file, line, what) { };
  49. };
  50. /// @brief Base class for all tokens
  51. ///
  52. /// It provides an interface for all tokens and storage for string representation
  53. /// (all tokens evaluate to string).
  54. ///
  55. /// This class represents a single token. Examples of a token are:
  56. /// - "foo" (a constant string)
  57. /// - option[123].text (a token that extracts textual value of option 123)
  58. /// - == (an operator that compares two other tokens)
  59. /// - substring(a,b,c) (an operator that takes three arguments: a string,
  60. /// first character and length)
  61. class Token {
  62. public:
  63. /// @brief This is a generic method for evaluating a packet.
  64. ///
  65. /// We need to pass the packet being evaluated and possibly previously
  66. /// evaluated values. Specific implementations may ignore the packet altogether
  67. /// and just put their own value on the stack (constant tokens), look at the
  68. /// packet and put some data extracted from it on the stack (option tokens),
  69. /// or pop arguments from the stack and put back the result (operators).
  70. ///
  71. /// The parameters passed will be:
  72. ///
  73. /// @param pkt - packet being classified
  74. /// @param values - stack of values with previously evaluated tokens
  75. virtual void evaluate(const Pkt& pkt, ValueStack& values) = 0;
  76. /// @brief Virtual destructor
  77. virtual ~Token() {}
  78. };
  79. /// @brief Token representing a constant string
  80. ///
  81. /// This token holds value of a constant string, e.g. it represents
  82. /// "MSFT" in expression option[vendor-class].text == "MSFT"
  83. class TokenString : public Token {
  84. public:
  85. /// Value is set during token construction.
  86. ///
  87. /// @param str constant string to be represented.
  88. TokenString(const std::string& str)
  89. :value_(str){
  90. }
  91. /// @brief Token evaluation (puts value of the constant string on the stack)
  92. ///
  93. /// @param pkt (ignored)
  94. /// @param values (represented string will be pushed here)
  95. void evaluate(const Pkt& pkt, ValueStack& values);
  96. protected:
  97. std::string value_; ///< Constant value
  98. };
  99. /// @brief Token representing a constant string in hexadecimal format
  100. ///
  101. /// This token holds value of a constant string giving in an hexadecimal
  102. /// format, for instance 0x666f6f is "foo"
  103. class TokenHexString : public Token {
  104. public:
  105. /// Value is set during token construction.
  106. ///
  107. /// @param str constant string to be represented
  108. /// (must be "0x" or "0X" followed by a string of hexadecimal digits
  109. /// or decoding will fail)
  110. TokenHexString(const std::string& str);
  111. /// @brief Token evaluation (puts value of the constant string on
  112. /// the stack after decoding or an empty string if decoding fails
  113. /// (note it should not if the parser is correct)
  114. ///
  115. /// @param pkt (ignored)
  116. /// @param values (represented string will be pushed here)
  117. void evaluate(const Pkt& pkt, ValueStack& values);
  118. protected:
  119. std::string value_; ///< Constant value
  120. };
  121. /// @brief Token that represents a value of an option
  122. ///
  123. /// This represents a reference to a given option, e.g. in the expression
  124. /// option[vendor-class].text == "MSFT", it represents
  125. /// option[vendor-class].text
  126. ///
  127. /// During the evaluation it tries to extract the value of the specified
  128. /// option. If the option is not found, an empty string ("") is returned.
  129. class TokenOption : public Token {
  130. public:
  131. /// @brief Token representation type.
  132. ///
  133. /// There are many possible ways in which option can be presented.
  134. /// Currently the textual and hexadecimal representations are
  135. /// supported. The type of representation is specified in the
  136. /// constructor and it affects the value generated by the
  137. /// @c TokenOption::evaluate function.
  138. enum RepresentationType {
  139. TEXTUAL,
  140. HEXADECIMAL
  141. };
  142. /// @brief Constructor that takes an option code as a parameter
  143. ///
  144. /// @param option_code Code of the option to be represented.
  145. /// @param rep_type Token representation type.
  146. TokenOption(const uint16_t option_code, const RepresentationType& rep_type)
  147. : option_code_(option_code), representation_type_(rep_type) {}
  148. /// @brief Constructor that takes option name as a parameter.
  149. ///
  150. /// This constructor will throw exception if there is no definition using
  151. /// specified option name in libdhcp++.
  152. ///
  153. /// @param option_name Name of the option to be represented.
  154. /// @param option_universe Option universe: DHCPv4 or DHCPv6.
  155. /// @param rep_type Token representation type.
  156. /// @throw BadValue when the option_name cannot be resolved
  157. TokenOption(const std::string& option_name,
  158. const Option::Universe& option_universe,
  159. const RepresentationType& rep_type);
  160. /// @brief Evaluates the values of the option
  161. ///
  162. /// This token represents a value of the option, so this method attempts
  163. /// to extract the option from the packet and put its value on the stack.
  164. /// If the option is not there, an empty string ("") is put on the stack.
  165. ///
  166. /// @param pkt specified option will be extracted from this packet (if present)
  167. /// @param values value of the option will be pushed here (or "")
  168. void evaluate(const Pkt& pkt, ValueStack& values);
  169. /// @brief Returns option-code
  170. ///
  171. /// This method is used in testing to determine if the parser had
  172. /// instantiated TokenOption with correct parameters.
  173. ///
  174. /// @return option-code of the option this token expects to extract.
  175. uint16_t getCode() const {
  176. return (option_code_);
  177. }
  178. private:
  179. uint16_t option_code_; ///< Code of the option to be extracted
  180. RepresentationType representation_type_; ///< Representation type.
  181. };
  182. /// @brief Token that represents equality operator (compares two other tokens)
  183. ///
  184. /// For example in the expression option[vendor-class].text == "MSFT"
  185. /// this token represents the equal (==) sign.
  186. class TokenEqual : public Token {
  187. public:
  188. /// @brief Constructor (does nothing)
  189. TokenEqual() {}
  190. /// @brief Compare two values.
  191. ///
  192. /// Evaluation does not use packet information, but rather consumes the last
  193. /// two parameters. It does a simple string comparison and sets the value to
  194. /// either "true" or "false". It requires at least two parameters to be
  195. /// present on stack.
  196. ///
  197. /// @throw EvalBadStack if there are less than 2 values on stack
  198. ///
  199. /// @param pkt (unused)
  200. /// @param values - stack of values (2 arguments will be popped, 1 result
  201. /// will be pushed)
  202. void evaluate(const Pkt& pkt, ValueStack& values);
  203. };
  204. /// @brief Token that represents the substring operator (returns a portion
  205. /// of the supplied string)
  206. ///
  207. /// This token represents substring(str, start, len) An operator that takes three
  208. /// arguments: a string, the first character and the length.
  209. class TokenSubstring : public Token {
  210. public:
  211. /// @brief Constructor (does nothing)
  212. TokenSubstring() {}
  213. /// @brief Extract a substring from a string
  214. ///
  215. /// Evaluation does not use packet information. It requires at least
  216. /// three values to be present on the stack. It will consume the top
  217. /// three values on the stack as parameters and push the resulting substring
  218. /// onto the stack. From the top it expects the values on the stack as:
  219. /// - len
  220. /// - start
  221. /// - str
  222. ///
  223. /// str is the string to extract a substring from. If it is empty, an empty
  224. /// string is pushed onto the value stack.
  225. ///
  226. /// start is the postion from which the code starts extracting the substring.
  227. /// 0 is the first character and a negative number starts from the end, with
  228. /// -1 being the last character. If the starting point is outside of the
  229. /// original string an empty string is pushed onto the value stack.
  230. ///
  231. /// length is the number of characters from the string to extract.
  232. /// "all" means all remaining characters from start to the end of string.
  233. /// A negative number means to go from start towards the beginning of
  234. /// the string, but doesn't include start.
  235. /// If length is longer than the remaining portion of string
  236. /// then the entire remaining portion is placed on the value stack.
  237. ///
  238. /// The following examples all use the base string "foobar", the first number
  239. /// is the starting position and the second is the length. Note that
  240. /// a negative length only selects which characters to extract it does not
  241. /// indicate an attempt to reverse the string.
  242. /// - 0, all => "foobar"
  243. /// - 0, 6 => "foobar"
  244. /// - 0, 4 => "foob"
  245. /// - 2, all => "obar"
  246. /// - 2, 6 => "obar"
  247. /// - -1, all => "r"
  248. /// - -1, -4 => "ooba"
  249. ///
  250. /// @throw EvalBadStack if there are less than 3 values on stack
  251. /// @throw EvalTypeError if start is not a number or length a number or
  252. /// the special value "all".
  253. ///
  254. /// @param pkt (unused)
  255. /// @param values - stack of values (3 arguments will be popped, 1 result
  256. /// will be pushed)
  257. void evaluate(const Pkt& pkt, ValueStack& values);
  258. };
  259. }; // end of isc::dhcp namespace
  260. }; // end of isc namespace
  261. #endif