Squid Web Cache master
Loading...
Searching...
No Matches
Address.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/* DEBUG: section 14 IP Storage and Handling */
10
11#include "squid.h"
12#include "debug/Stream.h"
13#include "ip/Address.h"
14#include "ip/tools.h"
15#include "util.h"
16
17#include <cassert>
18#include <cstring>
19#if HAVE_ARPA_INET_H
20/* for inet_ntoa() */
21#include <arpa/inet.h>
22#endif
23#if HAVE_WS2TCPIP_H
24// Windows IPv6 definitions
25#include <ws2tcpip.h>
26#endif
27
28// some OS (ie WIndows) define IN6_ADDR_EQUAL instead
29#if !defined(IN6_ARE_ADDR_EQUAL) && _SQUID_WINDOWS_
30#define IN6_ARE_ADDR_EQUAL IN6_ADDR_EQUAL
31#endif
32
33/* Debugging only. Dump the address content when a fatal assert is encountered. */
34#define IASSERT(a,b) \
35 if(!(b)){ printf("assert \"%s\" at line %d\n", a, __LINE__); \
36 printf("Ip::Address invalid? with isIPv4()=%c, isIPv6()=%c\n",(isIPv4()?'T':'F'),(isIPv6()?'T':'F')); \
37 printf("ADDRESS:"); \
38 for(unsigned int i = 0; i < sizeof(mSocketAddr_.sin6_addr); ++i) { \
39 printf(" %x", mSocketAddr_.sin6_addr.s6_addr[i]); \
40 } printf("\n"); assert(b); \
41 }
42
43std::optional<Ip::Address>
44Ip::Address::Parse(const char * const raw)
45{
46 Address tmp;
47 // TODO: Merge with lookupHostIP() after removing DNS lookups from Ip.
48 if (tmp.lookupHostIP(raw, true))
49 return tmp;
50 return std::nullopt;
51}
52
53int
55{
56 uint8_t shift,ipbyte;
57 uint8_t bit,caught;
58 int len = 0;
59 const uint8_t *ptr= mSocketAddr_.sin6_addr.s6_addr;
60
61 /* Let's scan all the bits from Most Significant to Least */
62 /* Until we find an "0" bit. Then, we return */
63 shift=0;
64
65 /* return IPv4 CIDR for any Mapped address */
66 /* Thus only check the mapped bit */
67
68 if ( !isIPv6() ) {
69 shift = 12;
70 }
71
72 for (; shift<sizeof(mSocketAddr_.sin6_addr) ; ++shift) {
73 ipbyte= *(ptr+shift);
74
75 if (ipbyte == 0xFF) {
76 len += 8;
77 continue ; /* A short-cut */
78 }
79
80 for (caught = 0, bit= 7 ; !caught && (bit <= 7); --bit) {
81 caught = ((ipbyte & 0x80) == 0x00); /* Found a '0' at 'bit' ? */
82
83 if (!caught)
84 ++len;
85
86 ipbyte <<= 1;
87 }
88
89 if (caught)
90 break; /* We have found the most significant "0" bit. */
91 }
92
93 return len;
94}
95
96int
98{
99 uint32_t *p1 = (uint32_t*)(&mSocketAddr_.sin6_addr);
100 uint32_t const *p2 = (uint32_t const *)(&mask_addr.mSocketAddr_.sin6_addr);
101 unsigned int blen = sizeof(mSocketAddr_.sin6_addr)/sizeof(uint32_t);
102 unsigned int changes = 0;
103
104 for (unsigned int i = 0; i < blen; ++i) {
105 if ((p1[i] & p2[i]) != p1[i])
106 ++changes;
107
108 p1[i] &= p2[i];
109 }
110
111 return changes;
112}
113
114void
116{
117 const auto addressWords = reinterpret_cast<uint32_t*>(&mSocketAddr_.sin6_addr);
118 const auto maskWords = reinterpret_cast<const uint32_t*>(&mask.mSocketAddr_.sin6_addr);
119 const auto len = sizeof(mSocketAddr_.sin6_addr)/sizeof(uint32_t);
120 for (size_t i = 0; i < len; ++i)
121 addressWords[i] |= ~maskWords[i];
122}
123
124void
126{
127 if (!isLocalhost() && isIPv4())
128 (void)applyMask(mask);
129}
130
131bool
132Ip::Address::applyMask(const unsigned int cidrMask, int mtype)
133{
134 uint8_t clearbits = 0;
135 uint8_t* p = nullptr;
136
137 // validation and short-cuts.
138 if (cidrMask > 128)
139 return false;
140
141 if (cidrMask > 32 && mtype == AF_INET)
142 return false;
143
144 if (cidrMask == 0) {
145 /* CIDR /0 is NoAddr regardless of the IPv4/IPv6 protocol */
146 setNoAddr();
147 return true;
148 }
149
150 clearbits = (uint8_t)( (mtype==AF_INET6?128:32) - cidrMask);
151
152 // short-cut
153 if (clearbits == 0)
154 return true;
155
156 p = (uint8_t*)(&mSocketAddr_.sin6_addr) + 15;
157
158 for (; clearbits>0 && p >= (uint8_t*)&mSocketAddr_.sin6_addr ; --p ) {
159 if (clearbits < 8) {
160 *p &= ((0xFF << clearbits) & 0xFF);
161 clearbits = 0;
162 } else {
163 *p &= 0x00;
164 clearbits -= 8;
165 }
166 }
167
168 return true;
169}
170
171bool
173{
174 return (mSocketAddr_.sin6_port != 0);
175}
176
177bool
179{
180 return IN6_IS_ADDR_V4MAPPED( &mSocketAddr_.sin6_addr );
181}
182
183bool
185{
186 return !isIPv4();
187}
188
189bool
191{
192 return IN6_IS_ADDR_UNSPECIFIED(&mSocketAddr_.sin6_addr) || IN6_ARE_ADDR_EQUAL(&mSocketAddr_.sin6_addr, &v4_anyaddr);
193}
194
196void
198{
199 memset(&mSocketAddr_.sin6_addr, 0, sizeof(struct in6_addr) );
200}
201
203void
205{
206 memset(&mSocketAddr_, 0, sizeof(mSocketAddr_) );
207}
208
209#if _SQUID_AIX_
210// Bug 2885 comment 78 explains.
211// In short AIX has a different netinet/in.h union definition
212const struct in6_addr Ip::Address::v4_localhost = {{{ 0x00000000, 0x00000000, 0x0000ffff, 0x7f000001 }}};
213const struct in6_addr Ip::Address::v4_anyaddr = {{{ 0x00000000, 0x00000000, 0x0000ffff, 0x00000000 }}};
214const struct in6_addr Ip::Address::v4_noaddr = {{{ 0x00000000, 0x00000000, 0x0000ffff, 0xffffffff }}};
215const struct in6_addr Ip::Address::v6_noaddr = {{{ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }}};
216#else
217const struct in6_addr Ip::Address::v4_localhost = {{{
218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01
220 }
221 }
222};
223const struct in6_addr Ip::Address::v4_anyaddr = {{{
224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00
226 }
227 }
228};
229const struct in6_addr Ip::Address::v4_noaddr = {{{
230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
232 }
233 }
234};
235const struct in6_addr Ip::Address::v6_noaddr = {{{
236 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
237 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
238 }
239 }
240};
241#endif
242
243bool
245{
246 if ( isLocalhost() ) {
247 mSocketAddr_.sin6_addr = v4_localhost;
248 return true;
249 }
250
251 if ( isAnyAddr() ) {
252 mSocketAddr_.sin6_addr = v4_anyaddr;
253 return true;
254 }
255
256 if ( isNoAddr() ) {
257 mSocketAddr_.sin6_addr = v4_noaddr;
258 return true;
259 }
260
261 if ( isIPv4())
262 return true;
263
264 // anything non-IPv4 and non-convertable is BAD.
265 return false;
266}
267
268bool
270{
271 return IN6_IS_ADDR_LOOPBACK( &mSocketAddr_.sin6_addr ) || IN6_ARE_ADDR_EQUAL( &mSocketAddr_.sin6_addr, &v4_localhost );
272}
273
274void
276{
277 if (Ip::EnableIpv6) {
278 mSocketAddr_.sin6_addr = in6addr_loopback;
279 mSocketAddr_.sin6_family = AF_INET6;
280 } else {
281 mSocketAddr_.sin6_addr = v4_localhost;
282 mSocketAddr_.sin6_family = AF_INET;
283 }
284}
285
286bool
288{
289 // RFC 4193 the site-local allocated range is fc00::/7
290 // with fd00::/8 as the only currently allocated range (so we test it first).
291 // BUG: as of 2010-02 Linux and BSD define IN6_IS_ADDR_SITELOCAL() to check for fec::/10
292 return mSocketAddr_.sin6_addr.s6_addr[0] == static_cast<uint8_t>(0xfd) ||
293 mSocketAddr_.sin6_addr.s6_addr[0] == static_cast<uint8_t>(0xfc);
294}
295
296bool
298{
299 return mSocketAddr_.sin6_addr.s6_addr[11] == static_cast<uint8_t>(0xff) &&
300 mSocketAddr_.sin6_addr.s6_addr[12] == static_cast<uint8_t>(0xfe);
301}
302
303bool
305{
306 // IFF the address == 0xff..ff (all ones)
307 return IN6_ARE_ADDR_EQUAL( &mSocketAddr_.sin6_addr, &v6_noaddr )
308 || IN6_ARE_ADDR_EQUAL( &mSocketAddr_.sin6_addr, &v4_noaddr );
309}
310
311void
313{
314 memset(&mSocketAddr_.sin6_addr, 0xFF, sizeof(struct in6_addr) );
315 mSocketAddr_.sin6_family = AF_INET6;
316}
317
318bool
319Ip::Address::getReverseString6(char buf[MAX_IPSTRLEN], const struct in6_addr &dat) const
320{
321 char *p = buf;
322 unsigned char const *r = dat.s6_addr;
323
324 /* RFC1886 says: */
325 /* 4321:0:1:2:3:4:567:89ab */
326 /* must be sent */
327 /* b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.ip6.int. */
328
329 /* Work from the binary field. Anything else may have representation changes. */
330 /* The sin6_port and sin6_addr members shall be in network byte order. */
331
332 /* Compile Err: 'Too many arguments for format. */
333
334 for (int i = 15; i >= 0; --i, p+=4) {
335 snprintf(p, 5, "%x.%x.", ((r[i])&0xf), (((r[i])>>4)&0xf) );
336 }
337
338 /* RFC3152 says: */
339 /* ip6.int is now deprecated TLD, use ip6.arpa instead. */
340 snprintf(p,10,"ip6.arpa.");
341
342 return true;
343}
344
345bool
346Ip::Address::getReverseString4(char buf[MAX_IPSTRLEN], const struct in_addr &dat) const
347{
348 unsigned int i = (unsigned int) ntohl(dat.s_addr);
349 snprintf(buf, 32, "%u.%u.%u.%u.in-addr.arpa.",
350 i & 255,
351 (i >> 8) & 255,
352 (i >> 16) & 255,
353 (i >> 24) & 255);
354 return true;
355}
356
357bool
358Ip::Address::getReverseString(char buf[MAX_IPSTRLEN], int show_type) const
359{
360
361 if (show_type == AF_UNSPEC) {
362 show_type = isIPv6() ? AF_INET6 : AF_INET ;
363 }
364
365 if (show_type == AF_INET && isIPv4()) {
366 struct in_addr* tmp = (struct in_addr*)&mSocketAddr_.sin6_addr.s6_addr[12];
367 return getReverseString4(buf, *tmp);
368 } else if ( show_type == AF_INET6 && isIPv6() ) {
369 return getReverseString6(buf, mSocketAddr_.sin6_addr);
370 }
371
372 debugs(14, DBG_CRITICAL, "ERROR: Unable to convert '" << toStr(buf,MAX_IPSTRLEN) << "' to the rDNS type requested.");
373
374 buf[0] = '\0';
375
376 return false;
377}
378
380{
381 setEmpty();
382 lookupHostIP(s, true);
383}
384
385bool
387{
388 return lookupHostIP(s, true);
389}
390
391bool
393{
394 return lookupHostIP(s, false);
395}
396
397bool
398Ip::Address::lookupHostIP(const char *s, bool nodns)
399{
400 struct addrinfo want;
401 memset(&want, 0, sizeof(struct addrinfo));
402 if (nodns) {
403 want.ai_flags = AI_NUMERICHOST; // prevent actual DNS lookups!
404 }
405
406 int err = 0;
407 struct addrinfo *res = nullptr;
408 if ( (err = getaddrinfo(s, nullptr, &want, &res)) != 0) {
409 debugs(14,3, "Given Non-IP '" << s << "': " << gai_strerror(err) );
410 /* free the memory getaddrinfo() dynamically allocated. */
411 if (res)
412 freeaddrinfo(res);
413 return false;
414 }
415
416 struct addrinfo *resHead = res; // we need to free the whole list later
417 if (!Ip::EnableIpv6) {
418 // if we are IPv6-disabled, use first-IPv4 instead of first-IP.
419 struct addrinfo *maybeIpv4 = res;
420 while (maybeIpv4) {
421 if (maybeIpv4->ai_family == AF_INET)
422 break;
423 maybeIpv4 = maybeIpv4->ai_next;
424 }
425 if (maybeIpv4 != nullptr)
426 res = maybeIpv4;
427 // else IPv6-only host, let the caller deal with first-IP anyway.
428 }
429
430 /*
431 * NP: =(sockaddr_*) may alter the port. we don't want that.
432 * all we have been given as input was an IPA.
433 */
434 short portSaved = port();
435 operator=(*res);
436 port(portSaved);
437
438 /* free the memory getaddrinfo() dynamically allocated. */
439 freeaddrinfo(resHead);
440 return true;
441}
442
443Ip::Address::Address(struct sockaddr_in const &s)
444{
445 setEmpty();
446 operator=(s);
447};
448
450Ip::Address::operator =(struct sockaddr_in const &s)
451{
452 map4to6((const in_addr)s.sin_addr, mSocketAddr_.sin6_addr);
453 mSocketAddr_.sin6_port = s.sin_port;
454 mSocketAddr_.sin6_family = AF_INET6;
455 return *this;
456};
457
459Ip::Address::operator =(const struct sockaddr_storage &s)
460{
461 /* some AF_* magic to tell socket types apart and what we need to do */
462 if (s.ss_family == AF_INET6) {
463 memmove(&mSocketAddr_, &s, sizeof(struct sockaddr_in6));
464 } else { // convert it to our storage mapping.
465 struct sockaddr_in *sin = (struct sockaddr_in*)&s;
466 mSocketAddr_.sin6_port = sin->sin_port;
467 map4to6( sin->sin_addr, mSocketAddr_.sin6_addr);
468 }
469 return *this;
470};
471
472Ip::Address::Address(struct sockaddr_in6 const &s)
473{
474 setEmpty();
475 operator=(s);
476};
477
479Ip::Address::operator =(struct sockaddr_in6 const &s)
480{
481 memmove(&mSocketAddr_, &s, sizeof(struct sockaddr_in6));
482 return *this;
483};
484
485Ip::Address::Address(struct in_addr const &s)
486{
487 setEmpty();
488 operator=(s);
489};
490
492Ip::Address::operator =(struct in_addr const &s)
493{
494 map4to6((const in_addr)s, mSocketAddr_.sin6_addr);
495 mSocketAddr_.sin6_family = AF_INET6;
496 return *this;
497};
498
499Ip::Address::Address(struct in6_addr const &s)
500{
501 setEmpty();
502 operator=(s);
503};
504
506Ip::Address::operator =(struct in6_addr const &s)
507{
508 memmove(&mSocketAddr_.sin6_addr, &s, sizeof(struct in6_addr));
509 mSocketAddr_.sin6_family = AF_INET6;
510
511 return *this;
512};
513
514Ip::Address::Address(const struct hostent &s)
515{
516 setEmpty();
517 operator=(s);
518}
519
520bool
521Ip::Address::operator =(const struct hostent &s)
522{
523
524 struct in_addr* ipv4 = nullptr;
525
526 struct in6_addr* ipv6 = nullptr;
527
528 //struct hostent {
529 // char *h_name; /* official name of host */
530 // char **h_aliases; /* alias list */
531 // int h_addrtype; /* host address type */
532 // int h_length; /* length of address */
533 // char **h_addr_list; /* list of addresses */
534 //}
535
536 switch (s.h_addrtype) {
537
538 case AF_INET:
539 ipv4 = (in_addr*)(s.h_addr_list[0]);
540 /* this */
541 operator=(*ipv4);
542 break;
543
544 case AF_INET6:
545 ipv6 = (in6_addr*)(s.h_addr_list[0]);
546 /* this */
547 operator=(*ipv6);
548 break;
549
550 default:
551 IASSERT("false",false);
552 return false;
553 }
554
555 return true;
556}
557
558Ip::Address::Address(const struct addrinfo &s)
559{
560 setEmpty();
561 operator=(s);
562}
563
564bool
565Ip::Address::operator =(const struct addrinfo &s)
566{
567
568 struct sockaddr_in* ipv4 = nullptr;
569
570 struct sockaddr_in6* ipv6 = nullptr;
571
572 //struct addrinfo {
573 // int ai_flags; /* input flags */
574 // int ai_family; /* protocol family for socket */
575 // int ai_socktype; /* socket type */
576 // int ai_protocol; /* protocol for socket */
577 // socklen_t ai_addrlen; /* length of socket-address */
578 // struct sockaddr *ai_addr; /* socket-address for socket */
579 // char *ai_canonname; /* canonical name for service location */
580 // struct addrinfo *ai_next; /* pointer to next in list */
581 //}
582
583 switch (s.ai_family) {
584
585 case AF_INET:
586 ipv4 = (sockaddr_in*)(s.ai_addr);
587 /* this */
588 assert(ipv4);
589 operator=(*ipv4);
590 break;
591
592 case AF_INET6:
593 ipv6 = (sockaddr_in6*)(s.ai_addr);
594 /* this */
595 assert(ipv6);
596 operator=(*ipv6);
597 break;
598
599 case AF_UNSPEC:
600 default:
601 // attempt to handle partially initialised addrinfo.
602 // such as those where data only comes from getsockopt()
603 if (s.ai_addr != nullptr) {
604 if (s.ai_addrlen == sizeof(struct sockaddr_in6)) {
605 operator=(*((struct sockaddr_in6*)s.ai_addr));
606 return true;
607 } else if (s.ai_addrlen == sizeof(struct sockaddr_in)) {
608 operator=(*((struct sockaddr_in*)s.ai_addr));
609 return true;
610 }
611 }
612 return false;
613 }
614
615 return true;
616}
617
618void
619Ip::Address::getAddrInfo(struct addrinfo *&dst, int force) const
620{
621 if (dst == nullptr) {
622 dst = new addrinfo;
623 }
624
625 memset(dst, 0, sizeof(struct addrinfo));
626
627 // set defaults
628 // Mac OS X does not emit a flag indicating the output is numeric (IP address)
629#if _SQUID_APPLE_
630 dst->ai_flags = 0;
631#else
632 dst->ai_flags = AI_NUMERICHOST;
633#endif
634
635 if (dst->ai_socktype == 0)
636 dst->ai_socktype = SOCK_STREAM;
637
638 if (dst->ai_socktype == SOCK_STREAM // implies TCP
639 && dst->ai_protocol == 0)
640 dst->ai_protocol = IPPROTO_TCP;
641
642 if (dst->ai_socktype == SOCK_DGRAM // implies UDP
643 && dst->ai_protocol == 0)
644 dst->ai_protocol = IPPROTO_UDP;
645
646 InitAddr(dst);
647 if (force == AF_INET6 || (force == AF_UNSPEC && isIPv6()) ) {
648 getSockAddr(*((struct sockaddr_in6*)dst->ai_addr));
649
650 dst->ai_addrlen = sizeof(struct sockaddr_in6);
651
652 dst->ai_family = ((struct sockaddr_in6*)dst->ai_addr)->sin6_family;
653
654#if 0
665 dst->ai_protocol = IPPROTO_IPV6;
666#endif
667
668 } else if ( force == AF_INET || (force == AF_UNSPEC && isIPv4()) ) {
669 getSockAddr(*((struct sockaddr_in*)dst->ai_addr));
670
671 dst->ai_addrlen = sizeof(struct sockaddr_in);
672
673 dst->ai_family = ((struct sockaddr_in*)dst->ai_addr)->sin_family;
674 } else {
675 IASSERT("false",false);
676 }
677}
678
679void
680Ip::Address::InitAddr(struct addrinfo *&ai)
681{
682 if (ai == nullptr) {
683 ai = new addrinfo;
684 memset(ai,0,sizeof(struct addrinfo));
685 }
686
687 // remove any existing data.
688 delete reinterpret_cast<struct sockaddr_storage *>(ai->ai_addr);
689
690 ai->ai_addr = reinterpret_cast<struct sockaddr *>(new sockaddr_storage);
691 memset(ai->ai_addr, 0, sizeof(struct sockaddr_storage));
692
693 ai->ai_addrlen = sizeof(struct sockaddr_storage);
694
695}
696
697void
698Ip::Address::FreeAddr(struct addrinfo *&ai)
699{
700 if (ai == nullptr) return;
701
702 delete reinterpret_cast<struct sockaddr_storage *>(ai->ai_addr);
703
704 ai->ai_addr = nullptr;
705
706 ai->ai_addrlen = 0;
707
708 // NP: name fields are NOT allocated at present.
709 delete ai;
710
711 ai = nullptr;
712}
713
714int
716{
717 uint8_t *l = (uint8_t*)mSocketAddr_.sin6_addr.s6_addr;
718 uint8_t *r = (uint8_t*)rhs.mSocketAddr_.sin6_addr.s6_addr;
719
720 // loop a byte-wise compare
721 // NP: match MUST be R-to-L : L-to-R produces inconsistent gt/lt results at varying CIDR
722 // expected difference on CIDR is gt/eq or lt/eq ONLY.
723 for (unsigned int i = 0 ; i < sizeof(mSocketAddr_.sin6_addr) ; ++i) {
724
725 if (l[i] < r[i])
726 return -1;
727
728 if (l[i] > r[i])
729 return 1;
730 }
731
732 return 0;
733}
734
735int
737{
738 return memcmp(this, &rhs, sizeof(*this));
739}
740
741bool
743{
744 return (0 == matchIPAddr(s));
745}
746
747bool
749{
750 return ! ( operator==(s) );
751}
752
753bool
755{
756 if (isAnyAddr() && !rhs.isAnyAddr())
757 return true;
758
759 return (matchIPAddr(rhs) <= 0);
760}
761
762bool
764{
765 if (isNoAddr() && !rhs.isNoAddr())
766 return true;
767
768 return ( matchIPAddr(rhs) >= 0);
769}
770
771bool
773{
774 if (isNoAddr() && !rhs.isNoAddr())
775 return true;
776
777 return ( matchIPAddr(rhs) > 0);
778}
779
780bool
781Ip::Address::operator <(const Ip::Address &rhs) const
782{
783 if (isAnyAddr() && !rhs.isAnyAddr())
784 return true;
785
786 return ( matchIPAddr(rhs) < 0);
787}
788
789unsigned short
791{
792 return ntohs( mSocketAddr_.sin6_port );
793}
794
795unsigned short
796Ip::Address::port(unsigned short prt)
797{
798 mSocketAddr_.sin6_port = htons(prt);
799
800 return prt;
801}
802
803char *
804Ip::Address::toStr(char* buf, const unsigned int blen, int force) const
805{
806 // Ensure we have a buffer.
807 if (buf == nullptr) {
808 return nullptr;
809 }
810
811 /* some external code may have blindly memset a parent. */
812 /* that's okay, our default is known */
813 if ( isAnyAddr() ) {
814 if (isIPv6())
815 memcpy(buf,"::\0", min(static_cast<unsigned int>(3),blen));
816 else if (isIPv4())
817 memcpy(buf,"0.0.0.0\0", min(static_cast<unsigned int>(8),blen));
818 return buf;
819 }
820
821 memset(buf,0,blen); // clear buffer before write
822
823 /* Pure-IPv6 CANNOT be displayed in IPv4 format. */
824 /* However IPv4 CAN. */
825 if ( force == AF_INET && !isIPv4() ) {
826 if ( isIPv6() ) {
827 memcpy(buf, "{!IPv4}\0", min(static_cast<unsigned int>(8),blen));
828 }
829 return buf;
830 }
831
832 if ( force == AF_INET6 || (force == AF_UNSPEC && isIPv6()) ) {
833
834 inet_ntop(AF_INET6, &mSocketAddr_.sin6_addr, buf, blen);
835
836 } else if ( force == AF_INET || (force == AF_UNSPEC && isIPv4()) ) {
837
838 struct in_addr tmp;
839 getInAddr(tmp);
840 inet_ntop(AF_INET, &tmp, buf, blen);
841 } else {
842 debugs(14, DBG_CRITICAL, "WARNING: Corrupt IP Address details OR required to display in unknown format (" <<
843 force << "). accepted={" << AF_UNSPEC << "," << AF_INET << "," << AF_INET6 << "}");
844 fprintf(stderr,"WARNING: Corrupt IP Address details OR required to display in unknown format (%d). accepted={%d,%d,%d} ",
845 force, AF_UNSPEC, AF_INET, AF_INET6);
846 memcpy(buf,"dead:beef::\0", min(static_cast<unsigned int>(13),blen));
847 assert(false);
848 }
849
850 return buf;
851}
852
853unsigned int
854Ip::Address::toHostStr(char *buf, const unsigned int blen) const
855{
856 char *p = buf;
857
858 if (isIPv6() && blen > 0) {
859 *p = '[';
860 ++p;
861 }
862
863 /* 8 being space for [ ] : and port digits */
864 if ( isIPv6() )
865 toStr(p, blen-8, AF_INET6);
866 else
867 toStr(p, blen-8, AF_INET);
868
869 // find the end of the new string
870 while (*p != '\0' && p < buf+blen)
871 ++p;
872
873 if (isIPv6() && p < (buf+blen-1) ) {
874 *p = ']';
875 ++p;
876 }
877
878 /* terminate just in case. */
879 *p = '\0';
880
881 /* return size of buffer now used */
882 return (p - buf);
883}
884
885char *
886Ip::Address::toUrl(char* buf, unsigned int blen) const
887{
888 char *p = buf;
889
890 // Ensure we have a buffer.
891
892 if (buf == nullptr) {
893 return nullptr;
894 }
895
896 p += toHostStr(p, blen);
897
898 if (mSocketAddr_.sin6_port > 0 && p <= (buf+blen-7) ) {
899 // ':port' (short int) needs at most 6 bytes plus 1 for 0-terminator
900 snprintf(p, 7, ":%d", port() );
901 }
902
903 // force a null-terminated string
904 buf[blen-1] = '\0';
905
906 return buf;
907}
908
909bool
910Ip::Address::fromHost(const char *host)
911{
912 setEmpty();
913
914 if (!host)
915 return false;
916
917 if (host[0] != '[')
918 return lookupHostIP(host, true); // no brackets
919
920 /* unwrap a bracketed [presumably IPv6] address, presumably without port */
921
922 const char *start = host + 1;
923 if (!*start)
924 return false; // missing address after an opening bracket
925
926 // XXX: Check that there is a closing bracket and no trailing garbage.
927
928 char *tmp = xstrdup(start); // XXX: Slow. TODO: Bail on huge strings and use an on-stack buffer.
929 tmp[strlen(tmp)-1] = '\0'; // XXX: Wasteful: xstrdup() just did strlen().
930 const bool result = lookupHostIP(tmp, true);
931 xfree(tmp);
932 return result;
933}
934
935void
936Ip::Address::getSockAddr(struct sockaddr_storage &addr, const int family) const
937{
938 struct sockaddr_in *sin = nullptr;
939
940 if ( family == AF_INET && !isIPv4()) {
941 // TODO INET6: caller using the wrong socket type!
942 debugs(14, DBG_CRITICAL, "ERROR: Ip::Address::getSockAddr : Cannot convert non-IPv4 to IPv4. from " << *this);
943 assert(false);
944 }
945
946 if ( family == AF_INET6 || (family == AF_UNSPEC && isIPv6()) ) {
947 struct sockaddr_in6 *ss6 = (struct sockaddr_in6*)&addr;
948 getSockAddr(*ss6);
949 } else if ( family == AF_INET || (family == AF_UNSPEC && isIPv4()) ) {
950 sin = (struct sockaddr_in*)&addr;
951 getSockAddr(*sin);
952 } else {
953 IASSERT("false",false);
954 }
955}
956
957void
958Ip::Address::getSockAddr(struct sockaddr_in &buf) const
959{
960 if ( isIPv4() ) {
961 buf.sin_family = AF_INET;
962 buf.sin_port = mSocketAddr_.sin6_port;
963 map6to4( mSocketAddr_.sin6_addr, buf.sin_addr);
964 } else {
965 debugs(14, DBG_CRITICAL, "ERROR: Ip::Address::getSockAddr : Cannot convert non-IPv4 to IPv4. from " << *this );
966
967 memset(&buf,0xFFFFFFFF,sizeof(struct sockaddr_in));
968 assert(false);
969 }
970
971#if HAVE_SIN_LEN_IN_SAI
972 /* not all OS have this field, BUT when they do it can be a problem if set wrong */
973 buf.sin_len = sizeof(struct sockaddr_in);
974#endif
975}
976
977void
978Ip::Address::getSockAddr(struct sockaddr_in6 &buf) const
979{
980 memmove(&buf, &mSocketAddr_, sizeof(struct sockaddr_in6));
981 /* maintain address family. It may have changed inside us. */
982 buf.sin6_family = AF_INET6;
983
984#if HAVE_SIN6_LEN_IN_SAI
985 /* not all OS have this field, BUT when they do it can be a problem if set wrong */
986 buf.sin6_len = sizeof(struct sockaddr_in6);
987#endif
988}
989
990void
991Ip::Address::map4to6(const struct in_addr &in, struct in6_addr &out) const
992{
993 /* check for special cases */
994
995 if ( in.s_addr == 0x00000000) {
996 /* ANYADDR */
997 out = v4_anyaddr;
998 } else if ( in.s_addr == 0xFFFFFFFF) {
999 /* NOADDR */
1000 out = v4_noaddr;
1001 } else {
1002 /* general */
1003 out = v4_anyaddr;
1004 out.s6_addr[12] = ((uint8_t *)&in.s_addr)[0];
1005 out.s6_addr[13] = ((uint8_t *)&in.s_addr)[1];
1006 out.s6_addr[14] = ((uint8_t *)&in.s_addr)[2];
1007 out.s6_addr[15] = ((uint8_t *)&in.s_addr)[3];
1008 }
1009}
1010
1011void
1012Ip::Address::map6to4(const struct in6_addr &in, struct in_addr &out) const
1013{
1014 /* ANYADDR */
1015 /* NOADDR */
1016 /* general */
1017
1018 memset(&out, 0, sizeof(struct in_addr));
1019 ((uint8_t *)&out.s_addr)[0] = in.s6_addr[12];
1020 ((uint8_t *)&out.s_addr)[1] = in.s6_addr[13];
1021 ((uint8_t *)&out.s_addr)[2] = in.s6_addr[14];
1022 ((uint8_t *)&out.s_addr)[3] = in.s6_addr[15];
1023}
1024
1025void
1026Ip::Address::getInAddr(struct in6_addr &buf) const
1027{
1028 memmove(&buf, &mSocketAddr_.sin6_addr, sizeof(struct in6_addr));
1029}
1030
1031bool
1032Ip::Address::getInAddr(struct in_addr &buf) const
1033{
1034 if ( isIPv4() ) {
1035 map6to4(mSocketAddr_.sin6_addr, buf);
1036 return true;
1037 }
1038
1039 // default:
1040 // non-compatible IPv6 Pure Address
1041
1042 debugs(14, DBG_IMPORTANT, "ERROR: Ip::Address::getInAddr : Cannot convert non-IPv4 to IPv4. IPA=" << *this);
1043 memset(&buf,0xFFFFFFFF,sizeof(struct in_addr));
1044 assert(false);
1045 return false;
1046}
1047
bool operator==(const PoolingAllocator< L > &, const PoolingAllocator< R > &) noexcept
#define assert(EX)
Definition assert.h:17
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition Address.cc:804
void map4to6(const struct in_addr &src, struct in6_addr &dest) const
Definition Address.cc:991
bool isSiteLocal6() const
Definition Address.cc:287
void setEmpty()
Fast reset of the stored content to what would be after default constructor.
Definition Address.cc:204
static void InitAddr(struct addrinfo *&ai)
Definition Address.cc:680
bool setIPv4()
Definition Address.cc:244
void getSockAddr(struct sockaddr_storage &addr, const int family) const
Definition Address.cc:936
bool operator==(Address const &s) const
Definition Address.cc:742
void setLocalhost()
Definition Address.cc:275
bool isLocalhost() const
Definition Address.cc:269
unsigned int toHostStr(char *buf, const unsigned int len) const
Definition Address.cc:854
bool operator>(Address const &rhs) const
Definition Address.cc:772
bool isSockAddr() const
Definition Address.cc:172
int compareWhole(const Ip::Address &rhs) const
Definition Address.cc:736
static void FreeAddr(struct addrinfo *&ai)
Definition Address.cc:698
bool lookupHostIP(const char *s, bool nodns)
Definition Address.cc:398
static std::optional< Address > Parse(const char *)
Definition Address.cc:44
bool getReverseString6(char buf[MAX_IPSTRLEN], const struct in6_addr &dat) const
Definition Address.cc:319
void getAddrInfo(struct addrinfo *&ai, int force=AF_UNSPEC) const
Definition Address.cc:619
bool operator>=(Address const &rhs) const
Definition Address.cc:763
bool GetHostByName(const char *s)
Definition Address.cc:392
void applyClientMask(const Address &mask)
Definition Address.cc:125
bool isIPv4() const
Definition Address.cc:178
bool getReverseString4(char buf[MAX_IPSTRLEN], const struct in_addr &dat) const
Definition Address.cc:346
bool fromHost(const char *hostWithoutPort)
Definition Address.cc:910
int matchIPAddr(const Address &rhs) const
Definition Address.cc:715
struct sockaddr_in6 mSocketAddr_
Definition Address.h:355
void turnMaskedBitsOn(const Address &mask)
Definition Address.cc:115
static const struct in6_addr v6_noaddr
Definition Address.h:370
bool isSiteLocalAuto() const
Definition Address.cc:297
bool operator<(Address const &rhs) const
Definition Address.cc:781
bool operator!=(Address const &s) const
Definition Address.cc:748
bool isNoAddr() const
Definition Address.cc:304
static const struct in6_addr v4_noaddr
Definition Address.h:369
bool isAnyAddr() const
Definition Address.cc:190
bool isIPv6() const
Definition Address.cc:184
bool getReverseString(char buf[MAX_IPSTRLEN], int show_type=AF_UNSPEC) const
Definition Address.cc:358
void setNoAddr()
Definition Address.cc:312
Address & operator=(struct sockaddr_in const &s)
Definition Address.cc:450
char * toUrl(char *buf, unsigned int len) const
Definition Address.cc:886
bool getInAddr(struct in_addr &) const
Definition Address.cc:1032
int applyMask(const Address &mask)
Definition Address.cc:97
int cidr() const
Definition Address.cc:54
void setAnyAddr()
NOTE: Does NOT clear the Port stored. Only the Address and Type.
Definition Address.cc:197
bool operator<=(Address const &rhs) const
Definition Address.cc:754
static const struct in6_addr v4_localhost
Definition Address.h:367
unsigned short port() const
Definition Address.cc:790
static const struct in6_addr v4_anyaddr
Definition Address.h:368
void map6to4(const struct in6_addr &src, struct in_addr &dest) const
Definition Address.cc:1012
A const & min(A const &lhs, A const &rhs)
#define DBG_IMPORTANT
Definition Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
#define DBG_CRITICAL
Definition Stream.h:37
static int port
#define IASSERT(a, b)
Definition Address.cc:34
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition forward.h:25
Definition Xaction.cc:137
#define xfree
#define xstrdup
int unsigned int
Definition stub_fd.cc:19