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