option4_addrlst.cc 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // Copyright (C) 2011-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 <asiolink/io_address.h>
  7. #include <dhcp/option4_addrlst.h>
  8. #include <exceptions/exceptions.h>
  9. #include <util/io_utilities.h>
  10. #include <iomanip>
  11. #include <sstream>
  12. #include <arpa/inet.h>
  13. #include <stdint.h>
  14. #include <string.h>
  15. using namespace std;
  16. using namespace isc::util;
  17. using namespace isc::asiolink;
  18. namespace isc {
  19. namespace dhcp {
  20. Option4AddrLst::Option4AddrLst(uint8_t type)
  21. :Option(V4, type) {
  22. }
  23. Option4AddrLst::Option4AddrLst(uint8_t type, const AddressContainer& addrs)
  24. :Option(V4, type) {
  25. setAddresses(addrs);
  26. // don't set addrs_ directly. setAddresses() will do additional checks.
  27. }
  28. Option4AddrLst::Option4AddrLst(uint8_t type, OptionBufferConstIter first,
  29. OptionBufferConstIter last)
  30. :Option(V4, type) {
  31. if ( (distance(first, last) % V4ADDRESS_LEN) ) {
  32. isc_throw(OutOfRange, "DHCPv4 Option4AddrLst " << type_
  33. << " has invalid length=" << distance(first, last)
  34. << ", must be divisible by 4.");
  35. }
  36. while (first != last) {
  37. const uint8_t* ptr = &(*first);
  38. addAddress(IOAddress(readUint32(ptr, distance(first, last))));
  39. first += V4ADDRESS_LEN;
  40. }
  41. }
  42. Option4AddrLst::Option4AddrLst(uint8_t type, const IOAddress& addr)
  43. :Option(V4, type) {
  44. setAddress(addr);
  45. }
  46. OptionPtr
  47. Option4AddrLst::clone() const {
  48. return (cloneInternal<Option4AddrLst>());
  49. }
  50. void
  51. Option4AddrLst::pack(isc::util::OutputBuffer& buf) const {
  52. if (addrs_.size() * V4ADDRESS_LEN > 255) {
  53. isc_throw(OutOfRange, "DHCPv4 Option4AddrLst " << type_ << " is too big."
  54. << "At most 255 bytes are supported.");
  55. /// TODO Larger options can be stored as separate instances
  56. /// of DHCPv4 options. Clients MUST concatenate them.
  57. /// Fortunately, there are no such large options used today.
  58. }
  59. buf.writeUint8(type_);
  60. buf.writeUint8(len() - getHeaderLen());
  61. AddressContainer::const_iterator addr = addrs_.begin();
  62. while (addr != addrs_.end()) {
  63. buf.writeUint32(addr->toUint32());
  64. ++addr;
  65. }
  66. }
  67. void Option4AddrLst::setAddress(const isc::asiolink::IOAddress& addr) {
  68. if (!addr.isV4()) {
  69. isc_throw(BadValue, "Can't store non-IPv4 address in "
  70. << "Option4AddrLst option");
  71. }
  72. addrs_.clear();
  73. addAddress(addr);
  74. }
  75. void Option4AddrLst::setAddresses(const AddressContainer& addrs) {
  76. // Do not copy it as a whole. addAddress() does sanity checks.
  77. // i.e. throw if someone tries to set IPv6 address.
  78. addrs_.clear();
  79. for (AddressContainer::const_iterator addr = addrs.begin();
  80. addr != addrs.end(); ++addr) {
  81. addAddress(*addr);
  82. }
  83. }
  84. void Option4AddrLst::addAddress(const isc::asiolink::IOAddress& addr) {
  85. if (!addr.isV4()) {
  86. isc_throw(BadValue, "Can't store non-IPv4 address in "
  87. << "Option4AddrLst option");
  88. }
  89. addrs_.push_back(addr);
  90. }
  91. uint16_t Option4AddrLst::len() const {
  92. // Returns length of the complete option (option header + data length)
  93. return (getHeaderLen() + addrs_.size() * V4ADDRESS_LEN);
  94. }
  95. std::string Option4AddrLst::toText(int indent) const {
  96. std::stringstream output;
  97. output << headerToText(indent) << ":";
  98. for (AddressContainer::const_iterator addr = addrs_.begin();
  99. addr != addrs_.end(); ++addr) {
  100. output << " " << (*addr);
  101. }
  102. return (output.str());
  103. }
  104. } // end of isc::dhcp namespace
  105. } // end of isc namespace