pkt.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. // Copyright (C) 2014 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 <utility>
  15. #include <dhcp/pkt.h>
  16. #include <dhcp/iface_mgr.h>
  17. #include <vector>
  18. namespace isc {
  19. namespace dhcp {
  20. Pkt::Pkt(uint32_t transid, const isc::asiolink::IOAddress& local_addr,
  21. const isc::asiolink::IOAddress& remote_addr, uint16_t local_port,
  22. uint16_t remote_port)
  23. :transid_(transid),
  24. iface_(""),
  25. ifindex_(-1),
  26. local_addr_(local_addr),
  27. remote_addr_(remote_addr),
  28. local_port_(local_port),
  29. remote_port_(remote_port),
  30. buffer_out_(0)
  31. {
  32. }
  33. Pkt::Pkt(const uint8_t* buf, uint32_t len, const isc::asiolink::IOAddress& local_addr,
  34. const isc::asiolink::IOAddress& remote_addr, uint16_t local_port,
  35. uint16_t remote_port)
  36. :transid_(0),
  37. iface_(""),
  38. ifindex_(-1),
  39. local_addr_(local_addr),
  40. remote_addr_(remote_addr),
  41. local_port_(local_port),
  42. remote_port_(remote_port),
  43. buffer_out_(0)
  44. {
  45. data_.resize(len);
  46. if (len) {
  47. memcpy(&data_[0], buf, len);
  48. }
  49. }
  50. void
  51. Pkt::addOption(const OptionPtr& opt) {
  52. options_.insert(std::pair<int, OptionPtr>(opt->getType(), opt));
  53. }
  54. OptionPtr
  55. Pkt::getOption(uint16_t type) const {
  56. OptionCollection::const_iterator x = options_.find(type);
  57. if (x != options_.end()) {
  58. return (*x).second;
  59. }
  60. return (OptionPtr()); // NULL
  61. }
  62. bool
  63. Pkt::delOption(uint16_t type) {
  64. isc::dhcp::OptionCollection::iterator x = options_.find(type);
  65. if (x!=options_.end()) {
  66. options_.erase(x);
  67. return (true); // delete successful
  68. } else {
  69. return (false); // can't find option to be deleted
  70. }
  71. }
  72. bool
  73. Pkt::inClass(const std::string& client_class) {
  74. return (classes_.find(client_class) != classes_.end());
  75. }
  76. void
  77. Pkt::addClass(const std::string& client_class) {
  78. if (classes_.find(client_class) == classes_.end()) {
  79. classes_.insert(client_class);
  80. }
  81. }
  82. void
  83. Pkt::updateTimestamp() {
  84. timestamp_ = boost::posix_time::microsec_clock::universal_time();
  85. }
  86. void Pkt::repack() {
  87. if (!data_.empty()) {
  88. buffer_out_.writeData(&data_[0], data_.size());
  89. }
  90. }
  91. void
  92. Pkt::setRemoteHWAddr(const uint8_t htype, const uint8_t hlen,
  93. const std::vector<uint8_t>& hw_addr) {
  94. setHWAddrMember(htype, hlen, hw_addr, remote_hwaddr_);
  95. }
  96. void
  97. Pkt::setRemoteHWAddr(const HWAddrPtr& hw_addr) {
  98. if (!hw_addr) {
  99. isc_throw(BadValue, "Setting remote HW address to NULL is"
  100. << " forbidden.");
  101. }
  102. remote_hwaddr_ = hw_addr;
  103. }
  104. void
  105. Pkt::setHWAddrMember(const uint8_t htype, const uint8_t,
  106. const std::vector<uint8_t>& hw_addr,
  107. HWAddrPtr& storage) {
  108. storage.reset(new HWAddr(hw_addr, htype));
  109. }
  110. HWAddrPtr
  111. Pkt::getMAC(uint32_t hw_addr_src) {
  112. HWAddrPtr mac;
  113. // Method 1: from raw sockets.
  114. if (hw_addr_src & HWADDR_SOURCE_RAW) {
  115. mac = getRemoteHWAddr();
  116. if (mac) {
  117. return (mac);
  118. } else if (hw_addr_src == HWADDR_SOURCE_RAW) {
  119. // If we're interested only in RAW sockets as source of that info,
  120. // there's no point in trying other options.
  121. return (HWAddrPtr());
  122. }
  123. }
  124. // Method 2: Extracted from DUID-LLT or DUID-LL
  125. // Method 3: Extracted from source IPv6 link-local address
  126. if (hw_addr_src & HWADDR_SOURCE_IPV6_LINK_LOCAL) {
  127. mac = getMACFromSrcLinkLocalAddr();
  128. if (mac) {
  129. return (mac);
  130. } else if (hw_addr_src == HWADDR_SOURCE_IPV6_LINK_LOCAL) {
  131. // If we're interested only in link-local addr as source of that
  132. // info, there's no point in trying other options.
  133. return (HWAddrPtr());
  134. }
  135. }
  136. // Method 4: From client link-layer address option inserted by a relay
  137. // Method 5: From remote-id option inserted by a relay
  138. // Method 6: From subscriber-id option inserted by a relay
  139. // Method 7: From docsis options
  140. /// @todo: add other MAC acquisition methods here
  141. // Ok, none of the methods were suitable. Return NULL.
  142. return (HWAddrPtr());
  143. }
  144. HWAddrPtr
  145. Pkt::getMACFromIPv6(const isc::asiolink::IOAddress& addr) {
  146. if (!addr.isV6LinkLocal()) {
  147. return (HWAddrPtr());
  148. }
  149. std::vector<uint8_t> bin = addr.toBytes();
  150. // Double check that it's of appropriate size
  151. if ((bin.size() != isc::asiolink::V6ADDRESS_LEN) ||
  152. // Check that it's link-local (starts with fe80).
  153. (bin[0] != 0xfe) || (bin[1] != 0x80) ||
  154. // Check that u bit is set and g is clear. See Section 2.5.1 of RFC2373
  155. // for details.
  156. ((bin[8] & 3) != 2) ||
  157. // And that the IID is of EUI-64 type.
  158. (bin[11] != 0xff) || (bin[12] != 0xfe)) {
  159. return (HWAddrPtr());
  160. }
  161. // Remove 8 most significant bytes
  162. bin.erase(bin.begin(), bin.begin() + 8);
  163. // Ok, we're down to EUI-64 only now: XX:XX:XX:ff:fe:XX:XX:XX
  164. bin.erase(bin.begin() + 3, bin.begin() + 5);
  165. // MAC-48 to EUI-64 involves inverting u bit (see explanation in Section
  166. // 2.5.1 of RFC2373). We need to revert that.
  167. bin[0] = bin[0] ^ 2;
  168. // Let's get the interface this packet was received on. We need it to get
  169. // hardware type
  170. Iface* iface = IfaceMgr::instance().getIface(iface_);
  171. uint16_t hwtype = 0; // not specified
  172. if (iface) {
  173. hwtype = iface->getHWType();
  174. }
  175. return (HWAddrPtr(new HWAddr(bin, hwtype)));
  176. }
  177. };
  178. };