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