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