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