Kea: ip_range_permutation.cc Source File

| Kea 3.2.0-git

ip_range_permutation.cc
Go to the documentation of this file.
1// Copyright (C) 2020-2026 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
7#include <config.h>
8#include <asiolink/addr_utilities.h>
9#include <dhcpsrv/ip_range_permutation.h>
10
11#include <iostream>
12
13using namespace isc::asiolink;
14
15namespace isc {
16namespace dhcp {
17
18IPRangePermutation::IPRangePermutation(const AddressRange& range)
19 : range_start_(range.start_), step_(1), cursor_(addrsInRange(range_start_, range.end_) - 1),
20 initial_cursor_(cursor_), state_(), done_(false), generator_() {
21 std::random_device rd;
22 generator_.seed(rd());
23 // One address in range case.
24 if (!initial_cursor_) {
25 state_.insert(std::make_pair(0, range_start_));
26 }
27}
28
29 IPRangePermutation::IPRangePermutation(const PrefixRange& range)
30 : range_start_(range.start_), step_(isc::util::uint128_t(1) << (128 - range.delegated_length_)),
31 cursor_(prefixesInRange(range.prefix_length_, range.delegated_length_) - 1),
32 initial_cursor_(cursor_), state_(), done_(false), generator_() {
33 std::random_device rd;
34 generator_.seed(rd());
35 // One address in range case.
36 if (!initial_cursor_) {
37 state_.insert(std::make_pair(0, range_start_));
38 }
39}
40
41 IOAddress
42IPRangePermutation::next(bool& done) {
43 // If we're done iterating over the pool let's return zero address and
44 // set the user supplied done flag to true.
45 if (done_) {
46 done = true;
47 return (range_start_.isV4() ? IOAddress::IPV4_ZERO_ADDRESS() : IOAddress::IPV6_ZERO_ADDRESS());
48 }
49
50 // If there is one address left, return this address.
51 if (cursor_ == 0) {
52 done = done_ = true;
53 return (state_.at(0));
54 }
55
56 // We're not done.
57 done = false;
58
59 // The cursor indicates where we're in the range starting from its end. The
60 // addresses between the cursor and the end of the range have been already
61 // returned by this function. Therefore we focus on the remaining cursor-1
62 // addresses. Let's get random address from this sub-range.
63 uint64_t max_limit = std::numeric_limits<uint64_t>::max();
64 if ((cursor_ - 1) < isc::util::int128_t(max_limit)) {
65 max_limit = static_cast<uint64_t>(cursor_ - 1);
66 }
67 std::uniform_int_distribution<uint64_t> dist(0, max_limit);
68 auto next_loc = dist(generator_);
69
70 IOAddress next_loc_address = IOAddress::IPV4_ZERO_ADDRESS();
71
72 // Check whether this address exists in our map or not. If it exists
73 // it means it was swapped with some other address in previous calls to
74 // this function.
75 auto next_loc_existing = state_.find(next_loc);
76 if (next_loc_existing != state_.end()) {
77 // Address exists, so let's record it.
78 next_loc_address = next_loc_existing->second;
79 } else {
80 // Address does not exist on this position. We infer this address from
81 // its position by advancing the range start by position. For example,
82 // if the range is 192.0.2.1-192.0.2.10 and the picked random position is
83 // 5, the address we get is 192.0.2.6. This random address will be later
84 // returned to the caller.
85 next_loc_address = offsetAddress(range_start_, next_loc * step_);
86 }
87
88 // Let's get the address at cursor position in the same way.
89 IOAddress cursor_address = IOAddress::IPV4_ZERO_ADDRESS();
90 auto cursor_existing = state_.find(cursor_);
91 if (cursor_existing != state_.end()) {
92 cursor_address = cursor_existing->second;
93 } else {
94 cursor_address = offsetAddress(range_start_, cursor_ * step_);
95 }
96
97 // Now we swap them.... in fact we don't swap because as an optimization
98 // we don't record the addresses we returned by this function. We merely
99 // replace the address at random position with the address from cursor
100 // position. This address will be returned in the future if we get back
101 // to this position as a result of randomization.
102 if (next_loc_existing == state_.end()) {
103 state_.insert(std::make_pair(next_loc, cursor_address));
104 } else {
105 state_.at(next_loc) = cursor_address;
106 }
107 // Move the cursor one position backwards.
108 --cursor_;
109
110 // Return the address from the random position.
111 return (next_loc_address);
112}
113
114void
115IPRangePermutation::reset() {
116 state_.clear();
117 cursor_ = initial_cursor_;
118 done_ = false;
119 // One address in range case.
120 if (!initial_cursor_) {
121 state_.insert(std::make_pair(0, range_start_));
122 }
123}
124
125} // end of namespace isc::dhcp
126} // end of namespace isc
addr_utilities.h
isc::asiolink::IOAddress
The IOAddress class represents an IP addresses (version agnostic).
Definition io_address.h:53
isc::asiolink::IOAddress::IPV4_ZERO_ADDRESS
static const IOAddress & IPV4_ZERO_ADDRESS()
Returns an address set to all zeros.
Definition io_address.h:285
isc::asiolink::IOAddress::IPV6_ZERO_ADDRESS
static const IOAddress & IPV6_ZERO_ADDRESS()
Returns an IPv6 zero address.
Definition io_address.h:297
isc::dhcp::IPRangePermutation::next
asiolink::IOAddress next(bool &done)
Returns next random address or prefix from the permutation.
Definition ip_range_permutation.cc:42
isc::dhcp::IPRangePermutation::reset
void reset()
Resets the permutation state.
Definition ip_range_permutation.cc:115
isc::dhcp::IPRangePermutation::IPRangePermutation
IPRangePermutation(const AddressRange &range)
Constructor for address ranges.
Definition ip_range_permutation.cc:18
ip_range_permutation.h
isc::asiolink
Definition addr_utilities.cc:170
isc::asiolink::addrsInRange
uint128_t addrsInRange(const IOAddress &min, const IOAddress &max)
Returns number of available addresses in the specified range (min - max).
Definition addr_utilities.cc:203
isc::asiolink::prefixesInRange
uint128_t prefixesInRange(const uint8_t pool_len, const uint8_t delegated_len)
Returns number of available IPv6 prefixes in the specified prefix.
Definition addr_utilities.cc:352
isc::asiolink::offsetAddress
IOAddress offsetAddress(const IOAddress &addr, uint128_t offset)
Finds the address increased by offset.
Definition addr_utilities.cc:368
isc::dhcp
Definition dhcp4/client_handler.cc:20
isc::util
Definition time_utils.cc:43
isc::util::int128_t
boost::multiprecision::checked_int128_t int128_t
Definition bigints.h:19
isc::util::uint128_t
boost::multiprecision::checked_uint128_t uint128_t
Definition bigints.h:21
isc
Defines the logger used by the top-level component of kea-lfc.
Definition check_exists_add.cc:18
isc::dhcp::AddressRange
Structure representing IP address range.
Definition ip_range.h:16
isc::dhcp::PrefixRange
Structure representing delegated prefix range.
Definition ip_range.h:32