Kea: ip_range_permutation.cc Source File

| Kea 3.0.0

ip_range_permutation.cc
Go to the documentation of this file.
1// Copyright (C) 2020-2023 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}
24
25 IPRangePermutation::IPRangePermutation(const PrefixRange& range)
26 : range_start_(range.start_), step_(isc::util::uint128_t(1) << (128 - range.delegated_length_)),
27 cursor_(prefixesInRange(range.prefix_length_, range.delegated_length_) - 1),
28 initial_cursor_(cursor_), state_(), done_(false), generator_() {
29 std::random_device rd;
30 generator_.seed(rd());
31}
32
33 IOAddress
34IPRangePermutation::next(bool& done) {
35 // If we're done iterating over the pool let's return zero address and
36 // set the user supplied done flag to true.
37 if (done_) {
38 done = true;
39 return (range_start_.isV4() ? IOAddress::IPV4_ZERO_ADDRESS() : IOAddress::IPV6_ZERO_ADDRESS());
40 }
41
42 // If there is one address left, return this address.
43 if (cursor_ == 0) {
44 done = done_ = true;
45 return (state_.at(0));
46 }
47
48 // We're not done.
49 done = false;
50
51 // The cursor indicates where we're in the range starting from its end. The
52 // addresses between the cursor and the end of the range have been already
53 // returned by this function. Therefore we focus on the remaining cursor-1
54 // addresses. Let's get random address from this sub-range.
55 uint64_t max_limit = std::numeric_limits<uint64_t>::max();
56 if ((cursor_ - 1) < isc::util::int128_t(max_limit)) {
57 max_limit = static_cast<uint64_t>(cursor_ - 1);
58 }
59 std::uniform_int_distribution<uint64_t> dist(0, max_limit);
60 auto next_loc = dist(generator_);
61
62 IOAddress next_loc_address = IOAddress::IPV4_ZERO_ADDRESS();
63
64 // Check whether this address exists in our map or not. If it exists
65 // it means it was swapped with some other address in previous calls to
66 // this function.
67 auto next_loc_existing = state_.find(next_loc);
68 if (next_loc_existing != state_.end()) {
69 // Address exists, so let's record it.
70 next_loc_address = next_loc_existing->second;
71 } else {
72 // Address does not exist on this position. We infer this address from
73 // its position by advancing the range start by position. For example,
74 // if the range is 192.0.2.1-192.0.2.10 and the picked random position is
75 // 5, the address we get is 192.0.2.6. This random address will be later
76 // returned to the caller.
77 next_loc_address = offsetAddress(range_start_, next_loc * step_);
78 }
79
80 // Let's get the address at cursor position in the same way.
81 IOAddress cursor_address = IOAddress::IPV4_ZERO_ADDRESS();
82 auto cursor_existing = state_.find(cursor_);
83 if (cursor_existing != state_.end()) {
84 cursor_address = cursor_existing->second;
85 } else {
86 cursor_address = offsetAddress(range_start_, cursor_ * step_);
87 }
88
89 // Now we swap them.... in fact we don't swap because as an optimization
90 // we don't record the addresses we returned by this function. We merely
91 // replace the address at random position with the address from cursor
92 // position. This address will be returned in the future if we get back
93 // to this position as a result of randomization.
94 if (next_loc_existing == state_.end()) {
95 state_.insert(std::make_pair(next_loc, cursor_address));
96 } else {
97 state_.at(next_loc) = cursor_address;
98 }
99 // Move the cursor one position backwards.
100 --cursor_;
101
102 // Return the address from the random position.
103 return (next_loc_address);
104}
105
106void
107IPRangePermutation::reset() {
108 state_.clear();
109 cursor_ = initial_cursor_;
110 done_ = false;
111}
112
113} // end of namespace isc::dhcp
114} // end of namespace isc
addr_utilities.h
isc::asiolink::IOAddress
The IOAddress class represents an IP addresses (version agnostic)
Definition io_address.h:45
isc::asiolink::IOAddress::IPV4_ZERO_ADDRESS
static const IOAddress & IPV4_ZERO_ADDRESS()
Returns an address set to all zeros.
Definition io_address.h:277
isc::asiolink::IOAddress::IPV6_ZERO_ADDRESS
static const IOAddress & IPV6_ZERO_ADDRESS()
Returns an IPv6 zero address.
Definition io_address.h:289
isc::dhcp::IPRangePermutation::next
asiolink::IOAddress next(bool &done)
Returns next random address or prefix from the permutation.
Definition ip_range_permutation.cc:34
isc::dhcp::IPRangePermutation::reset
void reset()
Resets the permutation state.
Definition ip_range_permutation.cc:107
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 agent_parser.cc:148
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