]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ip/Address.cc
Maintenance: Removed most NULLs using modernize-use-nullptr (#1075)
[thirdparty/squid.git] / src / ip / Address.cc
CommitLineData
41d93087 1/*
bf95c10a 2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
bbc27441
AJ
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.
41d93087 7 */
bbc27441
AJ
8
9/* DEBUG: section 14 IP Storage and Handling */
10
f7f3304a 11#include "squid.h"
675b8408 12#include "debug/Stream.h"
96d89ea0 13#include "ip/Address.h"
055421ee 14#include "ip/tools.h"
1ef0b9ce
AJ
15#include "util.h"
16
074d6a40
AJ
17#include <cassert>
18#include <cstring>
41d93087 19#if HAVE_ARPA_INET_H
489520a9
AJ
20/* for inet_ntoa() */
21#include <arpa/inet.h>
41d93087 22#endif
760da772
AJ
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
41d93087 32
41d93087 33/* Debugging only. Dump the address content when a fatal assert is encountered. */
41d93087 34#define IASSERT(a,b) \
f53969cc
SM
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 }
41d93087 42
41d93087 43int
4dd643d5 44Ip::Address::cidr() const
41d93087 45{
760da772 46 uint8_t shift,ipbyte;
41d93087 47 uint8_t bit,caught;
48 int len = 0;
4dd643d5 49 const uint8_t *ptr= mSocketAddr_.sin6_addr.s6_addr;
41d93087 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
41d93087 55 /* return IPv4 CIDR for any Mapped address */
56 /* Thus only check the mapped bit */
57
4dd643d5 58 if ( !isIPv6() ) {
41d93087 59 shift = 12;
60 }
61
4dd643d5 62 for (; shift<sizeof(mSocketAddr_.sin6_addr) ; ++shift) {
760da772 63 ipbyte= *(ptr+shift);
41d93087 64
760da772 65 if (ipbyte == 0xFF) {
41d93087 66 len += 8;
67 continue ; /* A short-cut */
68 }
69
9e167fa2 70 for (caught = 0, bit= 7 ; !caught && (bit <= 7); --bit) {
760da772 71 caught = ((ipbyte & 0x80) == 0x00); /* Found a '0' at 'bit' ? */
41d93087 72
73 if (!caught)
d7ae3534 74 ++len;
41d93087 75
760da772 76 ipbyte <<= 1;
41d93087 77 }
78
79 if (caught)
80 break; /* We have found the most significant "0" bit. */
81 }
82
83 return len;
84}
85
881c4733 86int
4dd643d5 87Ip::Address::applyMask(Ip::Address const &mask_addr)
41d93087 88{
4dd643d5
AJ
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);
41d93087 92 unsigned int changes = 0;
93
d7ae3534 94 for (unsigned int i = 0; i < blen; ++i) {
26ac0430 95 if ((p1[i] & p2[i]) != p1[i])
d7ae3534 96 ++changes;
41d93087 97
98 p1[i] &= p2[i];
99 }
100
41d93087 101 return changes;
102}
103
36c774f7
EB
104void
105Ip::Address::applyClientMask(const Address &mask)
106{
107 if (!isLocalhost() && isIPv4())
108 (void)applyMask(mask);
109}
110
b7ac5457 111bool
4dd643d5 112Ip::Address::applyMask(const unsigned int cidrMask, int mtype)
41d93087 113{
114 uint8_t clearbits = 0;
aee3523a 115 uint8_t* p = nullptr;
41d93087 116
41d93087 117 // validation and short-cuts.
4dd643d5 118 if (cidrMask > 128)
41d93087 119 return false;
120
4dd643d5 121 if (cidrMask > 32 && mtype == AF_INET)
41d93087 122 return false;
123
4dd643d5 124 if (cidrMask == 0) {
2c1b9590 125 /* CIDR /0 is NoAddr regardless of the IPv4/IPv6 protocol */
4dd643d5 126 setNoAddr();
2c1b9590
AJ
127 return true;
128 }
129
4dd643d5 130 clearbits = (uint8_t)( (mtype==AF_INET6?128:32) - cidrMask);
41d93087 131
132 // short-cut
26ac0430 133 if (clearbits == 0)
41d93087 134 return true;
135
4dd643d5 136 p = (uint8_t*)(&mSocketAddr_.sin6_addr) + 15;
41d93087 137
4dd643d5 138 for (; clearbits>0 && p >= (uint8_t*)&mSocketAddr_.sin6_addr ; --p ) {
26ac0430 139 if (clearbits < 8) {
41d93087 140 *p &= ((0xFF << clearbits) & 0xFF);
141 clearbits = 0;
142 } else {
143 *p &= 0x00;
144 clearbits -= 8;
145 }
146 }
147
148 return true;
149}
150
b7ac5457 151bool
4dd643d5 152Ip::Address::isSockAddr() const
41d93087 153{
4dd643d5 154 return (mSocketAddr_.sin6_port != 0);
41d93087 155}
156
b7ac5457 157bool
4dd643d5 158Ip::Address::isIPv4() const
41d93087 159{
4dd643d5 160 return IN6_IS_ADDR_V4MAPPED( &mSocketAddr_.sin6_addr );
41d93087 161}
162
b7ac5457 163bool
4dd643d5 164Ip::Address::isIPv6() const
41d93087 165{
4dd643d5 166 return !isIPv4();
41d93087 167}
168
b7ac5457 169bool
4dd643d5 170Ip::Address::isAnyAddr() const
41d93087 171{
4dd643d5 172 return IN6_IS_ADDR_UNSPECIFIED(&mSocketAddr_.sin6_addr) || IN6_ARE_ADDR_EQUAL(&mSocketAddr_.sin6_addr, &v4_anyaddr);
41d93087 173}
174
2f8abb64 175/// NOTE: Does NOT clear the Port stored. Only the Address and Type.
b7ac5457 176void
4dd643d5 177Ip::Address::setAnyAddr()
41d93087 178{
4dd643d5 179 memset(&mSocketAddr_.sin6_addr, 0, sizeof(struct in6_addr) );
41d93087 180}
181
b7ac5457
AJ
182/// NOTE: completely empties the Ip::Address structure. Address, Port, Type, everything.
183void
4dd643d5 184Ip::Address::setEmpty()
41d93087 185{
4dd643d5 186 memset(&mSocketAddr_, 0, sizeof(mSocketAddr_) );
41d93087 187}
188
349a322f 189#if _SQUID_AIX_
d48a52bf
A
190// Bug 2885 comment 78 explains.
191// In short AIX has a different netinet/in.h union definition
349a322f
AJ
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
f53969cc
SM
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 }
c0248e14 202};
f53969cc
SM
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 }
c0248e14 208};
f53969cc
SM
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 }
0eb08770 214};
f53969cc
SM
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 }
c0248e14 220};
349a322f 221#endif
41d93087 222
b7ac5457 223bool
4dd643d5 224Ip::Address::setIPv4()
c0248e14 225{
4dd643d5
AJ
226 if ( isLocalhost() ) {
227 mSocketAddr_.sin6_addr = v4_localhost;
41d93087 228 return true;
229 }
41d93087 230
4dd643d5
AJ
231 if ( isAnyAddr() ) {
232 mSocketAddr_.sin6_addr = v4_anyaddr;
41d93087 233 return true;
234 }
235
4dd643d5
AJ
236 if ( isNoAddr() ) {
237 mSocketAddr_.sin6_addr = v4_noaddr;
0906f01d
CT
238 return true;
239 }
240
4dd643d5 241 if ( isIPv4())
41d93087 242 return true;
243
244 // anything non-IPv4 and non-convertable is BAD.
245 return false;
41d93087 246}
247
b7ac5457 248bool
4dd643d5 249Ip::Address::isLocalhost() const
41d93087 250{
4dd643d5 251 return IN6_IS_ADDR_LOOPBACK( &mSocketAddr_.sin6_addr ) || IN6_ARE_ADDR_EQUAL( &mSocketAddr_.sin6_addr, &v4_localhost );
41d93087 252}
253
b7ac5457 254void
4dd643d5 255Ip::Address::setLocalhost()
41d93087 256{
055421ee 257 if (Ip::EnableIpv6) {
4dd643d5
AJ
258 mSocketAddr_.sin6_addr = in6addr_loopback;
259 mSocketAddr_.sin6_family = AF_INET6;
055421ee 260 } else {
4dd643d5
AJ
261 mSocketAddr_.sin6_addr = v4_localhost;
262 mSocketAddr_.sin6_family = AF_INET;
055421ee 263 }
41d93087 264}
265
b7ac5457 266bool
4dd643d5 267Ip::Address::isSiteLocal6() const
a98c2da5 268{
dd19b634
AJ
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
4dd643d5
AJ
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);
a98c2da5
AJ
274}
275
b7ac5457 276bool
4dd643d5 277Ip::Address::isSiteLocalAuto() const
a98c2da5 278{
b6a91265
AJ
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);
a98c2da5
AJ
281}
282
b7ac5457 283bool
4dd643d5 284Ip::Address::isNoAddr() const
41d93087 285{
286 // IFF the address == 0xff..ff (all ones)
4dd643d5
AJ
287 return IN6_ARE_ADDR_EQUAL( &mSocketAddr_.sin6_addr, &v6_noaddr )
288 || IN6_ARE_ADDR_EQUAL( &mSocketAddr_.sin6_addr, &v4_noaddr );
41d93087 289}
290
b7ac5457 291void
4dd643d5 292Ip::Address::setNoAddr()
41d93087 293{
4dd643d5
AJ
294 memset(&mSocketAddr_.sin6_addr, 0xFF, sizeof(struct in6_addr) );
295 mSocketAddr_.sin6_family = AF_INET6;
41d93087 296}
297
b7ac5457 298bool
4dd643d5 299Ip::Address::getReverseString6(char buf[MAX_IPSTRLEN], const struct in6_addr &dat) const
41d93087 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
5e263176 314 for (int i = 15; i >= 0; --i, p+=4) {
41d93087 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}
41d93087 324
b7ac5457 325bool
4dd643d5 326Ip::Address::getReverseString4(char buf[MAX_IPSTRLEN], const struct in_addr &dat) const
41d93087 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
b7ac5457 337bool
4dd643d5 338Ip::Address::getReverseString(char buf[MAX_IPSTRLEN], int show_type) const
41d93087 339{
340
26ac0430 341 if (show_type == AF_UNSPEC) {
4dd643d5 342 show_type = isIPv6() ? AF_INET6 : AF_INET ;
41d93087 343 }
344
4dd643d5
AJ
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);
41d93087 350 }
351
d816f28d 352 debugs(14, DBG_CRITICAL, "ERROR: Unable to convert '" << toStr(buf,MAX_IPSTRLEN) << "' to the rDNS type requested.");
41d93087 353
354 buf[0] = '\0';
355
356 return false;
357}
358
b7ac5457 359Ip::Address::Address(const char*s)
41d93087 360{
4dd643d5
AJ
361 setEmpty();
362 lookupHostIP(s, true);
41d93087 363}
364
b7ac5457
AJ
365bool
366Ip::Address::operator =(const char* s)
41d93087 367{
4dd643d5 368 return lookupHostIP(s, true);
41d93087 369}
370
b7ac5457
AJ
371bool
372Ip::Address::GetHostByName(const char* s)
41d93087 373{
4dd643d5 374 return lookupHostIP(s, false);
41d93087 375}
376
b7ac5457 377bool
4dd643d5 378Ip::Address::lookupHostIP(const char *s, bool nodns)
41d93087 379{
41d93087 380 struct addrinfo want;
41d93087 381 memset(&want, 0, sizeof(struct addrinfo));
26ac0430 382 if (nodns) {
41d93087 383 want.ai_flags = AI_NUMERICHOST; // prevent actual DNS lookups!
384 }
41d93087 385
4dd643d5 386 int err = 0;
aee3523a
AR
387 struct addrinfo *res = nullptr;
388 if ( (err = getaddrinfo(s, nullptr, &want, &res)) != 0) {
bf95c10a 389 debugs(14,3, "Given Non-IP '" << s << "': " << gai_strerror(err) );
27bc2077 390 /* free the memory getaddrinfo() dynamically allocated. */
4dd643d5 391 if (res)
27bc2077 392 freeaddrinfo(res);
41d93087 393 return false;
394 }
395
8b96fe86 396 struct addrinfo *resHead = res; // we need to free the whole list later
430b5d15
AJ
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 }
aee3523a 405 if (maybeIpv4 != nullptr)
430b5d15
AJ
406 res = maybeIpv4;
407 // else IPv6-only host, let the caller deal with first-IP anyway.
408 }
409
41d93087 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 */
4dd643d5 414 short portSaved = port();
41d93087 415 operator=(*res);
4dd643d5 416 port(portSaved);
41d93087 417
27bc2077 418 /* free the memory getaddrinfo() dynamically allocated. */
8b96fe86 419 freeaddrinfo(resHead);
41d93087 420 return true;
421}
422
b7ac5457 423Ip::Address::Address(struct sockaddr_in const &s)
41d93087 424{
4dd643d5 425 setEmpty();
41d93087 426 operator=(s);
427};
428
b7ac5457
AJ
429Ip::Address &
430Ip::Address::operator =(struct sockaddr_in const &s)
41d93087 431{
4dd643d5
AJ
432 map4to6((const in_addr)s.sin_addr, mSocketAddr_.sin6_addr);
433 mSocketAddr_.sin6_port = s.sin_port;
434 mSocketAddr_.sin6_family = AF_INET6;
41d93087 435 return *this;
436};
437
b7ac5457
AJ
438Ip::Address &
439Ip::Address::operator =(const struct sockaddr_storage &s)
0e1a47f0 440{
0e1a47f0 441 /* some AF_* magic to tell socket types apart and what we need to do */
26ac0430 442 if (s.ss_family == AF_INET6) {
9f15dc43 443 memmove(&mSocketAddr_, &s, sizeof(struct sockaddr_in6));
26ac0430 444 } else { // convert it to our storage mapping.
0e1a47f0 445 struct sockaddr_in *sin = (struct sockaddr_in*)&s;
4dd643d5
AJ
446 mSocketAddr_.sin6_port = sin->sin_port;
447 map4to6( sin->sin_addr, mSocketAddr_.sin6_addr);
0e1a47f0 448 }
0e1a47f0
AJ
449 return *this;
450};
451
b7ac5457 452Ip::Address::Address(struct sockaddr_in6 const &s)
41d93087 453{
4dd643d5 454 setEmpty();
41d93087 455 operator=(s);
456};
457
b7ac5457
AJ
458Ip::Address &
459Ip::Address::operator =(struct sockaddr_in6 const &s)
41d93087 460{
9f15dc43 461 memmove(&mSocketAddr_, &s, sizeof(struct sockaddr_in6));
41d93087 462 return *this;
463};
41d93087 464
b7ac5457 465Ip::Address::Address(struct in_addr const &s)
41d93087 466{
4dd643d5 467 setEmpty();
41d93087 468 operator=(s);
469};
470
b7ac5457
AJ
471Ip::Address &
472Ip::Address::operator =(struct in_addr const &s)
41d93087 473{
4dd643d5
AJ
474 map4to6((const in_addr)s, mSocketAddr_.sin6_addr);
475 mSocketAddr_.sin6_family = AF_INET6;
41d93087 476 return *this;
477};
478
b7ac5457 479Ip::Address::Address(struct in6_addr const &s)
41d93087 480{
4dd643d5 481 setEmpty();
41d93087 482 operator=(s);
483};
484
b7ac5457
AJ
485Ip::Address &
486Ip::Address::operator =(struct in6_addr const &s)
41d93087 487{
9f15dc43 488 memmove(&mSocketAddr_.sin6_addr, &s, sizeof(struct in6_addr));
4dd643d5 489 mSocketAddr_.sin6_family = AF_INET6;
b5587d15 490
41d93087 491 return *this;
492};
41d93087 493
b7ac5457 494Ip::Address::Address(const struct hostent &s)
41d93087 495{
4dd643d5 496 setEmpty();
41d93087 497 operator=(s);
498}
499
b7ac5457
AJ
500bool
501Ip::Address::operator =(const struct hostent &s)
41d93087 502{
503
aee3523a 504 struct in_addr* ipv4 = nullptr;
41d93087 505
aee3523a 506 struct in6_addr* ipv6 = nullptr;
41d93087 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
26ac0430 516 switch (s.h_addrtype) {
41d93087 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]);
41d93087 526 /* this */
527 operator=(*ipv6);
41d93087 528 break;
529
530 default:
26ac0430
AJ
531 IASSERT("false",false);
532 return false;
41d93087 533 }
534
535 return true;
536}
537
b7ac5457 538Ip::Address::Address(const struct addrinfo &s)
41d93087 539{
4dd643d5 540 setEmpty();
41d93087 541 operator=(s);
542}
543
b7ac5457
AJ
544bool
545Ip::Address::operator =(const struct addrinfo &s)
41d93087 546{
547
aee3523a 548 struct sockaddr_in* ipv4 = nullptr;
41d93087 549
aee3523a 550 struct sockaddr_in6* ipv6 = nullptr;
41d93087 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
26ac0430 563 switch (s.ai_family) {
41d93087 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);
41d93087 574 /* this */
575 assert(ipv6);
576 operator=(*ipv6);
41d93087 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()
aee3523a 583 if (s.ai_addr != nullptr) {
26ac0430 584 if (s.ai_addrlen == sizeof(struct sockaddr_in6)) {
41d93087 585 operator=(*((struct sockaddr_in6*)s.ai_addr));
586 return true;
055421ee
AJ
587 } else if (s.ai_addrlen == sizeof(struct sockaddr_in)) {
588 operator=(*((struct sockaddr_in*)s.ai_addr));
589 return true;
590 }
41d93087 591 }
592 return false;
593 }
594
595 return true;
596}
597
b7ac5457 598void
4dd643d5 599Ip::Address::getAddrInfo(struct addrinfo *&dst, int force) const
41d93087 600{
aee3523a 601 if (dst == nullptr) {
41d93087 602 dst = new addrinfo;
603 }
604
605 memset(dst, 0, sizeof(struct addrinfo));
606
607 // set defaults
3db830d3
AJ
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
41d93087 612 dst->ai_flags = AI_NUMERICHOST;
3db830d3 613#endif
41d93087 614
26ac0430 615 if (dst->ai_socktype == 0)
41d93087 616 dst->ai_socktype = SOCK_STREAM;
617
26ac0430 618 if (dst->ai_socktype == SOCK_STREAM // implies TCP
41d93087 619 && dst->ai_protocol == 0)
620 dst->ai_protocol = IPPROTO_TCP;
621
26ac0430 622 if (dst->ai_socktype == SOCK_DGRAM // implies UDP
41d93087 623 && dst->ai_protocol == 0)
624 dst->ai_protocol = IPPROTO_UDP;
625
4dd643d5 626 if (force == AF_INET6 || (force == AF_UNSPEC && Ip::EnableIpv6 && isIPv6()) ) {
41d93087 627 dst->ai_addr = (struct sockaddr*)new sockaddr_in6;
628
629 memset(dst->ai_addr,0,sizeof(struct sockaddr_in6));
630
4dd643d5 631 getSockAddr(*((struct sockaddr_in6*)dst->ai_addr));
41d93087 632
633 dst->ai_addrlen = sizeof(struct sockaddr_in6);
634
635 dst->ai_family = ((struct sockaddr_in6*)dst->ai_addr)->sin6_family;
9d92af86
AJ
636
637#if 0
638 /**
639 * Enable only if you must and please report to squid-dev if you find a need for this.
640 *
641 * Vista may need this to cope with dual-stack (unsetting IP6_V6ONLY).
642 * http://msdn.microsoft.com/en-us/library/ms738574(VS.85).aspx
643 * Linux appears to only do some things when its present.
644 * (93) Bad Protocol
645 * FreeBSD dies horribly when using dual-stack with it set.
646 * (43) Protocol not supported
647 */
41d93087 648 dst->ai_protocol = IPPROTO_IPV6;
9d92af86
AJ
649#endif
650
4dd643d5 651 } else if ( force == AF_INET || (force == AF_UNSPEC && isIPv4()) ) {
41d93087 652
055421ee 653 dst->ai_addr = (struct sockaddr*)new sockaddr_in;
41d93087 654
055421ee 655 memset(dst->ai_addr,0,sizeof(struct sockaddr_in));
41d93087 656
4dd643d5 657 getSockAddr(*((struct sockaddr_in*)dst->ai_addr));
41d93087 658
055421ee 659 dst->ai_addrlen = sizeof(struct sockaddr_in);
41d93087 660
055421ee
AJ
661 dst->ai_family = ((struct sockaddr_in*)dst->ai_addr)->sin_family;
662 } else {
663 IASSERT("false",false);
664 }
41d93087 665}
666
b7ac5457 667void
851614a8 668Ip::Address::InitAddr(struct addrinfo *&ai)
41d93087 669{
aee3523a 670 if (ai == nullptr) {
41d93087 671 ai = new addrinfo;
672 memset(ai,0,sizeof(struct addrinfo));
673 }
674
675 // remove any existing data.
26ac0430 676 if (ai->ai_addr) delete ai->ai_addr;
41d93087 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
b7ac5457 685void
851614a8 686Ip::Address::FreeAddr(struct addrinfo *&ai)
41d93087 687{
aee3523a 688 if (ai == nullptr) return;
41d93087 689
26ac0430 690 if (ai->ai_addr) delete ai->ai_addr;
41d93087 691
aee3523a 692 ai->ai_addr = nullptr;
41d93087 693
694 ai->ai_addrlen = 0;
695
696 // NP: name fields are NOT allocated at present.
697 delete ai;
698
aee3523a 699 ai = nullptr;
41d93087 700}
701
b7ac5457
AJ
702int
703Ip::Address::matchIPAddr(const Ip::Address &rhs) const
41d93087 704{
4dd643d5
AJ
705 uint8_t *l = (uint8_t*)mSocketAddr_.sin6_addr.s6_addr;
706 uint8_t *r = (uint8_t*)rhs.mSocketAddr_.sin6_addr.s6_addr;
41d93087 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.
4dd643d5 711 for (unsigned int i = 0 ; i < sizeof(mSocketAddr_.sin6_addr) ; ++i) {
41d93087 712
26ac0430 713 if (l[i] < r[i])
41d93087 714 return -1;
715
26ac0430 716 if (l[i] > r[i])
41d93087 717 return 1;
718 }
719
720 return 0;
721}
722
a67d2b2e
AR
723int
724Ip::Address::compareWhole(const Ip::Address &rhs) const
607a7bd4
AR
725{
726 return memcmp(this, &rhs, sizeof(*this));
727}
728
b7ac5457
AJ
729bool
730Ip::Address::operator ==(const Ip::Address &s) const
41d93087 731{
732 return (0 == matchIPAddr(s));
733}
734
b7ac5457
AJ
735bool
736Ip::Address::operator !=(const Ip::Address &s) const
41d93087 737{
738 return ! ( operator==(s) );
739}
740
b7ac5457
AJ
741bool
742Ip::Address::operator <=(const Ip::Address &rhs) const
41d93087 743{
4dd643d5 744 if (isAnyAddr() && !rhs.isAnyAddr())
41d93087 745 return true;
746
747 return (matchIPAddr(rhs) <= 0);
748}
749
b7ac5457
AJ
750bool
751Ip::Address::operator >=(const Ip::Address &rhs) const
41d93087 752{
4dd643d5 753 if (isNoAddr() && !rhs.isNoAddr())
41d93087 754 return true;
755
756 return ( matchIPAddr(rhs) >= 0);
757}
758
b7ac5457
AJ
759bool
760Ip::Address::operator >(const Ip::Address &rhs) const
41d93087 761{
4dd643d5 762 if (isNoAddr() && !rhs.isNoAddr())
41d93087 763 return true;
764
765 return ( matchIPAddr(rhs) > 0);
766}
767
b7ac5457
AJ
768bool
769Ip::Address::operator <(const Ip::Address &rhs) const
41d93087 770{
4dd643d5 771 if (isAnyAddr() && !rhs.isAnyAddr())
41d93087 772 return true;
773
774 return ( matchIPAddr(rhs) < 0);
775}
776
f45dd259 777unsigned short
4dd643d5 778Ip::Address::port() const
41d93087 779{
4dd643d5 780 return ntohs( mSocketAddr_.sin6_port );
41d93087 781}
782
f45dd259 783unsigned short
4dd643d5 784Ip::Address::port(unsigned short prt)
41d93087 785{
4dd643d5 786 mSocketAddr_.sin6_port = htons(prt);
41d93087 787
788 return prt;
789}
790
b7ac5457 791char *
4dd643d5 792Ip::Address::toStr(char* buf, const unsigned int blen, int force) const
41d93087 793{
794 // Ensure we have a buffer.
aee3523a
AR
795 if (buf == nullptr) {
796 return nullptr;
41d93087 797 }
798
799 /* some external code may have blindly memset a parent. */
2f8abb64 800 /* that's okay, our default is known */
4dd643d5
AJ
801 if ( isAnyAddr() ) {
802 if (isIPv6())
8ea75675 803 memcpy(buf,"::\0", min(static_cast<unsigned int>(3),blen));
4dd643d5 804 else if (isIPv4())
8ea75675 805 memcpy(buf,"0.0.0.0\0", min(static_cast<unsigned int>(8),blen));
41d93087 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. */
4dd643d5
AJ
813 if ( force == AF_INET && !isIPv4() ) {
814 if ( isIPv6() ) {
1dc746da 815 memcpy(buf, "{!IPv4}\0", min(static_cast<unsigned int>(8),blen));
41d93087 816 }
817 return buf;
818 }
819
4dd643d5 820 if ( force == AF_INET6 || (force == AF_UNSPEC && isIPv6()) ) {
41d93087 821
4dd643d5 822 inet_ntop(AF_INET6, &mSocketAddr_.sin6_addr, buf, blen);
41d93087 823
4dd643d5 824 } else if ( force == AF_INET || (force == AF_UNSPEC && isIPv4()) ) {
41d93087 825
826 struct in_addr tmp;
4dd643d5 827 getInAddr(tmp);
27bc2077 828 inet_ntop(AF_INET, &tmp, buf, blen);
41d93087 829 } else {
fa84c01d 830 debugs(14, DBG_CRITICAL, "WARNING: Corrupt IP Address details OR required to display in unknown format (" <<
26ac0430 831 force << "). accepted={" << AF_UNSPEC << "," << AF_INET << "," << AF_INET6 << "}");
41d93087 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);
1dc746da 834 memcpy(buf,"dead:beef::\0", min(static_cast<unsigned int>(13),blen));
41d93087 835 assert(false);
836 }
837
838 return buf;
839}
840
b7ac5457 841unsigned int
4dd643d5 842Ip::Address::toHostStr(char *buf, const unsigned int blen) const
e1381638 843{
41d93087 844 char *p = buf;
845
4dd643d5 846 if (isIPv6() && blen > 0) {
41d93087 847 *p = '[';
d7ae3534 848 ++p;
41d93087 849 }
850
188a640f 851 /* 8 being space for [ ] : and port digits */
4dd643d5
AJ
852 if ( isIPv6() )
853 toStr(p, blen-8, AF_INET6);
41d93087 854 else
4dd643d5 855 toStr(p, blen-8, AF_INET);
41d93087 856
857 // find the end of the new string
26ac0430 858 while (*p != '\0' && p < buf+blen)
d7ae3534 859 ++p;
41d93087 860
4dd643d5 861 if (isIPv6() && p < (buf+blen-1) ) {
41d93087 862 *p = ']';
d7ae3534 863 ++p;
41d93087 864 }
865
866 /* terminate just in case. */
867 *p = '\0';
868
869 /* return size of buffer now used */
870 return (p - buf);
871}
872
b7ac5457 873char *
4dd643d5 874Ip::Address::toUrl(char* buf, unsigned int blen) const
e1381638 875{
41d93087 876 char *p = buf;
877
878 // Ensure we have a buffer.
879
aee3523a
AR
880 if (buf == nullptr) {
881 return nullptr;
41d93087 882 }
883
4dd643d5 884 p += toHostStr(p, blen);
41d93087 885
4dd643d5 886 if (mSocketAddr_.sin6_port > 0 && p <= (buf+blen-7) ) {
842fe4cc 887 // ':port' (short int) needs at most 6 bytes plus 1 for 0-terminator
4dd643d5 888 snprintf(p, 7, ":%d", port() );
41d93087 889 }
890
891 // force a null-terminated string
303bfd76 892 buf[blen-1] = '\0';
41d93087 893
894 return buf;
895}
896
fd9c47d1
AR
897bool
898Ip::Address::fromHost(const char *host)
899{
900 setEmpty();
901
05caa1bb
AR
902 if (!host)
903 return false;
904
905 if (host[0] != '[')
fd9c47d1
AR
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
b7ac5457 923void
4dd643d5 924Ip::Address::getSockAddr(struct sockaddr_storage &addr, const int family) const
e1381638 925{
aee3523a 926 struct sockaddr_in *sin = nullptr;
52b694c2 927
4dd643d5 928 if ( family == AF_INET && !isIPv4()) {
9837567d 929 // TODO INET6: caller using the wrong socket type!
d816f28d 930 debugs(14, DBG_CRITICAL, "ERROR: Ip::Address::getSockAddr : Cannot convert non-IPv4 to IPv4. from " << *this);
0e1a47f0
AJ
931 assert(false);
932 }
933
4dd643d5 934 if ( family == AF_INET6 || (family == AF_UNSPEC && isIPv6()) ) {
1ef0b9ce 935 struct sockaddr_in6 *ss6 = (struct sockaddr_in6*)&addr;
4dd643d5
AJ
936 getSockAddr(*ss6);
937 } else if ( family == AF_INET || (family == AF_UNSPEC && isIPv4()) ) {
52b694c2 938 sin = (struct sockaddr_in*)&addr;
4dd643d5 939 getSockAddr(*sin);
52b694c2
AJ
940 } else {
941 IASSERT("false",false);
0e1a47f0 942 }
0e1a47f0
AJ
943}
944
b7ac5457 945void
4dd643d5 946Ip::Address::getSockAddr(struct sockaddr_in &buf) const
e1381638 947{
4dd643d5 948 if ( isIPv4() ) {
41d93087 949 buf.sin_family = AF_INET;
4dd643d5
AJ
950 buf.sin_port = mSocketAddr_.sin6_port;
951 map6to4( mSocketAddr_.sin6_addr, buf.sin_addr);
26ac0430 952 } else {
d816f28d 953 debugs(14, DBG_CRITICAL, "ERROR: Ip::Address::getSockAddr : Cannot convert non-IPv4 to IPv4. from " << *this );
41d93087 954
955 memset(&buf,0xFFFFFFFF,sizeof(struct sockaddr_in));
956 assert(false);
957 }
958
12f45551
AJ
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 */
1ef0b9ce 961 buf.sin_len = sizeof(struct sockaddr_in);
12f45551 962#endif
41d93087 963}
964
b7ac5457 965void
4dd643d5 966Ip::Address::getSockAddr(struct sockaddr_in6 &buf) const
e1381638 967{
9f15dc43 968 memmove(&buf, &mSocketAddr_, sizeof(struct sockaddr_in6));
41d93087 969 /* maintain address family. It may have changed inside us. */
970 buf.sin6_family = AF_INET6;
12f45551
AJ
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 */
1ef0b9ce 974 buf.sin6_len = sizeof(struct sockaddr_in6);
12f45551 975#endif
41d93087 976}
41d93087 977
b7ac5457 978void
4dd643d5 979Ip::Address::map4to6(const struct in_addr &in, struct in6_addr &out) const
e1381638 980{
41d93087 981 /* check for special cases */
982
26ac0430 983 if ( in.s_addr == 0x00000000) {
41d93087 984 /* ANYADDR */
0eb08770 985 out = v4_anyaddr;
26ac0430 986 } else if ( in.s_addr == 0xFFFFFFFF) {
41d93087 987 /* NOADDR */
0eb08770 988 out = v4_noaddr;
26ac0430 989 } else {
41d93087 990 /* general */
0eb08770 991 out = v4_anyaddr;
2c8fff41
AJ
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];
41d93087 996 }
997}
998
b7ac5457 999void
4dd643d5 1000Ip::Address::map6to4(const struct in6_addr &in, struct in_addr &out) const
e1381638 1001{
41d93087 1002 /* ANYADDR */
1003 /* NOADDR */
1004 /* general */
1005
1006 memset(&out, 0, sizeof(struct in_addr));
2c8fff41
AJ
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];
41d93087 1011}
1012
b7ac5457 1013void
68fb74b0 1014Ip::Address::getInAddr(struct in6_addr &buf) const
e1381638 1015{
9f15dc43 1016 memmove(&buf, &mSocketAddr_.sin6_addr, sizeof(struct in6_addr));
41d93087 1017}
41d93087 1018
b7ac5457 1019bool
4dd643d5 1020Ip::Address::getInAddr(struct in_addr &buf) const
e1381638 1021{
4dd643d5 1022 if ( isIPv4() ) {
68fb74b0 1023 map6to4(mSocketAddr_.sin6_addr, buf);
41d93087 1024 return true;
1025 }
41d93087 1026
1027 // default:
1028 // non-compatible IPv6 Pure Address
1029
d816f28d 1030 debugs(14, DBG_IMPORTANT, "ERROR: Ip::Address::getInAddr : Cannot convert non-IPv4 to IPv4. IPA=" << *this);
41d93087 1031 memset(&buf,0xFFFFFFFF,sizeof(struct in_addr));
1032 assert(false);
1033 return false;
1034}
f53969cc 1035