LibSWOC++ 1.5.14
Solid Wall of C++
Loading...
Searching...
No Matches
swoc_ip.cc
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright Network Geographics 2014
7
8#include "swoc/swoc_ip.h"
9#include "swoc/swoc_meta.h"
10
11using swoc::TextView;
12using swoc::svtoi;
13using swoc::svtou;
14using namespace swoc::literals;
15
16namespace {
17// Handle the @c sin_len member, the presence of which varies across compilation environments.
18template <typename T>
19auto
20Set_Sockaddr_Len_Case(T *, swoc::meta::CaseTag<0>) -> decltype(swoc::meta::TypeFunc<void>()) {}
21
22template <typename T>
23auto
24Set_Sockaddr_Len_Case(T *addr, swoc::meta::CaseTag<1>) -> decltype(T::sin_len, swoc::meta::TypeFunc<void>()) {
25 addr->sin_len = sizeof(T);
26}
27
28template <typename T>
29void
30Set_Sockaddr_Len(T *addr) {
31 Set_Sockaddr_Len_Case(addr, swoc::meta::CaseArg);
32}
33
34} // namespace
35
36namespace swoc { inline namespace SWOC_VERSION_NS {
37
38IPAddr const IPAddr::INVALID;
39IP4Addr const IP4Addr::MIN{INADDR_ANY};
40IP4Addr const IP4Addr::MAX{INADDR_BROADCAST};
41IP6Addr const IP6Addr::MIN{0, 0};
42IP6Addr const IP6Addr::MAX{std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::max()};
43
44IPEndpoint::IPEndpoint(string_view const &text) {
45 this->invalidate();
46 this->parse(text);
47}
48
49bool
50IPEndpoint::assign(sockaddr *dst, sockaddr const *src) {
51 size_t n = 0;
52 if (dst != src) {
54 switch (src->sa_family) {
55 case AF_INET:
56 n = sizeof(sockaddr_in);
57 break;
58 case AF_INET6:
59 n = sizeof(sockaddr_in6);
60 break;
61 }
62 if (n) {
63 memcpy(dst, src, n);
64 }
65 }
66 return n != 0;
67}
68
71 memset(&sa4, 0, sizeof sa4);
72 sa4.sin_family = AF_INET;
73 sa4.sin_addr.s_addr = addr.network_order();
74 Set_Sockaddr_Len(&sa4);
75 return *this;
76}
77
80 memset(&sa6, 0, sizeof sa6);
81 sa6.sin6_family = AF_INET6;
82 addr.network_order(sa6.sin6_addr);
83 Set_Sockaddr_Len(&sa6);
84 return *this;
85}
86
89 switch (src.family()) {
90 case AF_INET: {
91 memset(&sa4, 0, sizeof sa4);
92 sa4.sin_family = AF_INET;
93 sa4.sin_addr.s_addr = src.ip4().network_order();
94 Set_Sockaddr_Len(&sa4);
95 } break;
96 case AF_INET6: {
97 memset(&sa6, 0, sizeof sa6);
98 sa6.sin6_family = AF_INET6;
99 sa6.sin6_addr = src.ip6().network_order();
100 Set_Sockaddr_Len(&sa6);
101 } break;
102 }
103 return *this;
104}
105
107IPEndpoint::assign(IPAddr const &addr, in_port_t port) {
108 if (addr.is_ip4()) {
109 this->assign(IP4Srv(addr.ip4(), port));
110 } else if (addr.is_ip6()) {
111 this->assign(IP6Srv(addr.ip6(), port));
112 }
113 return *this;
114}
115
116IPEndpoint &
118 memset(&sa4, 0, sizeof sa4);
119 sa4.sin_family = AF_INET;
120 sa4.sin_addr.s_addr = src.addr().network_order();
121 sa4.sin_port = src.network_order_port();
122 Set_Sockaddr_Len(&sa4);
123 return *this;
124}
125
128 memset(&sa6, 0, sizeof sa6);
129 sa6.sin6_family = AF_INET6;
130 sa6.sin6_addr = src.addr().network_order();
131 sa6.sin6_port = src.network_order_port();
132 Set_Sockaddr_Len(&sa6);
133 return *this;
134}
135
138 if (srv.is_ip4()) {
139 return this->assign(srv.ip4());
140 } else if (srv.is_ip6()) {
141 return this->assign(srv.ip6());
142 }
143 return *this;
144}
145
146bool
147IPEndpoint::tokenize(std::string_view str, std::string_view *addr, std::string_view *port, std::string_view *rest) {
148 TextView src(str);
149 // In case the incoming arguments are null, set them here and only check for null once.
150 // it doesn't matter if it's all the same, the results will be thrown away.
151 std::string_view local;
152 if (!addr) {
153 addr = &local;
154 }
155 if (!port) {
156 port = &local;
157 }
158 if (!rest) {
159 rest = &local;
160 }
161
162 *addr = std::string_view{};
163 *port = std::string_view{};
164 *rest = std::string_view{};
165
166 // Let's see if we can find out what's in the address string.
167 if (src) {
168 bool colon_p = false;
169 src.ltrim_if(&isspace);
170 // Check for brackets.
171 if ('[' == *src) {
172 ++src; // skip bracket.
173 *addr = src.take_prefix_at(']');
174 if (':' == *src) {
175 colon_p = true;
176 ++src;
177 }
178 } else {
179 TextView::size_type last = src.rfind(':');
180 if (last != TextView::npos && last == src.find(':')) {
181 // Exactly one colon - leave post colon stuff in @a src.
182 *addr = src.take_prefix(last);
183 colon_p = true;
184 } else { // presume no port, use everything.
185 *addr = src;
186 src.clear();
187 }
188 }
189 if (colon_p) {
190 TextView tmp{src};
191 src.ltrim_if(&isdigit);
192
193 if (tmp.data() == src.data()) { // no digits at all
194 src.assign(tmp.data() - 1, tmp.size() + 1); // back up to include colon
195 } else {
196 *port = std::string_view(tmp.data(), src.data() - tmp.data());
197 }
198 }
199 *rest = src;
200 }
201 return !addr->empty(); // true if we found an address.
202}
203
204bool
205IPEndpoint::parse(std::string_view const &str) {
206 if (IPSrv srv; srv.load(TextView(str).trim_if(&isspace))) {
207 this->assign(srv);
208 return true;
209 }
210 return false;
211}
212
213socklen_t
215 switch (sa.sa_family) {
216 case AF_INET:
217 return sizeof(sockaddr_in);
218 case AF_INET6:
219 return sizeof(sockaddr_in6);
220 default:
221 return sizeof(sockaddr);
222 }
223}
224
225std::string_view
227 switch (family) {
228 case AF_INET:
229 return "ipv4"_sv;
230 case AF_INET6:
231 return "ipv6"_sv;
232 case AF_UNIX:
233 return "unix"_sv;
234 case AF_UNSPEC:
235 return "unspec"_sv;
236 }
237 return "unknown"_sv;
238}
239
242 memset(this, 0, sizeof(*this));
243 if (AF_INET == family) {
244 sa4.sin_family = family;
245 sa4.sin_addr.s_addr = INADDR_ANY;
246 Set_Sockaddr_Len(&sa4);
247 } else if (AF_INET6 == family) {
248 sa6.sin6_family = family;
249 sa6.sin6_addr = in6addr_any;
250 Set_Sockaddr_Len(&sa6);
251 }
252 return *this;
253}
254
255bool
257 bool zret = false;
258 switch (this->family()) {
259 case AF_INET:
260 zret = sa4.sin_addr.s_addr == INADDR_ANY;
261 break;
262 case AF_INET6:
263 zret = IN6_IS_ADDR_UNSPECIFIED(&sa6.sin6_addr);
264 break;
265 }
266 return zret;
267}
268
271 memset(this, 0, sizeof(*this));
272 if (AF_INET == family) {
273 sa.sa_family = family;
274 sa4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
275 Set_Sockaddr_Len(&sa4);
276 } else if (AF_INET6 == family) {
277 sa.sa_family = family;
278 sa6.sin6_addr = in6addr_loopback;
279 Set_Sockaddr_Len(&sa6);
280 }
281 return *this;
282}
283
284bool
286 bool zret = false;
287 switch (this->family()) {
288 case AF_INET:
289 zret = ((ntohl(sa4.sin_addr.s_addr) & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET;
290 break;
291 case AF_INET6:
292 zret = IN6_IS_ADDR_LOOPBACK(&sa6.sin6_addr);
293 break;
294 }
295 return zret;
296}
297
298bool
299IP4Addr::load(std::string_view const &text) {
300 TextView src{text};
301 int n = SIZE;
302
303 _addr = INADDR_ANY; // clear to zero.
304
305 // empty or trailing dot or empty brackets or unmatched brackets.
306 src.trim_if(&isspace);
307 if (src.empty() || src.back() == '.' || ('[' == *src && ((++src).empty() || src.back() != ']'))) {
308 return false;
309 }
310
311 in_addr_t max = std::numeric_limits<in_addr_t>::max();
312 while (n > 0) {
313 TextView parsed;
314 auto token = src.take_prefix_at('.');
315 auto v = svtou(token, &parsed);
316 if (parsed.size() != token.size()) {
317 break;
318 }
319 if (src.empty()) {
320 if (v <= max) {
321 _addr += v;
322 n = 0; // signal complete.
323 }
324 break;
325 } else if (v <= std::numeric_limits<uint8_t>::max()) {
326 _addr += v << (--n * 8);
327 } else {
328 break; // invalid.
329 }
330 max >>= 8; // reduce by one octet.
331 }
332
333 // If there's text left, or not all the octets were filled, fail.
334 if (!src.empty() || n != 0) {
335 _addr = INADDR_ANY;
336 return false;
337 }
338
339 return true;
340}
341
342IP4Addr::IP4Addr(sockaddr_in const *sa) : _addr(reorder(sa->sin_addr.s_addr)) {}
343
344auto
345IP4Addr::operator=(sockaddr_in const *sa) -> self_type & {
346 _addr = reorder(sa->sin_addr.s_addr);
347 return *this;
348}
349
350sockaddr_in *
351IP4Addr::copy_to(sockaddr_in *sin) const {
352 sin->sin_family = AF_INET;
353 sin->sin_addr.s_addr = this->network_order();
354 Set_Sockaddr_Len(sin);
355 return sin;
356}
357
358// --- IPv6
359
360sockaddr_in6 *
361IP6Addr::copy_to(sockaddr_in6 *sin6) const {
362 sin6->sin6_family = AF_INET6;
363 self_type::reorder(sin6->sin6_addr, _addr._raw);
364 Set_Sockaddr_Len(sin6);
365 return sin6;
366}
367
368int
369IP6Addr::cmp(const self_type &that) const {
370 return *this < that ? -1 : *this > that ? 1 : 0;
371}
372
374IP6Addr::operator<<=(unsigned int n) {
375 static constexpr auto MASK = ~word_type{0};
376 if (n < WORD_WIDTH) {
377 _addr._store[MSW] <<= n;
378 _addr._store[MSW] |= (_addr._store[LSW] >> (WORD_WIDTH - n)) & ~(MASK << n);
379 _addr._store[LSW] <<= n;
380 } else {
381 n -= WORD_WIDTH;
382 _addr._store[MSW] = _addr._store[LSW] << n;
383 _addr._store[LSW] = 0;
384 }
385 return *this;
386}
387
388IP6Addr &
389IP6Addr::operator>>=(unsigned int n) {
390 static constexpr auto MASK = ~word_type{0};
391 if (n < WORD_WIDTH) {
392 _addr._store[LSW] >>= n;
393 _addr._store[LSW] |= (_addr._store[MSW] & ~(MASK << n)) << (WORD_WIDTH - n);
394 _addr._store[MSW] >>= n;
395 } else {
396 n -= WORD_WIDTH;
397 _addr._store[LSW] = _addr._store[MSW] >> n;
398 _addr._store[MSW] = 0;
399 }
400 return *this;
401}
402
403IP6Addr &
404IP6Addr::operator&=(self_type const &that) {
405 _addr._store[MSW] &= that._addr._store[MSW];
406 _addr._store[LSW] &= that._addr._store[LSW];
407 return *this;
408}
409
410IP6Addr &
411IP6Addr::operator|=(self_type const &that) {
412 _addr._store[MSW] |= that._addr._store[MSW];
413 _addr._store[LSW] |= that._addr._store[LSW];
414 return *this;
415}
416
417bool
418IP6Addr::load(std::string_view const &str) {
419 TextView src{str};
420 int n = 0;
421 int empty_idx = -1;
422 auto quad = _addr._quad.data();
423
424 src.trim_if(&isspace);
425 if (src && '[' == *src) {
426 ++src;
427 if (src.empty() || src.back() != ']') {
428 return false;
429 }
430 src.remove_suffix(1);
431 }
432
433 if (src.size() < 2) {
434 return false;
435 }
436
437 // If the first character is ':' then it is an error for it not to be followed by another ':'.
438 // Special case the empty address and loopback, otherwise just make a note of the leading '::'.
439 if (src[0] == ':') {
440 if (src[1] == ':') {
441 if (src.size() == 2) {
442 this->clear();
443 return true;
444 } else if (src.size() == 3 && src[2] == '1') {
445 _addr._store[0] = 0;
446 _addr._store[1] = 1;
447 return true;
448 } else {
449 empty_idx = n;
450 src.remove_prefix(2);
451 }
452 } else {
453 return false;
454 }
455 }
456
457 // Sadly the empty quads can't be done in line because it's not possible to know the correct index
458 // of the next present quad until the entire address has been parsed.
459 while (n < static_cast<int>(N_QUADS) && !src.empty()) {
460 TextView token{src.take_prefix_at(':')};
461 if (token.empty()) {
462 if (empty_idx >= 0) { // two instances of "::", fail.
463 return false;
464 }
465 empty_idx = n;
466 } else {
467 TextView r;
468 auto x = svtoi(token, &r, 16);
469 if (r.size() == token.size()) {
470 quad[QUAD_IDX[n++]] = x;
471 } else {
472 break;
473 }
474 }
475 }
476
477 // Handle empty quads - invalid if empty and still had a full set of quads
478 if (empty_idx >= 0) {
479 if (n < static_cast<int>(N_QUADS)) {
480 int nil_idx = N_QUADS - (n - empty_idx);
481 int delta = N_QUADS - n;
482 for (int k = N_QUADS - 1; k >= empty_idx; --k) {
483 quad[QUAD_IDX[k]] = (k >= nil_idx ? quad[QUAD_IDX[k - delta]] : 0);
484 }
485 n = N_QUADS; // Mark success.
486 } else {
487 return false; // too many quads - full set plus empty.
488 }
489 }
490
491 if (n == N_QUADS && src.empty()) {
492 return true;
493 }
494
495 this->clear();
496 return false;
497}
498
499// These are Intel correct, at some point will need to be architecture dependent.
500
501void
502IP6Addr::reorder(in6_addr &dst, raw_type const &src) {
503 self_type::reorder(dst.s6_addr, src.data());
504 self_type::reorder(dst.s6_addr + WORD_SIZE, src.data() + WORD_SIZE);
505}
506
507void
508IP6Addr::reorder(raw_type &dst, in6_addr const &src) {
509 self_type::reorder(dst.data(), src.s6_addr);
510 self_type::reorder(dst.data() + WORD_SIZE, src.s6_addr + WORD_SIZE);
511}
512
514 this->assign(&addr.sa);
515}
516
517IPAddr &
519 return this->assign(&addr.sa);
520}
521
522sockaddr *
523IPAddr::copy_to(sockaddr *sa) const {
524 if (this->is_ip4()) {
525 _addr._ip4.copy_to(sa);
526 } else if (this->is_ip6()) {
527 _addr._ip6.copy_to(sa);
528 }
529 return sa;
530}
531
532bool
533IPAddr::load(const std::string_view &text) {
534 TextView src{text};
535 src.ltrim_if(&isspace);
536
537 if (TextView::npos != src.prefix(5).find_first_of('.')) {
538 _family = AF_INET;
539 } else if (TextView::npos != src.prefix(6).find_first_of(':')) {
540 _family = AF_INET6;
541 } else {
542 _family = AF_UNSPEC;
543 }
544
545 // Do the real parse now
546 switch (_family) {
547 case AF_INET:
548 if (!_addr._ip4.load(src)) {
549 _family = AF_UNSPEC;
550 }
551 break;
552 case AF_INET6:
553 if (!_addr._ip6.load(src)) {
554 _family = AF_UNSPEC;
555 }
556 break;
557 }
558 return this->is_valid();
559}
560
561IPAddr &
562IPAddr::assign(sockaddr const *addr) {
563 if (addr) {
564 switch (addr->sa_family) {
565 case AF_INET:
566 return this->assign(reinterpret_cast<sockaddr_in const *>(addr));
567 case AF_INET6:
568 return this->assign(reinterpret_cast<sockaddr_in6 const *>(addr));
569 default:
570 break;
571 }
572 }
573 _family = AF_UNSPEC;
574 return *this;
575}
576
577bool
578IPAddr::operator<(self_type const &that) const {
579 if (AF_INET == _family) {
580 switch (that._family) {
581 case AF_INET:
582 return _addr._ip4 < that._addr._ip4;
583 case AF_INET6:
584 return true;
585 default:
586 return false;
587 }
588 } else if (AF_INET6 == _family) {
589 switch (that._family) {
590 case AF_INET:
591 return true;
592 case AF_INET6:
593 return _addr._ip6 < that._addr._ip6;
594 default:
595 return false;
596 }
597 }
598 return that.is_valid();
599}
600
601int
602IPAddr::cmp(self_type const &that) const {
603 if (AF_INET == _family) {
604 switch (that._family) {
605 case AF_INET:
606 return _addr._ip4.cmp(that._addr._ip4);
607 case AF_INET6:
608 return -1;
609 default:
610 return 1;
611 }
612 } else if (AF_INET6 == _family) {
613 switch (that._family) {
614 case AF_INET:
615 return 1;
616 case AF_INET6:
617 return _addr._ip6.cmp(that._addr._ip6);
618 default:
619 return 1;
620 }
621 }
622 return that.is_valid() ? -1 : 0;
623}
624
625IPAddr::self_type &
626IPAddr::operator&=(IPMask const &mask) {
627 if (_family == AF_INET) {
628 _addr._ip4 &= mask;
629 } else if (_family == AF_INET6) {
630 _addr._ip6 &= mask;
631 }
632 return *this;
633}
634
635IPAddr::self_type &
636IPAddr::operator|=(IPMask const &mask) {
637 if (_family == AF_INET) {
638 _addr._ip4 |= mask;
639 } else if (_family == AF_INET6) {
640 _addr._ip6 |= mask;
641 }
642 return *this;
643}
644
645bool
647 return (AF_INET == _family && _addr._ip4.is_multicast()) || (AF_INET6 == _family && _addr._ip6.is_multicast());
648}
649
650bool operator == (IPAddr const& lhs, sockaddr const * sa) {
651 using sa4 = sockaddr_in const *;
652 using sa6 = sockaddr_in6 const *;
653
654 if (lhs.family() != sa->sa_family) {
655 return false;
656 }
657 return lhs.family() == AF_UNSPEC ||
658 ( lhs.is_ip4() && (lhs.ip4().network_order() == sa4(sa)->sin_addr.s_addr) ) ||
659 ( lhs.is_ip6() && (lhs.ip6().network_order() == sa6(sa)->sin6_addr) );
660}
661
662bool
663IPMask::load(string_view const &text) {
664 TextView parsed;
665 _cidr = swoc::svtou(text, &parsed);
666 if (parsed.size() != text.size()) {
667 _cidr = 0;
668 return false;
669 }
670 return true;
671}
672
673IPMask
675 if (addr.is_ip4()) {
676 return self_type::mask_for(addr.ip4());
677 } else if (addr.is_ip6()) {
678 return self_type::mask_for(addr.ip6());
679 }
680 return {};
681}
682
683auto
686 if (q != 0) {
688 do {
689 mask <<= 1;
690 --cidr;
691 } while ((q & mask) == q);
692 ++cidr; // loop goes exactly 1 too far.
693 }
694 return cidr;
695}
696
697IPMask
698IPMask::mask_for(IP4Addr const &addr) {
699 auto n = addr.host_order();
700 raw_type cidr = 0;
701 if (auto q = (n & IP6Addr::QUAD_MASK); q != 0) {
703 } else if (q = ((n >> IP6Addr::QUAD_WIDTH) & IP6Addr::QUAD_MASK); q != 0) {
704 cidr = self_type::mask_for_quad(q);
705 }
706 return self_type(cidr);
707}
708
709IPMask
710IPMask::mask_for(IP6Addr const &addr) {
711 auto cidr = IP6Addr::WIDTH;
712 for (unsigned idx = IP6Addr::N_QUADS; idx > 0;) {
713 auto q = addr._addr._quad[IP6Addr::QUAD_IDX[--idx]];
714 cidr -= IP6Addr::QUAD_WIDTH;
715 if (q != 0) {
716 cidr += self_type::mask_for_quad(q);
717 break;
718 }
719 }
720 return self_type(cidr);
721}
722
725 static constexpr auto MASK = ~IP6Addr::word_type{0};
726 if (_cidr == 0) {
727 return {0, 0};
728 } else if (_cidr <= IP6Addr::WORD_WIDTH) {
729 return {MASK << (IP6Addr::WORD_WIDTH - _cidr), 0};
730 } else if (_cidr < 2 * IP6Addr::WORD_WIDTH) {
731 return {MASK, MASK << (2 * IP6Addr::WORD_WIDTH - _cidr)};
732 }
733 return {MASK, MASK};
734}
735
736// --- SRV ---
737
739 this->load(text);
740}
741
742bool
744 TextView addr_text, port_text, rest;
745 if (IPEndpoint::tokenize(text, &addr_text, &port_text, &rest)) {
746 if (rest.empty()) {
747 uintmax_t n = 0;
748 if (!port_text.empty()) {
749 n = swoc::svtou(port_text, &rest);
750 if (rest.size() != port_text.size() || n > std::numeric_limits<in_port_t>::max()) {
751 return false; // bad port.
752 }
753 }
755 if (addr.load(addr_text)) {
756 this->assign(addr, n);
757 return true;
758 }
759 }
760 }
761 return false;
762}
763
765 this->load(text);
766}
767
768bool
770 TextView addr_text, port_text, rest;
771 if (IPEndpoint::tokenize(text, &addr_text, &port_text, &rest)) {
772 if (rest.empty()) {
773 uintmax_t n = 0;
774 if (!port_text.empty()) {
775 n = swoc::svtou(port_text, &rest);
776 if (rest.size() != port_text.size() || n > std::numeric_limits<in_port_t>::max()) {
777 return false; // bad port.
778 }
779 }
781 if (addr.load(addr_text)) {
782 this->assign(addr, n);
783 return true;
784 }
785 }
786 }
787 return false;
788}
789
791 this->load(text);
792}
793
794bool
796 TextView addr_text, port_text, rest;
797 if (IPEndpoint::tokenize(text, &addr_text, &port_text, &rest)) {
798 if (rest.empty()) {
799 uintmax_t n = 0;
800 if (!port_text.empty()) {
801 n = swoc::svtou(port_text, &rest);
802 if (rest.size() != port_text.size() || n > std::numeric_limits<in_port_t>::max()) {
803 return false; // bad port.
804 }
805 }
806 IPAddr addr;
807 if (addr.load(addr_text)) {
808 this->assign(addr, n);
809 return true;
810 }
811 }
812 }
813 return false;
814}
815
816IPSrv::IPSrv(IPAddr addr, in_port_t port) : _family(addr.family()) {
817 if (addr.is_ip4()) {
818 _srv._ip4.assign(addr.ip4(), port);
819 } else if (addr.is_ip6()) {
820 _srv._ip6.assign(addr.ip6(), port);
821 } else {
822 _family = AF_UNSPEC;
823 }
824}
825
827 if (ep.is_ip4()) {
828 _family = _srv._ip4.family();
829 _srv._ip4.assign(&ep.sa4);
830 } else if (ep.is_ip6()) {
831 _family = _srv._ip6.family();
832 _srv._ip6.assign(&ep.sa6);
833 }
834}
835
836auto
837IPSrv::assign(const sockaddr *sa) -> self_type & {
838 if (AF_INET == sa->sa_family) {
839 _family = AF_INET;
840 _srv._ip4.assign(reinterpret_cast<sockaddr_in const *>(sa));
841 } else if (AF_INET6 == sa->sa_family) {
842 _family = AF_INET6;
843 _srv._ip6.assign(reinterpret_cast<sockaddr_in6 const *>(sa));
844 }
845 return *this;
846}
847
848// ++ IPNet ++
849
850bool
852 if (auto mask_text = text.split_suffix_at('/'); !mask_text.empty()) {
853 IPMask mask;
854 bool mask_p = mask.load(mask_text);
855 if (IP4Addr addr; addr.load(text)) {
856 if (!mask_p) {
857 if (IP4Addr m; m.load(mask_text)) {
859 mask_p = (m == mask.as_ip4()); // must be an actual mask like address.
860 }
861 }
862 if (mask_p) {
863 this->assign(addr, mask);
864 return true;
865 }
866 }
867 }
868
869 this->clear();
870 return false;
871}
872
873bool
875 if (auto mask_text = text.split_suffix_at('/'); !mask_text.empty()) {
876 IPMask mask;
877 bool mask_p = mask.load(mask_text);
878 if (IP6Addr addr; addr.load(text)) {
879 if (!mask_p) {
880 if (IP6Addr m; m.load(mask_text)) {
882 mask_p = (m == mask.as_ip6()); // must be an actual mask like address.
883 }
884 }
885 if (mask_p) {
886 this->assign(addr, mask);
887 return true;
888 }
889 }
890 }
891
892 this->clear();
893 return false;
894}
895
896bool
898 if (auto mask_text = text.split_suffix_at('/'); !mask_text.empty()) {
899 IPMask mask;
900 bool mask_p = mask.load(mask_text);
901
902 if (IP6Addr a6; a6.load(text)) { // load the address
903 if (!mask_p) {
904 if (IP6Addr m; m.load(mask_text)) {
906 mask_p = (m == mask.as_ip6()); // must be an actual mask like address.
907 }
908 }
909 if (mask_p) {
910 this->assign(a6, mask);
911 return true;
912 }
913 } else if (IP4Addr a4; a4.load(text)) {
914 if (!mask_p) {
915 if (IP4Addr m; m.load(mask_text)) {
917 mask_p = (m == mask.as_ip4()); // must be an actual mask like address.
918 }
919 }
920 if (mask_p) {
921 this->assign(a4, mask);
922 return true;
923 }
924 }
925 }
926 this->clear();
927 return false;
928}
929
930// +++ IP4Range +++
931
933 this->assign(addr, mask);
934}
935
936IP4Range &
937IP4Range::assign(swoc::IP4Addr const &addr, swoc::IPMask const &mask) {
938 // Special case the cidr sizes for 0, maximum
939 if (0 == mask.width()) {
942 } else {
943 _min = _max = addr;
944 if (mask.width() < 32) {
945 in_addr_t bits = INADDR_BROADCAST << (32 - mask.width());
946 _min._addr &= bits;
947 _max._addr |= ~bits;
948 }
949 }
950 return *this;
951}
952
953bool
954IP4Range::load(string_view text) {
955 static const string_view SEPARATORS("/-");
956 auto idx = text.find_first_of(SEPARATORS);
957 if (idx != text.npos) {
958 if (idx + 1 < text.size()) { // must have something past the separator or it's bogus.
959 if ('/' == text[idx]) {
960 metric_type addr;
961 if (addr.load(text.substr(0, idx))) { // load the address
962 IPMask mask;
963 text.remove_prefix(idx + 1); // drop address and separator.
964 if (mask.load(text)) {
965 this->assign(addr, mask);
966 return true;
967 }
968 }
969 } else if (_min.load(text.substr(0, idx)) && _max.load(text.substr(idx + 1))) {
970 return true;
971 }
972 }
973 } else if (_min.load(text)) {
974 _max = _min;
975 return true;
976 }
977
978 this->clear();
979 return false;
980}
981
982IPMask
984 NetSource nets{*this};
985 if (!nets.empty() && (*nets).as_range() == *this) {
986 return nets->mask();
987 }
988 return {}; // default constructed (invalid) mask.
989}
990
992 if (!_range.empty()) {
993 this->search_wider();
994 }
995}
996
997auto
999 auto upper(IP4Addr{_range._min._addr | ~_mask._addr});
1000 if (upper >= _range.max()) {
1001 _range.clear();
1002 } else {
1003 _range.assign_min(++upper);
1004 // @a _range is not empty, because there's at least one address still not covered.
1005 if (this->is_valid(_mask)) {
1006 this->search_wider();
1007 } else {
1008 this->search_narrower();
1009 }
1010 }
1011 return *this;
1012}
1013
1014auto
1016 auto zret{*this};
1017 ++*this;
1018 return zret;
1019}
1020
1021void
1022IP4Range::NetSource::search_wider() {
1023 while (_cidr > 0) {
1024 auto m = _mask;
1025 m <<= 1;
1026 if (this->is_valid(m)) {
1027 _mask = m;
1028 --_cidr;
1029 } else {
1030 break;
1031 }
1032 }
1033}
1034
1035void
1036IP4Range::NetSource::search_narrower() {
1037 while (!this->is_valid(_mask)) {
1038 _mask._addr >>= 1;
1039 _mask._addr |= 1U << (IP4Addr::WIDTH - 1); // put top bit back.
1040 ++_cidr;
1041 }
1042}
1043
1044// +++ IP6Range +++
1045
1046IP6Range &
1047IP6Range::assign(IP6Addr const &addr, IPMask const &mask) {
1048 static constexpr auto FULL_MASK{std::numeric_limits<uint64_t>::max()};
1049 auto cidr = mask.width();
1050 if (cidr == 0) {
1053 } else if (cidr < 64) { // only upper bytes affected, lower bytes are forced.
1054 auto bits = FULL_MASK << (64 - cidr);
1055 _min._addr._store[0] = addr._addr._store[0] & bits;
1056 _min._addr._store[1] = 0;
1057 _max._addr._store[0] = addr._addr._store[0] | ~bits;
1058 _max._addr._store[1] = FULL_MASK;
1059 } else if (cidr == 64) {
1060 _min._addr._store[0] = _max._addr._store[0] = addr._addr._store[0];
1061 _min._addr._store[1] = 0;
1062 _max._addr._store[1] = FULL_MASK;
1063 } else if (cidr <= 128) { // _min bytes changed, _max bytes unaffected.
1064 _min = _max = addr;
1065 if (cidr < 128) {
1066 auto bits = FULL_MASK << (128 - cidr);
1067 _min._addr._store[1] &= bits;
1068 _max._addr._store[1] |= ~bits;
1069 }
1070 }
1071 return *this;
1072}
1073
1074bool
1075IP6Range::load(std::string_view text) {
1076 static const string_view SEPARATORS("/-");
1077 auto idx = text.find_first_of(SEPARATORS);
1078 if (idx != text.npos) {
1079 if (idx + 1 < text.size()) { // must have something past the separator or it's bogus.
1080 if ('/' == text[idx]) {
1081 metric_type addr;
1082 if (addr.load(text.substr(0, idx))) { // load the address
1083 IPMask mask;
1084 text.remove_prefix(idx + 1); // drop address and separator.
1085 if (mask.load(text)) {
1086 this->assign(addr, mask);
1087 return true;
1088 }
1089 }
1090 } else if (_min.load(text.substr(0, idx)) && _max.load(text.substr(idx + 1))) {
1091 return true;
1092 }
1093 }
1094 } else if (_min.load(text)) {
1095 _max = _min;
1096 return true;
1097 }
1098 this->clear();
1099 return false;
1100}
1101
1103 if (min.is_ip4() && max.is_ip4()) {
1104 this->assign(min.ip4(), max.ip4());
1105 } else if (min.is_ip6() && max.is_ip6()) {
1106 this->assign(min.ip6(), max.ip6());
1107 }
1108}
1109
1110bool
1111IPRange::load(std::string_view const &text) {
1112 if (auto idx = text.find_first_of(':'); idx != text.npos) {
1113 if (_range._ip6.load(text)) {
1114 _family = AF_INET6;
1115 return true;
1116 }
1117 } else if (_range._ip4.load(text)) {
1118 _family = AF_INET;
1119 return true;
1120 }
1121
1122 return false;
1123}
1124
1125IPAddr
1127 switch (_family) {
1128 case AF_INET:
1129 return _range._ip4.min();
1130 case AF_INET6:
1131 return _range._ip6.min();
1132 default:
1133 break;
1134 }
1135 return {};
1136}
1137
1138IPAddr
1140 switch (_family) {
1141 case AF_INET:
1142 return _range._ip4.max();
1143 case AF_INET6:
1144 return _range._ip6.max();
1145 default:
1146 break;
1147 }
1148 return {};
1149}
1150
1151bool
1153 switch (_family) {
1154 case AF_INET:
1155 return _range._ip4.empty();
1156 case AF_INET6:
1157 return _range._ip6.empty();
1158 default:
1159 break;
1160 }
1161 return true;
1162}
1163
1164IPMask
1166 switch (_family) {
1167 case AF_INET:
1168 return _range._ip4.network_mask();
1169 case AF_INET6:
1170 return _range._ip6.network_mask();
1171 default:
1172 break;
1173 }
1174 return {};
1175}
1176
1177bool
1178IPRange::operator==(self_type const &that) const {
1179 if (_family != that._family) {
1180 return false;
1181 }
1182 if (this->is_ip4()) {
1183 return _range._ip4 == that._range._ip4;
1184 }
1185 if (this->is_ip6()) {
1186 return _range._ip6 == that._range._ip6;
1187 }
1188 return true;
1189}
1190
1191IPMask
1193 NetSource nets{*this};
1194 if (!nets.empty() && (*nets).as_range() == *this) {
1195 return nets->mask();
1196 }
1197 return {}; // default constructed (invalid) mask.
1198}
1199
1201 if (!_range.empty()) {
1202 this->search_wider();
1203 }
1204}
1205
1206auto
1208 auto upper = _range.min() | _mask;
1209 if (upper >= _range.max()) {
1210 _range.clear();
1211 } else {
1212 _range.assign_min(++upper);
1213 // @a _range is not empty, because there's at least one address still not covered.
1214 if (this->is_valid(_mask)) {
1215 this->search_wider();
1216 } else {
1217 this->search_narrower();
1218 }
1219 }
1220 return *this;
1221}
1222
1223void
1224IP6Range::NetSource::search_wider() {
1225 while (_mask.width() > 0) {
1226 auto m = _mask;
1227 m <<= 1;
1228 if (this->is_valid(m)) {
1229 _mask = m;
1230 } else {
1231 break;
1232 }
1233 }
1234}
1235
1236void
1237IP6Range::NetSource::search_narrower() {
1238 while (!this->is_valid(_mask)) {
1239 _mask >>= 1;
1240 }
1241}
1242
1243bool
1244IPRangeView::operator==(IPRange const &r) const {
1245 if (_family == r.family()) {
1246 if (AF_INET == _family) {
1247 return *_raw._4 == r.ip4();
1248 } else if (AF_INET6 == _family) {
1249 return *_raw._6 == r.ip6();
1250 }
1251 return true;
1252 }
1253 return false;
1254}
1255
1256bool
1257IPRangeView::operator==(IPRangeView::self_type const &that) const {
1258 if (_family == that._family) { // different families are not equal
1259 if (AF_INET == _family) {
1260 return (_raw._4 == that._raw._4) || (*_raw._4 == *that._raw._4);
1261 } else if (AF_INET6 == _family) {
1262 return (_raw._6 == that._raw._6) || (*_raw._6 == *that._raw._6);
1263 }
1264 return true;
1265 }
1266 return false;
1267}
1268
1269}} // namespace swoc::SWOC_VERSION_NS
static constexpr in_addr_t reorder(in_addr_t src)
Definition IPAddr.h:921
in_addr_t network_order() const
Definition IPAddr.h:815
in_addr_t host_order() const
Definition IPAddr.h:820
static const self_type MIN
Minimum value.
Definition IPAddr.h:35
static constexpr size_t SIZE
Size of IPv4 address in bytes.
Definition IPAddr.h:32
static constexpr size_t WIDTH
Definition IPAddr.h:33
sockaddr * copy_to(sockaddr *sa) const
Definition IPAddr.h:831
in_addr_t _addr
Address in host order.
Definition IPAddr.h:192
static const self_type MAX
Maximum value.
Definition IPAddr.h:36
self_type & operator=(self_type const &that)=default
Self assignment.
bool load(string_view const &text)
Definition swoc_ip.cc:299
constexpr IP4Addr()=default
Default constructor - ANY address.
bool empty() const
Definition IPRange.h:2128
self_type & clear()
Reset network to invalid state.
Definition IPRange.h:769
self_type & assign(IP4Addr const &addr, IPMask const &mask)
Definition IPRange.h:2158
bool load(swoc::TextView text)
Definition swoc_ip.cc:851
IPMask const & mask() const
Definition IPRange.h:2123
IP4Addr _mask
Mask for current network.
Definition IPRange.h:168
self_type & operator++()
Move to next network.
Definition swoc_ip.cc:998
IP4Range range_type
Import base range type.
Definition IPRange.h:120
NetSource(range_type const &range)
Construct from range.
Definition swoc_ip.cc:991
bool load(string_view text)
< Import assign methods.
Definition swoc_ip.cc:954
self_type & assign(IP4Addr const &addr, IPMask const &mask)
< Import super class constructors.
Definition swoc_ip.cc:937
constexpr IP4Range()=default
Default constructor, invalid range.
IPMask network_mask() const
Definition swoc_ip.cc:983
An IPv4 address and host_order_port, modeled on an SRV type for DNS.
Definition IPSrv.h:20
constexpr IP4Addr const & addr() const
Definition IPSrv.h:433
in_port_t network_order_port() const
Definition IPSrv.h:441
bool load(swoc::TextView text)
Definition swoc_ip.cc:743
constexpr IP4Srv()=default
Default constructor.
self_type & assign(IP4Addr const &addr)
Definition IPSrv.h:408
static void reorder(in6_addr &dst, raw_type const &src)
Definition swoc_ip.cc:502
int cmp(self_type const &that) const
Generic three value compare.
Definition swoc_ip.cc:369
uint16_t quad_type
Size of one segment of an IPv6 address.
Definition IPAddr.h:211
self_type & operator<<=(unsigned n)
Definition swoc_ip.cc:374
static constexpr unsigned MSW
Most significant word index.
Definition IPAddr.h:466
static const self_type MIN
Minimum value of an address.
Definition IPAddr.h:221
static constexpr size_t QUAD_WIDTH
Number of bits per quad.
Definition IPAddr.h:214
static constexpr quad_type QUAD_MASK
A bit mask of all 1 bits the size of a quad.
Definition IPAddr.h:434
self_type & operator>>=(unsigned n)
Definition swoc_ip.cc:389
uint64_t word_type
Type used as a "word", the natural working unit of the address.
Definition IPAddr.h:437
bool load(string_view const &str)
Definition swoc_ip.cc:418
static const self_type MAX
Maximum value of an address.
Definition IPAddr.h:223
static constexpr std::array< unsigned, N_QUADS > QUAD_IDX
Definition IPAddr.h:470
static constexpr unsigned LSW
Least significant word index.
Definition IPAddr.h:465
static constexpr size_t N_QUADS
Definition IPAddr.h:212
in6_addr network_order() const
Return the address in network order.
Definition IPAddr.h:997
self_type & operator|=(self_type const &that)
Definition swoc_ip.cc:411
sockaddr_in6 * copy_to(sockaddr_in6 *sin6) const
Definition swoc_ip.cc:361
static constexpr size_t WIDTH
Number of bits in the address.
Definition IPAddr.h:207
std::array< uint8_t, SIZE > raw_type
Definition IPAddr.h:218
self_type & operator&=(self_type const &that)
Definition swoc_ip.cc:404
self_type & clear()
Definition IPAddr.h:1009
IP6Addr()=default
Default constructor - ANY address.
static constexpr size_t WORD_WIDTH
Number of bits per word.
Definition IPAddr.h:442
bool empty() const
Definition IPRange.h:2172
self_type & assign(IP6Addr const &addr, IPMask const &mask)
Definition IPRange.h:2202
IPMask const & mask() const
Definition IPRange.h:2167
self_type & clear()
Reset network to invalid state.
Definition IPRange.h:844
bool load(swoc::TextView text)
Definition swoc_ip.cc:874
IPMask _mask
Current CIDR value.
Definition IPRange.h:310
IP6Range _range
Remaining range.
Definition IPRange.h:309
NetSource(range_type const &range)
Construct from range.
Definition swoc_ip.cc:1200
self_type & operator++()
Move to next network.
Definition swoc_ip.cc:1207
IP6Range range_type
Import base range type.
Definition IPRange.h:264
bool load(string_view text)
< Import assign methods.
Definition swoc_ip.cc:1075
IPMask network_mask() const
Definition swoc_ip.cc:1192
self_type & assign(IP6Addr const &addr, IPMask const &mask)
< Import super class constructors.
Definition swoc_ip.cc:1047
An IPv6 address and host_order_port, modeled on an SRV type for DNS.
Definition IPSrv.h:123
self_type & assign(IP6Addr const &addr)
Definition IPSrv.h:532
bool load(swoc::TextView text)
Definition swoc_ip.cc:769
IP6Srv()=default
Default constructor.
in_port_t network_order_port() const
Definition IPSrv.h:492
constexpr IP6Addr const & addr() const
Definition IPSrv.h:484
self_type & operator=(self_type const &that)=default
Copy assignment.
bool is_valid() const
Test for validity.
Definition IPAddr.h:1335
bool is_ip6() const
Test for IPv6.
Definition IPAddr.h:1274
bool is_multicast() const
Test for multicast.
Definition swoc_ip.cc:646
bool is_ip4() const
Test for IPv4.
Definition IPAddr.h:1269
IPAddr()=default
Default constructor - invalid result.
int cmp(self_type const &that) const
Generic compare.
Definition swoc_ip.cc:602
IP6Addr const & ip6() const
Definition IPAddr.h:1377
sockaddr * copy_to(sockaddr *sa) const
Definition swoc_ip.cc:523
bool load(string_view const &text)
Definition swoc_ip.cc:533
IP4Addr const & ip4() const
Definition IPAddr.h:1369
sa_family_t _family
Protocol family.
Definition IPAddr.h:659
self_type & assign(sockaddr const *addr)
Set to the address in addr.
Definition swoc_ip.cc:562
sa_family_t family() const
Definition IPAddr.h:1264
bool load(string_view const &text)
Definition swoc_ip.cc:663
uint8_t raw_type
Storage for mask width.
Definition IPAddr.h:673
raw_type _cidr
Mask width in bits.
Definition IPAddr.h:757
IP6Addr as_ip6() const
Definition swoc_ip.cc:724
raw_type width() const
The width of the mask.
Definition IPAddr.h:1143
static self_type mask_for(IPAddr const &addr)
Definition swoc_ip.cc:674
static raw_type mask_for_quad(IP6Addr::quad_type q)
Compute a partial IPv6 mask, sized for the basic storage type.
Definition swoc_ip.cc:684
self_type & assign(IPAddr const &addr, IPMask const &mask)
Definition IPRange.h:2245
bool empty() const
Definition IPRange.h:2215
bool load(swoc::TextView text)
Definition swoc_ip.cc:897
IPMask const & mask() const
Definition IPRange.h:2235
self_type & clear()
Reset network to invalid state.
Definition IPRange.h:2292
bool operator==(IPRange const &r) const
Compare to a range.
Definition swoc_ip.cc:1244
storage_type _raw
Storage for the view pointer.
Definition IPRange.h:713
sa_family_t _family
Range address family.
Definition IPRange.h:714
bool is_ip6() const
Definition IPRange.h:1989
bool load(std::string_view const &text)
Definition swoc_ip.cc:1111
IP4Range const & ip4() const
Definition IPRange.h:1996
sa_family_t family() const
Definition IPRange.h:1993
bool is_ip4() const
Definition IPRange.h:1984
IP6Range _ip6
IPv6 range.
Definition IPRange.h:519
bool operator==(self_type const &that) const
Equality.
Definition swoc_ip.cc:1178
IP4Range _ip4
IPv4 range.
Definition IPRange.h:518
sa_family_t _family
Family of _range.
Definition IPRange.h:523
IP6Range const & ip6() const
Definition IPRange.h:2000
IPRange()=default
Default constructor - construct invalid range.
IPAddr max() const
Definition swoc_ip.cc:1139
IPMask network_mask() const
Definition swoc_ip.cc:1165
IPAddr min() const
Definition swoc_ip.cc:1126
bool empty() const
Definition swoc_ip.cc:1152
An IP address and host_order_port, modeled on an SRV type for DNS.
Definition IPSrv.h:224
bool is_ip4() const
Definition IPSrv.h:572
bool is_ip6() const
Definition IPSrv.h:577
IP4Srv const & ip4() const
Definition IPSrv.h:581
IP6Srv const & ip6() const
Definition IPSrv.h:585
sa_family_t _family
Protocol family.
Definition IPSrv.h:399
IPAddr addr() const
Definition IPSrv.h:560
IPSrv()=default
Default constructor.
constexpr sa_family_t family() const
Definition IPSrv.h:565
self_type & assign(IP4Addr const &addr)
Definition IPSrv.h:621
bool load(swoc::TextView text)
Definition swoc_ip.cc:795
self_type & clear()
Clear the view (become an empty view).
self_type & assign(char *&c_str)
self_type & ltrim_if(F const &pred)
self_type take_prefix_at(char c)
self_type split_suffix_at(char c)
self_type take_prefix(size_t n)
constexpr value_type const * data() const noexcept
For template deduction guides.
Definition ArenaWriter.cc:9
uintmax_t svtou(TextView src, TextView *out, int base)
Definition TextView.cc:81
intmax_t svtoi(TextView src, TextView *out, int base)
Definition TextView.cc:45
bool operator==(IPAddr const &lhs, sockaddr const *sa)
Equality.
Definition swoc_ip.cc:650
MemSpan< T > const & memset(MemSpan< T > const &dst, T const &value)
Definition MemSpan.h:1022
void * memcpy(void *dst, const std::string_view &src)
Case hierarchy.
Definition swoc_meta.h:66
uintmax_t svtou(TextView src, TextView *out, int base)
Definition TextView.cc:81
quad_store_type _quad
By quad.
Definition IPAddr.h:459
word_store_type _store
0 is MSW, 1 is LSW.
Definition IPAddr.h:458
IP4Addr _ip4
IPv4 address (host)
Definition IPAddr.h:645
IP6Addr _ip6
IPv6 address (host)
Definition IPAddr.h:646
bool parse(string_view const &str)
Definition swoc_ip.cc:205
socklen_t size() const
Definition swoc_ip.cc:214
struct sockaddr_in sa4
IPv4.
Definition IPEndpoint.h:41
bool is_ip6() const
Test for IPv6.
Definition IPEndpoint.h:350
static in_port_t & port(sockaddr *sa)
Definition IPEndpoint.h:395
self_type & set_to_loopback(int family)
Definition swoc_ip.cc:270
self_type & set_to_any(int family)
Definition swoc_ip.cc:241
bool is_any() const
Definition swoc_ip.cc:256
static bool tokenize(string_view src, string_view *host=nullptr, string_view *port=nullptr, string_view *rest=nullptr)
Definition swoc_ip.cc:147
static bool assign(sockaddr *dst, sockaddr const *src)
Definition swoc_ip.cc:50
static void invalidate(sockaddr *addr)
Invalidate a sockaddr.
Definition IPEndpoint.h:305
sa_family_t family() const
Definition IPEndpoint.h:355
bool is_loopback() const
Definition swoc_ip.cc:285
bool is_ip4() const
Test for IPv4.
Definition IPEndpoint.h:345
struct sockaddr sa
Generic address.
Definition IPEndpoint.h:40
static string_view family_name(sa_family_t family)
The string name of the address family.
Definition swoc_ip.cc:226
struct sockaddr_in6 sa6
IPv6.
Definition IPEndpoint.h:42
IPEndpoint()
Default construct invalid instance.
Definition IPEndpoint.h:280