]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/iputils.hh
rec: allow exception to proxy protocal usage for specific listen addresses
[thirdparty/pdns.git] / pdns / iputils.hh
CommitLineData
12c86877 1/*
12471842
PL
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
e8c59f2d 22#pragma once
12c86877 23#include <string>
092f210a
BH
24#include <sys/socket.h>
25#include <netinet/in.h>
26#include <arpa/inet.h>
12c86877
BH
27#include <iostream>
28#include <stdio.h>
29#include <functional>
44845aab 30#include <bitset>
5c409fa2 31#include "pdnsexception.hh"
809fe23f 32#include "misc.hh"
506a9050 33#include <netdb.h>
335da0ba 34#include <sstream>
fd4ed0ab 35
10f4eea8 36#include "namespaces.hh"
12c86877 37
323c477a
PD
38#ifdef __APPLE__
39#include <libkern/OSByteOrder.h>
40
41#define htobe16(x) OSSwapHostToBigInt16(x)
42#define htole16(x) OSSwapHostToLittleInt16(x)
43#define be16toh(x) OSSwapBigToHostInt16(x)
44#define le16toh(x) OSSwapLittleToHostInt16(x)
45
46#define htobe32(x) OSSwapHostToBigInt32(x)
47#define htole32(x) OSSwapHostToLittleInt32(x)
48#define be32toh(x) OSSwapBigToHostInt32(x)
49#define le32toh(x) OSSwapLittleToHostInt32(x)
50
51#define htobe64(x) OSSwapHostToBigInt64(x)
52#define htole64(x) OSSwapHostToLittleInt64(x)
53#define be64toh(x) OSSwapBigToHostInt64(x)
54#define le64toh(x) OSSwapLittleToHostInt64(x)
55#endif
56
28fe507d 57#ifdef __sun
b0228347
AT
58
59#define htobe16(x) BE_16(x)
60#define htole16(x) LE_16(x)
28fe507d
RD
61#define be16toh(x) BE_IN16(&(x))
62#define le16toh(x) LE_IN16(&(x))
b0228347
AT
63
64#define htobe32(x) BE_32(x)
65#define htole32(x) LE_32(x)
28fe507d
RD
66#define be32toh(x) BE_IN32(&(x))
67#define le32toh(x) LE_IN32(&(x))
b0228347
AT
68
69#define htobe64(x) BE_64(x)
70#define htole64(x) LE_64(x)
28fe507d
RD
71#define be64toh(x) BE_IN64(&(x))
72#define le64toh(x) LE_IN64(&(x))
b0228347
AT
73
74#endif
75
e95bd1ae
RK
76#ifdef __FreeBSD__
77#include <sys/endian.h>
78#endif
79
4d39d7f3
TIH
80#if defined(__NetBSD__) && defined(IP_PKTINFO) && !defined(IP_SENDSRCADDR)
81// The IP_PKTINFO option in NetBSD was incompatible with Linux until a
82// change that also introduced IP_SENDSRCADDR for FreeBSD compatibility.
83#undef IP_PKTINFO
84#endif
85
37d3f960
BH
86union ComboAddress {
87 struct sockaddr_in sin4;
88 struct sockaddr_in6 sin6;
89
fd4ed0ab
BH
90 bool operator==(const ComboAddress& rhs) const
91 {
905dae56 92 if(std::tie(sin4.sin_family, sin4.sin_port) != std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
fd4ed0ab
BH
93 return false;
94 if(sin4.sin_family == AF_INET)
95 return sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr;
96 else
a683e8bd 97 return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr))==0;
fd4ed0ab
BH
98 }
99
bb6f86bd
PL
100 bool operator!=(const ComboAddress& rhs) const
101 {
102 return(!operator==(rhs));
103 }
104
37d3f960
BH
105 bool operator<(const ComboAddress& rhs) const
106 {
f563fff4 107 if(sin4.sin_family == 0) {
108 return false;
389fa92e 109 }
905dae56 110 if(std::tie(sin4.sin_family, sin4.sin_port) < std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
37d3f960 111 return true;
905dae56 112 if(std::tie(sin4.sin_family, sin4.sin_port) > std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
37d3f960 113 return false;
389fa92e 114
37d3f960
BH
115 if(sin4.sin_family == AF_INET)
116 return sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr;
117 else
a683e8bd 118 return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr)) < 0;
37d3f960
BH
119 }
120
fd4ed0ab
BH
121 bool operator>(const ComboAddress& rhs) const
122 {
5f15ee47 123 return rhs.operator<(*this);
fd4ed0ab
BH
124 }
125
a61dd3f3
Y
126 struct addressPortOnlyHash
127 {
128 uint32_t operator()(const ComboAddress& ca) const
129 {
130 const unsigned char* start = nullptr;
131 if (ca.sin4.sin_family == AF_INET) {
132 start = reinterpret_cast<const unsigned char*>(&ca.sin4.sin_addr.s_addr);
133 auto tmp = burtle(start, 4, 0);
134 return burtle(reinterpret_cast<const uint8_t*>(&ca.sin4.sin_port), 2, tmp);
135 }
136 {
137 start = reinterpret_cast<const unsigned char*>(&ca.sin6.sin6_addr.s6_addr);
138 auto tmp = burtle(start, 16, 0);
139 return burtle(reinterpret_cast<const unsigned char*>(&ca.sin6.sin6_port), 2, tmp);
140 }
141 }
142 };
143
545725f2 144 struct addressOnlyHash
145 {
389fa92e
SB
146 uint32_t operator()(const ComboAddress& ca) const
147 {
c173228a
RG
148 const unsigned char* start = nullptr;
149 uint32_t len = 0;
150 if (ca.sin4.sin_family == AF_INET) {
151 start = reinterpret_cast<const unsigned char*>(&ca.sin4.sin_addr.s_addr);
152 len = 4;
545725f2 153 }
154 else {
c173228a
RG
155 start = reinterpret_cast<const unsigned char*>(&ca.sin6.sin6_addr.s6_addr);
156 len = 16;
545725f2 157 }
158 return burtle(start, len, 0);
159 }
160 };
161
7587bcbe 162 struct addressOnlyLessThan
11a7242f
BH
163 {
164 bool operator()(const ComboAddress& a, const ComboAddress& b) const
165 {
166 if(a.sin4.sin_family < b.sin4.sin_family)
4957a608 167 return true;
11a7242f 168 if(a.sin4.sin_family > b.sin4.sin_family)
4957a608 169 return false;
11a7242f 170 if(a.sin4.sin_family == AF_INET)
4957a608 171 return a.sin4.sin_addr.s_addr < b.sin4.sin_addr.s_addr;
11a7242f 172 else
a683e8bd 173 return memcmp(&a.sin6.sin6_addr.s6_addr, &b.sin6.sin6_addr.s6_addr, sizeof(a.sin6.sin6_addr.s6_addr)) < 0;
11a7242f
BH
174 }
175 };
fd4ed0ab 176
7587bcbe 177 struct addressOnlyEqual
0940e4eb 178 {
179 bool operator()(const ComboAddress& a, const ComboAddress& b) const
180 {
181 if(a.sin4.sin_family != b.sin4.sin_family)
182 return false;
183 if(a.sin4.sin_family == AF_INET)
184 return a.sin4.sin_addr.s_addr == b.sin4.sin_addr.s_addr;
185 else
a683e8bd 186 return !memcmp(&a.sin6.sin6_addr.s6_addr, &b.sin6.sin6_addr.s6_addr, sizeof(a.sin6.sin6_addr.s6_addr));
0940e4eb 187 }
188 };
189
190
fd4ed0ab 191 socklen_t getSocklen() const
a9af3782
BH
192 {
193 if(sin4.sin_family == AF_INET)
194 return sizeof(sin4);
195 else
196 return sizeof(sin6);
197 }
389fa92e
SB
198
199 ComboAddress()
fd4ed0ab
BH
200 {
201 sin4.sin_family=AF_INET;
202 sin4.sin_addr.s_addr=0;
203 sin4.sin_port=0;
5cc8371b
RG
204 sin6.sin6_scope_id = 0;
205 sin6.sin6_flowinfo = 0;
fd4ed0ab
BH
206 }
207
a7360cd9
AT
208 ComboAddress(const struct sockaddr *sa, socklen_t salen) {
209 setSockaddr(sa, salen);
210 };
211
212 ComboAddress(const struct sockaddr_in6 *sa) {
213 setSockaddr((const struct sockaddr*)sa, sizeof(struct sockaddr_in6));
214 };
215
216 ComboAddress(const struct sockaddr_in *sa) {
217 setSockaddr((const struct sockaddr*)sa, sizeof(struct sockaddr_in));
218 };
219
220 void setSockaddr(const struct sockaddr *sa, socklen_t salen) {
221 if (salen > sizeof(struct sockaddr_in6)) throw PDNSException("ComboAddress can't handle other than sockaddr_in or sockaddr_in6");
222 memcpy(this, sa, salen);
223 }
224
85db02c5 225 // 'port' sets a default value in case 'str' does not set a port
fd4ed0ab
BH
226 explicit ComboAddress(const string& str, uint16_t port=0)
227 {
228 memset(&sin6, 0, sizeof(sin6));
229 sin4.sin_family = AF_INET;
85db02c5
BH
230 sin4.sin_port = 0;
231 if(makeIPv4sockaddr(str, &sin4)) {
fd4ed0ab 232 sin6.sin6_family = AF_INET6;
c0f8e484 233 if(makeIPv6sockaddr(str, &sin6) < 0) {
389fa92e 234 throw PDNSException("Unable to convert presentation address '"+ str +"'");
c0f8e484 235 }
389fa92e 236
fd4ed0ab 237 }
85db02c5
BH
238 if(!sin4.sin_port) // 'str' overrides port!
239 sin4.sin_port=htons(port);
fd4ed0ab 240 }
a9af3782 241
a94673ea
RG
242 bool isIPv6() const
243 {
244 return sin4.sin_family == AF_INET6;
245 }
246 bool isIPv4() const
247 {
248 return sin4.sin_family == AF_INET;
249 }
250
eb5bae86 251 bool isMappedIPv4() const
2914b022
BH
252 {
253 if(sin4.sin_family!=AF_INET6)
254 return false;
389fa92e 255
2914b022 256 int n=0;
f1b2ae9b 257 const unsigned char* ptr = reinterpret_cast<const unsigned char*>(&sin6.sin6_addr.s6_addr);
2914b022
BH
258 for(n=0; n < 10; ++n)
259 if(ptr[n])
4957a608 260 return false;
389fa92e 261
2914b022
BH
262 for(; n < 12; ++n)
263 if(ptr[n]!=0xff)
4957a608 264 return false;
389fa92e 265
2914b022
BH
266 return true;
267 }
389fa92e 268
eb5bae86 269 ComboAddress mapToIPv4() const
2914b022
BH
270 {
271 if(!isMappedIPv4())
3f81d239 272 throw PDNSException("ComboAddress can't map non-mapped IPv6 address back to IPv4");
2914b022
BH
273 ComboAddress ret;
274 ret.sin4.sin_family=AF_INET;
11a7242f 275 ret.sin4.sin_port=sin4.sin_port;
389fa92e 276
f1b2ae9b 277 const unsigned char* ptr = reinterpret_cast<const unsigned char*>(&sin6.sin6_addr.s6_addr);
a683e8bd
RG
278 ptr+=(sizeof(sin6.sin6_addr.s6_addr) - sizeof(ret.sin4.sin_addr.s_addr));
279 memcpy(&ret.sin4.sin_addr.s_addr, ptr, sizeof(ret.sin4.sin_addr.s_addr));
2914b022
BH
280 return ret;
281 }
282
37d3f960
BH
283 string toString() const
284 {
506a9050 285 char host[1024];
5cc8371b 286 int retval = 0;
f1b2ae9b 287 if(sin4.sin_family && !(retval = getnameinfo(reinterpret_cast<const struct sockaddr*>(this), getSocklen(), host, sizeof(host),0, 0, NI_NUMERICHOST)))
bfbf6814 288 return string(host);
c44d3917 289 else
f4352636 290 return "invalid "+string(gai_strerror(retval));
37d3f960 291 }
b8c3ea84 292
f5afee4d
CH
293 //! Ignores any interface specifiers possibly available in the sockaddr data.
294 string toStringNoInterface() const
295 {
296 char host[1024];
297 if(sin4.sin_family == AF_INET && (nullptr != inet_ntop(sin4.sin_family, &sin4.sin_addr, host, sizeof(host))))
298 return string(host);
299 else if(sin4.sin_family == AF_INET6 && (nullptr != inet_ntop(sin4.sin_family, &sin6.sin6_addr, host, sizeof(host))))
300 return string(host);
301 else
302 return "invalid "+stringerror();
303 }
304
b56aad58
FM
305 [[nodiscard]] string toStringReversed() const
306 {
307 if (isIPv4()) {
308 const auto ip = ntohl(sin4.sin_addr.s_addr);
309 auto a = (ip >> 0) & 0xFF;
310 auto b = (ip >> 8) & 0xFF;
311 auto c = (ip >> 16) & 0xFF;
312 auto d = (ip >> 24) & 0xFF;
313 return std::to_string(a) + "." + std::to_string(b) + "." + std::to_string(c) + "." + std::to_string(d);
314 }
315 else {
316 const auto* addr = &sin6.sin6_addr;
317 std::stringstream res{};
318 res << std::hex;
319 for (int i = 15; i >= 0; i--) {
320 auto byte = addr->s6_addr[i];
321 res << ((byte >> 0) & 0xF) << ".";
322 res << ((byte >> 4) & 0xF);
323 if (i != 0) {
324 res << ".";
325 }
326 }
327 return res.str();
328 }
329 }
330
b8c3ea84
BH
331 string toStringWithPort() const
332 {
333 if(sin4.sin_family==AF_INET)
335da0ba 334 return toString() + ":" + std::to_string(ntohs(sin4.sin_port));
b8c3ea84 335 else
335da0ba 336 return "["+toString() + "]:" + std::to_string(ntohs(sin4.sin_port));
b8c3ea84 337 }
22779196 338
d622042f 339 string toStringWithPortExcept(int port) const
340 {
341 if(ntohs(sin4.sin_port) == port)
342 return toString();
343 if(sin4.sin_family==AF_INET)
344 return toString() + ":" + std::to_string(ntohs(sin4.sin_port));
345 else
346 return "["+toString() + "]:" + std::to_string(ntohs(sin4.sin_port));
347 }
348
9b0f144f
KM
349 string toLogString() const
350 {
351 return toStringWithPortExcept(53);
352 }
353
a632f29b
OM
354 [[nodiscard]] string toStructuredLogString() const
355 {
356 return toStringWithPort();
357 }
358
4ef05f92
PL
359 string toByteString() const
360 {
361 if (isIPv4()) {
362 return string(reinterpret_cast<const char*>(&sin4.sin_addr.s_addr), sizeof(sin4.sin_addr.s_addr));
363 }
364 return string(reinterpret_cast<const char*>(&sin6.sin6_addr.s6_addr), sizeof(sin6.sin6_addr.s6_addr));
365 }
366
5b6099b2 367 void truncate(unsigned int bits) noexcept;
0affb140 368
a61dd3f3 369 uint16_t getNetworkOrderPort() const noexcept
0affb140 370 {
a61dd3f3
Y
371 return sin4.sin_port;
372 }
373 uint16_t getPort() const noexcept
374 {
375 return ntohs(getNetworkOrderPort());
0affb140 376 }
79816288 377 void setPort(uint16_t port)
f43e6a40 378 {
79816288 379 sin4.sin_port = htons(port);
f43e6a40
KM
380 }
381
d38e2ba9
RG
382 void reset()
383 {
384 memset(&sin4, 0, sizeof(sin4));
385 memset(&sin6, 0, sizeof(sin6));
386 }
387
20c33d95
SB
388 //! Get the total number of address bits (either 32 or 128 depending on IP version)
389 uint8_t getBits() const
390 {
391 if (isIPv4())
392 return 32;
393 if (isIPv6())
394 return 128;
395 return 0;
396 }
cdd23120
SB
397 /** Get the value of the bit at the provided bit index. When the index >= 0,
398 the index is relative to the LSB starting at index zero. When the index < 0,
399 the index is relative to the MSB starting at index -1 and counting down.
400 */
401 bool getBit(int index) const
402 {
403 if(isIPv4()) {
404 if (index >= 32)
405 return false;
406 if (index < 0) {
407 if (index < -32)
408 return false;
409 index = 32 + index;
410 }
411
a3739f30 412 uint32_t ls_addr = ntohl(sin4.sin_addr.s_addr);
cdd23120 413
753240f1 414 return ((ls_addr & (1U<<index)) != 0x00000000);
cdd23120
SB
415 }
416 if(isIPv6()) {
417 if (index >= 128)
418 return false;
419 if (index < 0) {
420 if (index < -128)
421 return false;
422 index = 128 + index;
423 }
424
f1b2ae9b 425 const uint8_t* ls_addr = reinterpret_cast<const uint8_t*>(sin6.sin6_addr.s6_addr);
cdd23120
SB
426 uint8_t byte_idx = index / 8;
427 uint8_t bit_idx = index % 8;
428
753240f1 429 return ((ls_addr[15-byte_idx] & (1U << bit_idx)) != 0x00);
cdd23120
SB
430 }
431 return false;
432 }
27a82613
PL
433
434 /*! Returns a comma-separated string of IP addresses
435 *
436 * \param c An stl container with ComboAddresses
437 * \param withPort Also print the port (default true)
438 * \param portExcept Print the port, except when this is the port (default 53)
439 */
440 template < template < class ... > class Container, class ... Args >
441 static string caContainerToString(const Container<ComboAddress, Args...>& c, const bool withPort = true, const uint16_t portExcept = 53) {
442 vector<string> strs;
443 for (const auto& ca : c) {
444 if (withPort) {
445 strs.push_back(ca.toStringWithPortExcept(portExcept));
446 continue;
447 }
448 strs.push_back(ca.toString());
449 }
450 return boost::join(strs, ",");
451 };
37d3f960
BH
452};
453
12c86877 454/** This exception is thrown by the Netmask class and by extension by the NetmaskGroup class */
389fa92e 455class NetmaskException: public PDNSException
12c86877
BH
456{
457public:
3f81d239 458 NetmaskException(const string &a) : PDNSException(a) {}
12c86877
BH
459};
460
37d3f960
BH
461inline ComboAddress makeComboAddress(const string& str)
462{
463 ComboAddress address;
464 address.sin4.sin_family=AF_INET;
1e77c17c 465 if(inet_pton(AF_INET, str.c_str(), &address.sin4.sin_addr) <= 0) {
37d3f960 466 address.sin4.sin_family=AF_INET6;
f71bc087 467 if(makeIPv6sockaddr(str, &address.sin6) < 0)
389fa92e 468 throw NetmaskException("Unable to convert '"+str+"' to a netmask");
37d3f960
BH
469 }
470 return address;
471}
472
5cc8371b 473inline ComboAddress makeComboAddressFromRaw(uint8_t version, const char* raw, size_t len)
f4352636
PD
474{
475 ComboAddress address;
f4352636 476
45fab880 477 if (version == 4) {
5cc8371b
RG
478 address.sin4.sin_family = AF_INET;
479 if (len != sizeof(address.sin4.sin_addr)) throw NetmaskException("invalid raw address length");
480 memcpy(&address.sin4.sin_addr, raw, sizeof(address.sin4.sin_addr));
45fab880
PD
481 }
482 else if (version == 6) {
5cc8371b
RG
483 address.sin6.sin6_family = AF_INET6;
484 if (len != sizeof(address.sin6.sin6_addr)) throw NetmaskException("invalid raw address length");
485 memcpy(&address.sin6.sin6_addr, raw, sizeof(address.sin6.sin6_addr));
45fab880 486 }
f4352636 487 else throw NetmaskException("invalid address family");
f4352636
PD
488
489 return address;
490}
491
5cc8371b
RG
492inline ComboAddress makeComboAddressFromRaw(uint8_t version, const string &str)
493{
494 return makeComboAddressFromRaw(version, str.c_str(), str.size());
495}
496
12c86877
BH
497/** This class represents a netmask and can be queried to see if a certain
498 IP address is matched by this mask */
12c86877
BH
499class Netmask
500{
501public:
6f97329b
BH
502 Netmask()
503 {
7c408ab4 504 d_network.sin4.sin_family = 0; // disable this doing anything useful
389fa92e 505 d_network.sin4.sin_port = 0; // this guarantees d_network compares identical
7c408ab4
RG
506 d_mask = 0;
507 d_bits = 0;
6f97329b 508 }
389fa92e 509
5708a729 510 Netmask(const ComboAddress& network, uint8_t bits=0xff): d_network(network)
6f97329b 511 {
7c408ab4 512 d_network.sin4.sin_port = 0;
7d6458b7 513 setBits(bits);
7c408ab4 514 }
389fa92e 515
783b8632
Y
516 Netmask(const sockaddr_in* network, uint8_t bits = 0xff): d_network(network)
517 {
518 d_network.sin4.sin_port = 0;
7d6458b7 519 setBits(bits);
783b8632
Y
520 }
521 Netmask(const sockaddr_in6* network, uint8_t bits = 0xff): d_network(network)
522 {
523 d_network.sin4.sin_port = 0;
7d6458b7 524 setBits(bits);
783b8632 525 }
7c408ab4
RG
526 void setBits(uint8_t value)
527 {
7d6458b7 528 d_bits = d_network.isIPv4() ? std::min(value, static_cast<uint8_t>(32U)) : std::min(value, static_cast<uint8_t>(128U));
7c408ab4
RG
529
530 if (d_bits < 32) {
531 d_mask = ~(0xFFFFFFFF >> d_bits);
532 }
533 else {
534 // note that d_mask is unused for IPv6
535 d_mask = 0xFFFFFFFF;
536 }
537
538 if (isIPv4()) {
539 d_network.sin4.sin_addr.s_addr = htonl(ntohl(d_network.sin4.sin_addr.s_addr) & d_mask);
540 }
541 else if (isIPv6()) {
542 uint8_t bytes = d_bits/8;
543 uint8_t *us = (uint8_t*) &d_network.sin6.sin6_addr.s6_addr;
544 uint8_t bits = d_bits % 8;
545 uint8_t mask = (uint8_t) ~(0xFF>>bits);
546
547 if (bytes < sizeof(d_network.sin6.sin6_addr.s6_addr)) {
548 us[bytes] &= mask;
549 }
550
551 for(size_t idx = bytes + 1; idx < sizeof(d_network.sin6.sin6_addr.s6_addr); ++idx) {
552 us[idx] = 0;
553 }
554 }
6f97329b 555 }
389fa92e
SB
556
557 //! Constructor supplies the mask, which cannot be changed
558 Netmask(const string &mask)
12c86877 559 {
7c408ab4
RG
560 pair<string,string> split = splitField(mask,'/');
561 d_network = makeComboAddress(split.first);
389fa92e 562
7c408ab4 563 if (!split.second.empty()) {
a0383aad 564 setBits(pdns::checked_stoi<uint8_t>(split.second));
37d3f960 565 }
7c408ab4
RG
566 else if (d_network.sin4.sin_family == AF_INET) {
567 setBits(32);
37d3f960 568 }
5c1def57 569 else {
7c408ab4 570 setBits(128);
5c1def57 571 }
12c86877
BH
572 }
573
2914b022
BH
574 bool match(const ComboAddress& ip) const
575 {
576 return match(&ip);
577 }
578
12c86877 579 //! If this IP address in socket address matches
37d3f960 580 bool match(const ComboAddress *ip) const
12c86877 581 {
37d3f960
BH
582 if(d_network.sin4.sin_family != ip->sin4.sin_family) {
583 return false;
584 }
585 if(d_network.sin4.sin_family == AF_INET) {
586 return match4(htonl((unsigned int)ip->sin4.sin_addr.s_addr));
587 }
588 if(d_network.sin6.sin6_family == AF_INET6) {
589 uint8_t bytes=d_bits/8, n;
590 const uint8_t *us=(const uint8_t*) &d_network.sin6.sin6_addr.s6_addr;
591 const uint8_t *them=(const uint8_t*) &ip->sin6.sin6_addr.s6_addr;
389fa92e 592
37d3f960 593 for(n=0; n < bytes; ++n) {
4957a608
BH
594 if(us[n]!=them[n]) {
595 return false;
596 }
37d3f960
BH
597 }
598 // still here, now match remaining bits
f0739fb6 599 uint8_t bits= d_bits % 8;
a683e8bd 600 uint8_t mask= (uint8_t) ~(0xFF>>bits);
f0739fb6 601
7c408ab4 602 return((us[n]) == (them[n] & mask));
37d3f960
BH
603 }
604 return false;
12c86877
BH
605 }
606
607 //! If this ASCII IP address matches
608 bool match(const string &ip) const
609 {
37d3f960
BH
610 ComboAddress address=makeComboAddress(ip);
611 return match(&address);
12c86877
BH
612 }
613
614 //! If this IP address in native format matches
37d3f960 615 bool match4(uint32_t ip) const
12c86877 616 {
7c408ab4 617 return (ip & d_mask) == (ntohl(d_network.sin4.sin_addr.s_addr));
12c86877
BH
618 }
619
2c95fc65
BH
620 string toString() const
621 {
f5afee4d 622 return d_network.toStringNoInterface()+"/"+std::to_string((unsigned int)d_bits);
2c95fc65
BH
623 }
624
a4c8835f
BH
625 string toStringNoMask() const
626 {
f5afee4d 627 return d_network.toStringNoInterface();
a4c8835f 628 }
7c408ab4 629
9f84a557 630 const ComboAddress& getNetwork() const
a4c8835f
BH
631 {
632 return d_network;
633 }
e1c8a4bb 634
7c408ab4
RG
635 const ComboAddress& getMaskedNetwork() const
636 {
637 return getNetwork();
e1c8a4bb 638 }
7c408ab4 639
8a3a3822 640 uint8_t getBits() const
a4c8835f
BH
641 {
642 return d_bits;
643 }
7c408ab4 644
37e35fbc 645 bool isIPv6() const
709ca59f
AT
646 {
647 return d_network.sin6.sin6_family == AF_INET6;
648 }
7c408ab4 649
d14121a8 650 bool isIPv4() const
709ca59f
AT
651 {
652 return d_network.sin4.sin_family == AF_INET;
653 }
644dd1da 654
389fa92e 655 bool operator<(const Netmask& rhs) const
644dd1da 656 {
a009559d
RG
657 if (empty() && !rhs.empty())
658 return false;
659
660 if (!empty() && rhs.empty())
661 return true;
662
663 if (d_bits > rhs.d_bits)
664 return true;
665 if (d_bits < rhs.d_bits)
666 return false;
667
668 return d_network < rhs.d_network;
669 }
670
671 bool operator>(const Netmask& rhs) const
672 {
673 return rhs.operator<(*this);
644dd1da 674 }
39ec5d29 675
389fa92e 676 bool operator==(const Netmask& rhs) const
39ec5d29 677 {
905dae56 678 return std::tie(d_network, d_bits) == std::tie(rhs.d_network, rhs.d_bits);
39ec5d29 679 }
680
389fa92e 681 bool empty() const
87e665b1 682 {
683 return d_network.sin4.sin_family==0;
684 }
685
e9a5bdb1
SB
686 //! Get normalized version of the netmask. This means that all address bits below the network bits are zero.
687 Netmask getNormalized() const {
688 return Netmask(getMaskedNetwork(), d_bits);
689 }
664140b5
SB
690 //! Get Netmask for super network of this one (i.e. with fewer network bits)
691 Netmask getSuper(uint8_t bits) const {
692 return Netmask(d_network, std::min(d_bits, bits));
693 }
5d7557e3
SB
694
695 //! Get the total number of address bits for this netmask (either 32 or 128 depending on IP version)
6d4de128
RG
696 uint8_t getFullBits() const
697 {
c173228a 698 return d_network.getBits();
6d4de128
RG
699 }
700
8d8c1d77
SB
701 /** Get the value of the bit at the provided bit index. When the index >= 0,
702 the index is relative to the LSB starting at index zero. When the index < 0,
703 the index is relative to the MSB starting at index -1 and counting down.
704 When the index points outside the network bits, it always yields zero.
705 */
706 bool getBit(int bit) const
707 {
708 if (bit < -d_bits)
709 return false;
710 if (bit >= 0) {
711 if(isIPv4()) {
712 if (bit >= 32 || bit < (32 - d_bits))
713 return false;
714 }
715 if(isIPv6()) {
716 if (bit >= 128 || bit < (128 - d_bits))
717 return false;
718 }
719 }
720 return d_network.getBit(bit);
721 }
6d4de128 722
7da536df
OM
723 struct Hash {
724 size_t operator()(const Netmask& nm) const
725 {
726 return burtle(&nm.d_bits, 1, ComboAddress::addressOnlyHash()(nm.d_network));
727 }
728 };
729
12c86877 730private:
37d3f960 731 ComboAddress d_network;
092f210a 732 uint32_t d_mask;
37d3f960 733 uint8_t d_bits;
12c86877
BH
734};
735
7da536df
OM
736namespace std {
737 template<>
738 struct hash<Netmask> {
739 auto operator()(const Netmask& nm) const {
740 return Netmask::Hash{}(nm);
741 }
742 };
743}
744
4bb19027 745/** Binary tree map implementation with <Netmask,T> pair.
44845aab
AT
746 *
747 * This is an binary tree implementation for storing attributes for IPv4 and IPv6 prefixes.
748 * The most simple use case is simple NetmaskTree<bool> used by NetmaskGroup, which only
749 * wants to know if given IP address is matched in the prefixes stored.
750 *
751 * This element is useful for anything that needs to *STORE* prefixes, and *MATCH* IP addresses
752 * to a *LIST* of *PREFIXES*. Not the other way round.
753 *
754 * You can store IPv4 and IPv6 addresses to same tree, separate payload storage is kept per AFI.
80462253
SB
755 * Network prefixes (Netmasks) are always recorded in normalized fashion, meaning that only
756 * the network bits are set. This is what is returned in the insert() and lookup() return
757 * values.
44845aab 758 *
44845aab 759 * Use swap if you need to move the tree to another NetmaskTree instance, it is WAY faster
ba07e97e 760 * than using copy ctor or assignment operator, since it moves the nodes and tree root to
44845aab
AT
761 * new home instead of actually recreating the tree.
762 *
763 * Please see NetmaskGroup for example of simple use case. Other usecases can be found
764 * from GeoIPBackend and Sortlist, and from dnsdist.
765 */
6d4de128 766template <typename T, class K = Netmask>
44845aab
AT
767class NetmaskTree {
768public:
de1cde57
SB
769 class Iterator;
770
6d4de128 771 typedef K key_type;
44845aab 772 typedef T value_type;
0c4df7c3 773 typedef std::pair<const key_type,value_type> node_type;
44845aab 774 typedef size_t size_type;
de1cde57 775 typedef class Iterator iterator;
44845aab
AT
776
777private:
778 /** Single node in tree, internal use only.
779 */
780 class TreeNode : boost::noncopyable {
781 public:
4bb19027 782 explicit TreeNode() noexcept :
cba13f93 783 parent(nullptr), node(), assigned(false), d_bits(0) {
4bb19027 784 }
2d1e11bf 785 explicit TreeNode(const key_type& key) :
cba13f93 786 parent(nullptr), node({key.getNormalized(), value_type()}),
6d4de128 787 assigned(false), d_bits(key.getFullBits()) {
389fa92e
SB
788 }
789
4bb19027
SB
790 //<! Makes a left leaf node with specified key.
791 TreeNode* make_left(const key_type& key) {
cba13f93 792 d_bits = node.first.getBits();
4bb19027
SB
793 left = make_unique<TreeNode>(key);
794 left->parent = this;
389fa92e
SB
795 return left.get();
796 }
797
4bb19027
SB
798 //<! Makes a right leaf node with specified key.
799 TreeNode* make_right(const key_type& key) {
cba13f93 800 d_bits = node.first.getBits();
4bb19027
SB
801 right = make_unique<TreeNode>(key);
802 right->parent = this;
389fa92e
SB
803 return right.get();
804 }
805
4bb19027
SB
806 //<! Splits branch at indicated bit position by inserting key
807 TreeNode* split(const key_type& key, int bits) {
808 if (parent == nullptr) {
809 // not to be called on the root node
810 throw std::logic_error(
811 "NetmaskTree::TreeNode::split(): must not be called on root node");
812 }
813
814 // determine reference from parent
815 unique_ptr<TreeNode>& parent_ref =
816 (parent->left.get() == this ? parent->left : parent->right);
817 if (parent_ref.get() != this) {
818 throw std::logic_error(
819 "NetmaskTree::TreeNode::split(): parent node reference is invalid");
820 }
821
822 // create new tree node for the new key
823 TreeNode* new_node = new TreeNode(key);
824 new_node->d_bits = bits;
825
826 // attach the new node under our former parent
827 unique_ptr<TreeNode> new_child(new_node);
828 std::swap(parent_ref, new_child); // hereafter new_child points to "this"
829 new_node->parent = parent;
830
831 // attach "this" node below the new node
832 // (left or right depending on bit)
833 new_child->parent = new_node;
cba13f93 834 if (new_child->node.first.getBit(-1-bits)) {
4bb19027
SB
835 std::swap(new_node->right, new_child);
836 } else {
837 std::swap(new_node->left, new_child);
838 }
839
840 return new_node;
841 }
842
843 //<! Forks branch for new key at indicated bit position
844 TreeNode* fork(const key_type& key, int bits) {
845 if (parent == nullptr) {
846 // not to be called on the root node
847 throw std::logic_error(
848 "NetmaskTree::TreeNode::fork(): must not be called on root node");
849 }
850
851 // determine reference from parent
852 unique_ptr<TreeNode>& parent_ref =
853 (parent->left.get() == this ? parent->left : parent->right);
854 if (parent_ref.get() != this) {
855 throw std::logic_error(
856 "NetmaskTree::TreeNode::fork(): parent node reference is invalid");
857 }
858
859 // create new tree node for the branch point
cba13f93 860 TreeNode* branch_node = new TreeNode(node.first.getSuper(bits));
4bb19027
SB
861 branch_node->d_bits = bits;
862
7846373d
RG
863 // the current node will now be a child of the new branch node
864 // (hereafter new_child1 points to "this")
865 unique_ptr<TreeNode> new_child1 = std::move(parent_ref);
4bb19027 866 // attach the branch node under our former parent
7846373d 867 parent_ref = std::unique_ptr<TreeNode>(branch_node);
4bb19027
SB
868 branch_node->parent = parent;
869
870 // create second new leaf node for the new key
753240f1
RG
871 unique_ptr<TreeNode> new_child2 = make_unique<TreeNode>(key);
872 TreeNode* new_node = new_child2.get();
4bb19027
SB
873
874 // attach the new child nodes below the branch node
875 // (left or right depending on bit)
876 new_child1->parent = branch_node;
877 new_child2->parent = branch_node;
cba13f93 878 if (new_child1->node.first.getBit(-1-bits)) {
7846373d
RG
879 branch_node->right = std::move(new_child1);
880 branch_node->left = std::move(new_child2);
4bb19027 881 } else {
7846373d
RG
882 branch_node->right = std::move(new_child2);
883 branch_node->left = std::move(new_child1);
4bb19027 884 }
7846373d
RG
885 // now we have attached the new unique pointers to the tree:
886 // - branch_node is below its parent
887 // - new_child1 (ourselves) is below branch_node
888 // - new_child2, the new leaf node, is below branch_node as well
4bb19027
SB
889
890 return new_node;
891 }
892
fddcd1cc
SB
893 //<! Traverse left branch depth-first
894 TreeNode *traverse_l()
895 {
896 TreeNode *tnode = this;
897
898 while (tnode->left)
899 tnode = tnode->left.get();
900 return tnode;
901 }
902
903 //<! Traverse tree depth-first and in-order (L-N-R)
904 TreeNode *traverse_lnr()
905 {
906 TreeNode *tnode = this;
907
908 // precondition: descended left as deep as possible
909 if (tnode->right) {
910 // descend right
911 tnode = tnode->right.get();
912 // descend left as deep as possible and return next node
913 return tnode->traverse_l();
914 }
915
916 // ascend to parent
917 while (tnode->parent != nullptr) {
918 TreeNode *prev_child = tnode;
919 tnode = tnode->parent;
920
921 // return this node, but only when we come from the left child branch
922 if (tnode->left && tnode->left.get() == prev_child)
923 return tnode;
924 }
925 return nullptr;
926 }
927
928 //<! Traverse only assigned nodes
929 TreeNode *traverse_lnr_assigned()
930 {
931 TreeNode *tnode = traverse_lnr();
932
933 while (tnode != nullptr && !tnode->assigned)
934 tnode = tnode->traverse_lnr();
935 return tnode;
936 }
937
389fa92e
SB
938 unique_ptr<TreeNode> left;
939 unique_ptr<TreeNode> right;
940 TreeNode* parent;
941
cba13f93 942 node_type node;
956c6dc4 943 bool assigned; //<! Whether this node is assigned-to by the application
389fa92e
SB
944
945 int d_bits; //<! How many bits have been used so far
44845aab
AT
946 };
947
9b0ae5c8
SB
948 void cleanup_tree(TreeNode* node)
949 {
956c6dc4
SB
950 // only cleanup this node if it has no children and node not assigned
951 if (!(node->left || node->right || node->assigned)) {
9b0ae5c8
SB
952 // get parent node ptr
953 TreeNode* pparent = node->parent;
954 // delete this node
955 if (pparent) {
956 if (pparent->left.get() == node)
957 pparent->left.reset();
958 else
959 pparent->right.reset();
960 // now recurse up to the parent
961 cleanup_tree(pparent);
962 }
963 }
964 }
965
6d49c384 966 void copyTree(const NetmaskTree& rhs)
57e9d089
OM
967 {
968 try {
969 TreeNode *node = rhs.d_root.get();
970 if (node != nullptr)
971 node = node->traverse_l();
972 while (node != nullptr) {
973 if (node->assigned)
974 insert(node->node.first).second = node->node.second;
975 node = node->traverse_lnr();
976 }
977 }
6d49c384 978 catch (const NetmaskException&) {
57e9d089 979 abort();
1355a23f 980 }
a43e77a5
OM
981 catch (const std::logic_error&) {
982 abort();
983 }
1355a23f
SB
984 }
985
de1cde57
SB
986public:
987 class Iterator {
988 public:
7c888097
SB
989 typedef node_type value_type;
990 typedef node_type& reference;
991 typedef node_type* pointer;
de1cde57
SB
992 typedef std::forward_iterator_tag iterator_category;
993 typedef size_type difference_type;
994
995 private:
996 friend class NetmaskTree;
997
998 const NetmaskTree* d_tree;
999 TreeNode* d_node;
1000
1001 Iterator(const NetmaskTree* tree, TreeNode* node): d_tree(tree), d_node(node) {
1002 }
1003
1004 public:
1005 Iterator(): d_tree(nullptr), d_node(nullptr) {}
1006
1007 Iterator& operator++() // prefix
1008 {
1009 if (d_node == nullptr) {
1010 throw std::logic_error(
1011 "NetmaskTree::Iterator::operator++: iterator is invalid");
1012 }
1013 d_node = d_node->traverse_lnr_assigned();
1014 return *this;
1015 }
1016 Iterator operator++(int) // postfix
1017 {
1018 Iterator tmp(*this);
1019 operator++();
1020 return tmp;
1021 }
1022
1023 reference operator*()
1024 {
1025 if (d_node == nullptr) {
1026 throw std::logic_error(
1027 "NetmaskTree::Iterator::operator*: iterator is invalid");
1028 }
7c888097
SB
1029 return d_node->node;
1030 }
1031
1032 pointer operator->()
1033 {
1034 if (d_node == nullptr) {
1035 throw std::logic_error(
1036 "NetmaskTree::Iterator::operator->: iterator is invalid");
1037 }
cba13f93 1038 return &d_node->node;
de1cde57
SB
1039 }
1040
1041 bool operator==(const Iterator& rhs)
1042 {
1043 return (d_tree == rhs.d_tree && d_node == rhs.d_node);
1044 }
1045 bool operator!=(const Iterator& rhs)
1046 {
1047 return !(*this == rhs);
1048 }
1049 };
1050
44845aab 1051public:
dccd4976 1052 NetmaskTree() noexcept: d_root(new TreeNode()), d_left(nullptr), d_size(0) {
44845aab
AT
1053 }
1054
6d49c384 1055 NetmaskTree(const NetmaskTree& rhs): d_root(new TreeNode()), d_left(nullptr), d_size(0) {
1355a23f 1056 copyTree(rhs);
44845aab
AT
1057 }
1058
6d49c384 1059 NetmaskTree& operator=(const NetmaskTree& rhs) {
44845aab 1060 clear();
1355a23f 1061 copyTree(rhs);
44845aab
AT
1062 return *this;
1063 }
1064
de1cde57
SB
1065 const iterator begin() const {
1066 return Iterator(this, d_left);
1067 }
1068 const iterator end() const {
1069 return Iterator(this, nullptr);
1070 }
1071 iterator begin() {
1072 return Iterator(this, d_left);
1073 }
1074 iterator end() {
1075 return Iterator(this, nullptr);
1076 }
44845aab
AT
1077
1078 node_type& insert(const string &mask) {
1079 return insert(key_type(mask));
1080 }
1081
1082 //<! Creates new value-pair in tree and returns it.
1083 node_type& insert(const key_type& key) {
956c6dc4 1084 TreeNode* node;
9edc8e2b 1085 bool is_left = true;
136b2c6b
SB
1086
1087 // we turn left on IPv4 and right on IPv6
1088 if (key.isIPv4()) {
136b2c6b 1089 node = d_root->left.get();
4bb19027
SB
1090 if (node == nullptr) {
1091 node = new TreeNode(key);
1092 node->assigned = true;
1093 node->parent = d_root.get();
1094
1095 d_root->left = unique_ptr<TreeNode>(node);
dccd4976 1096 d_size++;
9edc8e2b 1097 d_left = node;
cba13f93 1098 return node->node;
4bb19027 1099 }
136b2c6b 1100 } else if (key.isIPv6()) {
136b2c6b 1101 node = d_root->right.get();
4bb19027
SB
1102 if (node == nullptr) {
1103 node = new TreeNode(key);
1104 node->assigned = true;
1105 node->parent = d_root.get();
1106
1107 d_root->right = unique_ptr<TreeNode>(node);
dccd4976 1108 d_size++;
9edc8e2b
SB
1109 if (!d_root->left)
1110 d_left = node;
cba13f93 1111 return node->node;
4bb19027 1112 }
9edc8e2b
SB
1113 if (d_root->left)
1114 is_left = false;
136b2c6b
SB
1115 } else
1116 throw NetmaskException("invalid address family");
1117
136b2c6b 1118 // we turn left on 0 and right on 1
ebb7e215 1119 int bits = 0;
243134ef 1120 for(; bits < key.getBits(); bits++) {
4bb19027
SB
1121 bool vall = key.getBit(-1-bits);
1122
1123 if (bits >= node->d_bits) {
1124 // the end of the current node is reached; continue with the next
1125 if (vall) {
9edc8e2b
SB
1126 if (node->left || node->assigned)
1127 is_left = false;
4bb19027
SB
1128 if (!node->right) {
1129 // the right branch doesn't exist yet; attach our key here
1130 node = node->make_right(key);
1131 break;
1132 }
1133 node = node->right.get();
1134 } else {
1135 if (!node->left) {
1136 // the left branch doesn't exist yet; attach our key here
1137 node = node->make_left(key);
1138 break;
1139 }
1140 node = node->left.get();
1141 }
1142 continue;
1143 }
cba13f93 1144 if (bits >= node->node.first.getBits()) {
4bb19027
SB
1145 // the matching branch ends here, yet the key netmask has more bits; add a
1146 // child node below the existing branch leaf.
1147 if (vall) {
9edc8e2b
SB
1148 if (node->assigned)
1149 is_left = false;
4bb19027
SB
1150 node = node->make_right(key);
1151 } else {
1152 node = node->make_left(key);
1153 }
1154 break;
1155 }
cba13f93 1156 bool valr = node->node.first.getBit(-1-bits);
4bb19027 1157 if (vall != valr) {
9edc8e2b
SB
1158 if (vall)
1159 is_left = false;
4bb19027
SB
1160 // the branch matches just upto this point, yet continues in a different
1161 // direction; fork the branch.
1162 node = node->fork(key, bits);
1163 break;
1164 }
1165 }
1166
cba13f93 1167 if (node->node.first.getBits() > key.getBits()) {
4bb19027
SB
1168 // key is a super-network of the matching node; split the branch and
1169 // insert a node for the key above the matching node.
1170 node = node->split(key, key.getBits());
136b2c6b 1171 }
44845aab 1172
9edc8e2b
SB
1173 if (node->left)
1174 is_left = false;
1175
cba13f93 1176 node_type& value = node->node;
956c6dc4 1177
956c6dc4 1178 if (!node->assigned) {
dccd4976
SB
1179 // only increment size if not assigned before
1180 d_size++;
9edc8e2b
SB
1181 // update the pointer to the left-most tree node
1182 if (is_left)
1183 d_left = node;
956c6dc4 1184 node->assigned = true;
9edc8e2b
SB
1185 } else {
1186 // tree node exists for this value
1187 if (is_left && d_left != node) {
1188 throw std::logic_error(
1189 "NetmaskTree::insert(): lost track of left-most node in tree");
1190 }
44845aab 1191 }
136b2c6b 1192
cba13f93 1193 return value;
44845aab
AT
1194 }
1195
2dfbbc41 1196 //<! Creates or updates value
44845aab
AT
1197 void insert_or_assign(const key_type& mask, const value_type& value) {
1198 insert(mask).second = value;
1199 }
1200
e6419866
AT
1201 void insert_or_assign(const string& mask, const value_type& value) {
1202 insert(key_type(mask)).second = value;
44845aab
AT
1203 }
1204
41d0adb7
AT
1205 //<! check if given key is present in TreeMap
1206 bool has_key(const key_type& key) const {
1207 const node_type *ptr = lookup(key);
1208 return ptr && ptr->first == key;
1209 }
1210
2dfbbc41 1211 //<! Returns "best match" for key_type, which might not be value
87743a9a 1212 [[nodiscard]] node_type* lookup(const key_type& value) const {
c173228a 1213 uint8_t max_bits = value.getBits();
5d2c20f7 1214 return lookupImpl(value, max_bits);
44845aab
AT
1215 }
1216
2dfbbc41 1217 //<! Perform best match lookup for value, using at most max_bits
87743a9a 1218 [[nodiscard]] node_type* lookup(const ComboAddress& value, int max_bits = 128) const {
4bb19027 1219 uint8_t addr_bits = value.getBits();
5d2c20f7 1220 if (max_bits < 0 || max_bits > addr_bits) {
4bb19027 1221 max_bits = addr_bits;
44845aab
AT
1222 }
1223
5d2c20f7 1224 return lookupImpl(key_type(value, max_bits), max_bits);
44845aab
AT
1225 }
1226
3d22a7ff 1227 //<! Removes key from TreeMap.
44845aab 1228 void erase(const key_type& key) {
136b2c6b
SB
1229 TreeNode *node = nullptr;
1230
1231 if (key.isIPv4())
1232 node = d_root->left.get();
1233 else if (key.isIPv6())
1234 node = d_root->right.get();
7c408ab4 1235 else
136b2c6b 1236 throw NetmaskException("invalid address family");
44845aab 1237 // no tree, no value
136b2c6b
SB
1238 if (node == nullptr) return;
1239
1240 int bits = 0;
ebb7e215 1241 for(; node && bits < key.getBits(); bits++) {
4bb19027
SB
1242 bool vall = key.getBit(-1-bits);
1243 if (bits >= node->d_bits) {
1244 // the end of the current node is reached; continue with the next
1245 if (vall) {
1246 node = node->right.get();
1247 } else {
1248 node = node->left.get();
1249 }
1250 continue;
1251 }
cba13f93 1252 if (bits >= node->node.first.getBits()) {
4bb19027 1253 // the matching branch ends here
cba13f93 1254 if (key.getBits() != node->node.first.getBits())
4bb19027
SB
1255 node = nullptr;
1256 break;
1257 }
cba13f93 1258 bool valr = node->node.first.getBit(-1-bits);
4bb19027
SB
1259 if (vall != valr) {
1260 // the branch matches just upto this point, yet continues in a different
1261 // direction
1262 node = nullptr;
1263 break;
44845aab 1264 }
136b2c6b
SB
1265 }
1266 if (node) {
dccd4976
SB
1267 if (d_size == 0) {
1268 throw std::logic_error(
1269 "NetmaskTree::erase(): size of tree is zero before erase");
1270 }
1271 d_size--;
956c6dc4 1272 node->assigned = false;
cba13f93 1273 node->node.second = value_type();
9edc8e2b
SB
1274
1275 if (node == d_left)
1276 d_left = d_left->traverse_lnr_assigned();
1277
9772e56d 1278 cleanup_tree(node);
44845aab
AT
1279 }
1280 }
1281
1282 void erase(const string& key) {
1283 erase(key_type(key));
1284 }
1285
1286 //<! checks whether the container is empty.
7b2c4969 1287 [[nodiscard]] bool empty() const {
dccd4976 1288 return (d_size == 0);
44845aab
AT
1289 }
1290
1291 //<! returns the number of elements
1292 size_type size() const {
dccd4976 1293 return d_size;
44845aab
AT
1294 }
1295
1296 //<! See if given ComboAddress matches any prefix
1297 bool match(const ComboAddress& value) const {
1298 return (lookup(value) != nullptr);
1299 }
1300
1301 bool match(const std::string& value) const {
1302 return match(ComboAddress(value));
1303 }
1304
1305 //<! Clean out the tree
1306 void clear() {
4bb19027 1307 d_root.reset(new TreeNode());
9edc8e2b 1308 d_left = nullptr;
dccd4976 1309 d_size = 0;
44845aab
AT
1310 }
1311
3d22a7ff 1312 //<! swaps the contents with another NetmaskTree
71633799
RP
1313 void swap(NetmaskTree& rhs) noexcept
1314 {
e4b291fe 1315 std::swap(d_root, rhs.d_root);
9edc8e2b 1316 std::swap(d_left, rhs.d_left);
dccd4976 1317 std::swap(d_size, rhs.d_size);
44845aab
AT
1318 }
1319
1320private:
5d2c20f7 1321
87743a9a 1322 [[nodiscard]] node_type* lookupImpl(const key_type& value, uint8_t max_bits) const {
5d2c20f7
RG
1323 TreeNode *node = nullptr;
1324
1325 if (value.isIPv4())
1326 node = d_root->left.get();
1327 else if (value.isIPv6())
1328 node = d_root->right.get();
1329 else
1330 throw NetmaskException("invalid address family");
1331 if (node == nullptr) return nullptr;
1332
1333 node_type *ret = nullptr;
1334
1335 int bits = 0;
1336 for(; bits < max_bits; bits++) {
1337 bool vall = value.getBit(-1-bits);
1338 if (bits >= node->d_bits) {
1339 // the end of the current node is reached; continue with the next
1340 // (we keep track of last assigned node)
1341 if (node->assigned && bits == node->node.first.getBits())
1342 ret = &node->node;
1343 if (vall) {
1344 if (!node->right)
1345 break;
1346 node = node->right.get();
1347 } else {
1348 if (!node->left)
1349 break;
1350 node = node->left.get();
1351 }
1352 continue;
1353 }
1354 if (bits >= node->node.first.getBits()) {
1355 // the matching branch ends here
1356 break;
1357 }
1358 bool valr = node->node.first.getBit(-1-bits);
1359 if (vall != valr) {
1360 // the branch matches just upto this point, yet continues in a different
1361 // direction
1362 break;
1363 }
1364 }
1365 // needed if we did not find one in loop
1366 if (node->assigned && bits == node->node.first.getBits())
1367 ret = &node->node;
1368
1369 // this can be nullptr.
1370 return ret;
1371 }
1372
e4b291fe 1373 unique_ptr<TreeNode> d_root; //<! Root of our tree
9edc8e2b 1374 TreeNode *d_left;
dccd4976 1375 size_type d_size;
44845aab
AT
1376};
1377
152f3626 1378/** This class represents a group of supplemental Netmask classes. An IP address matches
9d5607b0 1379 if it is matched by one or more of the Netmask objects within.
12c86877
BH
1380*/
1381class NetmaskGroup
1382{
1383public:
abb11ca4 1384 NetmaskGroup() noexcept = default;
11f4719b 1385
12c86877 1386 //! If this IP address is matched by any of the classes within
60af67b8 1387
1e77c17c 1388 bool match(const ComboAddress *ip) const
12c86877 1389 {
ee15a1e1
PD
1390 const auto &ret = tree.lookup(*ip);
1391 if(ret) return ret->second;
1392 return false;
12c86877 1393 }
60af67b8 1394
1e77c17c 1395 bool match(const ComboAddress& ip) const
60af67b8 1396 {
1397 return match(&ip);
1398 }
1399
11f4719b
RG
1400 bool lookup(const ComboAddress* ip, Netmask* nmp) const
1401 {
1402 const auto &ret = tree.lookup(*ip);
1403 if (ret) {
1404 if (nmp != nullptr)
1405 *nmp = ret->first;
1406
1407 return ret->second;
1408 }
1409 return false;
1410 }
1411
1412 bool lookup(const ComboAddress& ip, Netmask* nmp) const
1413 {
1414 return lookup(&ip, nmp);
1415 }
1416
376effcf 1417 //! Add this string to the list of possible matches
ee15a1e1 1418 void addMask(const string &ip, bool positive=true)
12c86877 1419 {
ee15a1e1
PD
1420 if(!ip.empty() && ip[0] == '!') {
1421 addMask(Netmask(ip.substr(1)), false);
1422 } else {
1423 addMask(Netmask(ip), positive);
1424 }
12c86877 1425 }
68b011bd 1426
376effcf 1427 //! Add this Netmask to the list of possible matches
ee15a1e1 1428 void addMask(const Netmask& nm, bool positive=true)
376effcf 1429 {
ee15a1e1 1430 tree.insert(nm).second=positive;
376effcf 1431 }
1432
5a2f3287
RG
1433 void addMasks(const NetmaskGroup& group, boost::optional<bool> positive)
1434 {
1435 for (const auto& entry : group.tree) {
1436 addMask(entry.first, positive ? *positive : entry.second);
1437 }
1438 }
1439
11f4719b
RG
1440 //! Delete this Netmask from the list of possible matches
1441 void deleteMask(const Netmask& nm)
1442 {
1443 tree.erase(nm);
1444 }
1445
59a8b338
RG
1446 void deleteMasks(const NetmaskGroup& group)
1447 {
1448 for (const auto& entry : group.tree) {
1449 deleteMask(entry.first);
1450 }
1451 }
1452
11f4719b
RG
1453 void deleteMask(const std::string& ip)
1454 {
1455 if (!ip.empty())
1456 deleteMask(Netmask(ip));
1457 }
1458
68b011bd
KM
1459 void clear()
1460 {
5ac553e1 1461 tree.clear();
68b011bd
KM
1462 }
1463
5ac553e1 1464 bool empty() const
12c86877 1465 {
5ac553e1 1466 return tree.empty();
12c86877
BH
1467 }
1468
5ac553e1 1469 size_t size() const
2c95fc65 1470 {
5ac553e1 1471 return tree.size();
2c95fc65
BH
1472 }
1473
1474 string toString() const
1475 {
1476 ostringstream str;
5ac553e1
AT
1477 for(auto iter = tree.begin(); iter != tree.end(); ++iter) {
1478 if(iter != tree.begin())
4957a608 1479 str <<", ";
7c888097 1480 if(!(iter->second))
ee15a1e1 1481 str<<"!";
7c888097 1482 str<<iter->first.toString();
2c95fc65
BH
1483 }
1484 return str.str();
1485 }
1486
25b3e633 1487 std::vector<std::string> toStringVector() const
41942bb3 1488 {
25b3e633
RG
1489 std::vector<std::string> out;
1490 out.reserve(tree.size());
1491 for (const auto& entry : tree) {
1492 out.push_back((entry.second ? "" : "!") + entry.first.toString());
ee15a1e1 1493 }
25b3e633 1494 return out;
41942bb3
CH
1495 }
1496
68b011bd
KM
1497 void toMasks(const string &ips)
1498 {
1499 vector<string> parts;
1500 stringtok(parts, ips, ", \t");
1501
1502 for (vector<string>::const_iterator iter = parts.begin(); iter != parts.end(); ++iter)
1503 addMask(*iter);
1504 }
1505
12c86877 1506private:
5ac553e1 1507 NetmaskTree<bool> tree;
12c86877
BH
1508};
1509
60c8afa8 1510struct SComboAddress
1511{
1512 SComboAddress(const ComboAddress& orig) : ca(orig) {}
1513 ComboAddress ca;
1514 bool operator<(const SComboAddress& rhs) const
1515 {
1516 return ComboAddress::addressOnlyLessThan()(ca, rhs.ca);
1517 }
1518 operator const ComboAddress&()
1519 {
1520 return ca;
1521 }
1522};
1523
73ba5999
CHB
1524class NetworkError : public runtime_error
1525{
1526public:
1527 NetworkError(const string& why="Network Error") : runtime_error(why.c_str())
1528 {}
1529 NetworkError(const char *why="Network Error") : runtime_error(why)
1530 {}
1531};
60c8afa8 1532
c173228a
RG
1533class AddressAndPortRange
1534{
1535public:
1536 AddressAndPortRange(): d_addrMask(0), d_portMask(0)
1537 {
1538 d_addr.sin4.sin_family = 0; // disable this doing anything useful
1539 d_addr.sin4.sin_port = 0; // this guarantees d_network compares identical
1540 }
1541
224085cc
RP
1542 AddressAndPortRange(ComboAddress ca, uint8_t addrMask, uint8_t portMask = 0) :
1543 d_addr(ca), d_addrMask(addrMask), d_portMask(portMask)
c173228a
RG
1544 {
1545 if (!d_addr.isIPv4()) {
1546 d_portMask = 0;
1547 }
1548
1549 uint16_t port = d_addr.getPort();
1550 if (d_portMask < 16) {
1551 uint16_t mask = ~(0xFFFF >> d_portMask);
1552 port = port & mask;
1553 }
1554
1555 if (d_addrMask < d_addr.getBits()) {
1556 if (d_portMask > 0) {
1557 throw std::runtime_error("Trying to create a AddressAndPortRange with a reduced address mask (" + std::to_string(d_addrMask) + ") and a port range (" + std::to_string(d_portMask) + ")");
1558 }
1559 d_addr = Netmask(d_addr, d_addrMask).getMaskedNetwork();
1560 }
1561 d_addr.setPort(port);
1562 }
1563
1564 uint8_t getFullBits() const
1565 {
1566 return d_addr.getBits() + 16;
1567 }
1568
1569 uint8_t getBits() const
1570 {
1571 if (d_addrMask < d_addr.getBits()) {
1572 return d_addrMask;
1573 }
1574
1575 return d_addr.getBits() + d_portMask;
1576 }
1577
1578 /** Get the value of the bit at the provided bit index. When the index >= 0,
1579 the index is relative to the LSB starting at index zero. When the index < 0,
1580 the index is relative to the MSB starting at index -1 and counting down.
1581 */
1582 bool getBit(int index) const
1583 {
1584 if (index >= getFullBits()) {
1585 return false;
1586 }
1587 if (index < 0) {
1588 index = getFullBits() + index;
1589 }
1590
1591 if (index < 16) {
1592 /* we are into the port bits */
1593 uint16_t port = d_addr.getPort();
1594 return ((port & (1U<<index)) != 0x0000);
1595 }
1596
1597 index -= 16;
1598
1599 return d_addr.getBit(index);
1600 }
1601
1602 bool isIPv4() const
1603 {
1604 return d_addr.isIPv4();
1605 }
1606
1607 bool isIPv6() const
1608 {
1609 return d_addr.isIPv6();
1610 }
1611
1612 AddressAndPortRange getNormalized() const
1613 {
1614 return AddressAndPortRange(d_addr, d_addrMask, d_portMask);
1615 }
1616
1617 AddressAndPortRange getSuper(uint8_t bits) const
1618 {
1619 if (bits <= d_addrMask) {
1620 return AddressAndPortRange(d_addr, bits, 0);
1621 }
1622 if (bits <= d_addrMask + d_portMask) {
1623 return AddressAndPortRange(d_addr, d_addrMask, d_portMask - (bits - d_addrMask));
1624 }
1625
1626 return AddressAndPortRange(d_addr, d_addrMask, d_portMask);
1627 }
1628
1629 const ComboAddress& getNetwork() const
1630 {
1631 return d_addr;
1632 }
1633
1634 string toString() const
1635 {
1636 if (d_addrMask < d_addr.getBits() || d_portMask == 0) {
1637 return d_addr.toStringNoInterface() + "/" + std::to_string(d_addrMask);
1638 }
1639 return d_addr.toStringNoInterface() + ":" + std::to_string(d_addr.getPort()) + "/" + std::to_string(d_portMask);
1640 }
1641
1642 bool empty() const
1643 {
1644 return d_addr.sin4.sin_family == 0;
1645 }
1646
1647 bool operator==(const AddressAndPortRange& rhs) const
1648 {
905dae56 1649 return std::tie(d_addr, d_addrMask, d_portMask) == std::tie(rhs.d_addr, rhs.d_addrMask, rhs.d_portMask);
c173228a
RG
1650 }
1651
1652 bool operator<(const AddressAndPortRange& rhs) const
1653 {
1654 if (empty() && !rhs.empty()) {
1655 return false;
1656 }
1657
1658 if (!empty() && rhs.empty()) {
1659 return true;
1660 }
1661
1662 if (d_addrMask > rhs.d_addrMask) {
1663 return true;
1664 }
1665
1666 if (d_addrMask < rhs.d_addrMask) {
1667 return false;
1668 }
1669
1670 if (d_addr < rhs.d_addr) {
1671 return true;
1672 }
1673
1674 if (d_addr > rhs.d_addr) {
1675 return false;
1676 }
1677
1678 if (d_portMask > rhs.d_portMask) {
1679 return true;
1680 }
1681
1682 if (d_portMask < rhs.d_portMask) {
1683 return false;
1684 }
1685
1686 return d_addr.getPort() < rhs.d_addr.getPort();
1687 }
1688
1689 bool operator>(const AddressAndPortRange& rhs) const
1690 {
1691 return rhs.operator<(*this);
1692 }
1693
1694 struct hash
1695 {
1696 uint32_t operator()(const AddressAndPortRange& apr) const
1697 {
1698 ComboAddress::addressOnlyHash hashOp;
1699 uint16_t port = apr.d_addr.getPort();
1700 /* it's fine to hash the whole address and port because the non-relevant parts have
1701 been masked to 0 */
1702 return burtle(reinterpret_cast<const unsigned char*>(&port), sizeof(port), hashOp(apr.d_addr));
1703 }
1704 };
1705
1706private:
1707 ComboAddress d_addr;
1708 uint8_t d_addrMask;
1709 /* only used for v4 addresses */
1710 uint8_t d_portMask;
1711};
1712
002c970a 1713int SSocket(int family, int type, int flags);
1714int SConnect(int sockfd, const ComboAddress& remote);
51959320
RG
1715/* tries to connect to remote for a maximum of timeout seconds.
1716 sockfd should be set to non-blocking beforehand.
1717 returns 0 on success (the socket is writable), throw a
1718 runtime_error otherwise */
50111728 1719int SConnectWithTimeout(int sockfd, const ComboAddress& remote, const struct timeval& timeout);
002c970a 1720int SBind(int sockfd, const ComboAddress& local);
1721int SAccept(int sockfd, ComboAddress& remote);
1722int SListen(int sockfd, int limit);
1723int SSetsockopt(int sockfd, int level, int opname, int value);
db63b4b6 1724void setSocketIgnorePMTU(int sockfd, int family);
3198b2c3 1725void setSocketForcePMTU(int sockfd, int family);
665821e1 1726bool setReusePort(int sockfd);
002c970a 1727
3e3f0358 1728#if defined(IP_PKTINFO)
1729 #define GEN_IP_PKTINFO IP_PKTINFO
1730#elif defined(IP_RECVDSTADDR)
389fa92e 1731 #define GEN_IP_PKTINFO IP_RECVDSTADDR
3e3f0358 1732#endif
4d39d7f3 1733
3e3f0358 1734bool IsAnyAddress(const ComboAddress& addr);
2b3eefc3 1735bool HarvestDestinationAddress(const struct msghdr* msgh, ComboAddress* destination);
3e3f0358 1736bool HarvestTimestamp(struct msghdr* msgh, struct timeval* tv);
7bec330a 1737void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, cmsgbuf_aligned* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr);
2ea1d2c0 1738int sendOnNBSocket(int fd, const struct msghdr *msgh);
6714b6ac
RG
1739size_t sendMsgWithOptions(int fd, const char* buffer, size_t len, const ComboAddress* dest, const ComboAddress* local, unsigned int localItf, int flags);
1740
840ed663
RG
1741/* requires a non-blocking, connected TCP socket */
1742bool isTCPSocketUsable(int sock);
f9f9592e
AT
1743
1744extern template class NetmaskTree<bool>;
7234d9fc 1745ComboAddress parseIPAndPort(const std::string& input, uint16_t port);
f402f388 1746
6ec09d51
RG
1747std::set<std::string> getListOfNetworkInterfaces();
1748std::vector<ComboAddress> getListOfAddressesOfNetworkInterface(const std::string& itf);
6f0bf6e8 1749std::vector<Netmask> getListOfRangesOfNetworkInterface(const std::string& itf);
6ec09d51 1750
f402f388
RG
1751/* These functions throw if the value was already set to a higher value,
1752 or on error */
1753void setSocketBuffer(int fd, int optname, uint32_t size);
1754void setSocketReceiveBuffer(int fd, uint32_t size);
1755void setSocketSendBuffer(int fd, uint32_t size);
37088b76
CHB
1756uint32_t raiseSocketReceiveBufferToMax(int socket);
1757uint32_t raiseSocketSendBufferToMax(int socket);