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