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