token.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832
  1. // Copyright (C) 2015-2016 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. #include <eval/token.h>
  7. #include <eval/eval_log.h>
  8. #include <util/encode/hex.h>
  9. #include <asiolink/io_address.h>
  10. #include <dhcp/pkt4.h>
  11. #include <boost/lexical_cast.hpp>
  12. #include <dhcp/pkt6.h>
  13. #include <dhcp/dhcp4.h>
  14. #include <dhcp/dhcp6.h>
  15. #include <dhcp/option_vendor.h>
  16. #include <dhcp/option_vendor_class.h>
  17. #include <cstring>
  18. #include <string>
  19. using namespace isc::dhcp;
  20. using namespace std;
  21. void
  22. TokenString::evaluate(Pkt& /*pkt*/, ValueStack& values) {
  23. // Literals only push, nothing to pop
  24. values.push(value_);
  25. // Log what we pushed
  26. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_STRING)
  27. .arg('\'' + value_ + '\'');
  28. }
  29. TokenHexString::TokenHexString(const string& str) : value_("") {
  30. // Check string starts "0x" or "0x" and has at least one additional character.
  31. if ((str.size() < 3) ||
  32. (str[0] != '0') ||
  33. ((str[1] != 'x') && (str[1] != 'X'))) {
  34. return;
  35. }
  36. string digits = str.substr(2);
  37. // Transform string of hexadecimal digits into binary format
  38. vector<uint8_t> binary;
  39. try {
  40. // The decodeHex function expects that the string contains an
  41. // even number of digits. If we don't meet this requirement,
  42. // we have to insert a leading 0.
  43. if ((digits.length() % 2) != 0) {
  44. digits = digits.insert(0, "0");
  45. }
  46. util::encode::decodeHex(digits, binary);
  47. } catch (...) {
  48. return;
  49. }
  50. // Convert to a string (note that binary.size() cannot be 0)
  51. value_.resize(binary.size());
  52. memmove(&value_[0], &binary[0], binary.size());
  53. }
  54. void
  55. TokenHexString::evaluate(Pkt& /*pkt*/, ValueStack& values) {
  56. // Literals only push, nothing to pop
  57. values.push(value_);
  58. // Log what we pushed
  59. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_HEXSTRING)
  60. .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(value_.begin(),
  61. value_.end())));
  62. }
  63. TokenIpAddress::TokenIpAddress(const string& addr) : value_("") {
  64. // Transform IP address into binary format
  65. vector<uint8_t> binary;
  66. try {
  67. asiolink::IOAddress ip(addr);
  68. binary = ip.toBytes();
  69. } catch (...) {
  70. return;
  71. }
  72. // Convert to a string (note that binary.size() is 4 or 16, so not 0)
  73. value_.resize(binary.size());
  74. memmove(&value_[0], &binary[0], binary.size());
  75. }
  76. void
  77. TokenIpAddress::evaluate(Pkt& /*pkt*/, ValueStack& values) {
  78. // Literals only push, nothing to pop
  79. values.push(value_);
  80. // Log what we pushed
  81. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_IPADDRESS)
  82. .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(value_.begin(),
  83. value_.end())));
  84. }
  85. OptionPtr
  86. TokenOption::getOption(Pkt& pkt) {
  87. return (pkt.getOption(option_code_));
  88. }
  89. void
  90. TokenOption::evaluate(Pkt& pkt, ValueStack& values) {
  91. OptionPtr opt = getOption(pkt);
  92. std::string opt_str;
  93. if (opt) {
  94. if (representation_type_ == TEXTUAL) {
  95. opt_str = opt->toString();
  96. } else if (representation_type_ == HEXADECIMAL) {
  97. std::vector<uint8_t> binary = opt->toBinary();
  98. opt_str.resize(binary.size());
  99. if (!binary.empty()) {
  100. memmove(&opt_str[0], &binary[0], binary.size());
  101. }
  102. } else {
  103. opt_str = "true";
  104. }
  105. } else if (representation_type_ == EXISTS) {
  106. opt_str = "false";
  107. }
  108. // Push value of the option or empty string if there was no such option
  109. // in the packet.
  110. values.push(opt_str);
  111. // Log what we pushed, both exists and textual are simple text
  112. // and can be output directly. We also include the code number
  113. // of the requested option.
  114. if (representation_type_ == HEXADECIMAL) {
  115. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_OPTION)
  116. .arg(option_code_)
  117. .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(opt_str.begin(),
  118. opt_str.end())));
  119. } else {
  120. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_OPTION)
  121. .arg(option_code_)
  122. .arg('\'' + opt_str + '\'');
  123. }
  124. }
  125. std::string
  126. TokenOption::pushFailure(ValueStack& values) {
  127. std::string txt;
  128. if (representation_type_ == EXISTS) {
  129. txt = "false";
  130. }
  131. values.push(txt);
  132. return (txt);
  133. }
  134. TokenRelay4Option::TokenRelay4Option(const uint16_t option_code,
  135. const RepresentationType& rep_type)
  136. :TokenOption(option_code, rep_type) {
  137. }
  138. OptionPtr TokenRelay4Option::getOption(Pkt& pkt) {
  139. // Check if there is Relay Agent Option.
  140. OptionPtr rai = pkt.getOption(DHO_DHCP_AGENT_OPTIONS);
  141. if (!rai) {
  142. return (OptionPtr());
  143. }
  144. // If there is, try to return its suboption
  145. return (rai->getOption(option_code_));
  146. }
  147. void
  148. TokenPkt4::evaluate(Pkt& pkt, ValueStack& values) {
  149. vector<uint8_t> binary;
  150. string type_str;
  151. try {
  152. // Check if it's a Pkt4. If it's not, the dynamic_cast will throw
  153. // std::bad_cast (failed dynamic_cast returns NULL for pointers and
  154. // throws for references).
  155. const Pkt4& pkt4 = dynamic_cast<const Pkt4&>(pkt);
  156. switch (type_) {
  157. case CHADDR: {
  158. HWAddrPtr hwaddr = pkt4.getHWAddr();
  159. if (!hwaddr) {
  160. // This should never happen. Every Pkt4 should always have
  161. // a hardware address.
  162. isc_throw(EvalTypeError,
  163. "Packet does not have hardware address");
  164. }
  165. binary = hwaddr->hwaddr_;
  166. type_str = "mac";
  167. break;
  168. }
  169. case GIADDR:
  170. binary = pkt4.getGiaddr().toBytes();
  171. type_str = "giaddr";
  172. break;
  173. case CIADDR:
  174. binary = pkt4.getCiaddr().toBytes();
  175. type_str = "ciaddr";
  176. break;
  177. case YIADDR:
  178. binary = pkt4.getYiaddr().toBytes();
  179. type_str = "yiaddr";
  180. break;
  181. case SIADDR:
  182. binary = pkt4.getSiaddr().toBytes();
  183. type_str = "siaddr";
  184. break;
  185. case HLEN:
  186. // Pad the uint8_t field to 4 bytes.
  187. binary.push_back(0);
  188. binary.push_back(0);
  189. binary.push_back(0);
  190. binary.push_back(pkt4.getHlen());
  191. type_str = "hlen";
  192. break;
  193. case HTYPE:
  194. // Pad the uint8_t field to 4 bytes.
  195. binary.push_back(0);
  196. binary.push_back(0);
  197. binary.push_back(0);
  198. binary.push_back(pkt4.getHtype());
  199. type_str = "htype";
  200. break;
  201. default:
  202. isc_throw(EvalTypeError, "Bad field specified: "
  203. << static_cast<int>(type_) );
  204. }
  205. } catch (const std::bad_cast&) {
  206. isc_throw(EvalTypeError, "Specified packet is not a Pkt4");
  207. }
  208. string value;
  209. value.resize(binary.size());
  210. if (!binary.empty()) {
  211. memmove(&value[0], &binary[0], binary.size());
  212. }
  213. values.push(value);
  214. // Log what we pushed
  215. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_PKT4)
  216. .arg(type_str)
  217. .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(value.begin(),
  218. value.end())));
  219. }
  220. void
  221. TokenEqual::evaluate(Pkt& /*pkt*/, ValueStack& values) {
  222. if (values.size() < 2) {
  223. isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
  224. "2 values for == operator, got " << values.size());
  225. }
  226. string op1 = values.top();
  227. values.pop();
  228. string op2 = values.top();
  229. values.pop(); // Dammit, std::stack interface is awkward.
  230. if (op1 == op2)
  231. values.push("true");
  232. else
  233. values.push("false");
  234. // Log what we popped and pushed
  235. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_EQUAL)
  236. .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(op1.begin(),
  237. op1.end())))
  238. .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(op2.begin(),
  239. op2.end())))
  240. .arg('\'' + values.top() + '\'');
  241. }
  242. void
  243. TokenSubstring::evaluate(Pkt& /*pkt*/, ValueStack& values) {
  244. if (values.size() < 3) {
  245. isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
  246. "3 values for substring operator, got " << values.size());
  247. }
  248. string len_str = values.top();
  249. values.pop();
  250. string start_str = values.top();
  251. values.pop();
  252. string string_str = values.top();
  253. values.pop();
  254. // If we have no string to start with we push an empty string and leave
  255. if (string_str.empty()) {
  256. values.push("");
  257. // Log what we popped and pushed
  258. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUBSTRING_EMPTY)
  259. .arg(len_str)
  260. .arg(start_str)
  261. .arg("0x")
  262. .arg("0x");
  263. return;
  264. }
  265. // Convert the starting position and length from strings to numbers
  266. // the length may also be "all" in which case simply make it the
  267. // length of the string.
  268. // If we have a problem push an empty string and leave
  269. int start_pos;
  270. int length;
  271. try {
  272. start_pos = boost::lexical_cast<int>(start_str);
  273. } catch (const boost::bad_lexical_cast&) {
  274. isc_throw(EvalTypeError, "the parameter '" << start_str
  275. << "' for the starting postion of the substring "
  276. << "couldn't be converted to an integer.");
  277. }
  278. try {
  279. if (len_str == "all") {
  280. length = string_str.length();
  281. } else {
  282. length = boost::lexical_cast<int>(len_str);
  283. }
  284. } catch (const boost::bad_lexical_cast&) {
  285. isc_throw(EvalTypeError, "the parameter '" << len_str
  286. << "' for the length of the substring "
  287. << "couldn't be converted to an integer.");
  288. }
  289. const int string_length = string_str.length();
  290. // If the starting postion is outside of the string push an
  291. // empty string and leave
  292. if ((start_pos < -string_length) || (start_pos >= string_length)) {
  293. values.push("");
  294. // Log what we popped and pushed
  295. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUBSTRING_RANGE)
  296. .arg(len_str)
  297. .arg(start_str)
  298. .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(string_str.begin(),
  299. string_str.end())))
  300. .arg("0x");
  301. return;
  302. }
  303. // Adjust the values to be something for substr. We first figure out
  304. // the starting postion, then update it and the length to get the
  305. // characters before or after it depending on the sign of length
  306. if (start_pos < 0) {
  307. start_pos = string_length + start_pos;
  308. }
  309. if (length < 0) {
  310. length = -length;
  311. if (length <= start_pos){
  312. start_pos -= length;
  313. } else {
  314. length = start_pos;
  315. start_pos = 0;
  316. }
  317. }
  318. // and finally get the substring
  319. values.push(string_str.substr(start_pos, length));
  320. // Log what we popped and pushed
  321. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_SUBSTRING)
  322. .arg(len_str)
  323. .arg(start_str)
  324. .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(string_str.begin(),
  325. string_str.end())))
  326. .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(values.top().begin(),
  327. values.top().end())));
  328. }
  329. void
  330. TokenConcat::evaluate(Pkt& /*pkt*/, ValueStack& values) {
  331. if (values.size() < 2) {
  332. isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
  333. "2 values for concat, got " << values.size());
  334. }
  335. string op1 = values.top();
  336. values.pop();
  337. string op2 = values.top();
  338. values.pop(); // Dammit, std::stack interface is awkward.
  339. // The top of the stack was evaluated last so this is the right order
  340. values.push(op2 + op1);
  341. // Log what we popped and pushed
  342. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_CONCAT)
  343. .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(op1.begin(),
  344. op1.end())))
  345. .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(op2.begin(),
  346. op2.end())))
  347. .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(values.top().begin(),
  348. values.top().end())));
  349. }
  350. void
  351. TokenNot::evaluate(Pkt& /*pkt*/, ValueStack& values) {
  352. if (values.size() == 0) {
  353. isc_throw(EvalBadStack, "Incorrect empty stack.");
  354. }
  355. string op = values.top();
  356. values.pop();
  357. bool val = toBool(op);
  358. if (!val) {
  359. values.push("true");
  360. } else {
  361. values.push("false");
  362. }
  363. // Log what we popped and pushed
  364. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_NOT)
  365. .arg('\'' + op + '\'')
  366. .arg('\'' + values.top() + '\'');
  367. }
  368. void
  369. TokenAnd::evaluate(Pkt& /*pkt*/, ValueStack& values) {
  370. if (values.size() < 2) {
  371. isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
  372. "2 values for and operator, got " << values.size());
  373. }
  374. string op1 = values.top();
  375. values.pop();
  376. bool val1 = toBool(op1);
  377. string op2 = values.top();
  378. values.pop(); // Dammit, std::stack interface is awkward.
  379. bool val2 = toBool(op2);
  380. if (val1 && val2) {
  381. values.push("true");
  382. } else {
  383. values.push("false");
  384. }
  385. // Log what we popped and pushed
  386. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_AND)
  387. .arg('\'' + op1 + '\'')
  388. .arg('\'' + op2 + '\'')
  389. .arg('\'' + values.top() + '\'');
  390. }
  391. void
  392. TokenOr::evaluate(Pkt& /*pkt*/, ValueStack& values) {
  393. if (values.size() < 2) {
  394. isc_throw(EvalBadStack, "Incorrect stack order. Expected at least "
  395. "2 values for or operator, got " << values.size());
  396. }
  397. string op1 = values.top();
  398. values.pop();
  399. bool val1 = toBool(op1);
  400. string op2 = values.top();
  401. values.pop(); // Dammit, std::stack interface is awkward.
  402. bool val2 = toBool(op2);
  403. if (val1 || val2) {
  404. values.push("true");
  405. } else {
  406. values.push("false");
  407. }
  408. // Log what we popped and pushed
  409. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_OR)
  410. .arg('\'' + op1 + '\'')
  411. .arg('\'' + op2 + '\'')
  412. .arg('\'' + values.top() + '\'');
  413. }
  414. OptionPtr TokenRelay6Option::getOption(Pkt& pkt) {
  415. try {
  416. // Check if it's a Pkt6. If it's not the dynamic_cast will
  417. // throw std::bad_cast.
  418. Pkt6& pkt6 = dynamic_cast<Pkt6&>(pkt);
  419. try {
  420. // Now that we have the right type of packet we can
  421. // get the option and return it.
  422. return(pkt6.getRelayOption(option_code_, nest_level_));
  423. }
  424. catch (const isc::OutOfRange&) {
  425. // The only exception we expect is OutOfRange if the nest
  426. // level is out of range of the encapsulations, for example
  427. // if nest_level_ is 4 and there are only 2 encapsulations.
  428. // We return a NULL in that case.
  429. return (OptionPtr());
  430. }
  431. } catch (const std::bad_cast&) {
  432. isc_throw(EvalTypeError, "Specified packet is not Pkt6");
  433. }
  434. }
  435. void
  436. TokenRelay6Field::evaluate(Pkt& pkt, ValueStack& values) {
  437. vector<uint8_t> binary;
  438. string type_str;
  439. try {
  440. // Check if it's a Pkt6. If it's not the dynamic_cast will
  441. // throw std::bad_cast.
  442. const Pkt6& pkt6 = dynamic_cast<const Pkt6&>(pkt);
  443. try {
  444. switch (type_) {
  445. // Now that we have the right type of packet we can
  446. // get the option and return it.
  447. case LINKADDR:
  448. type_str = "linkaddr";
  449. binary = pkt6.getRelay6LinkAddress(nest_level_).toBytes();
  450. break;
  451. case PEERADDR:
  452. type_str = "peeraddr";
  453. binary = pkt6.getRelay6PeerAddress(nest_level_).toBytes();
  454. break;
  455. }
  456. } catch (const isc::OutOfRange&) {
  457. // The only exception we expect is OutOfRange if the nest
  458. // level is invalid. We push "" in that case.
  459. values.push("");
  460. // Log what we pushed
  461. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_RELAY6_RANGE)
  462. .arg(type_str)
  463. .arg(unsigned(nest_level_))
  464. .arg("0x");
  465. return;
  466. }
  467. } catch (const std::bad_cast&) {
  468. isc_throw(EvalTypeError, "Specified packet is not Pkt6");
  469. }
  470. string value;
  471. value.resize(binary.size());
  472. if (!binary.empty()) {
  473. memmove(&value[0], &binary[0], binary.size());
  474. }
  475. values.push(value);
  476. // Log what we pushed
  477. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_RELAY6)
  478. .arg(type_str)
  479. .arg(unsigned(nest_level_))
  480. .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(value.begin(),
  481. value.end())));
  482. }
  483. void
  484. TokenPkt6::evaluate(Pkt& pkt, ValueStack& values) {
  485. vector<uint8_t> binary;
  486. string type_str;
  487. try {
  488. // Check if it's a Pkt6. If it's not the dynamic_cast will throw
  489. // std::bad_cast (failed dynamic_cast returns NULL for pointers and
  490. // throws for references).
  491. const Pkt6& pkt6 = dynamic_cast<const Pkt6&>(pkt);
  492. switch (type_) {
  493. case MSGTYPE: {
  494. // msg type is an uint8_t integer. We want a 4 byte string so 0 pad.
  495. binary.push_back(0);
  496. binary.push_back(0);
  497. binary.push_back(0);
  498. binary.push_back(pkt6.getType());
  499. type_str = "msgtype";
  500. break;
  501. }
  502. case TRANSID: {
  503. // transaction id is an uint32_t integer. We want a 4 byte string so copy
  504. uint32_t transid = pkt6.getTransid();
  505. binary.push_back(transid >> 24);
  506. binary.push_back((transid >> 16) & 0xFF);
  507. binary.push_back((transid >> 8) & 0xFF);
  508. binary.push_back(transid & 0xFF);
  509. type_str = "transid";
  510. break;
  511. }
  512. default:
  513. isc_throw(EvalTypeError, "Bad field specified: "
  514. << static_cast<int>(type_) );
  515. }
  516. } catch (const std::bad_cast&) {
  517. isc_throw(EvalTypeError, "Specified packet is not Pkt6");
  518. }
  519. string value;
  520. value.resize(binary.size());
  521. memmove(&value[0], &binary[0], binary.size());
  522. values.push(value);
  523. // Log what we pushed
  524. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_PKT6)
  525. .arg(type_str)
  526. .arg("0x" + util::encode::encodeHex(std::vector<uint8_t>(value.begin(),
  527. value.end())));
  528. }
  529. TokenVendor::TokenVendor(Option::Universe u, uint32_t vendor_id, RepresentationType repr,
  530. uint16_t option_code)
  531. :TokenOption(option_code, repr), universe_(u), vendor_id_(vendor_id),
  532. field_(option_code ? SUBOPTION : EXISTS)
  533. {
  534. }
  535. TokenVendor::TokenVendor(Option::Universe u, uint32_t vendor_id, FieldType field)
  536. :TokenOption(0, TokenOption::HEXADECIMAL), universe_(u), vendor_id_(vendor_id),
  537. field_(field)
  538. {
  539. if (field_ == EXISTS) {
  540. representation_type_ = TokenOption::EXISTS;
  541. }
  542. }
  543. uint32_t TokenVendor::getVendorId() const {
  544. return (vendor_id_);
  545. }
  546. TokenVendor::FieldType TokenVendor::getField() const {
  547. return (field_);
  548. }
  549. void TokenVendor::evaluate(Pkt& pkt, ValueStack& values) {
  550. // Get the option first.
  551. uint16_t code = 0;
  552. switch (universe_) {
  553. case Option::V4:
  554. code = DHO_VIVSO_SUBOPTIONS;
  555. break;
  556. case Option::V6:
  557. code = D6O_VENDOR_OPTS;
  558. break;
  559. }
  560. OptionPtr opt = pkt.getOption(code);
  561. OptionVendorPtr vendor = boost::dynamic_pointer_cast<OptionVendor>(opt);
  562. if (!vendor) {
  563. // There's no vendor option, give up.
  564. std::string txt = pushFailure(values);
  565. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_NO_OPTION)
  566. .arg(code)
  567. .arg(txt);
  568. return;
  569. }
  570. if (vendor_id_ && (vendor_id_ != vendor->getVendorId())) {
  571. // There is vendor option, but it has other vendor-id value
  572. // than we're looking for. (0 means accept any vendor-id)
  573. std::string txt = pushFailure(values);
  574. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_ENTERPRISE_ID_MISMATCH)
  575. .arg(vendor_id_)
  576. .arg(vendor->getVendorId())
  577. .arg(txt);
  578. return;
  579. }
  580. switch (field_) {
  581. case ENTERPRISE_ID:
  582. {
  583. // Extract enterprise-id
  584. string txt(sizeof(uint32_t), 0);
  585. uint32_t value = htonl(vendor->getVendorId());
  586. memcpy(&txt[0], &value, sizeof(uint32_t));
  587. values.push(txt);
  588. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_ENTERPRISE_ID)
  589. .arg(vendor_id_)
  590. .arg(util::encode::encodeHex(std::vector<uint8_t>(txt.begin(),
  591. txt.end())));
  592. return;
  593. }
  594. case SUBOPTION:
  595. /// This is vendor[X].option[Y].exists, let's try to
  596. /// extract the option
  597. TokenOption::evaluate(pkt, values);
  598. return;
  599. case EXISTS:
  600. // We already passed all the checks: the option is there and has specified
  601. // enterprise-id.
  602. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_EXISTS)
  603. .arg("true");
  604. values.push("true");
  605. return;
  606. case DATA:
  607. // This is for vendor-class option, we can skip it here.
  608. isc_throw(EvalTypeError, "Field None is not valid for vendor-class");
  609. return;
  610. }
  611. }
  612. OptionPtr TokenVendor::getOption(Pkt& pkt) {
  613. uint16_t code = 0;
  614. switch (universe_) {
  615. case Option::V4:
  616. code = DHO_VIVSO_SUBOPTIONS;
  617. break;
  618. case Option::V6:
  619. code = D6O_VENDOR_OPTS;
  620. break;
  621. }
  622. OptionPtr opt = pkt.getOption(code);
  623. if (!opt) {
  624. // If vendor option is not found, return NULL
  625. return (opt);
  626. }
  627. // If vendor option is found, try to return its
  628. // encapsulated option.
  629. return (opt->getOption(option_code_));
  630. }
  631. TokenVendorClass::TokenVendorClass(Option::Universe u, uint32_t vendor_id,
  632. RepresentationType repr)
  633. :TokenVendor(u, vendor_id, repr, 0), index_(0) {
  634. }
  635. TokenVendorClass::TokenVendorClass(Option::Universe u, uint32_t vendor_id,
  636. FieldType field, uint16_t index)
  637. :TokenVendor(u, vendor_id, TokenOption::HEXADECIMAL, 0), index_(index)
  638. {
  639. field_ = field;
  640. }
  641. uint16_t TokenVendorClass::getDataIndex() const {
  642. return (index_);
  643. }
  644. void TokenVendorClass::evaluate(Pkt& pkt, ValueStack& values) {
  645. // Get the option first.
  646. uint16_t code = 0;
  647. switch (universe_) {
  648. case Option::V4:
  649. code = DHO_VIVCO_SUBOPTIONS;
  650. break;
  651. case Option::V6:
  652. code = D6O_VENDOR_CLASS;
  653. break;
  654. }
  655. OptionPtr opt = pkt.getOption(code);
  656. OptionVendorClassPtr vendor = boost::dynamic_pointer_cast<OptionVendorClass>(opt);
  657. if (!vendor) {
  658. // There's no vendor class option, give up.
  659. std::string txt = pushFailure(values);
  660. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_NO_OPTION)
  661. .arg(code)
  662. .arg(txt);
  663. return;
  664. }
  665. if (vendor_id_ && (vendor_id_ != vendor->getVendorId())) {
  666. // There is vendor option, but it has other vendor-id value
  667. // than we're looking for. (0 means accept any vendor-id)
  668. std::string txt = pushFailure(values);
  669. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID_MISMATCH)
  670. .arg(vendor_id_)
  671. .arg(vendor->getVendorId())
  672. .arg(txt);
  673. return;
  674. }
  675. switch (field_) {
  676. case ENTERPRISE_ID:
  677. {
  678. // Extract enterprise-id
  679. string txt(sizeof(uint32_t), 0);
  680. uint32_t value = htonl(vendor->getVendorId());
  681. memcpy(&txt[0], &value, sizeof(uint32_t));
  682. values.push(txt);
  683. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_ENTERPRISE_ID)
  684. .arg(vendor_id_)
  685. .arg(util::encode::encodeHex(std::vector<uint8_t>(txt.begin(),
  686. txt.end())));
  687. return;
  688. }
  689. case SUBOPTION:
  690. // Extract sub-options
  691. isc_throw(EvalTypeError, "Field None is not valid for vendor-class");
  692. return;
  693. case EXISTS:
  694. // We already passed all the checks: the option is there and has specified
  695. // enterprise-id.
  696. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_EXISTS)
  697. .arg("true");
  698. values.push("true");
  699. return;
  700. case DATA:
  701. {
  702. size_t max = vendor->getTuplesNum();
  703. if (index_ + 1 > max) {
  704. // The index specified if out of bound, e.g. there are only
  705. // 2 tuples and index specified is 5.
  706. values.push("");
  707. return;
  708. }
  709. OpaqueDataTuple tuple = vendor->getTuple(index_);
  710. OpaqueDataTuple::Buffer buf = tuple.getData();
  711. string txt(buf.begin(), buf.end());
  712. LOG_DEBUG(eval_logger, EVAL_DBG_STACK, EVAL_DEBUG_VENDOR_CLASS_DATA)
  713. .arg(index_)
  714. .arg(max)
  715. .arg(util::encode::encodeHex(buf));
  716. values.push(txt);
  717. return;
  718. }
  719. default:
  720. isc_throw(EvalTypeError, "Invalid field specified." << field_);
  721. }
  722. }