subnet.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. // Copyright (C) 2012-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 <asiolink/io_address.h>
  15. #include <dhcp/option_space.h>
  16. #include <dhcpsrv/addr_utilities.h>
  17. #include <dhcpsrv/subnet.h>
  18. #include <sstream>
  19. using namespace isc::asiolink;
  20. namespace isc {
  21. namespace dhcp {
  22. // This is an initial value of subnet-id. See comments in subnet.h for details.
  23. SubnetID Subnet::static_id_ = 1;
  24. Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
  25. const Triplet<uint32_t>& t1,
  26. const Triplet<uint32_t>& t2,
  27. const Triplet<uint32_t>& valid_lifetime,
  28. const isc::dhcp::Subnet::RelayInfo& relay)
  29. :id_(generateNextID()), prefix_(prefix), prefix_len_(len),
  30. t1_(t1), t2_(t2), valid_(valid_lifetime),
  31. last_allocated_ia_(lastAddrInPrefix(prefix, len)),
  32. last_allocated_ta_(lastAddrInPrefix(prefix, len)),
  33. last_allocated_pd_(lastAddrInPrefix(prefix, len)), relay_(relay)
  34. {
  35. if ((prefix.isV6() && len > 128) ||
  36. (prefix.isV4() && len > 32)) {
  37. isc_throw(BadValue,
  38. "Invalid prefix length specified for subnet: " << len);
  39. }
  40. }
  41. Subnet::RelayInfo::RelayInfo(const isc::asiolink::IOAddress& addr)
  42. :addr_(addr) {
  43. }
  44. bool
  45. Subnet::inRange(const isc::asiolink::IOAddress& addr) const {
  46. IOAddress first = firstAddrInPrefix(prefix_, prefix_len_);
  47. IOAddress last = lastAddrInPrefix(prefix_, prefix_len_);
  48. return ((first <= addr) && (addr <= last));
  49. }
  50. void
  51. Subnet::addOption(const OptionPtr& option, bool persistent,
  52. const std::string& option_space) {
  53. // Check that the option space name is valid.
  54. if (!OptionSpace::validateName(option_space)) {
  55. isc_throw(isc::BadValue, "invalid option space name: '"
  56. << option_space << "'");
  57. }
  58. validateOption(option);
  59. // Actually add new option descriptor.
  60. option_spaces_.addItem(OptionDescriptor(option, persistent), option_space);
  61. }
  62. void
  63. Subnet::setRelayInfo(const isc::dhcp::Subnet::RelayInfo& relay) {
  64. relay_ = relay;
  65. }
  66. bool
  67. Subnet::clientSupported(const isc::dhcp::ClientClasses& classes) const {
  68. if (white_list_.empty()) {
  69. return (true); // There is no class defined for this subnet, so we do
  70. // support everyone.
  71. }
  72. for (ClientClasses::const_iterator it = white_list_.begin();
  73. it != white_list_.end(); ++it) {
  74. if (classes.contains(*it)) {
  75. return (true);
  76. }
  77. }
  78. return (false);
  79. }
  80. void
  81. Subnet::allowClientClass(const isc::dhcp::ClientClass& class_name) {
  82. white_list_.insert(class_name);
  83. }
  84. void
  85. Subnet::delOptions() {
  86. option_spaces_.clearItems();
  87. }
  88. Subnet::OptionContainerPtr
  89. Subnet::getOptionDescriptors(const std::string& option_space) const {
  90. return (option_spaces_.getItems(option_space));
  91. }
  92. Subnet::OptionDescriptor
  93. Subnet::getOptionDescriptor(const std::string& option_space,
  94. const uint16_t option_code) {
  95. OptionContainerPtr options = getOptionDescriptors(option_space);
  96. if (!options || options->empty()) {
  97. return (OptionDescriptor(false));
  98. }
  99. const OptionContainerTypeIndex& idx = options->get<1>();
  100. const OptionContainerTypeRange& range = idx.equal_range(option_code);
  101. if (std::distance(range.first, range.second) == 0) {
  102. return (OptionDescriptor(false));
  103. }
  104. return (*range.first);
  105. }
  106. void Subnet::addVendorOption(const OptionPtr& option, bool persistent,
  107. uint32_t vendor_id){
  108. validateOption(option);
  109. vendor_option_spaces_.addItem(OptionDescriptor(option, persistent), vendor_id);
  110. }
  111. Subnet::OptionContainerPtr
  112. Subnet::getVendorOptionDescriptors(uint32_t vendor_id) const {
  113. return (vendor_option_spaces_.getItems(vendor_id));
  114. }
  115. Subnet::OptionDescriptor
  116. Subnet::getVendorOptionDescriptor(uint32_t vendor_id, uint16_t option_code) {
  117. OptionContainerPtr options = getVendorOptionDescriptors(vendor_id);
  118. if (!options || options->empty()) {
  119. return (OptionDescriptor(false));
  120. }
  121. const OptionContainerTypeIndex& idx = options->get<1>();
  122. const OptionContainerTypeRange& range = idx.equal_range(option_code);
  123. if (std::distance(range.first, range.second) == 0) {
  124. return (OptionDescriptor(false));
  125. }
  126. return (*range.first);
  127. }
  128. void Subnet::delVendorOptions() {
  129. vendor_option_spaces_.clearItems();
  130. }
  131. isc::asiolink::IOAddress Subnet::getLastAllocated(Lease::Type type) const {
  132. // check if the type is valid (and throw if it isn't)
  133. checkType(type);
  134. switch (type) {
  135. case Lease::TYPE_V4:
  136. case Lease::TYPE_NA:
  137. return last_allocated_ia_;
  138. case Lease::TYPE_TA:
  139. return last_allocated_ta_;
  140. case Lease::TYPE_PD:
  141. return last_allocated_pd_;
  142. default:
  143. isc_throw(BadValue, "Pool type " << type << " not supported");
  144. }
  145. }
  146. void Subnet::setLastAllocated(Lease::Type type,
  147. const isc::asiolink::IOAddress& addr) {
  148. // check if the type is valid (and throw if it isn't)
  149. checkType(type);
  150. switch (type) {
  151. case Lease::TYPE_V4:
  152. case Lease::TYPE_NA:
  153. last_allocated_ia_ = addr;
  154. return;
  155. case Lease::TYPE_TA:
  156. last_allocated_ta_ = addr;
  157. return;
  158. case Lease::TYPE_PD:
  159. last_allocated_pd_ = addr;
  160. return;
  161. default:
  162. isc_throw(BadValue, "Pool type " << type << " not supported");
  163. }
  164. }
  165. std::string
  166. Subnet::toText() const {
  167. std::stringstream tmp;
  168. tmp << prefix_ << "/" << static_cast<unsigned int>(prefix_len_);
  169. return (tmp.str());
  170. }
  171. void Subnet4::checkType(Lease::Type type) const {
  172. if (type != Lease::TYPE_V4) {
  173. isc_throw(BadValue, "Only TYPE_V4 is allowed for Subnet4");
  174. }
  175. }
  176. Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
  177. const Triplet<uint32_t>& t1,
  178. const Triplet<uint32_t>& t2,
  179. const Triplet<uint32_t>& valid_lifetime)
  180. :Subnet(prefix, length, t1, t2, valid_lifetime,
  181. RelayInfo(IOAddress("0.0.0.0"))), siaddr_(IOAddress("0.0.0.0")) {
  182. if (!prefix.isV4()) {
  183. isc_throw(BadValue, "Non IPv4 prefix " << prefix.toText()
  184. << " specified in subnet4");
  185. }
  186. }
  187. void Subnet4::setSiaddr(const isc::asiolink::IOAddress& siaddr) {
  188. if (!siaddr.isV4()) {
  189. isc_throw(BadValue, "Can't set siaddr to non-IPv4 address "
  190. << siaddr);
  191. }
  192. siaddr_ = siaddr;
  193. }
  194. isc::asiolink::IOAddress Subnet4::getSiaddr() const {
  195. return (siaddr_);
  196. }
  197. const PoolCollection& Subnet::getPools(Lease::Type type) const {
  198. // check if the type is valid (and throw if it isn't)
  199. checkType(type);
  200. switch (type) {
  201. case Lease::TYPE_V4:
  202. case Lease::TYPE_NA:
  203. return (pools_);
  204. case Lease::TYPE_TA:
  205. return (pools_ta_);
  206. case Lease::TYPE_PD:
  207. return (pools_pd_);
  208. default:
  209. isc_throw(BadValue, "Unsupported pool type: "
  210. << static_cast<int>(type));
  211. }
  212. }
  213. PoolCollection& Subnet::getPoolsWritable(Lease::Type type) {
  214. // check if the type is valid (and throw if it isn't)
  215. checkType(type);
  216. switch (type) {
  217. case Lease::TYPE_V4:
  218. case Lease::TYPE_NA:
  219. return (pools_);
  220. case Lease::TYPE_TA:
  221. return (pools_ta_);
  222. case Lease::TYPE_PD:
  223. return (pools_pd_);
  224. default:
  225. isc_throw(BadValue, "Invalid pool type specified: "
  226. << static_cast<int>(type));
  227. }
  228. }
  229. const PoolPtr Subnet::getPool(Lease::Type type, const isc::asiolink::IOAddress& hint,
  230. bool anypool /* true */) const {
  231. // check if the type is valid (and throw if it isn't)
  232. checkType(type);
  233. const PoolCollection& pools = getPools(type);
  234. PoolPtr candidate;
  235. for (PoolCollection::const_iterator pool = pools.begin();
  236. pool != pools.end(); ++pool) {
  237. // if we won't find anything better, then let's just use the first pool
  238. if (anypool && !candidate) {
  239. candidate = *pool;
  240. }
  241. // if the client provided a pool and there's a pool that hint is valid
  242. // in, then let's use that pool
  243. if ((*pool)->inRange(hint)) {
  244. return (*pool);
  245. }
  246. }
  247. return (candidate);
  248. }
  249. void
  250. Subnet::addPool(const PoolPtr& pool) {
  251. IOAddress first_addr = pool->getFirstAddress();
  252. IOAddress last_addr = pool->getLastAddress();
  253. if (!inRange(first_addr) || !inRange(last_addr)) {
  254. isc_throw(BadValue, "Pool (" << first_addr << "-" << last_addr
  255. << " does not belong in this (" << prefix_ << "/"
  256. << static_cast<int>(prefix_len_) << ") subnet");
  257. }
  258. /// @todo: Check that pools do not overlap
  259. // check if the type is valid (and throw if it isn't)
  260. checkType(pool->getType());
  261. // Add the pool to the appropriate pools collection
  262. getPoolsWritable(pool->getType()).push_back(pool);
  263. }
  264. void
  265. Subnet::delPools(Lease::Type type) {
  266. getPoolsWritable(type).clear();
  267. }
  268. void
  269. Subnet::setIface(const std::string& iface_name) {
  270. iface_ = iface_name;
  271. }
  272. std::string
  273. Subnet::getIface() const {
  274. return (iface_);
  275. }
  276. void
  277. Subnet4::validateOption(const OptionPtr& option) const {
  278. if (!option) {
  279. isc_throw(isc::BadValue,
  280. "option configured for subnet must not be NULL");
  281. } else if (option->getUniverse() != Option::V4) {
  282. isc_throw(isc::BadValue,
  283. "expected V4 option to be added to the subnet");
  284. }
  285. }
  286. bool
  287. Subnet::inPool(Lease::Type type, const isc::asiolink::IOAddress& addr) const {
  288. // Let's start with checking if it even belongs to that subnet.
  289. if (!inRange(addr)) {
  290. return (false);
  291. }
  292. const PoolCollection& pools = getPools(type);
  293. for (PoolCollection::const_iterator pool = pools.begin();
  294. pool != pools.end(); ++pool) {
  295. if ((*pool)->inRange(addr)) {
  296. return (true);
  297. }
  298. }
  299. // There's no pool that address belongs to
  300. return (false);
  301. }
  302. Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
  303. const Triplet<uint32_t>& t1,
  304. const Triplet<uint32_t>& t2,
  305. const Triplet<uint32_t>& preferred_lifetime,
  306. const Triplet<uint32_t>& valid_lifetime)
  307. :Subnet(prefix, length, t1, t2, valid_lifetime, RelayInfo(IOAddress("::"))),
  308. preferred_(preferred_lifetime){
  309. if (!prefix.isV6()) {
  310. isc_throw(BadValue, "Non IPv6 prefix " << prefix
  311. << " specified in subnet6");
  312. }
  313. }
  314. void Subnet6::checkType(Lease::Type type) const {
  315. if ( (type != Lease::TYPE_NA) && (type != Lease::TYPE_TA) &&
  316. (type != Lease::TYPE_PD)) {
  317. isc_throw(BadValue, "Invalid Pool type: " << Lease::typeToText(type)
  318. << "(" << static_cast<int>(type)
  319. << "), must be TYPE_NA, TYPE_TA or TYPE_PD for Subnet6");
  320. }
  321. }
  322. void
  323. Subnet6::validateOption(const OptionPtr& option) const {
  324. if (!option) {
  325. isc_throw(isc::BadValue,
  326. "option configured for subnet must not be NULL");
  327. } else if (option->getUniverse() != Option::V6) {
  328. isc_throw(isc::BadValue,
  329. "expected V6 option to be added to the subnet");
  330. }
  331. }
  332. } // end of isc::dhcp namespace
  333. } // end of isc namespace