1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
|
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <dhcpsrv/addr_utilities.h>
#include <exceptions/exceptions.h>
#include <vector>
#include <limits>
#include <string.h>
using namespace isc;
using namespace isc::asiolink;
namespace {
/// @brief mask used for first/last address calculation in a IPv4 prefix
///
/// Using a static mask is faster than calculating it dynamically every time.
const uint32_t bitMask4[] = { 0xffffffff, 0x7fffffff, 0x3fffffff, 0x1fffffff,
0x0fffffff, 0x07ffffff, 0x03ffffff, 0x01ffffff,
0x00ffffff, 0x007fffff, 0x003fffff, 0x001fffff,
0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff,
0x0000ffff, 0x00007fff, 0x00003fff, 0x00001fff,
0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff,
0x000000ff, 0x0000007f, 0x0000003f, 0x0000001f,
0x0000000f, 0x00000007, 0x00000003, 0x00000001,
0x00000000 };
/// @brief mask used for first/last address calculation in a IPv6 prefix
const uint8_t bitMask6[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
/// @brief calculates the first IPv6 address in a IPv6 prefix
///
/// Note: This is a private function. Do not use it directly.
/// Please use firstAddrInPrefix() instead.
///
/// @param prefix IPv6 prefix
/// @param len prefix length
isc::asiolink::IOAddress firstAddrInPrefix6(const isc::asiolink::IOAddress& prefix,
uint8_t len) {
if (len > 128) {
isc_throw(isc::BadValue,
"Too large netmask. 0..128 is allowed in IPv6");
}
// First we copy the whole address as 16 bytes.
// We don't check that it is a valid IPv6 address and thus has
// the required length because it is already checked by
// the calling function.
uint8_t packed[V6ADDRESS_LEN];
memcpy(packed, &prefix.toBytes()[0], V6ADDRESS_LEN);
// If the length is divisible by 8, it is simple. We just zero out the host
// part. Otherwise we need to handle the byte that has to be partially
// zeroed.
if (len % 8 != 0) {
// Get the appropriate mask. It has relevant bits (those that should
// stay) set and irrelevant (those that should be wiped) cleared.
uint8_t mask = bitMask6[len % 8];
// Let's leave only whatever the mask says should not be cleared.
packed[len / 8] = packed[len / 8] & mask;
// Since we have just dealt with this byte, let's move the prefix length
// to the beginning of the next byte (len is expressed in bits).
len = (len / 8 + 1) * 8;
}
// Clear out the remaining bits.
for (int i = len / 8; i < sizeof(packed); ++i) {
packed[i] = 0x0;
}
// Finally, let's wrap this into nice and easy IOAddress object.
return (isc::asiolink::IOAddress::fromBytes(AF_INET6, packed));
}
/// @brief calculates the first IPv4 address in a IPv4 prefix
///
/// Note: This is a private function. Do not use it directly.
/// Please use firstAddrInPrefix() instead.
///
/// @param prefix IPv4 prefix
/// @param len netmask length (0-32)
isc::asiolink::IOAddress firstAddrInPrefix4(const isc::asiolink::IOAddress& prefix,
uint8_t len) {
if (len > 32) {
isc_throw(isc::BadValue, "Too large netmask. 0..32 is allowed in IPv4");
}
// We don't check that it is a valid IPv4 address and thus has
// a required length of 4 bytes because it has been already
// checked by the calling function.
uint32_t addr = prefix;
return (IOAddress(addr & (~bitMask4[len])));
}
/// @brief calculates the last IPv4 address in a IPv4 prefix
///
/// Note: This is a private function. Do not use it directly.
/// Please use firstAddrInPrefix() instead.
///
/// @param prefix IPv4 prefix that we calculate first address for
/// @param len netmask length (0-32)
isc::asiolink::IOAddress lastAddrInPrefix4(const isc::asiolink::IOAddress& prefix,
uint8_t len) {
if (len > 32) {
isc_throw(isc::BadValue, "Too large netmask. 0..32 is allowed in IPv4");
}
uint32_t addr = prefix;
return (IOAddress(addr | bitMask4[len]));
}
/// @brief calculates the last IPv6 address in a IPv6 prefix
///
/// Note: This is a private function. Do not use it directly.
/// Please use lastAddrInPrefix() instead.
///
/// @param prefix IPv6 prefix that we calculate first address for
/// @param len netmask length (0-128)
isc::asiolink::IOAddress lastAddrInPrefix6(const isc::asiolink::IOAddress& prefix,
uint8_t len) {
if (len > 128) {
isc_throw(isc::BadValue,
"Too large netmask. 0..128 is allowed in IPv6");
}
// First we copy the whole address as 16 bytes.
uint8_t packed[V6ADDRESS_LEN];
memcpy(packed, &prefix.toBytes()[0], 16);
// if the length is divisible by 8, it is simple. We just fill the host part
// with ones. Otherwise we need to handle the byte that has to be partially
// zeroed.
if (len % 8 != 0) {
// Get the appropriate mask. It has relevant bits (those that should
// stay) set and irrelevant (those that should be set to 1) cleared.
uint8_t mask = bitMask6[len % 8];
// Let's set those irrelevant bits with 1. It would be perhaps
// easier to not use negation here and invert bitMask6 content. However,
// with this approach, we can use the same mask in first and last
// address calculations.
packed[len / 8] = packed[len / 8] | ~mask;
// Since we have just dealt with this byte, let's move the prefix length
// to the beginning of the next byte (len is expressed in bits).
len = (len / 8 + 1) * 8;
}
// Finally set remaining bits to 1.
for (int i = len / 8; i < sizeof(packed); ++i) {
packed[i] = 0xff;
}
// Finally, let's wrap this into nice and easy IOAddress object.
return (isc::asiolink::IOAddress::fromBytes(AF_INET6, packed));
}
}; // end of anonymous namespace
namespace isc {
namespace dhcp {
isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefix,
uint8_t len) {
if (prefix.isV4()) {
return (firstAddrInPrefix4(prefix, len));
} else {
return (firstAddrInPrefix6(prefix, len));
}
}
isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix,
uint8_t len) {
if (prefix.isV4()) {
return (lastAddrInPrefix4(prefix, len));
} else {
return (lastAddrInPrefix6(prefix, len));
}
}
isc::asiolink::IOAddress getNetmask4(uint8_t len) {
if (len > 32) {
isc_throw(BadValue, "Invalid netmask size "
<< static_cast<unsigned>(len) << ", allowed range is 0..32");
}
uint32_t x = ~bitMask4[len];
return (IOAddress(x));
}
uint64_t
addrsInRange(const isc::asiolink::IOAddress& min,
const isc::asiolink::IOAddress& max) {
if (min.getFamily() != max.getFamily()) {
isc_throw(BadValue, "Both addresses have to be the same family");
}
if (max < min) {
isc_throw(BadValue, min.toText() << " must not be greater than "
<< max.toText());
}
if (min.isV4()) {
// Let's explicitly cast last_ and first_ (IOAddress). This conversion is
// automatic, but let's explicitly cast it show that we moved to integer
// domain and addresses are now substractable.
uint64_t max_numeric = static_cast<uint32_t>(max);
uint64_t min_numeric = static_cast<uint32_t>(min);
// We can simply subtract the values. We need to increase the result
// by one, as both min and max are included in the range. So even if
// min == max, there's one address.
return (max_numeric - min_numeric + 1);
} else {
// Calculating the difference in v6 is more involved. Let's subtract
// one from the other. By subtracting min from max, we move the
// [a, b] range to the [0, (b-a)] range. We don't care about the beginning
// of the new range (it's always zero). The upper bound now specifies
// the number of addresses minus one.
IOAddress count = IOAddress::subtract(max, min);
// There's one very special case. Someone is trying to check how many
// IPv6 addresses are in IPv6 address space. He called this method
// with ::, ffff:ffff:ffff:fffff:ffff:ffff:ffff:ffff. The diff is also
// all 1s. Had we increased it by one, the address would flip to all 0s.
// This will not happen in a real world. Apparently, unit-tests are
// sometimes nastier then a real world.
static IOAddress max6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
if (count == max6) {
return (std::numeric_limits<uint64_t>::max());
}
// Increase it by one (a..a range still contains one address, even though
// a subtracted from a is zero).
count = IOAddress::increase(count);
// We don't have uint128, so for anything greater than 2^64, we'll just
// assume numeric_limits<uint64_t>::max. Let's do it the manual way.
const std::vector<uint8_t>& bin(count.toBytes());
// If any of the most significant 64 bits is set, we have more than
// 2^64 addresses and can't represent it even on uint64_t.
for (int i = 0 ; i < 8; i++) {
if (bin[i]) {
return (std::numeric_limits<uint64_t>::max());
}
}
// Ok, we're good. The pool is sanely sized. It may be huge, but at least
// that's something we can represent on uint64_t.
uint64_t numeric = 0;
for (int i = 8; i < 16; i++) {
numeric <<= 8;
numeric += bin[i];
}
return (numeric);
}
}
uint64_t prefixesInRange(const uint8_t pool_len, const uint8_t delegated_len) {
if (delegated_len < pool_len) {
return (0);
}
uint64_t count = delegated_len - pool_len;
if (count == 0) {
// If we want to delegate /64 out of /64 pool, we have only
// one prefix.
return (1);
} else if (count >= 64) {
// If the difference is greater than or equal 64, e.g. we want to
// delegate /96 out of /16 pool, the number is bigger than we can
// express, so we'll stick with maximum value of uint64_t.
return (std::numeric_limits<uint64_t>::max());
} else {
// Now count specifies the exponent (e.g. if the difference between the
// delegated and pool length is 4, we have 16 prefixes), so we need
// to calculate 2^(count - 1)
return ((static_cast<uint64_t>(2)) << (count - 1));
}
}
};
};
|