subnet.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. // Copyright (C) 2012-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 <config.h>
  7. #include <asiolink/io_address.h>
  8. #include <dhcp/option_space.h>
  9. #include <dhcpsrv/addr_utilities.h>
  10. #include <dhcpsrv/subnet.h>
  11. #include <algorithm>
  12. #include <sstream>
  13. using namespace isc::asiolink;
  14. using namespace isc::dhcp;
  15. namespace {
  16. /// @brief Function used in calls to std::upper_bound to check
  17. /// if the specified prefix is lower than the first address a pool.
  18. ///
  19. /// @return true if prefix is lower than the first address in the pool.
  20. bool
  21. prefixLessThanFirstAddress(const IOAddress& prefix, const PoolPtr& pool) {
  22. return (prefix < pool->getFirstAddress());
  23. }
  24. /// @brief Function used in calls to std::sort to compare first
  25. /// prefixes of the two pools.
  26. ///
  27. /// @param pool1 First pool.
  28. /// @param pool2 Second pool.
  29. ///
  30. /// @return true if first prefix of the first pool is smaller than
  31. /// the first address of the second pool.
  32. bool
  33. comparePoolFirstAddress(const PoolPtr& pool1, const PoolPtr& pool2) {
  34. return (pool1->getFirstAddress() < pool2->getFirstAddress());
  35. };
  36. }
  37. namespace isc {
  38. namespace dhcp {
  39. // This is an initial value of subnet-id. See comments in subnet.h for details.
  40. SubnetID Subnet::static_id_ = 1;
  41. Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
  42. const Triplet<uint32_t>& t1,
  43. const Triplet<uint32_t>& t2,
  44. const Triplet<uint32_t>& valid_lifetime,
  45. const isc::dhcp::Subnet::RelayInfo& relay,
  46. const SubnetID id)
  47. :id_(id == 0 ? generateNextID() : id), prefix_(prefix), prefix_len_(len),
  48. t1_(t1), t2_(t2), valid_(valid_lifetime),
  49. last_allocated_ia_(lastAddrInPrefix(prefix, len)),
  50. last_allocated_ta_(lastAddrInPrefix(prefix, len)),
  51. last_allocated_pd_(lastAddrInPrefix(prefix, len)), relay_(relay),
  52. host_reservation_mode_(HR_ALL), cfg_option_(new CfgOption())
  53. {
  54. if ((prefix.isV6() && len > 128) ||
  55. (prefix.isV4() && len > 32)) {
  56. isc_throw(BadValue,
  57. "Invalid prefix length specified for subnet: " << len);
  58. }
  59. }
  60. Subnet::RelayInfo::RelayInfo(const isc::asiolink::IOAddress& addr)
  61. :addr_(addr) {
  62. }
  63. bool
  64. Subnet::inRange(const isc::asiolink::IOAddress& addr) const {
  65. IOAddress first = firstAddrInPrefix(prefix_, prefix_len_);
  66. IOAddress last = lastAddrInPrefix(prefix_, prefix_len_);
  67. return ((first <= addr) && (addr <= last));
  68. }
  69. void
  70. Subnet::setRelayInfo(const isc::dhcp::Subnet::RelayInfo& relay) {
  71. relay_ = relay;
  72. }
  73. bool
  74. Subnet::clientSupported(const isc::dhcp::ClientClasses& classes) const {
  75. if (white_list_.empty()) {
  76. return (true); // There is no class defined for this subnet, so we do
  77. // support everyone.
  78. }
  79. for (ClientClasses::const_iterator it = white_list_.begin();
  80. it != white_list_.end(); ++it) {
  81. if (classes.contains(*it)) {
  82. return (true);
  83. }
  84. }
  85. return (false);
  86. }
  87. void
  88. Subnet::allowClientClass(const isc::dhcp::ClientClass& class_name) {
  89. white_list_.insert(class_name);
  90. }
  91. isc::asiolink::IOAddress Subnet::getLastAllocated(Lease::Type type) const {
  92. // check if the type is valid (and throw if it isn't)
  93. checkType(type);
  94. switch (type) {
  95. case Lease::TYPE_V4:
  96. case Lease::TYPE_NA:
  97. return last_allocated_ia_;
  98. case Lease::TYPE_TA:
  99. return last_allocated_ta_;
  100. case Lease::TYPE_PD:
  101. return last_allocated_pd_;
  102. default:
  103. isc_throw(BadValue, "Pool type " << type << " not supported");
  104. }
  105. }
  106. void Subnet::setLastAllocated(Lease::Type type,
  107. const isc::asiolink::IOAddress& addr) {
  108. // check if the type is valid (and throw if it isn't)
  109. checkType(type);
  110. switch (type) {
  111. case Lease::TYPE_V4:
  112. case Lease::TYPE_NA:
  113. last_allocated_ia_ = addr;
  114. return;
  115. case Lease::TYPE_TA:
  116. last_allocated_ta_ = addr;
  117. return;
  118. case Lease::TYPE_PD:
  119. last_allocated_pd_ = addr;
  120. return;
  121. default:
  122. isc_throw(BadValue, "Pool type " << type << " not supported");
  123. }
  124. }
  125. std::string
  126. Subnet::toText() const {
  127. std::stringstream tmp;
  128. tmp << prefix_ << "/" << static_cast<unsigned int>(prefix_len_);
  129. return (tmp.str());
  130. }
  131. uint64_t
  132. Subnet::getPoolCapacity(Lease::Type type) const {
  133. switch (type) {
  134. case Lease::TYPE_V4:
  135. case Lease::TYPE_NA:
  136. return sumPoolCapacity(pools_);
  137. case Lease::TYPE_TA:
  138. return sumPoolCapacity(pools_ta_);
  139. case Lease::TYPE_PD:
  140. return sumPoolCapacity(pools_pd_);
  141. default:
  142. isc_throw(BadValue, "Unsupported pool type: "
  143. << static_cast<int>(type));
  144. }
  145. }
  146. uint64_t
  147. Subnet::sumPoolCapacity(const PoolCollection& pools) const {
  148. uint64_t sum = 0;
  149. for (PoolCollection::const_iterator p = pools.begin(); p != pools.end(); ++p) {
  150. uint64_t x = (*p)->getCapacity();
  151. // Check if we can add it. If sum + x > uint64::max, then we would have
  152. // overflown if we tried to add it.
  153. if (x > std::numeric_limits<uint64_t>::max() - sum) {
  154. return (std::numeric_limits<uint64_t>::max());
  155. }
  156. sum += x;
  157. }
  158. return (sum);
  159. }
  160. void Subnet4::checkType(Lease::Type type) const {
  161. if (type != Lease::TYPE_V4) {
  162. isc_throw(BadValue, "Only TYPE_V4 is allowed for Subnet4");
  163. }
  164. }
  165. Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
  166. const Triplet<uint32_t>& t1,
  167. const Triplet<uint32_t>& t2,
  168. const Triplet<uint32_t>& valid_lifetime,
  169. const SubnetID id)
  170. : Subnet(prefix, length, t1, t2, valid_lifetime, RelayInfo(IOAddress("0.0.0.0")), id),
  171. siaddr_(IOAddress("0.0.0.0")), match_client_id_(true) {
  172. if (!prefix.isV4()) {
  173. isc_throw(BadValue, "Non IPv4 prefix " << prefix.toText()
  174. << " specified in subnet4");
  175. }
  176. }
  177. void Subnet4::setSiaddr(const isc::asiolink::IOAddress& siaddr) {
  178. if (!siaddr.isV4()) {
  179. isc_throw(BadValue, "Can't set siaddr to non-IPv4 address "
  180. << siaddr);
  181. }
  182. siaddr_ = siaddr;
  183. }
  184. isc::asiolink::IOAddress Subnet4::getSiaddr() const {
  185. return (siaddr_);
  186. }
  187. const PoolCollection& Subnet::getPools(Lease::Type type) const {
  188. // check if the type is valid (and throw if it isn't)
  189. checkType(type);
  190. switch (type) {
  191. case Lease::TYPE_V4:
  192. case Lease::TYPE_NA:
  193. return (pools_);
  194. case Lease::TYPE_TA:
  195. return (pools_ta_);
  196. case Lease::TYPE_PD:
  197. return (pools_pd_);
  198. default:
  199. isc_throw(BadValue, "Unsupported pool type: "
  200. << static_cast<int>(type));
  201. }
  202. }
  203. PoolCollection& Subnet::getPoolsWritable(Lease::Type type) {
  204. // check if the type is valid (and throw if it isn't)
  205. checkType(type);
  206. switch (type) {
  207. case Lease::TYPE_V4:
  208. case Lease::TYPE_NA:
  209. return (pools_);
  210. case Lease::TYPE_TA:
  211. return (pools_ta_);
  212. case Lease::TYPE_PD:
  213. return (pools_pd_);
  214. default:
  215. isc_throw(BadValue, "Invalid pool type specified: "
  216. << static_cast<int>(type));
  217. }
  218. }
  219. const PoolPtr Subnet::getPool(Lease::Type type, const isc::asiolink::IOAddress& hint,
  220. bool anypool /* true */) const {
  221. // check if the type is valid (and throw if it isn't)
  222. checkType(type);
  223. const PoolCollection& pools = getPools(type);
  224. PoolPtr candidate;
  225. if (!pools.empty()) {
  226. // Pools are sorted by their first prefixes. For example: 2001::,
  227. // 2001::db8::, 3000:: etc. If our hint is 2001:db8:5:: we want to
  228. // find the pool with the longest matching prefix, so: 2001:db8::,
  229. // rather than 2001::. upper_bound returns the first pool with a prefix
  230. // that is greater than 2001:db8:5::, i.e. 3000::. To find the longest
  231. // matching prefix we use decrement operator to go back by one item.
  232. // If returned iterator points to begin it means that prefixes in all
  233. // pools are greater than out prefix, and thus there is no match.
  234. PoolCollection::const_iterator ub =
  235. std::upper_bound(pools.begin(), pools.end(), hint,
  236. prefixLessThanFirstAddress);
  237. if (ub != pools.begin()) {
  238. --ub;
  239. if ((*ub)->inRange(hint)) {
  240. candidate = *ub;
  241. }
  242. }
  243. // If we don't find anything better, then let's just use the first pool
  244. if (!candidate && anypool) {
  245. candidate = *pools.begin();
  246. }
  247. }
  248. // Return a pool or NULL if no match found.
  249. return (candidate);
  250. }
  251. void
  252. Subnet::addPool(const PoolPtr& pool) {
  253. // check if the type is valid (and throw if it isn't)
  254. checkType(pool->getType());
  255. // Check that the pool is in range with a subnet only if this is
  256. // not a pool of IPv6 prefixes. The IPv6 prefixes delegated for
  257. // the particular subnet don't need to match the prefix of the
  258. // subnet.
  259. if (pool->getType() != Lease::TYPE_PD) {
  260. if (!inRange(pool->getFirstAddress()) || !inRange(pool->getLastAddress())) {
  261. isc_throw(BadValue, "a pool of type "
  262. << Lease::typeToText(pool->getType())
  263. << ", with the following address range: "
  264. << pool->getFirstAddress() << "-"
  265. << pool->getLastAddress() << " does not match"
  266. << " the prefix of a subnet: "
  267. << prefix_ << "/" << static_cast<int>(prefix_len_)
  268. << " to which it is being added");
  269. }
  270. }
  271. bool overlaps = false;
  272. if (pool->getType() == Lease::TYPE_V4) {
  273. overlaps = poolOverlaps(Lease::TYPE_V4, pool);
  274. } else {
  275. overlaps =
  276. poolOverlaps(Lease::TYPE_NA, pool) ||
  277. poolOverlaps(Lease::TYPE_PD, pool) ||
  278. poolOverlaps(Lease::TYPE_TA, pool);
  279. }
  280. if (overlaps) {
  281. isc_throw(BadValue,"a pool of type "
  282. << Lease::typeToText(pool->getType())
  283. << ", with the following address range: "
  284. << pool->getFirstAddress() << "-"
  285. << pool->getLastAddress() << " overlaps with "
  286. "an existing pool in the subnet: "
  287. << prefix_ << "/" << static_cast<int>(prefix_len_)
  288. << " to which it is being added");
  289. }
  290. PoolCollection& pools_writable = getPoolsWritable(pool->getType());
  291. // Add the pool to the appropriate pools collection
  292. pools_writable.push_back(pool);
  293. // Sort pools by first address.
  294. std::sort(pools_writable.begin(), pools_writable.end(),
  295. comparePoolFirstAddress);
  296. }
  297. void
  298. Subnet::delPools(Lease::Type type) {
  299. getPoolsWritable(type).clear();
  300. }
  301. void
  302. Subnet::setIface(const std::string& iface_name) {
  303. iface_ = iface_name;
  304. }
  305. std::string
  306. Subnet::getIface() const {
  307. return (iface_);
  308. }
  309. bool
  310. Subnet::inPool(Lease::Type type, const isc::asiolink::IOAddress& addr) const {
  311. // Let's start with checking if it even belongs to that subnet.
  312. if (!inRange(addr)) {
  313. return (false);
  314. }
  315. const PoolCollection& pools = getPools(type);
  316. for (PoolCollection::const_iterator pool = pools.begin();
  317. pool != pools.end(); ++pool) {
  318. if ((*pool)->inRange(addr)) {
  319. return (true);
  320. }
  321. }
  322. // There's no pool that address belongs to
  323. return (false);
  324. }
  325. bool
  326. Subnet::poolOverlaps(const Lease::Type& pool_type, const PoolPtr& pool) const {
  327. const PoolCollection& pools = getPools(pool_type);
  328. // If no pools, we don't overlap. Nothing to do.
  329. if (pools.empty()) {
  330. return (false);
  331. }
  332. // We're going to insert a new pool, likely between two existing pools.
  333. // So we're going to end up with the following case:
  334. // |<---- pool1 ---->| |<-------- pool2 ------>| |<-- pool3 -->|
  335. // F1 L1 F2 L2 F3 L3
  336. // where pool1 and pool3 are existing pools, pool2 is a pool being
  337. // inserted and "F"/"L" mark first and last address in the pools
  338. // respectively. So the following conditions must be fulfilled:
  339. // F2 > L1 and L2 < F3. Obviously, for any pool: F < L.
  340. // Search for pool3. We use F2 and upper_bound to find the F3 (upper_bound
  341. // returns first pool in the sorted container which first address is
  342. // greater than F2). prefixLessThanPoolAddress with the first argument
  343. // set to "true" is the custom comparison function for upper_bound, which
  344. // compares F2 with the first addresses of the existing pools.
  345. PoolCollection::const_iterator pool3_it =
  346. std::upper_bound(pools.begin(), pools.end(), pool->getFirstAddress(),
  347. prefixLessThanFirstAddress);
  348. // upper_bound returns a first pool which first address is greater than the
  349. // address F2. However, it is also possible that there is a pool which first
  350. // address is equal to F2. Such pool is also in conflict with a new pool.
  351. // If the returned value is pools.begin() it means that all pools have greater
  352. // first address than F2, thus none of the pools can have first address equal
  353. // to F2. Otherwise, we'd need to check them for equality.
  354. if (pool3_it != pools.begin()) {
  355. // Go back one pool and check if addresses are equal.
  356. PoolPtr pool3 = *(pool3_it - 1);
  357. if (pool3->getFirstAddress() == pool->getFirstAddress()) {
  358. return (true);
  359. }
  360. }
  361. // If returned value is unequal pools.end() it means that there is a pool3,
  362. // with F3 > F2.
  363. if (pool3_it != pools.end()) {
  364. // Let's store the pointer to this pool.
  365. PoolPtr pool3 = *pool3_it;
  366. // F3 must be greater than L2, otherwise pools will overlap.
  367. if (pool3->getFirstAddress() <= pool->getLastAddress()) {
  368. return (true);
  369. }
  370. }
  371. // If L2 is ok, we now have to find the pool1. This pool should be
  372. // right before the pool3 if there is any pool before pool3.
  373. if (pool3_it != pools.begin()) {
  374. PoolPtr pool1 = *(pool3_it - 1);
  375. // F2 must be greater than L1.
  376. if (pool->getFirstAddress() <= pool1->getLastAddress()) {
  377. return (true);
  378. }
  379. }
  380. return (false);
  381. }
  382. Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
  383. const Triplet<uint32_t>& t1,
  384. const Triplet<uint32_t>& t2,
  385. const Triplet<uint32_t>& preferred_lifetime,
  386. const Triplet<uint32_t>& valid_lifetime,
  387. const SubnetID id)
  388. :Subnet(prefix, length, t1, t2, valid_lifetime, RelayInfo(IOAddress("::")), id),
  389. preferred_(preferred_lifetime), rapid_commit_(false) {
  390. if (!prefix.isV6()) {
  391. isc_throw(BadValue, "Non IPv6 prefix " << prefix
  392. << " specified in subnet6");
  393. }
  394. }
  395. void Subnet6::checkType(Lease::Type type) const {
  396. if ( (type != Lease::TYPE_NA) && (type != Lease::TYPE_TA) &&
  397. (type != Lease::TYPE_PD)) {
  398. isc_throw(BadValue, "Invalid Pool type: " << Lease::typeToText(type)
  399. << "(" << static_cast<int>(type)
  400. << "), must be TYPE_NA, TYPE_TA or TYPE_PD for Subnet6");
  401. }
  402. }
  403. } // end of isc::dhcp namespace
  404. } // end of isc namespace