Kea  2.3.9
token.cc
Go to the documentation of this file.
1 // Copyright (C) 2015-2022 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
9 #include <eval/token.h>
10 #include <eval/eval_log.h>
11 #include <eval/eval_context.h>
12 #include <util/encode/hex.h>
13 #include <util/io_utilities.h>
14 #include <asiolink/io_address.h>
15 #include <dhcp/pkt4.h>
16 #include <dhcp/pkt6.h>
17 #include <boost/lexical_cast.hpp>
18 #include <dhcp/dhcp4.h>
19 #include <dhcp/dhcp6.h>
20 #include <dhcp/option_vendor.h>
22 
23 #include <boost/algorithm/string/classification.hpp>
24 #include <boost/algorithm/string/split.hpp>
25 
26 #include <cstring>
27 #include <string>
28 #include <iomanip>
29 #include <sstream>
30 
31 using namespace isc::asiolink;
32 using namespace isc::dhcp;
33 using namespace isc::util;
34 using namespace std;
35 
37 
38 void
39 TokenString::evaluate(Pkt& /*pkt*/, ValueStack& values) {
40  // Literals only push, nothing to pop
41  values.push(value_);
42 
43  // Log what we pushed
45  .arg('\'' + value_ + '\'');
46 }
47 
48 TokenHexString::TokenHexString(const string& str) : value_("") {
49  // Check string starts "0x" or "0x" and has at least one additional character.
50  if ((str.size() < 3) ||
51  (str[0] != '0') ||
52  ((str[1] != 'x') && (str[1] != 'X'))) {
53  return;
54  }
55  string digits = str.substr(2);
56 
57  // Transform string of hexadecimal digits into binary format
58  vector<uint8_t> binary;
59  try {
60  // The decodeHex function expects that the string contains an
61  // even number of digits. If we don't meet this requirement,
62  // we have to insert a leading 0.
63  if ((digits.length() % 2) != 0) {
64  digits = digits.insert(0, "0");
65  }
66  util::encode::decodeHex(digits, binary);
67  } catch (...) {
68  return;
69  }
70 
71  // Convert to a string (note that binary.size() cannot be 0)
72  value_.resize(binary.size());
73  memmove(&value_[0], &binary[0], binary.size());
74 }
75 
76 void
78  // Literals only push, nothing to pop
79  values.push(value_);
80 
81  // Log what we pushed
83  .arg(toHex(value_));
84 }
85 
86 TokenIpAddress::TokenIpAddress(const string& addr) : value_("") {
87  // Transform IP address into binary format
88  vector<uint8_t> binary;
89  try {
90  asiolink::IOAddress ip(addr);
91  binary = ip.toBytes();
92  } catch (...) {
93  return;
94  }
95 
96  // Convert to a string (note that binary.size() is 4 or 16, so not 0)
97  value_.resize(binary.size());
98  memmove(&value_[0], &binary[0], binary.size());
99 }
100 
101 void
103  // Literals only push, nothing to pop
104  values.push(value_);
105 
106  // Log what we pushed
108  .arg(toHex(value_));
109 }
110 
111 void
113  if (values.size() == 0) {
114  isc_throw(EvalBadStack, "Incorrect empty stack.");
115  }
116 
117  string op = values.top();
118  size_t size = op.size();
119 
120  if (!size) {
121  return;
122  }
123 
124  values.pop();
125 
126  if ((size != V4ADDRESS_LEN) && (size != V6ADDRESS_LEN)) {
127  isc_throw(EvalTypeError, "Can not convert to valid address.");
128  }
129 
130  std::vector<uint8_t> binary(op.begin(), op.end());
131 
132  if (size == V4ADDRESS_LEN) {
133  op = asiolink::IOAddress::fromBytes(AF_INET, binary.data()).toText();
134  } else {
135  op = asiolink::IOAddress::fromBytes(AF_INET6, binary.data()).toText();
136  }
137 
138  values.push(op);
139 
140  // Log what we pushed
142  .arg(op);
143 }
144 
145 void
147  if (values.size() == 0) {
148  isc_throw(EvalBadStack, "Incorrect empty stack.");
149  }
150 
151  string op = values.top();
152  size_t size = op.size();
153 
154  if (!size) {
155  return;
156  }
157 
158  values.pop();
159 
160  if (size != sizeof(int8_t)) {
161  isc_throw(EvalTypeError, "Can not convert to valid int8.");
162  }
163 
164  stringstream tmp;
165  tmp << static_cast<int32_t>(*(reinterpret_cast<int8_t*>(const_cast<char*>(op.data()))));
166  op = tmp.str();
167  values.push(op);
168 
169  // Log what we pushed
171  .arg(op);
172 }
173 
174 void
176  if (values.size() == 0) {
177  isc_throw(EvalBadStack, "Incorrect empty stack.");
178  }
179 
180  string op = values.top();
181  size_t size = op.size();
182 
183  if (!size) {
184  return;
185  }
186 
187  values.pop();
188 
189  if (size != sizeof(int16_t)) {
190  isc_throw(EvalTypeError, "Can not convert to valid int16.");
191  }
192 
193  stringstream tmp;
194  uint16_t value = *(reinterpret_cast<uint16_t*>(const_cast<char*>(op.data())));
195  std::string data = EvalContext::fromUint16(value);
196  tmp << *(reinterpret_cast<int16_t*>(const_cast<char*>(data.data())));
197  op = tmp.str();
198  values.push(op);
199 
200  // Log what we pushed
202  .arg(op);
203 }
204 
205 void
207  if (values.size() == 0) {
208  isc_throw(EvalBadStack, "Incorrect empty stack.");
209  }
210 
211  string op = values.top();
212  size_t size = op.size();
213 
214  if (!size) {
215  return;
216  }
217 
218  values.pop();
219 
220  if (size != sizeof(int32_t)) {
221  isc_throw(EvalTypeError, "Can not convert to valid int32.");
222  }
223 
224  stringstream tmp;
225  uint32_t value = *(reinterpret_cast<uint32_t*>(const_cast<char*>(op.data())));
226  std::string data = EvalContext::fromUint32(value);
227  tmp << *(reinterpret_cast<int32_t*>(const_cast<char*>(data.data())));
228  op = tmp.str();
229  values.push(op);
230 
231  // Log what we pushed
233  .arg(op);
234 }
235 
236 void
238  if (values.size() == 0) {
239  isc_throw(EvalBadStack, "Incorrect empty stack.");
240  }
241 
242  string op = values.top();
243  size_t size = op.size();
244 
245  if (!size) {
246  return;
247  }
248 
249  values.pop();
250 
251  if (size != sizeof(uint8_t)) {
252  isc_throw(EvalTypeError, "Can not convert to valid uint8.");
253  }
254 
255  stringstream tmp;
256  tmp << static_cast<uint32_t>(*(reinterpret_cast<uint8_t*>(const_cast<char*>(op.data()))));
257  op = tmp.str();
258  values.push(op);
259 
260  // Log what we pushed
262  .arg(op);
263 }
264 
265 void
267  if (values.size() == 0) {
268  isc_throw(EvalBadStack, "Incorrect empty stack.");
269  }
270 
271  string op = values.top();
272  size_t size = op.size();
273 
274  if (!size) {
275  return;
276  }
277 
278  values.pop();
279 
280  if (size != sizeof(uint16_t)) {
281  isc_throw(EvalTypeError, "Can not convert to valid uint16.");
282  }
283 
284  stringstream tmp;
285  uint16_t value = *(reinterpret_cast<uint16_t*>(const_cast<char*>(op.data())));
286  std::string data = EvalContext::fromUint16(value);
287  tmp << *(reinterpret_cast<uint16_t*>(const_cast<char*>(data.data())));
288  op = tmp.str();
289  values.push(op);
290 
291  // Log what we pushed
293  .arg(op);
294 }
295 
296 void
298  if (values.size() == 0) {
299  isc_throw(EvalBadStack, "Incorrect empty stack.");
300  }
301 
302  string op = values.top();
303  size_t size = op.size();
304 
305  if (!size) {
306  return;
307  }
308 
309  values.pop();
310 
311  if (size != sizeof(uint32_t)) {
312  isc_throw(EvalTypeError, "Can not convert to valid uint32.");
313  }
314 
315  stringstream tmp;
316  uint32_t value = *(reinterpret_cast<uint32_t*>(const_cast<char*>(op.data())));
317  std::string data = EvalContext::fromUint32(value);
318  tmp << *(reinterpret_cast<uint32_t*>(const_cast<char*>(data.data())));
319  op = tmp.str();
320  values.push(op);
321 
322  // Log what we pushed
324  .arg(op);
325 }
326 
327 OptionPtr
329  return (pkt.getOption(option_code_));
330 }
331 
332 void
334  OptionPtr opt = getOption(pkt);
335  std::string opt_str;
336  if (opt) {
337  if (representation_type_ == TEXTUAL) {
338  opt_str = opt->toString();
339  } else if (representation_type_ == HEXADECIMAL) {
340  std::vector<uint8_t> binary = opt->toBinary();
341  opt_str.resize(binary.size());
342  if (!binary.empty()) {
343  memmove(&opt_str[0], &binary[0], binary.size());
344  }
345  } else {
346  opt_str = "true";
347  }
348  } else if (representation_type_ == EXISTS) {
349  opt_str = "false";
350  }
351 
352  // Push value of the option or empty string if there was no such option
353  // in the packet.
354  values.push(opt_str);
355 
356  // Log what we pushed, both exists and textual are simple text
357  // and can be output directly. We also include the code number
358  // of the requested option.
361  .arg(option_code_)
362  .arg(toHex(opt_str));
363  } else {
365  .arg(option_code_)
366  .arg('\'' + opt_str + '\'');
367  }
368 }
369 
370 std::string
372  std::string txt;
373  if (representation_type_ == EXISTS) {
374  txt = "false";
375  }
376  values.push(txt);
377  return (txt);
378 }
379 
380 TokenRelay4Option::TokenRelay4Option(const uint16_t option_code,
381  const RepresentationType& rep_type)
382  :TokenOption(option_code, rep_type) {
383 }
384 
386  // Check if there is Relay Agent Option.
388  if (!rai) {
389  return (OptionPtr());
390  }
391 
392  // If there is, try to return its suboption
393  return (rai->getOption(option_code_));
394 }
395 
397  try {
398  // Check if it's a Pkt6. If it's not the dynamic_cast will
399  // throw std::bad_cast.
400  Pkt6& pkt6 = dynamic_cast<Pkt6&>(pkt);
401 
402  try {
403  // Now that we have the right type of packet we can
404  // get the option and return it.
405  if (nest_level_ >= 0) {
406  uint8_t nesting_level = static_cast<uint8_t>(nest_level_);
407  return(pkt6.getRelayOption(option_code_, nesting_level));
408  } else {
409  int nesting_level = pkt6.relay_info_.size() + nest_level_;
410  if (nesting_level < 0) {
411  return (OptionPtr());
412  }
413  return(pkt6.getRelayOption(option_code_,
414  static_cast<uint8_t>(nesting_level)));
415  }
416  }
417  catch (const isc::OutOfRange&) {
418  // The only exception we expect is OutOfRange if the nest
419  // level is out of range of the encapsulations, for example
420  // if nest_level_ is 4 and there are only 2 encapsulations.
421  // We return a NULL in that case.
422  return (OptionPtr());
423  }
424 
425  } catch (const std::bad_cast&) {
426  isc_throw(EvalTypeError, "Specified packet is not Pkt6");
427  }
428 
429 }
430 
431 void
433  string value;
434  vector<uint8_t> binary;
435  string type_str;
436  bool is_binary = true;
437  bool print_hex = true;
438  switch (type_) {
439  case IFACE:
440  is_binary = false;
441  print_hex = false;
442  value = pkt.getIface();
443  type_str = "iface";
444  break;
445  case SRC:
446  binary = pkt.getRemoteAddr().toBytes();
447  type_str = "src";
448  break;
449  case DST:
450  binary = pkt.getLocalAddr().toBytes();
451  type_str = "dst";
452  break;
453  case LEN:
454  // len() returns a size_t but in fact it can't be very large
455  // (with UDP transport it fits in 16 bits)
456  // the len() method is not const because of DHCPv6 relays.
457  // We assume here it has no bad side effects...
458  value = EvalContext::fromUint32(static_cast<uint32_t>(const_cast<Pkt&>(pkt).len()));
459  is_binary = false;
460  type_str = "len";
461  break;
462 
463  default:
464  isc_throw(EvalTypeError, "Bad meta data specified: "
465  << static_cast<int>(type_) );
466  }
467 
468  if (is_binary) {
469  value.resize(binary.size());
470  if (!binary.empty()) {
471  memmove(&value[0], &binary[0], binary.size());
472  }
473  }
474  values.push(value);
475 
476  // Log what we pushed
478  .arg(type_str)
479  .arg(print_hex ? toHex(value) : value);
480 }
481 
482 void
484  vector<uint8_t> binary;
485  string value;
486  string type_str;
487  try {
488  // Check if it's a Pkt4. If it's not, the dynamic_cast will throw
489  // std::bad_cast (failed dynamic_cast returns NULL for pointers and
490  // throws for references).
491  const Pkt4& pkt4 = dynamic_cast<const Pkt4&>(pkt);
492 
493  switch (type_) {
494  case CHADDR: {
495  HWAddrPtr hwaddr = pkt4.getHWAddr();
496  if (!hwaddr) {
497  // This should never happen. Every Pkt4 should always have
498  // a hardware address.
500  "Packet does not have hardware address");
501  }
502  binary = hwaddr->hwaddr_;
503  type_str = "mac";
504  break;
505  }
506  case GIADDR:
507  binary = pkt4.getGiaddr().toBytes();
508  type_str = "giaddr";
509  break;
510  case CIADDR:
511  binary = pkt4.getCiaddr().toBytes();
512  type_str = "ciaddr";
513  break;
514  case YIADDR:
515  binary = pkt4.getYiaddr().toBytes();
516  type_str = "yiaddr";
517  break;
518  case SIADDR:
519  binary = pkt4.getSiaddr().toBytes();
520  type_str = "siaddr";
521  break;
522  case HLEN:
523  // Pad the uint8_t field to 4 bytes.
524  value = EvalContext::fromUint32(pkt4.getHlen());
525  type_str = "hlen";
526  break;
527  case HTYPE:
528  // Pad the uint8_t field to 4 bytes.
529  value = EvalContext::fromUint32(pkt4.getHtype());
530  type_str = "htype";
531  break;
532  case MSGTYPE:
533  value = EvalContext::fromUint32(pkt4.getType());
534  type_str = "msgtype";
535  break;
536  case TRANSID:
537  value = EvalContext::fromUint32(pkt4.getTransid());
538  type_str = "transid";
539  break;
540  default:
541  isc_throw(EvalTypeError, "Bad field specified: "
542  << static_cast<int>(type_) );
543  }
544 
545  } catch (const std::bad_cast&) {
546  isc_throw(EvalTypeError, "Specified packet is not a Pkt4");
547  }
548 
549  if (!binary.empty()) {
550  value.resize(binary.size());
551  memmove(&value[0], &binary[0], binary.size());
552  }
553  values.push(value);
554 
555  // Log what we pushed
557  .arg(type_str)
558  .arg(toHex(value));
559 }
560 
561 void
563  string value;
564  string type_str;
565  try {
566  // Check if it's a Pkt6. If it's not the dynamic_cast will throw
567  // std::bad_cast (failed dynamic_cast returns NULL for pointers and
568  // throws for references).
569  const Pkt6& pkt6 = dynamic_cast<const Pkt6&>(pkt);
570 
571  switch (type_) {
572  case MSGTYPE: {
573  // msg type is an uint8_t integer. We want a 4 byte string so 0 pad.
574  value = EvalContext::fromUint32(pkt6.getType());
575  type_str = "msgtype";
576  break;
577  }
578  case TRANSID: {
579  // transaction id is an uint32_t integer. We want a 4 byte string so copy
580  value = EvalContext::fromUint32(pkt6.getTransid());
581  type_str = "transid";
582  break;
583  }
584  default:
585  isc_throw(EvalTypeError, "Bad field specified: "
586  << static_cast<int>(type_) );
587  }
588 
589  } catch (const std::bad_cast&) {
590  isc_throw(EvalTypeError, "Specified packet is not Pkt6");
591  }
592 
593  values.push(value);
594 
595  // Log what we pushed
597  .arg(type_str)
598  .arg(toHex(value));
599 }
600 
601 void
603  vector<uint8_t> binary;
604  string type_str;
605  try {
606  // Check if it's a Pkt6. If it's not the dynamic_cast will
607  // throw std::bad_cast.
608  const Pkt6& pkt6 = dynamic_cast<const Pkt6&>(pkt);
609  uint8_t relay_level;
610 
611  try {
612  if (nest_level_ >= 0) {
613  relay_level = static_cast<uint8_t>(nest_level_);
614  } else {
615  int nesting_level = pkt6.relay_info_.size() + nest_level_;
616  if (nesting_level < 0) {
617  // Don't throw OutOfRange here
618  nesting_level = 32;
619  }
620  relay_level = static_cast<uint8_t>(nesting_level);
621  }
622  switch (type_) {
623  // Now that we have the right type of packet we can
624  // get the option and return it.
625  case LINKADDR:
626  type_str = "linkaddr";
627  binary = pkt6.getRelay6LinkAddress(relay_level).toBytes();
628  break;
629  case PEERADDR:
630  type_str = "peeraddr";
631  binary = pkt6.getRelay6PeerAddress(relay_level).toBytes();
632  break;
633  }
634  } catch (const isc::OutOfRange&) {
635  // The only exception we expect is OutOfRange if the nest
636  // level is invalid. We push "" in that case.
637  values.push("");
638  // Log what we pushed
640  .arg(type_str)
641  .arg(int(nest_level_))
642  .arg("0x");
643  return;
644  }
645  } catch (const std::bad_cast&) {
646  isc_throw(EvalTypeError, "Specified packet is not Pkt6");
647  }
648 
649  string value;
650  value.resize(binary.size());
651  if (!binary.empty()) {
652  memmove(&value[0], &binary[0], binary.size());
653  }
654  values.push(value);
655 
656  // Log what we pushed
658  .arg(type_str)
659  .arg(int(nest_level_))
660  .arg(toHex(value));
661 }
662 
663 void
664 TokenEqual::evaluate(Pkt& /*pkt*/, ValueStack& values) {
665  if (values.size() < 2) {
666  isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
667  "2 values for == operator, got " << values.size());
668  }
669 
670  string op1 = values.top();
671  values.pop();
672  string op2 = values.top();
673  values.pop(); // Dammit, std::stack interface is awkward.
674 
675  if (op1 == op2)
676  values.push("true");
677  else
678  values.push("false");
679 
680  // Log what we popped and pushed
682  .arg(toHex(op1))
683  .arg(toHex(op2))
684  .arg('\'' + values.top() + '\'');
685 }
686 
687 void
689  if (values.size() < 3) {
690  isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
691  "3 values for substring operator, got " << values.size());
692  }
693 
694  string len_str = values.top();
695  values.pop();
696  string start_str = values.top();
697  values.pop();
698  string string_str = values.top();
699  values.pop();
700 
701  // If we have no string to start with we push an empty string and leave
702  if (string_str.empty()) {
703  values.push("");
704 
705  // Log what we popped and pushed
707  .arg(len_str)
708  .arg(start_str)
709  .arg("0x")
710  .arg("0x");
711  return;
712  }
713 
714  // Convert the starting position and length from strings to numbers
715  // the length may also be "all" in which case simply make it the
716  // length of the string.
717  // If we have a problem push an empty string and leave
718  int start_pos;
719  int length;
720  try {
721  start_pos = boost::lexical_cast<int>(start_str);
722  } catch (const boost::bad_lexical_cast&) {
723  isc_throw(EvalTypeError, "the parameter '" << start_str
724  << "' for the starting position of the substring "
725  << "couldn't be converted to an integer.");
726  }
727  try {
728  if (len_str == "all") {
729  length = string_str.length();
730  } else {
731  length = boost::lexical_cast<int>(len_str);
732  }
733  } catch (const boost::bad_lexical_cast&) {
734  isc_throw(EvalTypeError, "the parameter '" << len_str
735  << "' for the length of the substring "
736  << "couldn't be converted to an integer.");
737  }
738 
739  const int string_length = string_str.length();
740  // If the starting position is outside of the string push an
741  // empty string and leave
742  if ((start_pos < -string_length) || (start_pos >= string_length)) {
743  values.push("");
744 
745  // Log what we popped and pushed
747  .arg(len_str)
748  .arg(start_str)
749  .arg(toHex(string_str))
750  .arg("0x");
751  return;
752  }
753 
754  // Adjust the values to be something for substr. We first figure out
755  // the starting position, then update it and the length to get the
756  // characters before or after it depending on the sign of length
757  if (start_pos < 0) {
758  start_pos = string_length + start_pos;
759  }
760 
761  if (length < 0) {
762  length = -length;
763  if (length <= start_pos){
764  start_pos -= length;
765  } else {
766  length = start_pos;
767  start_pos = 0;
768  }
769  }
770 
771  // and finally get the substring
772  values.push(string_str.substr(start_pos, length));
773 
774  // Log what we popped and pushed
776  .arg(len_str)
777  .arg(start_str)
778  .arg(toHex(string_str))
779  .arg(toHex(values.top()));
780 }
781 
782 void
783 TokenSplit::evaluate(Pkt& /*pkt*/, ValueStack& values) {
784  if (values.size() < 3) {
785  isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
786  "3 values for split operator, got " << values.size());
787  }
788 
789  // Pop the parameters.
790  string field_str = values.top();
791  values.pop();
792  string delim_str = values.top();
793  values.pop();
794  string string_str = values.top();
795  values.pop();
796 
797  // If we have no string to start with we push an empty string and leave
798  if (string_str.empty()) {
799  values.push("");
800 
801  // Log what we popped and pushed
803  .arg(field_str)
804  .arg(delim_str)
805  .arg(string_str)
806  .arg("0x");
807  return;
808  }
809 
810  // Convert the field position from string to number
811  // If we have a problem push an empty string and leave
812  int field;
813  try {
814  field = boost::lexical_cast<int>(field_str);
815  } catch (const boost::bad_lexical_cast&) {
816  isc_throw(EvalTypeError, "the parameter '" << field_str
817  << "' for the field field for split "
818  << "couldn't be converted to an integer.");
819  }
820 
821  // If we have no delimiter to start with we push the input string and leave
822  if (delim_str.empty()) {
823  values.push(string_str);
824 
825  // Log what we popped and pushed
827  .arg(field_str)
828  .arg(delim_str)
829  .arg(string_str)
830  .arg(toHex(values.top()));
831  return;
832  }
833 
834  // Split the string into fields.
835  std::vector<std::string> fields;
836  boost::split(fields, string_str, boost::is_any_of(delim_str),
837  boost::algorithm::token_compress_off);
838 
839  // Range check the field.
840  if (field < 1 || field > fields.size()) {
841  // Push an empty string if field is out of range.
842  values.push("");
843 
844  // Log what we popped and pushed
846  .arg(field_str)
847  .arg(delim_str)
848  .arg(string_str)
849  .arg("0x");
850  return;
851  }
852 
853  // Push the desired field.
854  values.push(fields[field - 1]);
855 
856  // Log what we popped and pushed
858  .arg(field_str)
859  .arg(delim_str)
860  .arg(string_str)
861  .arg(toHex(values.top()));
862 }
863 
864 void
866  if (values.size() < 2) {
867  isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
868  "2 values for concat, got " << values.size());
869  }
870 
871  string op1 = values.top();
872  values.pop();
873  string op2 = values.top();
874  values.pop(); // Dammit, std::stack interface is awkward.
875 
876  // The top of the stack was evaluated last so this is the right order
877  values.push(op2 + op1);
878 
879  // Log what we popped and pushed
881  .arg(toHex(op1))
882  .arg(toHex(op2))
883  .arg(toHex(values.top()));
884 }
885 
886 void
888  if (values.size() < 3) {
889  isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
890  "3 values for ifelse, got " << values.size());
891  }
892 
893  string iffalse = values.top();
894  values.pop();
895  string iftrue = values.top();
896  values.pop();
897  string cond = values.top();
898  values.pop();
899  bool val = toBool(cond);
900 
901  if (val) {
902  values.push(iftrue);
903  } else {
904  values.push(iffalse);
905  }
906 
907  // Log what we popped and pushed
908  if (val) {
910  .arg('\'' + cond + '\'')
911  .arg(toHex(iffalse))
912  .arg(toHex(iftrue));
913  } else {
915  .arg('\'' +cond + '\'')
916  .arg(toHex(iftrue))
917  .arg(toHex(iffalse));
918  }
919 }
920 
921 void
923  if (values.size() < 2) {
924  isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
925  "2 values for hexstring, got " << values.size());
926  }
927 
928  string separator = values.top();
929  values.pop();
930  string binary = values.top();
931  values.pop();
932 
933  bool first = true;
934  stringstream tmp;
935  tmp << hex;
936  for (size_t i = 0; i < binary.size(); ++i) {
937  if (!first) {
938  tmp << separator;
939  } else {
940  first = false;
941  }
942  tmp << setw(2) << setfill('0')
943  << (static_cast<unsigned>(binary[i]) & 0xff);
944  }
945  values.push(tmp.str());
946 
947  // Log what we popped and pushed
949  .arg(toHex(binary))
950  .arg(separator)
951  .arg(tmp.str());
952 }
953 
954 void
955 TokenNot::evaluate(Pkt& /*pkt*/, ValueStack& values) {
956  if (values.size() == 0) {
957  isc_throw(EvalBadStack, "Incorrect empty stack.");
958  }
959 
960  string op = values.top();
961  values.pop();
962  bool val = toBool(op);
963 
964  if (!val) {
965  values.push("true");
966  } else {
967  values.push("false");
968  }
969 
970  // Log what we popped and pushed
972  .arg('\'' + op + '\'')
973  .arg('\'' + values.top() + '\'');
974 }
975 
976 void
977 TokenAnd::evaluate(Pkt& /*pkt*/, ValueStack& values) {
978  if (values.size() < 2) {
979  isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
980  "2 values for and operator, got " << values.size());
981  }
982 
983  string op1 = values.top();
984  values.pop();
985  bool val1 = toBool(op1);
986  string op2 = values.top();
987  values.pop(); // Dammit, std::stack interface is awkward.
988  bool val2 = toBool(op2);
989 
990  if (val1 && val2) {
991  values.push("true");
992  } else {
993  values.push("false");
994  }
995 
996  // Log what we popped and pushed
998  .arg('\'' + op1 + '\'')
999  .arg('\'' + op2 + '\'')
1000  .arg('\'' + values.top() + '\'');
1001 }
1002 
1003 void
1004 TokenOr::evaluate(Pkt& /*pkt*/, ValueStack& values) {
1005  if (values.size() < 2) {
1006  isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
1007  "2 values for or operator, got " << values.size());
1008  }
1009 
1010  string op1 = values.top();
1011  values.pop();
1012  bool val1 = toBool(op1);
1013  string op2 = values.top();
1014  values.pop(); // Dammit, std::stack interface is awkward.
1015  bool val2 = toBool(op2);
1016 
1017  if (val1 || val2) {
1018  values.push("true");
1019  } else {
1020  values.push("false");
1021  }
1022 
1023  // Log what we popped and pushed
1025  .arg('\'' + op1 + '\'')
1026  .arg('\'' + op2 + '\'')
1027  .arg('\'' + values.top() + '\'');
1028 }
1029 
1030 void
1032  if (pkt.inClass(client_class_)) {
1033  values.push("true");
1034  } else {
1035  values.push("false");
1036  }
1037 
1038  // Log what we pushed
1040  .arg(client_class_)
1041  .arg('\'' + values.top() + '\'');
1042 }
1043 
1045  uint16_t option_code)
1046  :TokenOption(option_code, repr), universe_(u), vendor_id_(vendor_id),
1047  field_(option_code ? SUBOPTION : EXISTS) {
1048 }
1049 
1051  :TokenOption(0, TokenOption::HEXADECIMAL), universe_(u), vendor_id_(vendor_id),
1052  field_(field) {
1053  if (field_ == EXISTS) {
1055  }
1056 }
1057 
1058 uint32_t TokenVendor::getVendorId() const {
1059  return (vendor_id_);
1060 }
1061 
1063  return (field_);
1064 }
1065 
1066 void TokenVendor::evaluate(Pkt& pkt, ValueStack& values) {
1067  // Get the option first.
1068  uint16_t code = 0;
1069  switch (universe_) {
1070  case Option::V4:
1071  code = DHO_VIVSO_SUBOPTIONS;
1072  break;
1073  case Option::V6:
1074  code = D6O_VENDOR_OPTS;
1075  break;
1076  }
1077 
1078  OptionPtr opt = pkt.getOption(code);
1079  OptionVendorPtr vendor = boost::dynamic_pointer_cast<OptionVendor>(opt);
1080  if (!vendor) {
1081  // There's no vendor option, give up.
1082  std::string txt = pushFailure(values);
1084  .arg(code)
1085  .arg(txt);
1086  return;
1087  }
1088 
1089  if (vendor_id_ && (vendor_id_ != vendor->getVendorId())) {
1090  // There is vendor option, but it has other vendor-id value
1091  // than we're looking for. (0 means accept any vendor-id)
1092  std::string txt = pushFailure(values);
1094  .arg(vendor_id_)
1095  .arg(vendor->getVendorId())
1096  .arg(txt);
1097  return;
1098  }
1099 
1100  switch (field_) {
1101  case ENTERPRISE_ID:
1102  {
1103  // Extract enterprise-id
1104  string txt(sizeof(uint32_t), 0);
1105  uint32_t value = htonl(vendor->getVendorId());
1106  memcpy(&txt[0], &value, sizeof(uint32_t));
1107  values.push(txt);
1109  .arg(vendor->getVendorId())
1110  .arg(util::encode::encodeHex(std::vector<uint8_t>(txt.begin(),
1111  txt.end())));
1112  return;
1113  }
1114  case SUBOPTION:
1117  TokenOption::evaluate(pkt, values);
1118  return;
1119  case EXISTS:
1120  // We already passed all the checks: the option is there and has specified
1121  // enterprise-id.
1123  .arg(vendor->getVendorId())
1124  .arg("true");
1125  values.push("true");
1126  return;
1127  case DATA:
1128  // This is for vendor-class option, we can skip it here.
1129  isc_throw(EvalTypeError, "Field None is not valid for vendor-class");
1130  return;
1131  }
1132 }
1133 
1135  uint16_t code = 0;
1136  switch (universe_) {
1137  case Option::V4:
1138  code = DHO_VIVSO_SUBOPTIONS;
1139  break;
1140  case Option::V6:
1141  code = D6O_VENDOR_OPTS;
1142  break;
1143  }
1144 
1145  OptionPtr opt = pkt.getOption(code);
1146  if (!opt) {
1147  // If vendor option is not found, return NULL
1148  return (opt);
1149  }
1150 
1151  // If vendor option is found, try to return its
1152  // encapsulated option.
1153  return (opt->getOption(option_code_));
1154 }
1155 
1157  RepresentationType repr)
1158  :TokenVendor(u, vendor_id, repr, 0), index_(0) {
1159 }
1160 
1162  FieldType field, uint16_t index)
1163  :TokenVendor(u, vendor_id, TokenOption::HEXADECIMAL, 0), index_(index) {
1164  field_ = field;
1165 }
1166 
1168  return (index_);
1169 }
1170 
1172  // Get the option first.
1173  uint16_t code = 0;
1174  switch (universe_) {
1175  case Option::V4:
1176  code = DHO_VIVCO_SUBOPTIONS;
1177  break;
1178  case Option::V6:
1179  code = D6O_VENDOR_CLASS;
1180  break;
1181  }
1182 
1183  OptionPtr opt = pkt.getOption(code);
1184  OptionVendorClassPtr vendor = boost::dynamic_pointer_cast<OptionVendorClass>(opt);
1185  if (!vendor) {
1186  // There's no vendor class option, give up.
1187  std::string txt = pushFailure(values);
1189  .arg(code)
1190  .arg(txt);
1191  return;
1192  }
1193 
1194  if (vendor_id_ && (vendor_id_ != vendor->getVendorId())) {
1195  // There is vendor option, but it has other vendor-id value
1196  // than we're looking for. (0 means accept any vendor-id)
1197  std::string txt = pushFailure(values);
1199  .arg(vendor_id_)
1200  .arg(vendor->getVendorId())
1201  .arg(txt);
1202  return;
1203  }
1204 
1205  switch (field_) {
1206  case ENTERPRISE_ID:
1207  {
1208  // Extract enterprise-id
1209  string txt(sizeof(uint32_t), 0);
1210  uint32_t value = htonl(vendor->getVendorId());
1211  memcpy(&txt[0], &value, sizeof(uint32_t));
1212  values.push(txt);
1214  .arg(vendor->getVendorId())
1215  .arg(util::encode::encodeHex(std::vector<uint8_t>(txt.begin(),
1216  txt.end())));
1217  return;
1218  }
1219  case SUBOPTION:
1220  // Extract sub-options
1221  isc_throw(EvalTypeError, "Field None is not valid for vendor-class");
1222  return;
1223  case EXISTS:
1224  // We already passed all the checks: the option is there and has specified
1225  // enterprise-id.
1227  .arg(vendor->getVendorId())
1228  .arg("true");
1229  values.push("true");
1230  return;
1231  case DATA:
1232  {
1233  size_t max = vendor->getTuplesNum();
1234  if (index_ + 1 > max) {
1235  // The index specified is out of bounds, e.g. there are only
1236  // 2 tuples and index specified is 5.
1238  .arg(index_)
1239  .arg(vendor->getVendorId())
1240  .arg(max)
1241  .arg("");
1242  values.push("");
1243  return;
1244  }
1245 
1246  OpaqueDataTuple tuple = vendor->getTuple(index_);
1247  OpaqueDataTuple::Buffer buf = tuple.getData();
1248  string txt(buf.begin(), buf.end());
1249 
1251  .arg(index_)
1252  .arg(max)
1253  .arg(txt);
1254 
1255  values.push(txt);
1256  return;
1257  }
1258  default:
1259  isc_throw(EvalTypeError, "Invalid field specified." << field_);
1260  }
1261 }
1262 
1263 TokenInteger::TokenInteger(const uint32_t value)
1264  :TokenString(EvalContext::fromUint32(value)), int_value_(value) {
1265 }
1266 
1267 OptionPtr
1269  if (!parent) {
1270  return (OptionPtr());
1271  }
1272  return (parent->getOption(sub_option_code_));
1273 }
1274 
1275 void
1277  OptionPtr parent = getOption(pkt);
1278  std::string txt;
1280  if (!parent) {
1281  // There's no parent option, notify that.
1283  if (representation_type_ == EXISTS) {
1284  txt = "false";
1285  }
1286  } else {
1287  OptionPtr sub = getSubOption(parent);
1288  if (!sub) {
1289  // Failed to find the sub-option
1290  if (representation_type_ == EXISTS) {
1291  txt = "false";
1292  }
1293  } else {
1294  if (representation_type_ == TEXTUAL) {
1295  txt = sub->toString();
1296  } else if (representation_type_ == HEXADECIMAL) {
1297  std::vector<uint8_t> binary = sub->toBinary();
1298  txt.resize(binary.size());
1299  if (!binary.empty()) {
1300  memmove(&txt[0], &binary[0], binary.size());
1301  }
1302  } else {
1303  txt = "true";
1304  }
1305  }
1306  }
1307 
1308  // Push value of the sub-option or empty string if there was no
1309  // such parent option in the packet or sub-option in the parent.
1310  values.push(txt);
1311 
1312  // Log what we pushed, both exists and textual are simple text
1313  // and can be output directly. We also include the code numbers
1314  // of the requested parent option and sub-option.
1317  .arg(option_code_)
1318  .arg(sub_option_code_)
1319  .arg(toHex(txt));
1320  } else {
1322  .arg(option_code_)
1323  .arg(sub_option_code_)
1324  .arg('\'' + txt + '\'');
1325  }
1326 }
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
EvalBadStack is thrown when more or less parameters are on the stack than expected.
Definition: token.h:37
EvalTypeError is thrown when a value on the stack has a content with an unexpected type.
Definition: token.h:45
Represents a single instance of the opaque data preceded by length.
const Buffer & getData() const
Returns a reference to the buffer holding tuple data.
std::vector< uint8_t > Buffer
Defines a type of the data buffer used to hold the opaque data.
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:83
Represents DHCPv4 packet.
Definition: pkt4.h:37
const isc::asiolink::IOAddress & getCiaddr() const
Returns ciaddr field.
Definition: pkt4.h:182
const isc::asiolink::IOAddress & getSiaddr() const
Returns siaddr field.
Definition: pkt4.h:194
const isc::asiolink::IOAddress & getGiaddr() const
Returns giaddr field.
Definition: pkt4.h:218
HWAddrPtr getHWAddr() const
returns hardware address information
Definition: pkt4.h:324
uint8_t getHlen() const
Returns hlen field.
Definition: pkt4.cc:581
const isc::asiolink::IOAddress & getYiaddr() const
Returns yiaddr field.
Definition: pkt4.h:206
uint8_t getType() const
Returns DHCP message type (e.g.
Definition: pkt4.cc:239
uint8_t getHtype() const
Returns htype field.
Definition: pkt4.cc:573
Represents a DHCPv6 packet.
Definition: pkt6.h:44
OptionPtr getRelayOption(uint16_t option_code, uint8_t nesting_level)
Returns option inserted by relay.
Definition: pkt6.cc:260
const isc::asiolink::IOAddress & getRelay6PeerAddress(uint8_t relay_level) const
return the peer address field from a relay option
Definition: pkt6.cc:336
const isc::asiolink::IOAddress & getRelay6LinkAddress(uint8_t relay_level) const
return the link address field from a relay option
Definition: pkt6.cc:326
std::vector< RelayInfo > relay_info_
Relay information.
Definition: pkt6.h:473
virtual uint8_t getType() const
Returns message type (e.g.
Definition: pkt6.h:220
Base class for classes representing DHCP messages.
Definition: pkt.h:96
const isc::asiolink::IOAddress & getLocalAddr() const
Returns local IP address.
Definition: pkt.h:489
uint32_t getTransid() const
Returns value of transaction-id field.
Definition: pkt.h:276
std::string getIface() const
Returns interface name.
Definition: pkt.h:562
OptionPtr getOption(const uint16_t type)
Returns the first option of specified type.
Definition: pkt.cc:55
bool inClass(const isc::dhcp::ClientClass &client_class)
Checks whether a client belongs to a given class.
Definition: pkt.cc:106
const isc::asiolink::IOAddress & getRemoteAddr() const
Returns remote IP address.
Definition: pkt.h:475
void evaluate(Pkt &pkt, ValueStack &values)
Logical and.
Definition: token.cc:977
void evaluate(Pkt &pkt, ValueStack &values)
Concatenate two values.
Definition: token.cc:865
void evaluate(Pkt &pkt, ValueStack &values)
Compare two values.
Definition: token.cc:664
void evaluate(Pkt &pkt, ValueStack &values)
Token evaluation (puts value of the constant string on the stack after decoding or an empty string if...
Definition: token.cc:77
std::string value_
Constant value.
Definition: token.h:155
void evaluate(Pkt &pkt, ValueStack &values)
Alternative.
Definition: token.cc:887
void evaluate(Pkt &pkt, ValueStack &values)
Token evaluation (puts value of the string on the stack after decoding)
Definition: token.cc:175
void evaluate(Pkt &pkt, ValueStack &values)
Token evaluation (puts value of the string on the stack after decoding)
Definition: token.cc:206
void evaluate(Pkt &pkt, ValueStack &values)
Token evaluation (puts value of the string on the stack after decoding)
Definition: token.cc:146
TokenInteger(const uint32_t value)
Integer value set during construction.
Definition: token.cc:1263
void evaluate(Pkt &pkt, ValueStack &values)
Token evaluation (puts value of the string on the stack after decoding)
Definition: token.cc:112
void evaluate(Pkt &pkt, ValueStack &values)
Token evaluation (puts value of the constant string on the stack after decoding)
Definition: token.cc:102
std::string value_
< Constant value (empty string if the IP address cannot be converted)
Definition: token.h:207
TokenIpAddress(const std::string &addr)
Value is set during token construction.
Definition: token.cc:86
ClientClass client_class_
The client class name.
Definition: token.h:1042
void evaluate(Pkt &pkt, ValueStack &values)
Token evaluation (check if client_class_ was added to packet client classes)
Definition: token.cc:1031
void evaluate(Pkt &pkt, ValueStack &values)
Logical negation.
Definition: token.cc:955
Token that represents a value of an option.
Definition: token.h:344
virtual OptionPtr getOption(Pkt &pkt)
Attempts to retrieve an option.
Definition: token.cc:328
void evaluate(Pkt &pkt, ValueStack &values)
Evaluates the values of the option.
Definition: token.cc:333
RepresentationType representation_type_
Representation type.
Definition: token.h:421
uint16_t option_code_
Code of the option to be extracted.
Definition: token.h:420
RepresentationType
Token representation type.
Definition: token.h:354
virtual std::string pushFailure(ValueStack &values)
Auxiliary method that puts string representing a failure.
Definition: token.cc:371
void evaluate(Pkt &pkt, ValueStack &values)
Logical or.
Definition: token.cc:1004
@ CIADDR
ciaddr (IPv4 address)
Definition: token.h:566
@ HLEN
hlen (hardware address length)
Definition: token.h:569
@ HTYPE
htype (hardware address type)
Definition: token.h:570
@ GIADDR
giaddr (IPv4 address)
Definition: token.h:565
@ CHADDR
chaddr field (up to 16 bytes link-layer address)
Definition: token.h:564
@ YIADDR
yiaddr (IPv4 address)
Definition: token.h:567
@ SIADDR
siaddr (IPv4 address)
Definition: token.h:568
@ TRANSID
transaction-id (xid)
Definition: token.h:572
@ MSGTYPE
message type (not really a field, content of option 53)
Definition: token.h:571
void evaluate(Pkt &pkt, ValueStack &values)
Gets a value from the specified packet.
Definition: token.cc:483
void evaluate(Pkt &pkt, ValueStack &values)
Gets a value of the specified packet.
Definition: token.cc:562
@ TRANSID
transaction id (integer but manipulated as a string)
Definition: token.h:618
@ MSGTYPE
msg type
Definition: token.h:617
@ LEN
length (4 octets)
Definition: token.h:517
@ DST
destination (IP address)
Definition: token.h:516
@ IFACE
interface name (string)
Definition: token.h:514
@ SRC
source (IP address)
Definition: token.h:515
void evaluate(Pkt &pkt, ValueStack &values)
Gets a value from the specified packet.
Definition: token.cc:432
virtual OptionPtr getOption(Pkt &pkt)
Attempts to obtain specified sub-option of option 82 from the packet.
Definition: token.cc:385
TokenRelay4Option(const uint16_t option_code, const RepresentationType &rep_type)
Constructor for extracting sub-option from RAI (option 82)
Definition: token.cc:380
FieldType type_
field to get
Definition: token.h:714
void evaluate(Pkt &pkt, ValueStack &values)
Extracts the specified field from the requested relay.
Definition: token.cc:602
@ LINKADDR
Link address field (IPv6 address)
Definition: token.h:670
@ PEERADDR
Peer address field (IPv6 address)
Definition: token.h:669
int8_t nest_level_
Specifies field of the DHCPv6 relay option to get.
Definition: token.h:713
int8_t nest_level_
nesting level of the relay block to use
Definition: token.h:496
virtual OptionPtr getOption(Pkt &pkt)
Attempts to obtain specified option from the specified relay block.
Definition: token.cc:396
void evaluate(Pkt &pkt, ValueStack &values)
Extract a field from a delimited string.
Definition: token.cc:783
The order where Token subtypes are declared should be:
Definition: token.h:114
virtual void evaluate(Pkt &pkt, ValueStack &values)
This is a method for evaluating a packet.
Definition: token.cc:1276
uint16_t sub_option_code_
Code of the sub-option to be extracted.
Definition: token.h:1294
virtual OptionPtr getSubOption(const OptionPtr &parent)
Attempts to retrieve a sub-option.
Definition: token.cc:1268
void evaluate(Pkt &pkt, ValueStack &values)
Extract a substring from a string.
Definition: token.cc:688
void evaluate(Pkt &pkt, ValueStack &values)
Convert a binary value to its hexadecimal string representation.
Definition: token.cc:922
void evaluate(Pkt &pkt, ValueStack &values)
Token evaluation (puts value of the string on the stack after decoding)
Definition: token.cc:266
void evaluate(Pkt &pkt, ValueStack &values)
Token evaluation (puts value of the string on the stack after decoding)
Definition: token.cc:297
void evaluate(Pkt &pkt, ValueStack &values)
Token evaluation (puts value of the string on the stack after decoding)
Definition: token.cc:237
TokenVendorClass(Option::Universe u, uint32_t vendor_id, RepresentationType repr)
This constructor is used to access fields.
Definition: token.cc:1156
uint16_t getDataIndex() const
Returns data index.
Definition: token.cc:1167
uint16_t index_
Data chunk index.
Definition: token.h:1227
void evaluate(Pkt &pkt, ValueStack &values)
This is a method for evaluating a packet.
Definition: token.cc:1171
Token that represents vendor options in DHCPv4 and DHCPv6.
Definition: token.h:1059
FieldType
Specifies a field of the vendor option.
Definition: token.h:1063
@ DATA
data chunk, used in derived vendor-class only
Definition: token.h:1067
@ EXISTS
vendor[123].exists
Definition: token.h:1066
@ ENTERPRISE_ID
enterprise-id field (vendor-info, vendor-class)
Definition: token.h:1065
@ SUBOPTION
If this token fetches a suboption, not a field.
Definition: token.h:1064
Option::Universe universe_
Universe (V4 or V6)
Definition: token.h:1145
uint32_t vendor_id_
Enterprise-id value.
Definition: token.h:1151
FieldType field_
Specifies which field should be accessed.
Definition: token.h:1154
uint32_t getVendorId() const
Returns enterprise-id.
Definition: token.cc:1058
TokenVendor(Option::Universe u, uint32_t vendor_id, FieldType field)
Constructor used for accessing a field.
Definition: token.cc:1050
virtual OptionPtr getOption(Pkt &pkt)
Attempts to get a suboption.
Definition: token.cc:1134
virtual void evaluate(Pkt &pkt, ValueStack &values)
This is a method for evaluating a packet.
Definition: token.cc:1066
FieldType getField() const
Returns field.
Definition: token.cc:1062
static bool toBool(std::string value)
Coverts a (string) value to a boolean.
Definition: token.h:90
Evaluation context, an interface to the expression evaluation.
Definition: eval_context.h:34
@ D6O_VENDOR_OPTS
Definition: dhcp6.h:37
@ D6O_VENDOR_CLASS
Definition: dhcp6.h:36
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
boost::shared_ptr< OptionVendor > OptionVendorPtr
Pointer to a vendor option.
const isc::log::MessageID EVAL_DEBUG_RELAY6_RANGE
Definition: eval_messages.h:30
const isc::log::MessageID EVAL_DEBUG_UINT32TOTEXT
Definition: eval_messages.h:43
const isc::log::MessageID EVAL_DEBUG_UINT16TOTEXT
Definition: eval_messages.h:42
const isc::log::MessageID EVAL_DEBUG_SPLIT_EMPTY
Definition: eval_messages.h:33
const isc::log::MessageID EVAL_DEBUG_VENDOR_CLASS_EXISTS
Definition: eval_messages.h:49
const isc::log::MessageID EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND
Definition: eval_messages.h:46
const isc::log::MessageID EVAL_DEBUG_PKT
Definition: eval_messages.h:26
@ DHO_VIVCO_SUBOPTIONS
Definition: dhcp4.h:189
@ DHO_DHCP_AGENT_OPTIONS
Definition: dhcp4.h:151
@ DHO_VIVSO_SUBOPTIONS
Definition: dhcp4.h:190
const isc::log::MessageID EVAL_DEBUG_HEXSTRING
Definition: eval_messages.h:14
const isc::log::MessageID EVAL_DEBUG_TOHEXSTRING
Definition: eval_messages.h:41
const isc::log::MessageID EVAL_DEBUG_VENDOR_CLASS_DATA
Definition: eval_messages.h:45
const isc::log::MessageID EVAL_DEBUG_SPLIT_FIELD_OUT_OF_RANGE
Definition: eval_messages.h:34
const isc::log::MessageID EVAL_DEBUG_INT32TOTEXT
Definition: eval_messages.h:18
const isc::log::MessageID EVAL_DEBUG_OPTION
Definition: eval_messages.h:24
const int EVAL_DBG_STACK
Definition: eval_log.h:26
const isc::log::MessageID EVAL_DEBUG_SUBSTRING
Definition: eval_messages.h:36
const isc::log::MessageID EVAL_DEBUG_PKT6
Definition: eval_messages.h:28
const isc::log::MessageID EVAL_DEBUG_RELAY6
Definition: eval_messages.h:29
const isc::log::MessageID EVAL_DEBUG_OR
Definition: eval_messages.h:25
const isc::log::MessageID EVAL_DEBUG_SUB_OPTION_NO_OPTION
Definition: eval_messages.h:40
const isc::log::MessageID EVAL_DEBUG_INT8TOTEXT
Definition: eval_messages.h:19
const isc::log::MessageID EVAL_DEBUG_VENDOR_ENTERPRISE_ID
Definition: eval_messages.h:51
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
const isc::log::MessageID EVAL_DEBUG_STRING
Definition: eval_messages.h:35
const isc::log::MessageID EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH
Definition: eval_messages.h:52
const isc::log::MessageID EVAL_DEBUG_SUB_OPTION
Definition: eval_messages.h:39
const isc::log::MessageID EVAL_DEBUG_SPLIT
Definition: eval_messages.h:31
const isc::log::MessageID EVAL_DEBUG_PKT4
Definition: eval_messages.h:27
const isc::log::MessageID EVAL_DEBUG_INT16TOTEXT
Definition: eval_messages.h:17
isc::log::Logger eval_logger("eval")
Eval Logger.
Definition: eval_log.h:33
const isc::log::MessageID EVAL_DEBUG_CONCAT
Definition: eval_messages.h:12
const isc::log::MessageID EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH
Definition: eval_messages.h:48
const isc::log::MessageID EVAL_DEBUG_VENDOR_EXISTS
Definition: eval_messages.h:53
const isc::log::MessageID EVAL_DEBUG_VENDOR_NO_OPTION
Definition: eval_messages.h:54
boost::shared_ptr< OptionVendorClass > OptionVendorClassPtr
Defines a pointer to the OptionVendorClass.
const isc::log::MessageID EVAL_DEBUG_IPADDRESS
Definition: eval_messages.h:20
const isc::log::MessageID EVAL_DEBUG_AND
Definition: eval_messages.h:11
const isc::log::MessageID EVAL_DEBUG_VENDOR_CLASS_NO_OPTION
Definition: eval_messages.h:50
const isc::log::MessageID EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID
Definition: eval_messages.h:47
const isc::log::MessageID EVAL_DEBUG_UINT8TOTEXT
Definition: eval_messages.h:44
const isc::log::MessageID EVAL_DEBUG_EQUAL
Definition: eval_messages.h:13
const isc::log::MessageID EVAL_DEBUG_IPADDRESSTOTEXT
Definition: eval_messages.h:21
const isc::log::MessageID EVAL_DEBUG_SPLIT_DELIM_EMPTY
Definition: eval_messages.h:32
const isc::log::MessageID EVAL_DEBUG_MEMBER
Definition: eval_messages.h:22
const isc::log::MessageID EVAL_DEBUG_IFELSE_TRUE
Definition: eval_messages.h:16
const isc::log::MessageID EVAL_DEBUG_NOT
Definition: eval_messages.h:23
boost::shared_ptr< Option > OptionPtr
Definition: option.h:36
const isc::log::MessageID EVAL_DEBUG_SUBSTRING_RANGE
Definition: eval_messages.h:38
std::stack< std::string > ValueStack
Evaluated values are stored as a stack of strings.
Definition: token.h:33
const isc::log::MessageID EVAL_DEBUG_IFELSE_FALSE
Definition: eval_messages.h:15
const isc::log::MessageID EVAL_DEBUG_SUBSTRING_EMPTY
Definition: eval_messages.h:37
const char * MessageID
Definition: message_types.h:15
string encodeHex(const vector< uint8_t > &binary)
Encode binary data in the base16 ('hex') format.
Definition: base_n.cc:483
void decodeHex(const string &input, vector< uint8_t > &result)
Decode a text encoded in the base16 ('hex') format into the original data.
Definition: base_n.cc:488
std::string toHex(std::string value)
Encode in hexadecimal inline.
Definition: hex.h:53
Definition: edns.h:19