host.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. // Copyright (C) 2014-2015 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 <dhcpsrv/host.h>
  15. #include <util/strutil.h>
  16. #include <exceptions/exceptions.h>
  17. #include <sstream>
  18. namespace isc {
  19. namespace dhcp {
  20. IPv6Resrv::IPv6Resrv(const Type& type,
  21. const asiolink::IOAddress& prefix,
  22. const uint8_t prefix_len)
  23. : type_(type), prefix_(asiolink::IOAddress("::")), prefix_len_(128) {
  24. // Validate and set the actual values.
  25. set(type, prefix, prefix_len);
  26. }
  27. void
  28. IPv6Resrv::set(const Type& type, const asiolink::IOAddress& prefix,
  29. const uint8_t prefix_len) {
  30. if (!prefix.isV6() || prefix.isV6Multicast()) {
  31. isc_throw(isc::BadValue, "invalid prefix '" << prefix
  32. << "' for new IPv6 reservation");
  33. } else if (prefix_len > 128) {
  34. isc_throw(isc::BadValue, "invalid prefix length '"
  35. << static_cast<int>(prefix_len)
  36. << "' for new IPv6 reservation");
  37. } else if ((type == TYPE_NA) && (prefix_len != 128)) {
  38. isc_throw(isc::BadValue, "invalid prefix length '"
  39. << static_cast<int>(prefix_len)
  40. << "' for reserved IPv6 address, expected 128");
  41. }
  42. type_ = type;
  43. prefix_ = prefix;
  44. prefix_len_ = prefix_len;
  45. }
  46. std::string
  47. IPv6Resrv::toText() const {
  48. std::ostringstream s;
  49. s << prefix_;
  50. // For PD, append prefix length.
  51. if (getType() == TYPE_PD) {
  52. s << "/" << static_cast<int>(prefix_len_);
  53. }
  54. return (s.str());
  55. }
  56. bool
  57. IPv6Resrv::operator==(const IPv6Resrv& other) const {
  58. return (type_ == other.type_ &&
  59. prefix_ == other.prefix_ &&
  60. prefix_len_ == other.prefix_len_);
  61. }
  62. bool
  63. IPv6Resrv::operator!=(const IPv6Resrv& other) const {
  64. return (!operator==(other));
  65. }
  66. Host::Host(const uint8_t* identifier, const size_t identifier_len,
  67. const IdentifierType& identifier_type,
  68. const SubnetID ipv4_subnet_id, const SubnetID ipv6_subnet_id,
  69. const asiolink::IOAddress& ipv4_reservation,
  70. const std::string& hostname,
  71. const std::string& dhcp4_client_classes,
  72. const std::string& dhcp6_client_classes)
  73. : hw_address_(), duid_(), ipv4_subnet_id_(ipv4_subnet_id),
  74. ipv6_subnet_id_(ipv6_subnet_id),
  75. ipv4_reservation_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
  76. hostname_(hostname), dhcp4_client_classes_(dhcp4_client_classes),
  77. dhcp6_client_classes_(dhcp6_client_classes) {
  78. // Initialize HWAddr or DUID
  79. setIdentifier(identifier, identifier_len, identifier_type);
  80. if (!ipv4_reservation.isV4Zero()) {
  81. // Validate and set IPv4 address reservation.
  82. setIPv4Reservation(ipv4_reservation);
  83. }
  84. }
  85. Host::Host(const std::string& identifier, const std::string& identifier_name,
  86. const SubnetID ipv4_subnet_id, const SubnetID ipv6_subnet_id,
  87. const asiolink::IOAddress& ipv4_reservation,
  88. const std::string& hostname,
  89. const std::string& dhcp4_client_classes,
  90. const std::string& dhcp6_client_classes)
  91. : hw_address_(), duid_(), ipv4_subnet_id_(ipv4_subnet_id),
  92. ipv6_subnet_id_(ipv6_subnet_id),
  93. ipv4_reservation_(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
  94. hostname_(hostname), dhcp4_client_classes_(dhcp4_client_classes),
  95. dhcp6_client_classes_(dhcp6_client_classes) {
  96. // Initialize HWAddr or DUID
  97. setIdentifier(identifier, identifier_name);
  98. if (!ipv4_reservation.isV4Zero()) {
  99. // Validate and set IPv4 address reservation.
  100. setIPv4Reservation(ipv4_reservation);
  101. }
  102. }
  103. const std::vector<uint8_t>&
  104. Host::getIdentifier() const {
  105. if (hw_address_) {
  106. return (hw_address_->hwaddr_);
  107. } else if (duid_) {
  108. return (duid_->getDuid());
  109. }
  110. static std::vector<uint8_t> empty_vector;
  111. return (empty_vector);
  112. }
  113. Host::IdentifierType
  114. Host::getIdentifierType() const {
  115. if (hw_address_) {
  116. return (IDENT_HWADDR);
  117. }
  118. return (IDENT_DUID);
  119. }
  120. std::string
  121. Host::getIdentifierAsText() const {
  122. std::string txt;
  123. if (hw_address_) {
  124. txt = "hwaddr=" + hw_address_->toText(false);
  125. } else {
  126. txt = "duid=";
  127. if (duid_) {
  128. txt += duid_->toText();
  129. } else {
  130. txt += "(none)";
  131. }
  132. }
  133. return (txt);
  134. }
  135. void
  136. Host::setIdentifier(const uint8_t* identifier, const size_t len,
  137. const IdentifierType& type) {
  138. switch (type) {
  139. case IDENT_HWADDR:
  140. hw_address_ = HWAddrPtr(new HWAddr(identifier, len, HTYPE_ETHER));
  141. duid_.reset();
  142. break;
  143. case IDENT_DUID:
  144. duid_ = DuidPtr(new DUID(identifier, len));
  145. hw_address_.reset();
  146. break;
  147. default:
  148. isc_throw(isc::BadValue, "invalid client identifier type '"
  149. << static_cast<int>(type) << "' when creating host "
  150. " instance");
  151. }
  152. }
  153. void
  154. Host::setIdentifier(const std::string& identifier, const std::string& name) {
  155. if (name == "hw-address") {
  156. hw_address_ = HWAddrPtr(new HWAddr(HWAddr::fromText(identifier)));
  157. duid_.reset();
  158. } else if (name == "duid") {
  159. duid_ = DuidPtr(new DUID(DUID::fromText(identifier)));
  160. hw_address_.reset();
  161. } else {
  162. isc_throw(isc::BadValue, "invalid client identifier type '"
  163. << name << "' when creating host instance");
  164. }
  165. }
  166. void
  167. Host::setIPv4Reservation(const asiolink::IOAddress& address) {
  168. if (!address.isV4()) {
  169. isc_throw(isc::BadValue, "address '" << address << "' is not a valid"
  170. " IPv4 address");
  171. } else if (address.isV4Zero() || address.isV4Bcast()) {
  172. isc_throw(isc::BadValue, "must not make reservation for the '"
  173. << address << "' address");
  174. }
  175. ipv4_reservation_ = address;
  176. }
  177. void
  178. Host::removeIPv4Reservation() {
  179. ipv4_reservation_ = asiolink::IOAddress::IPV4_ZERO_ADDRESS();
  180. }
  181. void
  182. Host::addReservation(const IPv6Resrv& reservation) {
  183. // Check if it is not duplicating existing reservation.
  184. if (hasReservation(reservation)) {
  185. isc_throw(isc::InvalidOperation, "failed on attempt to add a duplicated"
  186. " host reservation for " << reservation.toText());
  187. }
  188. // Add it.
  189. ipv6_reservations_.insert(IPv6ResrvTuple(reservation.getType(),
  190. reservation));
  191. }
  192. IPv6ResrvRange
  193. Host::getIPv6Reservations(const IPv6Resrv::Type& type) const {
  194. return (ipv6_reservations_.equal_range(type));
  195. }
  196. IPv6ResrvRange
  197. Host::getIPv6Reservations() const {
  198. return (IPv6ResrvRange(ipv6_reservations_.begin(),
  199. ipv6_reservations_.end()));
  200. }
  201. bool
  202. Host::hasIPv6Reservation() const {
  203. return (!ipv6_reservations_.empty());
  204. }
  205. bool
  206. Host::hasReservation(const IPv6Resrv& reservation) const {
  207. IPv6ResrvRange reservations = getIPv6Reservations(reservation.getType());
  208. if (std::distance(reservations.first, reservations.second) > 0) {
  209. for (IPv6ResrvIterator it = reservations.first;
  210. it != reservations.second; ++it) {
  211. if (it->second == reservation) {
  212. return (true);
  213. }
  214. }
  215. }
  216. // No matching reservations found.
  217. return (false);
  218. }
  219. void
  220. Host::addClientClass4(const std::string& class_name) {
  221. addClientClassInternal(dhcp4_client_classes_, class_name);
  222. }
  223. void
  224. Host::addClientClass6(const std::string& class_name) {
  225. addClientClassInternal(dhcp6_client_classes_, class_name);
  226. }
  227. void
  228. Host::addClientClassInternal(ClientClasses& classes,
  229. const std::string& class_name) {
  230. std::string trimmed = util::str::trim(class_name);
  231. if (!trimmed.empty()) {
  232. classes.insert(ClientClass(trimmed));
  233. }
  234. }
  235. std::string
  236. Host::toText() const {
  237. std::ostringstream s;
  238. // Add HW address or DUID.
  239. s << getIdentifierAsText();
  240. // Add IPv4 subnet id if exists (non-zero).
  241. if (ipv4_subnet_id_) {
  242. s << " ipv4_subnet_id=" << ipv4_subnet_id_;
  243. }
  244. // Add IPv6 subnet id if exists (non-zero).
  245. if (ipv6_subnet_id_) {
  246. s << " ipv6_subnet_id=" << ipv6_subnet_id_;
  247. }
  248. // Add hostname.
  249. s << " hostname=" << (hostname_.empty() ? "(empty)" : hostname_);
  250. // Add IPv4 reservation.
  251. s << " ipv4_reservation=" << (ipv4_reservation_.isV4Zero() ? "(no)" :
  252. ipv4_reservation_.toText());
  253. if (ipv6_reservations_.empty()) {
  254. s << " ipv6_reservations=(none)";
  255. } else {
  256. // Add all IPv6 reservations.
  257. for (IPv6ResrvIterator resrv = ipv6_reservations_.begin();
  258. resrv != ipv6_reservations_.end(); ++resrv) {
  259. s << " ipv6_reservation"
  260. << std::distance(ipv6_reservations_.begin(), resrv)
  261. << "=" << resrv->second.toText();
  262. }
  263. }
  264. // Add DHCPv4 client classes.
  265. for (ClientClasses::const_iterator cclass = dhcp4_client_classes_.begin();
  266. cclass != dhcp4_client_classes_.end(); ++cclass) {
  267. s << " dhcp4_class"
  268. << std::distance(dhcp4_client_classes_.begin(), cclass)
  269. << "=" << *cclass;
  270. }
  271. // Add DHCPv6 client classes.
  272. for (ClientClasses::const_iterator cclass = dhcp6_client_classes_.begin();
  273. cclass != dhcp6_client_classes_.end(); ++cclass) {
  274. s << " dhcp6_class"
  275. << std::distance(dhcp6_client_classes_.begin(), cclass)
  276. << "=" << *cclass;
  277. }
  278. return (s.str());
  279. }
  280. } // end of namespace isc::dhcp
  281. } // end of namespace isc