Kea 1.5.0
token.cc
Go to the documentation of this file.
1// Copyright (C) 2015-2018 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::dhcp;
28using namespace isc::util;
29using namespace std;
30
32
33void
35 // Literals only push, nothing to pop
36 values.push(value_);
37
38 // Log what we pushed
39 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_STRING)
40 .arg('\'' + value_ + '\'');
41}
42
43TokenHexString::TokenHexString(const string& str) : value_("") {
44 // Check string starts "0x" or "0x" and has at least one additional character.
45 if ((str.size() < 3) ||
46 (str[0] != '0') ||
47 ((str[1] != 'x') && (str[1] != 'X'))) {
48 return;
49 }
50 string digits = str.substr(2);
51
52 // Transform string of hexadecimal digits into binary format
53 vector<uint8_t> binary;
54 try {
55 // The decodeHex function expects that the string contains an
56 // even number of digits. If we don't meet this requirement,
57 // we have to insert a leading 0.
58 if ((digits.length() % 2) != 0) {
59 digits = digits.insert(0, "0");
60 }
61 util::encode::decodeHex(digits, binary);
62 } catch (...) {
63 return;
64 }
65
66 // Convert to a string (note that binary.size() cannot be 0)
67 value_.resize(binary.size());
68 memmove(&value_[0], &binary[0], binary.size());
69}
70
71void
73 // Literals only push, nothing to pop
74 values.push(value_);
75
76 // Log what we pushed
77 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_HEXSTRING)
78 .arg(toHex(value_));
79}
80
81TokenIpAddress::TokenIpAddress(const string& addr) : value_("") {
82 // Transform IP address into binary format
83 vector<uint8_t> binary;
84 try {
85 asiolink::IOAddress ip(addr);
86 binary = ip.toBytes();
87 } catch (...) {
88 return;
89 }
90
91 // Convert to a string (note that binary.size() is 4 or 16, so not 0)
92 value_.resize(binary.size());
93 memmove(&value_[0], &binary[0], binary.size());
94}
95
96void
98 // Literals only push, nothing to pop
99 values.push(value_);
100
101 // Log what we pushed
102 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_IPADDRESS)
103 .arg(toHex(value_));
104}
105
108 return (pkt.getOption(option_code_));
109}
110
111void
113 OptionPtr opt = getOption(pkt);
114 std::string opt_str;
115 if (opt) {
117 opt_str = opt->toString();
118 } else if (representation_type_ == HEXADECIMAL) {
119 std::vector<uint8_t> binary = opt->toBinary();
120 opt_str.resize(binary.size());
121 if (!binary.empty()) {
122 memmove(&opt_str[0], &binary[0], binary.size());
123 }
124 } else {
125 opt_str = "true";
126 }
127 } else if (representation_type_ == EXISTS) {
128 opt_str = "false";
129 }
130
131 // Push value of the option or empty string if there was no such option
132 // in the packet.
133 values.push(opt_str);
134
135 // Log what we pushed, both exists and textual are simple text
136 // and can be output directly. We also include the code number
137 // of the requested option.
139 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_OPTION)
140 .arg(option_code_)
141 .arg(toHex(opt_str));
142 } else {
143 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_OPTION)
144 .arg(option_code_)
145 .arg('\'' + opt_str + '\'');
146 }
147}
148
149std::string
151 std::string txt;
153 txt = "false";
154 }
155 values.push(txt);
156 return (txt);
157}
158
159TokenRelay4Option::TokenRelay4Option(const uint16_t option_code,
160 const RepresentationType& rep_type)
161 :TokenOption(option_code, rep_type) {
162}
163
165
166 // Check if there is Relay Agent Option.
168 if (!rai) {
169 return (OptionPtr());
170 }
171
172 // If there is, try to return its suboption
173 return (rai->getOption(option_code_));
174}
175
177
178 try {
179 // Check if it's a Pkt6. If it's not the dynamic_cast will
180 // throw std::bad_cast.
181 Pkt6& pkt6 = dynamic_cast<Pkt6&>(pkt);
182
183 try {
184 // Now that we have the right type of packet we can
185 // get the option and return it.
186 if (nest_level_ >= 0) {
187 uint8_t nesting_level = static_cast<uint8_t>(nest_level_);
188 return(pkt6.getRelayOption(option_code_, nesting_level));
189 } else {
190 int nesting_level = pkt6.relay_info_.size() + nest_level_;
191 if (nesting_level < 0) {
192 return (OptionPtr());
193 }
194 return(pkt6.getRelayOption(option_code_,
195 static_cast<uint8_t>(nesting_level)));
196 }
197 }
198 catch (const isc::OutOfRange&) {
199 // The only exception we expect is OutOfRange if the nest
200 // level is out of range of the encapsulations, for example
201 // if nest_level_ is 4 and there are only 2 encapsulations.
202 // We return a NULL in that case.
203 return (OptionPtr());
204 }
205
206 } catch (const std::bad_cast&) {
207 isc_throw(EvalTypeError, "Specified packet is not Pkt6");
208 }
209
210}
211
212void
214
215 string value;
216 vector<uint8_t> binary;
217 string type_str;
218 bool is_binary = true;
219 bool print_hex = true;
220 switch (type_) {
221 case IFACE:
222 is_binary = false;
223 print_hex = false;
224 value = pkt.getIface();
225 type_str = "iface";
226 break;
227 case SRC:
228 binary = pkt.getRemoteAddr().toBytes();
229 type_str = "src";
230 break;
231 case DST:
232 binary = pkt.getLocalAddr().toBytes();
233 type_str = "dst";
234 break;
235 case LEN:
236 // len() returns a size_t but in fact it can't be very large
237 // (with UDP transport it fits in 16 bits)
238 // the len() method is not const because of DHCPv6 relays.
239 // We assume here it has no bad side effects...
240 value = EvalContext::fromUint32(static_cast<uint32_t>(const_cast<Pkt&>(pkt).len()));
241 is_binary = false;
242 type_str = "len";
243 break;
244
245 default:
246 isc_throw(EvalTypeError, "Bad meta data specified: "
247 << static_cast<int>(type_) );
248 }
249
250 if (is_binary) {
251 value.resize(binary.size());
252 if (!binary.empty()) {
253 memmove(&value[0], &binary[0], binary.size());
254 }
255 }
256 values.push(value);
257
258 // Log what we pushed
259 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_PKT)
260 .arg(type_str)
261 .arg(print_hex ? toHex(value) : value);
262}
263
264void
266
267 vector<uint8_t> binary;
268 string value;
269 string type_str;
270 try {
271 // Check if it's a Pkt4. If it's not, the dynamic_cast will throw
272 // std::bad_cast (failed dynamic_cast returns NULL for pointers and
273 // throws for references).
274 const Pkt4& pkt4 = dynamic_cast<const Pkt4&>(pkt);
275
276 switch (type_) {
277 case CHADDR: {
278 HWAddrPtr hwaddr = pkt4.getHWAddr();
279 if (!hwaddr) {
280 // This should never happen. Every Pkt4 should always have
281 // a hardware address.
283 "Packet does not have hardware address");
284 }
285 binary = hwaddr->hwaddr_;
286 type_str = "mac";
287 break;
288 }
289 case GIADDR:
290 binary = pkt4.getGiaddr().toBytes();
291 type_str = "giaddr";
292 break;
293
294 case CIADDR:
295 binary = pkt4.getCiaddr().toBytes();
296 type_str = "ciaddr";
297 break;
298
299 case YIADDR:
300 binary = pkt4.getYiaddr().toBytes();
301 type_str = "yiaddr";
302 break;
303
304 case SIADDR:
305 binary = pkt4.getSiaddr().toBytes();
306 type_str = "siaddr";
307 break;
308
309 case HLEN:
310 // Pad the uint8_t field to 4 bytes.
311 value = EvalContext::fromUint32(pkt4.getHlen());
312 type_str = "hlen";
313 break;
314
315 case HTYPE:
316 // Pad the uint8_t field to 4 bytes.
317 value = EvalContext::fromUint32(pkt4.getHtype());
318 type_str = "htype";
319 break;
320 case MSGTYPE:
321 value = EvalContext::fromUint32(pkt4.getType());
322 type_str = "msgtype";
323 break;
324 case TRANSID:
325 value = EvalContext::fromUint32(pkt4.getTransid());
326 type_str = "transid";
327 break;
328
329 default:
330 isc_throw(EvalTypeError, "Bad field specified: "
331 << static_cast<int>(type_) );
332 }
333
334 } catch (const std::bad_cast&) {
335 isc_throw(EvalTypeError, "Specified packet is not a Pkt4");
336 }
337
338 if (!binary.empty()) {
339 value.resize(binary.size());
340 memmove(&value[0], &binary[0], binary.size());
341 }
342 values.push(value);
343
344 // Log what we pushed
345 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_PKT4)
346 .arg(type_str)
347 .arg(toHex(value));
348}
349
350void
352
353 string value;
354 string type_str;
355 try {
356 // Check if it's a Pkt6. If it's not the dynamic_cast will throw
357 // std::bad_cast (failed dynamic_cast returns NULL for pointers and
358 // throws for references).
359 const Pkt6& pkt6 = dynamic_cast<const Pkt6&>(pkt);
360
361 switch (type_) {
362 case MSGTYPE: {
363 // msg type is an uint8_t integer. We want a 4 byte string so 0 pad.
364 value = EvalContext::fromUint32(pkt6.getType());
365 type_str = "msgtype";
366 break;
367 }
368 case TRANSID: {
369 // transaction id is an uint32_t integer. We want a 4 byte string so copy
370 value = EvalContext::fromUint32(pkt6.getTransid());
371 type_str = "transid";
372 break;
373 }
374 default:
375 isc_throw(EvalTypeError, "Bad field specified: "
376 << static_cast<int>(type_) );
377 }
378
379 } catch (const std::bad_cast&) {
380 isc_throw(EvalTypeError, "Specified packet is not Pkt6");
381 }
382
383 values.push(value);
384
385 // Log what we pushed
386 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_PKT6)
387 .arg(type_str)
388 .arg(toHex(value));
389}
390
391void
393
394 vector<uint8_t> binary;
395 string type_str;
396 try {
397 // Check if it's a Pkt6. If it's not the dynamic_cast will
398 // throw std::bad_cast.
399 const Pkt6& pkt6 = dynamic_cast<const Pkt6&>(pkt);
400 uint8_t relay_level;
401
402 try {
403 if (nest_level_ >= 0) {
404 relay_level = static_cast<uint8_t>(nest_level_);
405 } else {
406 int nesting_level = pkt6.relay_info_.size() + nest_level_;
407 if (nesting_level < 0) {
408 // Don't throw OutOfRange here
409 nesting_level = 32;
410 }
411 relay_level = static_cast<uint8_t>(nesting_level);
412 }
413 switch (type_) {
414 // Now that we have the right type of packet we can
415 // get the option and return it.
416 case LINKADDR:
417 type_str = "linkaddr";
418 binary = pkt6.getRelay6LinkAddress(relay_level).toBytes();
419 break;
420 case PEERADDR:
421 type_str = "peeraddr";
422 binary = pkt6.getRelay6PeerAddress(relay_level).toBytes();
423 break;
424 }
425 } catch (const isc::OutOfRange&) {
426 // The only exception we expect is OutOfRange if the nest
427 // level is invalid. We push "" in that case.
428 values.push("");
429 // Log what we pushed
430 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_RELAY6_RANGE)
431 .arg(type_str)
432 .arg(int(nest_level_))
433 .arg("0x");
434 return;
435 }
436 } catch (const std::bad_cast&) {
437 isc_throw(EvalTypeError, "Specified packet is not Pkt6");
438 }
439
440 string value;
441 value.resize(binary.size());
442 if (!binary.empty()) {
443 memmove(&value[0], &binary[0], binary.size());
444 }
445 values.push(value);
446
447 // Log what we pushed
448 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_RELAY6)
449 .arg(type_str)
450 .arg(int(nest_level_))
451 .arg(toHex(value));
452}
453
454void
456
457 if (values.size() < 2) {
458 isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
459 "2 values for == operator, got " << values.size());
460 }
461
462 string op1 = values.top();
463 values.pop();
464 string op2 = values.top();
465 values.pop(); // Dammit, std::stack interface is awkward.
466
467 if (op1 == op2)
468 values.push("true");
469 else
470 values.push("false");
471
472 // Log what we popped and pushed
473 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_EQUAL)
474 .arg(toHex(op1))
475 .arg(toHex(op2))
476 .arg('\'' + values.top() + '\'');
477}
478
479void
481
482 if (values.size() < 3) {
483 isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
484 "3 values for substring operator, got " << values.size());
485 }
486
487 string len_str = values.top();
488 values.pop();
489 string start_str = values.top();
490 values.pop();
491 string string_str = values.top();
492 values.pop();
493
494 // If we have no string to start with we push an empty string and leave
495 if (string_str.empty()) {
496 values.push("");
497
498 // Log what we popped and pushed
499 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUBSTRING_EMPTY)
500 .arg(len_str)
501 .arg(start_str)
502 .arg("0x")
503 .arg("0x");
504 return;
505 }
506
507 // Convert the starting position and length from strings to numbers
508 // the length may also be "all" in which case simply make it the
509 // length of the string.
510 // If we have a problem push an empty string and leave
511 int start_pos;
512 int length;
513 try {
514 start_pos = boost::lexical_cast<int>(start_str);
515 } catch (const boost::bad_lexical_cast&) {
516 isc_throw(EvalTypeError, "the parameter '" << start_str
517 << "' for the starting position of the substring "
518 << "couldn't be converted to an integer.");
519 }
520 try {
521 if (len_str == "all") {
522 length = string_str.length();
523 } else {
524 length = boost::lexical_cast<int>(len_str);
525 }
526 } catch (const boost::bad_lexical_cast&) {
527 isc_throw(EvalTypeError, "the parameter '" << len_str
528 << "' for the length of the substring "
529 << "couldn't be converted to an integer.");
530 }
531
532 const int string_length = string_str.length();
533 // If the starting position is outside of the string push an
534 // empty string and leave
535 if ((start_pos < -string_length) || (start_pos >= string_length)) {
536 values.push("");
537
538 // Log what we popped and pushed
539 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUBSTRING_RANGE)
540 .arg(len_str)
541 .arg(start_str)
542 .arg(toHex(string_str))
543 .arg("0x");
544 return;
545 }
546
547 // Adjust the values to be something for substr. We first figure out
548 // the starting position, then update it and the length to get the
549 // characters before or after it depending on the sign of length
550 if (start_pos < 0) {
551 start_pos = string_length + start_pos;
552 }
553
554 if (length < 0) {
555 length = -length;
556 if (length <= start_pos){
557 start_pos -= length;
558 } else {
559 length = start_pos;
560 start_pos = 0;
561 }
562 }
563
564 // and finally get the substring
565 values.push(string_str.substr(start_pos, length));
566
567 // Log what we popped and pushed
568 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUBSTRING)
569 .arg(len_str)
570 .arg(start_str)
571 .arg(toHex(string_str))
572 .arg(toHex(values.top()));
573}
574
575void
577
578 if (values.size() < 2) {
579 isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
580 "2 values for concat, got " << values.size());
581 }
582
583 string op1 = values.top();
584 values.pop();
585 string op2 = values.top();
586 values.pop(); // Dammit, std::stack interface is awkward.
587
588 // The top of the stack was evaluated last so this is the right order
589 values.push(op2 + op1);
590
591 // Log what we popped and pushed
592 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_CONCAT)
593 .arg(toHex(op1))
594 .arg(toHex(op2))
595 .arg(toHex(values.top()));
596}
597
598void
600
601 if (values.size() < 3) {
602 isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
603 "3 values for ifelse, got " << values.size());
604 }
605
606 string iffalse = values.top();
607 values.pop();
608 string iftrue = values.top();
609 values.pop();
610 string cond = values.top();
611 values.pop();
612 bool val = toBool(cond);
613
614 if (val) {
615 values.push(iftrue);
616 } else {
617 values.push(iffalse);
618 }
619
620 // Log what we popped and pushed
621 if (val) {
622 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_IFELSE_TRUE)
623 .arg('\'' + cond + '\'')
624 .arg(toHex(iffalse))
625 .arg(toHex(iftrue));
626 } else {
627 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_IFELSE_FALSE)
628 .arg('\'' +cond + '\'')
629 .arg(toHex(iftrue))
630 .arg(toHex(iffalse));
631 }
632}
633
634void
636 if (values.size() < 2) {
637 isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
638 "2 values for hexstring, got " << values.size());
639 }
640
641 string separator = values.top();
642 values.pop();
643 string binary = values.top();
644 values.pop();
645
646 bool first = true;
647 stringstream tmp;
648 tmp << hex;
649 for (size_t i = 0; i < binary.size(); ++i) {
650 if (!first) {
651 tmp << separator;
652 } else {
653 first = false;
654 }
655 tmp << setw(2) << setfill('0')
656 << (static_cast<unsigned>(binary[i]) & 0xff);
657 }
658 values.push(tmp.str());
659
660 // Log what we popped and pushed
661 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_TOHEXSTRING)
662 .arg(toHex(binary))
663 .arg(separator)
664 .arg(tmp.str());
665}
666
667void
669
670 if (values.size() == 0) {
671 isc_throw(EvalBadStack, "Incorrect empty stack.");
672 }
673
674 string op = values.top();
675 values.pop();
676 bool val = toBool(op);
677
678 if (!val) {
679 values.push("true");
680 } else {
681 values.push("false");
682 }
683
684 // Log what we popped and pushed
685 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_NOT)
686 .arg('\'' + op + '\'')
687 .arg('\'' + values.top() + '\'');
688}
689
690void
692
693 if (values.size() < 2) {
694 isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
695 "2 values for and operator, got " << values.size());
696 }
697
698 string op1 = values.top();
699 values.pop();
700 bool val1 = toBool(op1);
701 string op2 = values.top();
702 values.pop(); // Dammit, std::stack interface is awkward.
703 bool val2 = toBool(op2);
704
705 if (val1 && val2) {
706 values.push("true");
707 } else {
708 values.push("false");
709 }
710
711 // Log what we popped and pushed
712 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_AND)
713 .arg('\'' + op1 + '\'')
714 .arg('\'' + op2 + '\'')
715 .arg('\'' + values.top() + '\'');
716}
717
718void
719TokenOr::evaluate(Pkt& /*pkt*/, ValueStack& values) {
720
721 if (values.size() < 2) {
722 isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
723 "2 values for or operator, got " << values.size());
724 }
725
726 string op1 = values.top();
727 values.pop();
728 bool val1 = toBool(op1);
729 string op2 = values.top();
730 values.pop(); // Dammit, std::stack interface is awkward.
731 bool val2 = toBool(op2);
732
733 if (val1 || val2) {
734 values.push("true");
735 } else {
736 values.push("false");
737 }
738
739 // Log what we popped and pushed
740 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_OR)
741 .arg('\'' + op1 + '\'')
742 .arg('\'' + op2 + '\'')
743 .arg('\'' + values.top() + '\'');
744}
745
746void
748 if (pkt.inClass(client_class_)) {
749 values.push("true");
750 } else {
751 values.push("false");
752 }
753
754 // Log what we pushed
755 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_MEMBER)
756 .arg(client_class_)
757 .arg('\'' + values.top() + '\'');
758}
759
761 uint16_t option_code)
762 :TokenOption(option_code, repr), universe_(u), vendor_id_(vendor_id),
763 field_(option_code ? SUBOPTION : EXISTS)
764{
765}
766
768 :TokenOption(0, TokenOption::HEXADECIMAL), universe_(u), vendor_id_(vendor_id),
769 field_(field)
770{
771 if (field_ == EXISTS) {
773 }
774}
775
776uint32_t TokenVendor::getVendorId() const {
777 return (vendor_id_);
778}
779
781 return (field_);
782}
783
785
786 // Get the option first.
787 uint16_t code = 0;
788 switch (universe_) {
789 case Option::V4:
791 break;
792 case Option::V6:
793 code = D6O_VENDOR_OPTS;
794 break;
795 }
796
797 OptionPtr opt = pkt.getOption(code);
798 OptionVendorPtr vendor = boost::dynamic_pointer_cast<OptionVendor>(opt);
799 if (!vendor) {
800 // There's no vendor option, give up.
801 std::string txt = pushFailure(values);
802 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_NO_OPTION)
803 .arg(code)
804 .arg(txt);
805 return;
806 }
807
808 if (vendor_id_ && (vendor_id_ != vendor->getVendorId())) {
809 // There is vendor option, but it has other vendor-id value
810 // than we're looking for. (0 means accept any vendor-id)
811 std::string txt = pushFailure(values);
812 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH)
813 .arg(vendor_id_)
814 .arg(vendor->getVendorId())
815 .arg(txt);
816 return;
817 }
818
819 switch (field_) {
820 case ENTERPRISE_ID:
821 {
822 // Extract enterprise-id
823 string txt(sizeof(uint32_t), 0);
824 uint32_t value = htonl(vendor->getVendorId());
825 memcpy(&txt[0], &value, sizeof(uint32_t));
826 values.push(txt);
827 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_ENTERPRISE_ID)
828 .arg(vendor->getVendorId())
829 .arg(util::encode::encodeHex(std::vector<uint8_t>(txt.begin(),
830 txt.end())));
831 return;
832 }
833 case SUBOPTION:
836 TokenOption::evaluate(pkt, values);
837 return;
838 case EXISTS:
839 // We already passed all the checks: the option is there and has specified
840 // enterprise-id.
841 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_EXISTS)
842 .arg(vendor->getVendorId())
843 .arg("true");
844 values.push("true");
845 return;
846 case DATA:
847 // This is for vendor-class option, we can skip it here.
848 isc_throw(EvalTypeError, "Field None is not valid for vendor-class");
849 return;
850 }
851}
852
854 uint16_t code = 0;
855 switch (universe_) {
856 case Option::V4:
858 break;
859 case Option::V6:
860 code = D6O_VENDOR_OPTS;
861 break;
862 }
863
864 OptionPtr opt = pkt.getOption(code);
865 if (!opt) {
866 // If vendor option is not found, return NULL
867 return (opt);
868 }
869
870 // If vendor option is found, try to return its
871 // encapsulated option.
872 return (opt->getOption(option_code_));
873}
874
877 :TokenVendor(u, vendor_id, repr, 0), index_(0) {
878}
879
881 FieldType field, uint16_t index)
882 :TokenVendor(u, vendor_id, TokenOption::HEXADECIMAL, 0), index_(index)
883{
884 field_ = field;
885}
886
888 return (index_);
889}
890
892
893 // Get the option first.
894 uint16_t code = 0;
895 switch (universe_) {
896 case Option::V4:
898 break;
899 case Option::V6:
900 code = D6O_VENDOR_CLASS;
901 break;
902 }
903
904 OptionPtr opt = pkt.getOption(code);
905 OptionVendorClassPtr vendor = boost::dynamic_pointer_cast<OptionVendorClass>(opt);
906 if (!vendor) {
907 // There's no vendor class option, give up.
908 std::string txt = pushFailure(values);
909 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_NO_OPTION)
910 .arg(code)
911 .arg(txt);
912 return;
913 }
914
915 if (vendor_id_ && (vendor_id_ != vendor->getVendorId())) {
916 // There is vendor option, but it has other vendor-id value
917 // than we're looking for. (0 means accept any vendor-id)
918 std::string txt = pushFailure(values);
919 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH)
920 .arg(vendor_id_)
921 .arg(vendor->getVendorId())
922 .arg(txt);
923 return;
924 }
925
926 switch (field_) {
927 case ENTERPRISE_ID:
928 {
929 // Extract enterprise-id
930 string txt(sizeof(uint32_t), 0);
931 uint32_t value = htonl(vendor->getVendorId());
932 memcpy(&txt[0], &value, sizeof(uint32_t));
933 values.push(txt);
934 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID)
935 .arg(vendor->getVendorId())
936 .arg(util::encode::encodeHex(std::vector<uint8_t>(txt.begin(),
937 txt.end())));
938 return;
939 }
940 case SUBOPTION:
941 // Extract sub-options
942 isc_throw(EvalTypeError, "Field None is not valid for vendor-class");
943 return;
944 case EXISTS:
945 // We already passed all the checks: the option is there and has specified
946 // enterprise-id.
947 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_EXISTS)
948 .arg(vendor->getVendorId())
949 .arg("true");
950 values.push("true");
951 return;
952 case DATA:
953 {
954 size_t max = vendor->getTuplesNum();
955 if (index_ + 1 > max) {
956 // The index specified is out of bounds, e.g. there are only
957 // 2 tuples and index specified is 5.
958 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND)
959 .arg(index_)
960 .arg(vendor->getVendorId())
961 .arg(max)
962 .arg("");
963 values.push("");
964 return;
965 }
966
967 OpaqueDataTuple tuple = vendor->getTuple(index_);
968 OpaqueDataTuple::Buffer buf = tuple.getData();
969 string txt(buf.begin(), buf.end());
970
971 LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_DATA)
972 .arg(index_)
973 .arg(max)
974 .arg(txt);
975
976 values.push(txt);
977 return;
978 }
979 default:
980 isc_throw(EvalTypeError, "Invalid field specified." << field_);
981 }
982}
983
984TokenInteger::TokenInteger(const uint32_t value)
985 :TokenString(EvalContext::fromUint32(value)), int_value_(value) {
986
987}
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:67
Represents DHCPv4 packet.
Definition: pkt4.h:38
const isc::asiolink::IOAddress & getSiaddr() const
Returns siaddr field.
Definition: pkt4.h:196
const isc::asiolink::IOAddress & getYiaddr() const
Returns yiaddr field.
Definition: pkt4.h:208
const isc::asiolink::IOAddress & getGiaddr() const
Returns giaddr field.
Definition: pkt4.h:220
const isc::asiolink::IOAddress & getCiaddr() const
Returns ciaddr field.
Definition: pkt4.h:183
HWAddrPtr getHWAddr() const
returns hardware address information
Definition: pkt4.h:326
uint8_t getHlen() const
Returns hlen field.
Definition: pkt4.cc:541
uint8_t getType() const
Returns DHCP message type (e.g.
Definition: pkt4.cc:230
uint8_t getHtype() const
Returns htype field.
Definition: pkt4.cc:533
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:434
virtual uint8_t getType() const
Returns message type (e.g.
Definition: pkt6.h:218
Base class for classes representing DHCP messages.
Definition: pkt.h:90
const isc::asiolink::IOAddress & getLocalAddr() const
Returns local IP address.
Definition: pkt.h:431
const isc::asiolink::IOAddress & getRemoteAddr() const
Returns remote IP address.
Definition: pkt.h:417
uint32_t getTransid() const
Returns value of transaction-id field.
Definition: pkt.h:266
std::string getIface() const
Returns interface name.
Definition: pkt.h:504
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:691
void evaluate(Pkt &pkt, ValueStack &values)
Concatenate two values.
Definition: token.cc:576
void evaluate(Pkt &pkt, ValueStack &values)
Compare two values.
Definition: token.cc:455
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:72
std::string value_
Constant value.
Definition: token.h:155
TokenHexString(const std::string &str)
Value is set during token construction.
Definition: token.cc:43
void evaluate(Pkt &pkt, ValueStack &values)
Alternative.
Definition: token.cc:599
TokenInteger(const uint32_t value)
Integer value set during construction.
Definition: token.cc:984
void evaluate(Pkt &pkt, ValueStack &values)
Token evaluation (puts value of the constant string on the stack after decoding)
Definition: token.cc:97
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:81
ClientClass client_class_
The client class name.
Definition: token.h:873
void evaluate(Pkt &pkt, ValueStack &values)
Token evaluation (check if client_class_ was added to packet client classes)
Definition: token.cc:747
void evaluate(Pkt &pkt, ValueStack &values)
Logical negation.
Definition: token.cc:668
Token that represents a value of an option.
Definition: token.h:219
virtual OptionPtr getOption(Pkt &pkt)
Attempts to retrieve an option.
Definition: token.cc:107
void evaluate(Pkt &pkt, ValueStack &values)
Evaluates the values of the option.
Definition: token.cc:112
RepresentationType representation_type_
Representation type.
Definition: token.h:297
uint16_t option_code_
Code of the option to be extracted.
Definition: token.h:296
RepresentationType
Token representation type.
Definition: token.h:229
virtual std::string pushFailure(ValueStack &values)
Auxiliary method that puts string representing a failure.
Definition: token.cc:150
void evaluate(Pkt &pkt, ValueStack &values)
Logical or.
Definition: token.cc:719
@ CIADDR
ciaddr (IPv4 address)
Definition: token.h:442
@ HLEN
hlen (hardware address length)
Definition: token.h:445
@ HTYPE
htype (hardware address type)
Definition: token.h:446
@ GIADDR
giaddr (IPv4 address)
Definition: token.h:441
@ CHADDR
chaddr field (up to 16 bytes link-layer address)
Definition: token.h:440
@ YIADDR
yiaddr (IPv4 address)
Definition: token.h:443
@ SIADDR
siaddr (IPv4 address)
Definition: token.h:444
@ TRANSID
transaction-id (xid)
Definition: token.h:448
@ MSGTYPE
message type (not really a field, content of option 53)
Definition: token.h:447
void evaluate(Pkt &pkt, ValueStack &values)
Gets a value from the specified packet.
Definition: token.cc:265
void evaluate(Pkt &pkt, ValueStack &values)
Gets a value of the specified packet.
Definition: token.cc:351
@ TRANSID
transaction id (integer but manipulated as a string)
Definition: token.h:494
@ MSGTYPE
msg type
Definition: token.h:493
@ LEN
length (4 octets)
Definition: token.h:393
@ DST
destination (IP address)
Definition: token.h:392
@ IFACE
interface name (string)
Definition: token.h:390
@ SRC
source (IP address)
Definition: token.h:391
void evaluate(Pkt &pkt, ValueStack &values)
Gets a value from the specified packet.
Definition: token.cc:213
virtual OptionPtr getOption(Pkt &pkt)
Attempts to obtain specified sub-option of option 82 from the packet.
Definition: token.cc:164
TokenRelay4Option(const uint16_t option_code, const RepresentationType &rep_type)
Constructor for extracting sub-option from RAI (option 82)
Definition: token.cc:159
FieldType type_
field to get
Definition: token.h:590
void evaluate(Pkt &pkt, ValueStack &values)
Extracts the specified field from the requested relay.
Definition: token.cc:392
@ LINKADDR
Link address field (IPv6 address)
Definition: token.h:546
@ PEERADDR
Peer address field (IPv6 address)
Definition: token.h:545
int8_t nest_level_
Specifies field of the DHCPv6 relay option to get.
Definition: token.h:589
int8_t nest_level_
nesting level of the relay block to use
Definition: token.h:372
virtual OptionPtr getOption(Pkt &pkt)
Attempts to obtain specified option from the specified relay block.
Definition: token.cc:176
The order where Token subtypes are declared should be:
Definition: token.h:114
std::string value_
Constant value.
Definition: token.h:130
void evaluate(Pkt &pkt, ValueStack &values)
Token evaluation (puts value of the constant string on the stack)
Definition: token.cc:34
void evaluate(Pkt &pkt, ValueStack &values)
Extract a substring from a string.
Definition: token.cc:480
void evaluate(Pkt &pkt, ValueStack &values)
Convert a binary value to its hexadecimal string representation.
Definition: token.cc:635
TokenVendorClass(Option::Universe u, uint32_t vendor_id, RepresentationType repr)
This constructor is used to access fields.
Definition: token.cc:875
uint16_t getDataIndex() const
Returns data index.
Definition: token.cc:887
uint16_t index_
Data chunk index.
Definition: token.h:1058
void evaluate(Pkt &pkt, ValueStack &values)
This is a method for evaluating a packet.
Definition: token.cc:891
Token that represents vendor options in DHCPv4 and DHCPv6.
Definition: token.h:890
FieldType
Specifies a field of the vendor option.
Definition: token.h:894
@ DATA
data chunk, used in derived vendor-class only
Definition: token.h:898
@ EXISTS
vendor[123].exists
Definition: token.h:897
@ ENTERPRISE_ID
enterprise-id field (vendor-info, vendor-class)
Definition: token.h:896
@ SUBOPTION
If this token fetches a suboption, not a field.
Definition: token.h:895
Option::Universe universe_
Universe (V4 or V6)
Definition: token.h:976
uint32_t vendor_id_
Enterprise-id value.
Definition: token.h:982
FieldType field_
Specifies which field should be accessed.
Definition: token.h:985
uint32_t getVendorId() const
Returns enterprise-id.
Definition: token.cc:776
TokenVendor(Option::Universe u, uint32_t vendor_id, FieldType field)
Constructor used for accessing a field.
Definition: token.cc:767
virtual OptionPtr getOption(Pkt &pkt)
Attempts to get a suboption.
Definition: token.cc:853
virtual void evaluate(Pkt &pkt, ValueStack &values)
This is a method for evaluating a packet.
Definition: token.cc:784
FieldType getField() const
Returns field.
Definition: token.cc:780
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:35
static std::string fromUint32(const uint32_t integer)
Converts integer to string representation.
@ 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.
@ DHO_VIVCO_SUBOPTIONS
Definition: dhcp4.h:184
@ DHO_DHCP_AGENT_OPTIONS
Definition: dhcp4.h:151
@ DHO_VIVSO_SUBOPTIONS
Definition: dhcp4.h:185
const int EVAL_DBG_STACK
Definition: eval_log.h:26
boost::shared_ptr< HWAddr > HWAddrPtr
Shared pointer to a hardware address structure.
Definition: hwaddr.h:154
isc::log::Logger eval_logger("eval")
Eval Logger.
Definition: eval_log.h:33
boost::shared_ptr< OptionVendorClass > OptionVendorClassPtr
Defines a pointer to the OptionVendorClass.
boost::shared_ptr< Option > OptionPtr
Definition: option.h:38
std::stack< std::string > ValueStack
Evaluated values are stored as a stack of strings.
Definition: token.h:33
string encodeHex(const vector< uint8_t > &binary)
Encode binary data in the base16 ('hex') format.
Definition: base_n.cc:461
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:466
std::string toHex(std::string value)
Encode in hexadecimal inline.
Definition: hex.h:53
Definition: edns.h:19