Kea  1.5.0
addr_utilities.cc
Go to the documentation of this file.
1 // Copyright (C) 2012-2018 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 
10 #include <exceptions/exceptions.h>
11 
12 #include <vector>
13 #include <limits>
14 #include <string.h>
15 
16 using namespace isc;
17 using namespace isc::asiolink;
18 
19 namespace {
20 
24 const uint32_t bitMask4[] = { 0xffffffff, 0x7fffffff, 0x3fffffff, 0x1fffffff,
25  0x0fffffff, 0x07ffffff, 0x03ffffff, 0x01ffffff,
26  0x00ffffff, 0x007fffff, 0x003fffff, 0x001fffff,
27  0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff,
28  0x0000ffff, 0x00007fff, 0x00003fff, 0x00001fff,
29  0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff,
30  0x000000ff, 0x0000007f, 0x0000003f, 0x0000001f,
31  0x0000000f, 0x00000007, 0x00000003, 0x00000001,
32  0x00000000 };
33 
35 const uint8_t bitMask6[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
36 
38 const uint8_t revMask6[]= { 0xff, 0x7f, 0x3f, 0x1f, 0xf, 0x7, 0x3, 0x1 };
39 
40 
48 isc::asiolink::IOAddress firstAddrInPrefix6(const isc::asiolink::IOAddress& prefix,
49  uint8_t len) {
50  if (len > 128) {
52  "Too large netmask. 0..128 is allowed in IPv6");
53  }
54 
55  // First we copy the whole address as 16 bytes.
56  // We don't check that it is a valid IPv6 address and thus has
57  // the required length because it is already checked by
58  // the calling function.
59  uint8_t packed[V6ADDRESS_LEN];
60  memcpy(packed, &prefix.toBytes()[0], V6ADDRESS_LEN);
61 
62  // If the length is divisible by 8, it is simple. We just zero out the host
63  // part. Otherwise we need to handle the byte that has to be partially
64  // zeroed.
65  if (len % 8 != 0) {
66 
67  // Get the appropriate mask. It has relevant bits (those that should
68  // stay) set and irrelevant (those that should be wiped) cleared.
69  uint8_t mask = bitMask6[len % 8];
70 
71  // Let's leave only whatever the mask says should not be cleared.
72  packed[len / 8] = packed[len / 8] & mask;
73 
74  // Since we have just dealt with this byte, let's move the prefix length
75  // to the beginning of the next byte (len is expressed in bits).
76  len = (len / 8 + 1) * 8;
77  }
78 
79  // Clear out the remaining bits.
80  for (int i = len / 8; i < sizeof(packed); ++i) {
81  packed[i] = 0x0;
82  }
83 
84  // Finally, let's wrap this into nice and easy IOAddress object.
85  return (isc::asiolink::IOAddress::fromBytes(AF_INET6, packed));
86 }
87 
95 isc::asiolink::IOAddress firstAddrInPrefix4(const isc::asiolink::IOAddress& prefix,
96  uint8_t len) {
97  if (len > 32) {
98  isc_throw(isc::BadValue, "Too large netmask. 0..32 is allowed in IPv4");
99  }
100 
101  // We don't check that it is a valid IPv4 address and thus has
102  // a required length of 4 bytes because it has been already
103  // checked by the calling function.
104  uint32_t addr = prefix.toUint32();
105  return (IOAddress(addr & (~bitMask4[len])));
106 }
107 
115 isc::asiolink::IOAddress lastAddrInPrefix4(const isc::asiolink::IOAddress& prefix,
116  uint8_t len) {
117  if (len > 32) {
118  isc_throw(isc::BadValue, "Too large netmask. 0..32 is allowed in IPv4");
119  }
120 
121  uint32_t addr = prefix.toUint32();
122  return (IOAddress(addr | bitMask4[len]));
123 }
124 
132 isc::asiolink::IOAddress lastAddrInPrefix6(const isc::asiolink::IOAddress& prefix,
133  uint8_t len) {
134  if (len > 128) {
136  "Too large netmask. 0..128 is allowed in IPv6");
137  }
138 
139  // First we copy the whole address as 16 bytes.
140  uint8_t packed[V6ADDRESS_LEN];
141  memcpy(packed, &prefix.toBytes()[0], 16);
142 
143  // if the length is divisible by 8, it is simple. We just fill the host part
144  // with ones. Otherwise we need to handle the byte that has to be partially
145  // zeroed.
146  if (len % 8 != 0) {
147  // Get the appropriate mask. It has relevant bits (those that should
148  // stay) set and irrelevant (those that should be set to 1) cleared.
149  uint8_t mask = bitMask6[len % 8];
150 
151  // Let's set those irrelevant bits with 1. It would be perhaps
152  // easier to not use negation here and invert bitMask6 content. However,
153  // with this approach, we can use the same mask in first and last
154  // address calculations.
155  packed[len / 8] = packed[len / 8] | ~mask;
156 
157  // Since we have just dealt with this byte, let's move the prefix length
158  // to the beginning of the next byte (len is expressed in bits).
159  len = (len / 8 + 1) * 8;
160  }
161 
162  // Finally set remaining bits to 1.
163  for (int i = len / 8; i < sizeof(packed); ++i) {
164  packed[i] = 0xff;
165  }
166 
167  // Finally, let's wrap this into nice and easy IOAddress object.
168  return (isc::asiolink::IOAddress::fromBytes(AF_INET6, packed));
169 }
170 
171 }; // end of anonymous namespace
172 
173 namespace isc {
174 namespace dhcp {
175 
177  uint8_t len) {
178  if (prefix.isV4()) {
179  return (firstAddrInPrefix4(prefix, len));
180 
181  } else {
182  return (firstAddrInPrefix6(prefix, len));
183 
184  }
185 }
186 
188  uint8_t len) {
189  if (prefix.isV4()) {
190  return (lastAddrInPrefix4(prefix, len));
191 
192  } else {
193  return (lastAddrInPrefix6(prefix, len));
194 
195  }
196 }
197 
199  if (len > 32) {
200  isc_throw(BadValue, "Invalid netmask size "
201  << static_cast<unsigned>(len) << ", allowed range is 0..32");
202  }
203  uint32_t x = ~bitMask4[len];
204 
205  return (IOAddress(x));
206 }
207 
208 uint64_t
210  const isc::asiolink::IOAddress& max) {
211  if (min.getFamily() != max.getFamily()) {
212  isc_throw(BadValue, "Both addresses have to be the same family");
213  }
214 
215  if (max < min) {
216  isc_throw(BadValue, min.toText() << " must not be greater than "
217  << max.toText());
218  }
219 
220  if (min.isV4()) {
221  // Let's explicitly cast last_ and first_ (IOAddress). This conversion is
222  // automatic, but let's explicitly cast it show that we moved to integer
223  // domain and addresses are now substractable.
224  uint64_t max_numeric = static_cast<uint64_t>(max.toUint32());
225  uint64_t min_numeric = static_cast<uint64_t>(min.toUint32());
226 
227  // We can simply subtract the values. We need to increase the result
228  // by one, as both min and max are included in the range. So even if
229  // min == max, there's one address.
230  return (max_numeric - min_numeric + 1);
231  } else {
232 
233  // Calculating the difference in v6 is more involved. Let's subtract
234  // one from the other. By subtracting min from max, we move the
235  // [a, b] range to the [0, (b-a)] range. We don't care about the beginning
236  // of the new range (it's always zero). The upper bound now specifies
237  // the number of addresses minus one.
238  IOAddress count = IOAddress::subtract(max, min);
239 
240  // There's one very special case. Someone is trying to check how many
241  // IPv6 addresses are in IPv6 address space. He called this method
242  // with ::, ffff:ffff:ffff:fffff:ffff:ffff:ffff:ffff. The diff is also
243  // all 1s. Had we increased it by one, the address would flip to all 0s.
244  // This will not happen in a real world. Apparently, unit-tests are
245  // sometimes nastier then a real world.
246  static IOAddress max6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
247  if (count == max6) {
248  return (std::numeric_limits<uint64_t>::max());
249  }
250 
251  // Increase it by one (a..a range still contains one address, even though
252  // a subtracted from a is zero).
253  count = IOAddress::increase(count);
254 
255  // We don't have uint128, so for anything greater than 2^64, we'll just
256  // assume numeric_limits<uint64_t>::max. Let's do it the manual way.
257  const std::vector<uint8_t>& bin(count.toBytes());
258 
259  // If any of the most significant 64 bits is set, we have more than
260  // 2^64 addresses and can't represent it even on uint64_t.
261  for (int i = 0 ; i < 8; i++) {
262  if (bin[i]) {
263  return (std::numeric_limits<uint64_t>::max());
264  }
265  }
266 
267  // Ok, we're good. The pool is sanely sized. It may be huge, but at least
268  // that's something we can represent on uint64_t.
269  uint64_t numeric = 0;
270  for (int i = 8; i < 16; i++) {
271  numeric <<= 8;
272  numeric += bin[i];
273  }
274 
275  return (numeric);
276  }
277 }
278 
279 int
281  const isc::asiolink::IOAddress& max) {
282  if (min.getFamily() != max.getFamily()) {
283  isc_throw(BadValue, "Both addresses have to be the same family");
284  }
285 
286  if (max < min) {
287  isc_throw(BadValue, min.toText() << " must not be greater than "
288  << max.toText());
289  }
290 
291  if (min.isV4()) {
292  // Get addresses as integers
293  uint32_t max_numeric = max.toUint32();
294  uint32_t min_numeric = min.toUint32();
295 
296  // Get the exclusive or which must be one of the bit masks
297  uint32_t xor_numeric = max_numeric ^ min_numeric;
298  for (uint8_t prefix_len = 0; prefix_len <= 32; ++prefix_len) {
299  if (xor_numeric == bitMask4[prefix_len]) {
300  // Got it: the wanted value is also the index
301  return (static_cast<int>(prefix_len));
302  }
303  }
304 
305  // If it was not found the range is not from a prefix / prefix_len
306  return (-1);
307  } else {
308  // Get addresses as 16 bytes
309  uint8_t min_packed[V6ADDRESS_LEN];
310  memcpy(min_packed, &min.toBytes()[0], 16);
311  uint8_t max_packed[V6ADDRESS_LEN];
312  memcpy(max_packed, &max.toBytes()[0], 16);
313 
314  // Scan the exclusive or of addresses to find a difference
315  int candidate = 128;
316  bool zeroes = true;
317  for (uint8_t i = 0; i < 16; ++i) {
318  uint8_t xor_byte = min_packed[i] ^ max_packed[i];
319  if (zeroes) {
320  // Skipping zero bits searching for one bits
321  if (xor_byte == 0) {
322  continue;
323  }
324  // Found a one bit: note the fact
325  zeroes = false;
326  // Compare the exclusive or to masks
327  for (uint8_t j = 0; j < 8; ++j) {
328  if (xor_byte == revMask6[j]) {
329  // Got it the prefix length: note it
330  candidate = static_cast<int>((i * 8) + j);
331  }
332  }
333  if (candidate == 128) {
334  // Not found? The range is not from a prefix / prefix_len
335  return (-1);
336  }
337  } else {
338  // Checking that trailing bits are on bits
339  if (xor_byte == 0xff) {
340  continue;
341  }
342  // Not all ones is bad
343  return (-1);
344  }
345  }
346  return (candidate);
347  }
348 }
349 
350 uint64_t prefixesInRange(const uint8_t pool_len, const uint8_t delegated_len) {
351  if (delegated_len < pool_len) {
352  return (0);
353  }
354 
355  uint64_t count = delegated_len - pool_len;
356 
357  if (count == 0) {
358  // If we want to delegate /64 out of /64 pool, we have only
359  // one prefix.
360  return (1);
361  } else if (count >= 64) {
362  // If the difference is greater than or equal 64, e.g. we want to
363  // delegate /96 out of /16 pool, the number is bigger than we can
364  // express, so we'll stick with maximum value of uint64_t.
365  return (std::numeric_limits<uint64_t>::max());
366  } else {
367  // Now count specifies the exponent (e.g. if the difference between the
368  // delegated and pool length is 4, we have 16 prefixes), so we need
369  // to calculate 2^(count - 1)
370  return ((static_cast<uint64_t>(2)) << (count - 1));
371  }
372 }
373 
374 };
375 };
isc::dhcp::addrsInRange
uint64_t addrsInRange(const isc::asiolink::IOAddress &min, const isc::asiolink::IOAddress &max)
Returns number of available addresses in the specified range (min - max).
Definition: addr_utilities.cc:209
isc::dhcp::prefixLengthFromRange
int prefixLengthFromRange(const isc::asiolink::IOAddress &min, const isc::asiolink::IOAddress &max)
Returns prefix length from the specified range (min - max).
Definition: addr_utilities.cc:280
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
isc::dhcp::firstAddrInPrefix
isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress &prefix, uint8_t len)
This code is based on similar code from the Dibbler project.
Definition: addr_utilities.cc:176
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition: exceptions/exceptions.h:132
isc::dhcp::prefixesInRange
uint64_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:350
addr_utilities.h
exceptions.h
isc::dhcp::lastAddrInPrefix
isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress &prefix, uint8_t len)
returns a last address in a given prefix
Definition: addr_utilities.cc:187
isc::dhcp::getNetmask4
isc::asiolink::IOAddress getNetmask4(uint8_t len)
Generates an IPv4 netmask of specified length.
Definition: addr_utilities.cc:198