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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors