123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879 |
- // Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this
- // file, You can obtain one at http://mozilla.org/MPL/2.0/.
- #include <eval/token.h>
- #include <eval/eval_log.h>
- #include <eval/eval_context.h>
- #include <util/encode/hex.h>
- #include <util/io_utilities.h>
- #include <asiolink/io_address.h>
- #include <dhcp/pkt4.h>
- #include <dhcp/pkt6.h>
- #include <boost/lexical_cast.hpp>
- #include <dhcp/dhcp4.h>
- #include <dhcp/dhcp6.h>
- #include <dhcp/option_vendor.h>
- #include <dhcp/option_vendor_class.h>
- #include <cstring>
- #include <string>
- using namespace isc::dhcp;
- using namespace isc::util;
- using namespace std;
- using isc::util::encode::toHex;
- void
- TokenString::evaluate(Pkt& /*pkt*/, ValueStack& values) {
- // Literals only push, nothing to pop
- values.push(value_);
- // Log what we pushed
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_STRING)
- .arg('\'' + value_ + '\'');
- }
- TokenHexString::TokenHexString(const string& str) : value_("") {
- // Check string starts "0x" or "0x" and has at least one additional character.
- if ((str.size() < 3) ||
- (str[0] != '0') ||
- ((str[1] != 'x') && (str[1] != 'X'))) {
- return;
- }
- string digits = str.substr(2);
- // Transform string of hexadecimal digits into binary format
- vector<uint8_t> binary;
- try {
- // The decodeHex function expects that the string contains an
- // even number of digits. If we don't meet this requirement,
- // we have to insert a leading 0.
- if ((digits.length() % 2) != 0) {
- digits = digits.insert(0, "0");
- }
- util::encode::decodeHex(digits, binary);
- } catch (...) {
- return;
- }
- // Convert to a string (note that binary.size() cannot be 0)
- value_.resize(binary.size());
- memmove(&value_[0], &binary[0], binary.size());
- }
- void
- TokenHexString::evaluate(Pkt& /*pkt*/, ValueStack& values) {
- // Literals only push, nothing to pop
- values.push(value_);
- // Log what we pushed
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_HEXSTRING)
- .arg(toHex(value_));
- }
- TokenIpAddress::TokenIpAddress(const string& addr) : value_("") {
- // Transform IP address into binary format
- vector<uint8_t> binary;
- try {
- asiolink::IOAddress ip(addr);
- binary = ip.toBytes();
- } catch (...) {
- return;
- }
- // Convert to a string (note that binary.size() is 4 or 16, so not 0)
- value_.resize(binary.size());
- memmove(&value_[0], &binary[0], binary.size());
- }
- void
- TokenIpAddress::evaluate(Pkt& /*pkt*/, ValueStack& values) {
- // Literals only push, nothing to pop
- values.push(value_);
- // Log what we pushed
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_IPADDRESS)
- .arg(toHex(value_));
- }
- OptionPtr
- TokenOption::getOption(Pkt& pkt) {
- return (pkt.getOption(option_code_));
- }
- void
- TokenOption::evaluate(Pkt& pkt, ValueStack& values) {
- OptionPtr opt = getOption(pkt);
- std::string opt_str;
- if (opt) {
- if (representation_type_ == TEXTUAL) {
- opt_str = opt->toString();
- } else if (representation_type_ == HEXADECIMAL) {
- std::vector<uint8_t> binary = opt->toBinary();
- opt_str.resize(binary.size());
- if (!binary.empty()) {
- memmove(&opt_str[0], &binary[0], binary.size());
- }
- } else {
- opt_str = "true";
- }
- } else if (representation_type_ == EXISTS) {
- opt_str = "false";
- }
- // Push value of the option or empty string if there was no such option
- // in the packet.
- values.push(opt_str);
- // Log what we pushed, both exists and textual are simple text
- // and can be output directly. We also include the code number
- // of the requested option.
- if (representation_type_ == HEXADECIMAL) {
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_OPTION)
- .arg(option_code_)
- .arg(toHex(opt_str));
- } else {
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_OPTION)
- .arg(option_code_)
- .arg('\'' + opt_str + '\'');
- }
- }
- std::string
- TokenOption::pushFailure(ValueStack& values) {
- std::string txt;
- if (representation_type_ == EXISTS) {
- txt = "false";
- }
- values.push(txt);
- return (txt);
- }
- TokenRelay4Option::TokenRelay4Option(const uint16_t option_code,
- const RepresentationType& rep_type)
- :TokenOption(option_code, rep_type) {
- }
- OptionPtr TokenRelay4Option::getOption(Pkt& pkt) {
- // Check if there is Relay Agent Option.
- OptionPtr rai = pkt.getOption(DHO_DHCP_AGENT_OPTIONS);
- if (!rai) {
- return (OptionPtr());
- }
- // If there is, try to return its suboption
- return (rai->getOption(option_code_));
- }
- OptionPtr TokenRelay6Option::getOption(Pkt& pkt) {
- try {
- // Check if it's a Pkt6. If it's not the dynamic_cast will
- // throw std::bad_cast.
- Pkt6& pkt6 = dynamic_cast<Pkt6&>(pkt);
- try {
- // Now that we have the right type of packet we can
- // get the option and return it.
- return(pkt6.getRelayOption(option_code_, nest_level_));
- }
- catch (const isc::OutOfRange&) {
- // The only exception we expect is OutOfRange if the nest
- // level is out of range of the encapsulations, for example
- // if nest_level_ is 4 and there are only 2 encapsulations.
- // We return a NULL in that case.
- return (OptionPtr());
- }
- } catch (const std::bad_cast&) {
- isc_throw(EvalTypeError, "Specified packet is not Pkt6");
- }
- }
- void
- TokenPkt::evaluate(Pkt& pkt, ValueStack& values) {
- string value;
- vector<uint8_t> binary;
- string type_str;
- bool is_binary = true;
- bool print_hex = true;
- switch (type_) {
- case IFACE:
- is_binary = false;
- print_hex = false;
- value = pkt.getIface();
- type_str = "iface";
- break;
- case SRC:
- binary = pkt.getRemoteAddr().toBytes();
- type_str = "src";
- break;
- case DST:
- binary = pkt.getLocalAddr().toBytes();
- type_str = "dst";
- break;
- case LEN:
- // len() returns a size_t but in fact it can't be very large
- // (with UDP transport it fits in 16 bits)
- // the len() method is not const because of DHCPv6 relays.
- // We assume here it has no bad side effects...
- value = EvalContext::fromUint32(static_cast<uint32_t>(const_cast<Pkt&>(pkt).len()));
- is_binary = false;
- type_str = "len";
- break;
- default:
- isc_throw(EvalTypeError, "Bad meta data specified: "
- << static_cast<int>(type_) );
- }
- if (is_binary) {
- value.resize(binary.size());
- if (!binary.empty()) {
- memmove(&value[0], &binary[0], binary.size());
- }
- }
- values.push(value);
- // Log what we pushed
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_PKT)
- .arg(type_str)
- .arg(print_hex ? toHex(value) : value);
- }
- void
- TokenPkt4::evaluate(Pkt& pkt, ValueStack& values) {
- vector<uint8_t> binary;
- string value;
- string type_str;
- try {
- // Check if it's a Pkt4. If it's not, the dynamic_cast will throw
- // std::bad_cast (failed dynamic_cast returns NULL for pointers and
- // throws for references).
- const Pkt4& pkt4 = dynamic_cast<const Pkt4&>(pkt);
- switch (type_) {
- case CHADDR: {
- HWAddrPtr hwaddr = pkt4.getHWAddr();
- if (!hwaddr) {
- // This should never happen. Every Pkt4 should always have
- // a hardware address.
- isc_throw(EvalTypeError,
- "Packet does not have hardware address");
- }
- binary = hwaddr->hwaddr_;
- type_str = "mac";
- break;
- }
- case GIADDR:
- binary = pkt4.getGiaddr().toBytes();
- type_str = "giaddr";
- break;
- case CIADDR:
- binary = pkt4.getCiaddr().toBytes();
- type_str = "ciaddr";
- break;
- case YIADDR:
- binary = pkt4.getYiaddr().toBytes();
- type_str = "yiaddr";
- break;
- case SIADDR:
- binary = pkt4.getSiaddr().toBytes();
- type_str = "siaddr";
- break;
- case HLEN:
- // Pad the uint8_t field to 4 bytes.
- value = EvalContext::fromUint32(pkt4.getHlen());
- type_str = "hlen";
- break;
- case HTYPE:
- // Pad the uint8_t field to 4 bytes.
- value = EvalContext::fromUint32(pkt4.getHtype());
- type_str = "htype";
- break;
- case MSGTYPE:
- value = EvalContext::fromUint32(pkt4.getType());
- type_str = "msgtype";
- break;
- case TRANSID:
- value = EvalContext::fromUint32(pkt4.getTransid());
- type_str = "transid";
- break;
- default:
- isc_throw(EvalTypeError, "Bad field specified: "
- << static_cast<int>(type_) );
- }
- } catch (const std::bad_cast&) {
- isc_throw(EvalTypeError, "Specified packet is not a Pkt4");
- }
- if (!binary.empty()) {
- value.resize(binary.size());
- memmove(&value[0], &binary[0], binary.size());
- }
- values.push(value);
- // Log what we pushed
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_PKT4)
- .arg(type_str)
- .arg(toHex(value));
- }
- void
- TokenPkt6::evaluate(Pkt& pkt, ValueStack& values) {
- string value;
- string type_str;
- try {
- // Check if it's a Pkt6. If it's not the dynamic_cast will throw
- // std::bad_cast (failed dynamic_cast returns NULL for pointers and
- // throws for references).
- const Pkt6& pkt6 = dynamic_cast<const Pkt6&>(pkt);
- switch (type_) {
- case MSGTYPE: {
- // msg type is an uint8_t integer. We want a 4 byte string so 0 pad.
- value = EvalContext::fromUint32(pkt6.getType());
- type_str = "msgtype";
- break;
- }
- case TRANSID: {
- // transaction id is an uint32_t integer. We want a 4 byte string so copy
- value = EvalContext::fromUint32(pkt6.getTransid());
- type_str = "transid";
- break;
- }
- default:
- isc_throw(EvalTypeError, "Bad field specified: "
- << static_cast<int>(type_) );
- }
- } catch (const std::bad_cast&) {
- isc_throw(EvalTypeError, "Specified packet is not Pkt6");
- }
- values.push(value);
- // Log what we pushed
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_PKT6)
- .arg(type_str)
- .arg(toHex(value));
- }
- void
- TokenRelay6Field::evaluate(Pkt& pkt, ValueStack& values) {
- vector<uint8_t> binary;
- string type_str;
- try {
- // Check if it's a Pkt6. If it's not the dynamic_cast will
- // throw std::bad_cast.
- const Pkt6& pkt6 = dynamic_cast<const Pkt6&>(pkt);
- try {
- switch (type_) {
- // Now that we have the right type of packet we can
- // get the option and return it.
- case LINKADDR:
- type_str = "linkaddr";
- binary = pkt6.getRelay6LinkAddress(nest_level_).toBytes();
- break;
- case PEERADDR:
- type_str = "peeraddr";
- binary = pkt6.getRelay6PeerAddress(nest_level_).toBytes();
- break;
- }
- } catch (const isc::OutOfRange&) {
- // The only exception we expect is OutOfRange if the nest
- // level is invalid. We push "" in that case.
- values.push("");
- // Log what we pushed
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_RELAY6_RANGE)
- .arg(type_str)
- .arg(unsigned(nest_level_))
- .arg("0x");
- return;
- }
- } catch (const std::bad_cast&) {
- isc_throw(EvalTypeError, "Specified packet is not Pkt6");
- }
- string value;
- value.resize(binary.size());
- if (!binary.empty()) {
- memmove(&value[0], &binary[0], binary.size());
- }
- values.push(value);
- // Log what we pushed
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_RELAY6)
- .arg(type_str)
- .arg(unsigned(nest_level_))
- .arg(toHex(value));
- }
- void
- TokenEqual::evaluate(Pkt& /*pkt*/, ValueStack& values) {
- if (values.size() < 2) {
- isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
- "2 values for == operator, got " << values.size());
- }
- string op1 = values.top();
- values.pop();
- string op2 = values.top();
- values.pop(); // Dammit, std::stack interface is awkward.
- if (op1 == op2)
- values.push("true");
- else
- values.push("false");
- // Log what we popped and pushed
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_EQUAL)
- .arg(toHex(op1))
- .arg(toHex(op2))
- .arg('\'' + values.top() + '\'');
- }
- void
- TokenSubstring::evaluate(Pkt& /*pkt*/, ValueStack& values) {
- if (values.size() < 3) {
- isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
- "3 values for substring operator, got " << values.size());
- }
- string len_str = values.top();
- values.pop();
- string start_str = values.top();
- values.pop();
- string string_str = values.top();
- values.pop();
- // If we have no string to start with we push an empty string and leave
- if (string_str.empty()) {
- values.push("");
- // Log what we popped and pushed
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUBSTRING_EMPTY)
- .arg(len_str)
- .arg(start_str)
- .arg("0x")
- .arg("0x");
- return;
- }
- // Convert the starting position and length from strings to numbers
- // the length may also be "all" in which case simply make it the
- // length of the string.
- // If we have a problem push an empty string and leave
- int start_pos;
- int length;
- try {
- start_pos = boost::lexical_cast<int>(start_str);
- } catch (const boost::bad_lexical_cast&) {
- isc_throw(EvalTypeError, "the parameter '" << start_str
- << "' for the starting postion of the substring "
- << "couldn't be converted to an integer.");
- }
- try {
- if (len_str == "all") {
- length = string_str.length();
- } else {
- length = boost::lexical_cast<int>(len_str);
- }
- } catch (const boost::bad_lexical_cast&) {
- isc_throw(EvalTypeError, "the parameter '" << len_str
- << "' for the length of the substring "
- << "couldn't be converted to an integer.");
- }
- const int string_length = string_str.length();
- // If the starting postion is outside of the string push an
- // empty string and leave
- if ((start_pos < -string_length) || (start_pos >= string_length)) {
- values.push("");
- // Log what we popped and pushed
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUBSTRING_RANGE)
- .arg(len_str)
- .arg(start_str)
- .arg(toHex(string_str))
- .arg("0x");
- return;
- }
- // Adjust the values to be something for substr. We first figure out
- // the starting postion, then update it and the length to get the
- // characters before or after it depending on the sign of length
- if (start_pos < 0) {
- start_pos = string_length + start_pos;
- }
- if (length < 0) {
- length = -length;
- if (length <= start_pos){
- start_pos -= length;
- } else {
- length = start_pos;
- start_pos = 0;
- }
- }
- // and finally get the substring
- values.push(string_str.substr(start_pos, length));
- // Log what we popped and pushed
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUBSTRING)
- .arg(len_str)
- .arg(start_str)
- .arg(toHex(string_str))
- .arg(toHex(values.top()));
- }
- void
- TokenConcat::evaluate(Pkt& /*pkt*/, ValueStack& values) {
- if (values.size() < 2) {
- isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
- "2 values for concat, got " << values.size());
- }
- string op1 = values.top();
- values.pop();
- string op2 = values.top();
- values.pop(); // Dammit, std::stack interface is awkward.
- // The top of the stack was evaluated last so this is the right order
- values.push(op2 + op1);
- // Log what we popped and pushed
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_CONCAT)
- .arg(toHex(op1))
- .arg(toHex(op2))
- .arg(toHex(values.top()));
- }
- void
- TokenNot::evaluate(Pkt& /*pkt*/, ValueStack& values) {
- if (values.size() == 0) {
- isc_throw(EvalBadStack, "Incorrect empty stack.");
- }
- string op = values.top();
- values.pop();
- bool val = toBool(op);
- if (!val) {
- values.push("true");
- } else {
- values.push("false");
- }
- // Log what we popped and pushed
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_NOT)
- .arg('\'' + op + '\'')
- .arg('\'' + values.top() + '\'');
- }
- void
- TokenAnd::evaluate(Pkt& /*pkt*/, ValueStack& values) {
- if (values.size() < 2) {
- isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
- "2 values for and operator, got " << values.size());
- }
- string op1 = values.top();
- values.pop();
- bool val1 = toBool(op1);
- string op2 = values.top();
- values.pop(); // Dammit, std::stack interface is awkward.
- bool val2 = toBool(op2);
- if (val1 && val2) {
- values.push("true");
- } else {
- values.push("false");
- }
- // Log what we popped and pushed
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_AND)
- .arg('\'' + op1 + '\'')
- .arg('\'' + op2 + '\'')
- .arg('\'' + values.top() + '\'');
- }
- void
- TokenOr::evaluate(Pkt& /*pkt*/, ValueStack& values) {
- if (values.size() < 2) {
- isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
- "2 values for or operator, got " << values.size());
- }
- string op1 = values.top();
- values.pop();
- bool val1 = toBool(op1);
- string op2 = values.top();
- values.pop(); // Dammit, std::stack interface is awkward.
- bool val2 = toBool(op2);
- if (val1 || val2) {
- values.push("true");
- } else {
- values.push("false");
- }
- // Log what we popped and pushed
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_OR)
- .arg('\'' + op1 + '\'')
- .arg('\'' + op2 + '\'')
- .arg('\'' + values.top() + '\'');
- }
- TokenVendor::TokenVendor(Option::Universe u, uint32_t vendor_id, RepresentationType repr,
- uint16_t option_code)
- :TokenOption(option_code, repr), universe_(u), vendor_id_(vendor_id),
- field_(option_code ? SUBOPTION : EXISTS)
- {
- }
- TokenVendor::TokenVendor(Option::Universe u, uint32_t vendor_id, FieldType field)
- :TokenOption(0, TokenOption::HEXADECIMAL), universe_(u), vendor_id_(vendor_id),
- field_(field)
- {
- if (field_ == EXISTS) {
- representation_type_ = TokenOption::EXISTS;
- }
- }
- uint32_t TokenVendor::getVendorId() const {
- return (vendor_id_);
- }
- TokenVendor::FieldType TokenVendor::getField() const {
- return (field_);
- }
- void TokenVendor::evaluate(Pkt& pkt, ValueStack& values) {
- // Get the option first.
- uint16_t code = 0;
- switch (universe_) {
- case Option::V4:
- code = DHO_VIVSO_SUBOPTIONS;
- break;
- case Option::V6:
- code = D6O_VENDOR_OPTS;
- break;
- }
- OptionPtr opt = pkt.getOption(code);
- OptionVendorPtr vendor = boost::dynamic_pointer_cast<OptionVendor>(opt);
- if (!vendor) {
- // There's no vendor option, give up.
- std::string txt = pushFailure(values);
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_NO_OPTION)
- .arg(code)
- .arg(txt);
- return;
- }
- if (vendor_id_ && (vendor_id_ != vendor->getVendorId())) {
- // There is vendor option, but it has other vendor-id value
- // than we're looking for. (0 means accept any vendor-id)
- std::string txt = pushFailure(values);
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH)
- .arg(vendor_id_)
- .arg(vendor->getVendorId())
- .arg(txt);
- return;
- }
- switch (field_) {
- case ENTERPRISE_ID:
- {
- // Extract enterprise-id
- string txt(sizeof(uint32_t), 0);
- uint32_t value = htonl(vendor->getVendorId());
- memcpy(&txt[0], &value, sizeof(uint32_t));
- values.push(txt);
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_ENTERPRISE_ID)
- .arg(vendor->getVendorId())
- .arg(util::encode::encodeHex(std::vector<uint8_t>(txt.begin(),
- txt.end())));
- return;
- }
- case SUBOPTION:
- /// This is vendor[X].option[Y].exists, let's try to
- /// extract the option
- TokenOption::evaluate(pkt, values);
- return;
- case EXISTS:
- // We already passed all the checks: the option is there and has specified
- // enterprise-id.
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_EXISTS)
- .arg(vendor->getVendorId())
- .arg("true");
- values.push("true");
- return;
- case DATA:
- // This is for vendor-class option, we can skip it here.
- isc_throw(EvalTypeError, "Field None is not valid for vendor-class");
- return;
- }
- }
- OptionPtr TokenVendor::getOption(Pkt& pkt) {
- uint16_t code = 0;
- switch (universe_) {
- case Option::V4:
- code = DHO_VIVSO_SUBOPTIONS;
- break;
- case Option::V6:
- code = D6O_VENDOR_OPTS;
- break;
- }
- OptionPtr opt = pkt.getOption(code);
- if (!opt) {
- // If vendor option is not found, return NULL
- return (opt);
- }
- // If vendor option is found, try to return its
- // encapsulated option.
- return (opt->getOption(option_code_));
- }
- TokenVendorClass::TokenVendorClass(Option::Universe u, uint32_t vendor_id,
- RepresentationType repr)
- :TokenVendor(u, vendor_id, repr, 0), index_(0) {
- }
- TokenVendorClass::TokenVendorClass(Option::Universe u, uint32_t vendor_id,
- FieldType field, uint16_t index)
- :TokenVendor(u, vendor_id, TokenOption::HEXADECIMAL, 0), index_(index)
- {
- field_ = field;
- }
- uint16_t TokenVendorClass::getDataIndex() const {
- return (index_);
- }
- void TokenVendorClass::evaluate(Pkt& pkt, ValueStack& values) {
- // Get the option first.
- uint16_t code = 0;
- switch (universe_) {
- case Option::V4:
- code = DHO_VIVCO_SUBOPTIONS;
- break;
- case Option::V6:
- code = D6O_VENDOR_CLASS;
- break;
- }
- OptionPtr opt = pkt.getOption(code);
- OptionVendorClassPtr vendor = boost::dynamic_pointer_cast<OptionVendorClass>(opt);
- if (!vendor) {
- // There's no vendor class option, give up.
- std::string txt = pushFailure(values);
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_NO_OPTION)
- .arg(code)
- .arg(txt);
- return;
- }
- if (vendor_id_ && (vendor_id_ != vendor->getVendorId())) {
- // There is vendor option, but it has other vendor-id value
- // than we're looking for. (0 means accept any vendor-id)
- std::string txt = pushFailure(values);
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH)
- .arg(vendor_id_)
- .arg(vendor->getVendorId())
- .arg(txt);
- return;
- }
- switch (field_) {
- case ENTERPRISE_ID:
- {
- // Extract enterprise-id
- string txt(sizeof(uint32_t), 0);
- uint32_t value = htonl(vendor->getVendorId());
- memcpy(&txt[0], &value, sizeof(uint32_t));
- values.push(txt);
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID)
- .arg(vendor->getVendorId())
- .arg(util::encode::encodeHex(std::vector<uint8_t>(txt.begin(),
- txt.end())));
- return;
- }
- case SUBOPTION:
- // Extract sub-options
- isc_throw(EvalTypeError, "Field None is not valid for vendor-class");
- return;
- case EXISTS:
- // We already passed all the checks: the option is there and has specified
- // enterprise-id.
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_EXISTS)
- .arg(vendor->getVendorId())
- .arg("true");
- values.push("true");
- return;
- case DATA:
- {
- size_t max = vendor->getTuplesNum();
- if (index_ + 1 > max) {
- // The index specified is out of bounds, e.g. there are only
- // 2 tuples and index specified is 5.
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_DATA_NOT_FOUND)
- .arg(index_)
- .arg(vendor->getVendorId())
- .arg(max)
- .arg("");
- values.push("");
- return;
- }
- OpaqueDataTuple tuple = vendor->getTuple(index_);
- OpaqueDataTuple::Buffer buf = tuple.getData();
- string txt(buf.begin(), buf.end());
- LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_DATA)
- .arg(index_)
- .arg(max)
- .arg(txt);
- values.push(txt);
- return;
- }
- default:
- isc_throw(EvalTypeError, "Invalid field specified." << field_);
- }
- }
- TokenInteger::TokenInteger(const uint32_t value)
- :TokenString(EvalContext::fromUint32(value)), int_value_(value) {
- }
|