perf_pkt6.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <iostream>
  15. #include <exceptions/exceptions.h>
  16. #include <dhcp/libdhcp++.h>
  17. #include <dhcp/dhcp6.h>
  18. #include "perf_pkt6.h"
  19. using namespace std;
  20. using namespace isc;
  21. using namespace dhcp;
  22. namespace isc {
  23. namespace perfdhcp {
  24. PerfPkt6::PerfPkt6(const uint8_t* buf, uint32_t len,
  25. uint32_t transid, const Offset& transid_offset) :
  26. Pkt6(buf, len, Pkt6::UDP),
  27. transid_offset_(transid_offset.get()) {
  28. transid_ = transid;
  29. }
  30. PerfPkt6::PerfPkt6(const uint8_t* buf,
  31. uint32_t len,
  32. const Offset&
  33. transid_offset) :
  34. Pkt6(buf, len, Pkt6::UDP),
  35. transid_offset_(transid_offset.get()) {
  36. }
  37. bool
  38. PerfPkt6::rawPack() {
  39. // Always override the packet if function is called.
  40. bufferOut_.clear();
  41. // Write whole buffer to output buffer.
  42. bufferOut_.writeData(&data_[0], data_.size());
  43. if ((transid_offset_ + 4 > data_.size()) ||
  44. (transid_offset_ == 0)) {
  45. cout << "Failed to build packet: provided transaction id offset: "
  46. << transid_offset_ << " is out of bounds (expected 1.."
  47. << data_.size()-1 << ")." << endl;
  48. return (false);
  49. }
  50. // Seek to the transaction id position in output buffer.
  51. bufferOut_.clear();
  52. bufferOut_.skip(transid_offset_);
  53. try {
  54. // Write 3 octets of transaction id
  55. bufferOut_.writeUint8(transid_ >> 16 & 0xFF);
  56. bufferOut_.writeUint8(transid_ >> 8 & 0xFF);
  57. bufferOut_.writeUint8(transid_ & 0xFF);
  58. // Buffer pointer is at the end of transaction id.
  59. // We have to seek to the end of buffer so as data don't
  60. // get truncated.
  61. bufferOut_.skip(data_.size() - bufferOut_.getLength());
  62. // We already have packet template stored in output buffer
  63. // but still some options have to be updated if client
  64. // specified them along with their offsets in the buffer.
  65. rawPackOptions();
  66. } catch (isc::BadValue& e) {
  67. cout << "Building packet failed: " << e.what() << endl;
  68. return (false);
  69. }
  70. return (true);
  71. }
  72. bool
  73. PerfPkt6::rawUnpack() {
  74. // Validate transaction id offset.
  75. if ((transid_offset_ + 4 > data_.size()) ||
  76. (transid_offset_ == 0)) {
  77. cout << "Failed to parse packet: provided transaction id offset: "
  78. << transid_offset_ << " is out of bounds (expected 1.."
  79. << data_.size()-1 << ")." << endl;
  80. return (false);
  81. }
  82. // Read transaction id from the packet at the given offset.
  83. transid_ = ( (data_[transid_offset_]) << 16 ) +
  84. ((data_[transid_offset_ + 1]) << 8) + (data_[transid_offset_ + 2]);
  85. transid_ = transid_ & 0xffffff;
  86. // Get message type - assume it is first octet in the packet.
  87. msg_type_ = data_[0];
  88. try {
  89. rawUnpackOptions();
  90. } catch (isc::BadValue& e) {
  91. cout << "Packet parsing failed: " << e.what() << endl;
  92. return (false);
  93. }
  94. return (true);
  95. }
  96. void
  97. PerfPkt6::rawPackOptions() {
  98. try {
  99. // If there are any options on the list, we will use provided
  100. // options offsets to override them in the output buffer
  101. // with new contents.
  102. for (Option::OptionCollection::const_iterator it = options_.begin();
  103. it != options_.end(); ++it) {
  104. // Get options with their position (offset).
  105. boost::shared_ptr<LocalizedOption> option =
  106. boost::dynamic_pointer_cast<LocalizedOption>(it->second);
  107. uint32_t offset = option->getOffset();
  108. if ((offset == 0) ||
  109. (offset + option->len() > data_.size())) {
  110. isc_throw(isc::BadValue,
  111. "option offset for option: " << option->getType()
  112. << " is out of bounds (expected 1.."
  113. << data_.size() - option->len() << ")");
  114. }
  115. bufferOut_.clear();
  116. bufferOut_.skip(offset);
  117. // Replace existing option with new value.
  118. option->pack(bufferOut_);
  119. }
  120. // Seek to the end of the buffer to make sure its size is correct.
  121. bufferOut_.skip(data_.size() - bufferOut_.getLength());
  122. }
  123. catch (const Exception&) {
  124. isc_throw(isc::BadValue, "failed to pack options into buffer.");
  125. }
  126. }
  127. void
  128. PerfPkt6::rawUnpackOptions() {
  129. for (Option::OptionCollection::const_iterator it = options_.begin();
  130. it != options_.end(); ++it) {
  131. LocalizedOptionPtr option =
  132. boost::dynamic_pointer_cast<LocalizedOption>(it->second);
  133. size_t opt_pos = option->getOffset();
  134. if (opt_pos == 0) {
  135. isc_throw(isc::BadValue, "failed to unpack packet from raw buffer "
  136. "(Option position not specified)");
  137. } else if (opt_pos + 4 > data_.size()) {
  138. isc_throw(isc::BadValue,
  139. "failed to unpack options from from raw buffer "
  140. "(Option position out of bounds)");
  141. }
  142. size_t offset = opt_pos;
  143. // Get option type from first two octets.
  144. uint16_t opt_type = data_[offset] * 256 + data_[offset + 1];
  145. if (opt_type != option->getType()) {
  146. isc_throw(isc::BadValue,
  147. "failed to unpack option from raw buffer "
  148. "(option type mismatch)");
  149. }
  150. // Get length from next two octets.
  151. offset += 2;
  152. uint16_t opt_len = data_[offset] * 256 + data_[offset + 1];
  153. if (offset + opt_len > data_.size()) {
  154. isc_throw(isc::BadValue,
  155. "failed to unpack option from raw buffer "
  156. "(option truncated)");
  157. }
  158. // Seek to actual option data and replace it.
  159. offset += 2;
  160. option->setData(data_.begin() + offset,
  161. data_.begin() + offset + opt_len);
  162. }
  163. }
  164. } // namespace perfdhcp
  165. } // namespace isc