]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ip/IpAddress.cc
SourceLayout: Shuffle TextException into libbase
[thirdparty/squid.git] / src / ip / IpAddress.cc
CommitLineData
41d93087 1/*
41d93087 2 * DEBUG: section 14 IP Storage and Handling
3 * AUTHOR: Amos Jeffries
4 *
5 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
6 * ----------------------------------------------------------
7 *
8 * Squid is the result of efforts by numerous individuals from the
9 * Internet community. Development is led by Duane Wessels of the
10 * National Laboratory for Applied Network Research and funded by the
11 * National Science Foundation. Squid is Copyrighted (C) 1998 by
12 * the Regents of the University of California. Please see the
13 * COPYRIGHT file for full details. Squid incorporates software
14 * developed and/or copyrighted by other sources. Please see the
15 * CREDITS file for full details.
16 *
565b233e 17 * This IpAddress code is copyright (C) 2007 by Treehouse Networks Ltd
41d93087 18 * of New Zealand. It is published and Lisenced as an extension of
19 * squid under the same conditions as the main squid application.
20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
26ac0430 25 *
41d93087 26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
26ac0430 30 *
41d93087 31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 *
35 */
36
37#include "config.h"
82b7abe3 38#include "Debug.h"
9837e5f0 39#include "ip/IpAddress.h"
1ef0b9ce
AJ
40#include "util.h"
41
41d93087 42
43#if HAVE_ASSERT_H
44#include <assert.h>
45#endif
46#if HAVE_STDLIB_H
47#include <stdlib.h>
48#endif
49#if HAVE_STRING_H
50#include <string.h>
51#endif
52#if HAVE_ARPA_INET_H
53#include <arpa/inet.h> /* inet_ntoa() */
54#endif
55
41d93087 56#ifdef INET6
57#error "INET6 defined but has been deprecated! Try running bootstrap and configure again."
58#endif
59
41d93087 60#if !USE_IPV6
61// So there are some places where I will drop to using Macros too.
62// At least I can restrict them to this file so they don't corrupt the app with C code.
63# define sin6_addr sin_addr
64# define sin6_port sin_port
65# define sin6_family sin_family
66#undef s6_addr
67# define s6_addr s_addr
68#endif
69
41d93087 70/* Debugging only. Dump the address content when a fatal assert is encountered. */
71#if USE_IPV6
72#define IASSERT(a,b) \
68b313c2 73 if(!(b)){ printf("assert \"%s\" at line %d\n", a, __LINE__); \
565b233e 74 printf("IpAddress invalid? with IsIPv4()=%c, IsIPv6()=%c\n",(IsIPv4()?'T':'F'),(IsIPv6()?'T':'F')); \
41d93087 75 printf("ADDRESS:"); \
76 for(unsigned int i = 0; i < sizeof(m_SocketAddr.sin6_addr); i++) { \
77 printf(" %x", m_SocketAddr.sin6_addr.s6_addr[i]); \
78 } printf("\n"); assert(b); \
79 }
80#else
81#define IASSERT(a,b) \
68b313c2 82 if(!(b)){ printf("assert \"%s\" at line %d\n", a, __LINE__); \
565b233e 83 printf("IpAddress invalid? with IsIPv4()=%c, IsIPv6()=%c\n",(IsIPv4()?'T':'F'),(IsIPv6()?'T':'F')); \
41d93087 84 printf("ADDRESS: %x\n", (unsigned int)m_SocketAddr.sin_addr.s_addr); \
85 assert(b); \
86 }
87#endif
88
23f6a720 89IpAddress::IpAddress()
41d93087 90{
91 SetEmpty();
92}
93
23f6a720 94IpAddress::~IpAddress()
41d93087 95{
565b233e 96 memset(this,0,sizeof(IpAddress));
41d93087 97}
98
99int
565b233e 100IpAddress::GetCIDR() const
41d93087 101{
102 uint8_t shift,byte;
103 uint8_t bit,caught;
104 int len = 0;
105#if USE_IPV6
df9617b9 106 const uint8_t *ptr= m_SocketAddr.sin6_addr.s6_addr;
41d93087 107#else
df9617b9 108 const uint8_t *ptr= (uint8_t *)&m_SocketAddr.sin_addr.s_addr;
41d93087 109#endif
110
111 /* Let's scan all the bits from Most Significant to Least */
112 /* Until we find an "0" bit. Then, we return */
113 shift=0;
114
115#if USE_IPV6
116 /* return IPv4 CIDR for any Mapped address */
117 /* Thus only check the mapped bit */
118
26ac0430 119 if ( !IsIPv6() ) {
41d93087 120 shift = 12;
121 }
122
123#endif
124
e1381638 125 for (; shift<sizeof(m_SocketAddr.sin6_addr) ; shift++) {
41d93087 126 byte= *(ptr+shift);
127
128 if (byte == 0xFF) {
129 len += 8;
130 continue ; /* A short-cut */
131 }
132
133 for (caught = 0 , bit= 7 ; !caught && (bit <= 7); bit--) {
134 caught = ((byte & 0x80) == 0x00); /* Found a '0' at 'bit' ? */
135
136 if (!caught)
137 len++;
138
139 byte <<= 1;
140 }
141
142 if (caught)
143 break; /* We have found the most significant "0" bit. */
144 }
145
146 return len;
147}
148
23f6a720 149const int IpAddress::ApplyMask(IpAddress const &mask_addr)
41d93087 150{
151 uint32_t *p1 = (uint32_t*)(&m_SocketAddr.sin6_addr);
152 uint32_t const *p2 = (uint32_t const *)(&mask_addr.m_SocketAddr.sin6_addr);
153 unsigned int blen = sizeof(m_SocketAddr.sin6_addr)/sizeof(uint32_t);
154 unsigned int changes = 0;
155
156 for (unsigned int i = 0; i < blen; i++) {
26ac0430 157 if ((p1[i] & p2[i]) != p1[i])
41d93087 158 changes++;
159
160 p1[i] &= p2[i];
161 }
162
b5587d15
AJ
163 /* we have found a situation where mask forms or destroys a IPv4 map. */
164 check4Mapped();
165
41d93087 166 return changes;
167}
168
565b233e 169bool IpAddress::ApplyMask(const unsigned int cidr, int mtype)
41d93087 170{
171 uint8_t clearbits = 0;
172 uint8_t* p = NULL;
173
174#if !USE_IPV6
175 IASSERT("mtype != AF_INET6", mtype != AF_INET6); /* using IPv6 in IPv4 is invalid. */
176
26ac0430 177 if (mtype == AF_UNSPEC)
41d93087 178 mtype = AF_INET;
179
180#else
26ac0430 181 if (mtype == AF_UNSPEC)
41d93087 182 mtype = AF_INET6;
183
184#endif
185
186 // validation and short-cuts.
187 if (cidr > 128)
188 return false;
189
190 if (cidr > 32 && mtype == AF_INET)
191 return false;
192
2c1b9590
AJ
193 if (cidr == 0) {
194 /* CIDR /0 is NoAddr regardless of the IPv4/IPv6 protocol */
195 SetNoAddr();
196 return true;
197 }
198
41d93087 199 clearbits = (uint8_t)( (mtype==AF_INET6?128:32) -cidr);
200
201 // short-cut
26ac0430 202 if (clearbits == 0)
41d93087 203 return true;
204
205#if USE_IPV6
206
207 p = (uint8_t*)(&m_SocketAddr.sin6_addr) + 15;
208
209#else
210
211 p = (uint8_t*)(&m_SocketAddr.sin_addr) + 3;
212
213#endif
214
215 for (; clearbits>0 && p >= (uint8_t*)&m_SocketAddr.sin6_addr ; p-- ) {
26ac0430 216 if (clearbits < 8) {
41d93087 217 *p &= ((0xFF << clearbits) & 0xFF);
218 clearbits = 0;
219 } else {
220 *p &= 0x00;
221 clearbits -= 8;
222 }
223 }
224
225 return true;
226}
227
565b233e 228bool IpAddress::IsSockAddr() const
41d93087 229{
230 return (m_SocketAddr.sin6_port != 0);
231}
232
565b233e 233bool IpAddress::IsIPv4() const
41d93087 234{
235#if USE_IPV6
2c8fff41 236 return IsAnyAddr() || IsNoAddr() || IN6_IS_ADDR_V4MAPPED( &m_SocketAddr.sin6_addr );
41d93087 237#else
238 return true; // enforce IPv4 in IPv4-only mode.
239#endif
240}
241
565b233e 242bool IpAddress::IsIPv6() const
41d93087 243{
244#if USE_IPV6
2c8fff41 245 return IsAnyAddr() || IsNoAddr() || !IN6_IS_ADDR_V4MAPPED( &m_SocketAddr.sin6_addr );
41d93087 246#else
247 return false; // enforce IPv4 in IPv4-only mode.
248#endif
249}
250
565b233e 251bool IpAddress::IsAnyAddr() const
41d93087 252{
253#if USE_IPV6
2c8fff41 254 return IN6_IS_ADDR_UNSPECIFIED( &m_SocketAddr.sin6_addr );
41d93087 255#else
41d93087 256 return (INADDR_ANY == m_SocketAddr.sin_addr.s_addr);
257#endif
258}
259
260/// NOTE: Does NOT clear the Port stored. Ony the Address and Type.
565b233e 261void IpAddress::SetAnyAddr()
41d93087 262{
263#if USE_IPV6
264 memset(&m_SocketAddr.sin6_addr, 0, sizeof(struct in6_addr) );
265#else
266 memset(&m_SocketAddr.sin_addr, 0, sizeof(struct in_addr) );
267#endif
268}
269
565b233e
AJ
270/// NOTE: completely empties the IpAddress structure. Address, Port, Type, everything.
271void IpAddress::SetEmpty()
41d93087 272{
273 memset(&m_SocketAddr, 0, sizeof(m_SocketAddr) );
274}
275
41d93087 276#if USE_IPV6
c0248e14 277const struct in6_addr IpAddress::v4_localhost = {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
d5b4b6c7 278 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01 }}
c0248e14
HN
279};
280const struct in6_addr IpAddress::v4_anyaddr = {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
d5b4b6c7 281 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }}
c0248e14
HN
282};
283const struct in6_addr IpAddress::v6_noaddr = {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
d5b4b6c7 284 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}
c0248e14
HN
285};
286#endif
287
41d93087 288
c0248e14
HN
289bool IpAddress::SetIPv4()
290{
291#if USE_IPV6
26ac0430 292 if ( IsLocalhost() ) {
2c8fff41 293 m_SocketAddr.sin6_addr = v4_localhost;
41d93087 294 return true;
295 }
41d93087 296
26ac0430 297 if ( IsAnyAddr() ) {
c0248e14 298 m_SocketAddr.sin6_addr = v4_anyaddr;
41d93087 299 return true;
300 }
301
26ac0430 302 if ( IsIPv4())
41d93087 303 return true;
304
305 // anything non-IPv4 and non-convertable is BAD.
306 return false;
307#else
308 return true; // Always IPv4 in IPv4-only builds.
309#endif
310}
311
565b233e 312bool IpAddress::IsLocalhost() const
41d93087 313{
314#if USE_IPV6
2c8fff41
AJ
315 return IN6_IS_ADDR_LOOPBACK( &m_SocketAddr.sin6_addr ) || IN6_ARE_ADDR_EQUAL( &m_SocketAddr.sin6_addr, &v4_localhost );
316#else
41d93087 317 return (htonl(0x7F000001) == m_SocketAddr.sin_addr.s_addr);
318#endif
319}
320
565b233e 321void IpAddress::SetLocalhost()
41d93087 322{
323#if USE_IPV6
01ed4c98 324 m_SocketAddr.sin6_addr = in6addr_loopback;
41d93087 325 m_SocketAddr.sin6_family = AF_INET6;
41d93087 326#else
327 m_SocketAddr.sin_addr.s_addr = htonl(0x7F000001);
328 m_SocketAddr.sin_family = AF_INET;
329#endif
330}
331
a98c2da5
AJ
332bool IpAddress::IsSiteLocal6() const
333{
334#if USE_IPV6
01ed4c98 335 return IN6_IS_ADDR_SITELOCAL( &m_SocketAddr.sin6_addr );
a98c2da5
AJ
336#else
337 return false;
338#endif
339}
340
341bool IpAddress::IsSlaac() const
342{
343#if USE_IPV6
2c8fff41
AJ
344 return m_SocketAddr.sin6_addr.s6_addr[10] == htons(0xff) &&
345 m_SocketAddr.sin6_addr.s6_addr[11] == htons(0xfe);
a98c2da5
AJ
346#else
347 return false;
348#endif
349}
350
565b233e 351bool IpAddress::IsNoAddr() const
41d93087 352{
353 // IFF the address == 0xff..ff (all ones)
354#if USE_IPV6
2c8fff41
AJ
355 return IN6_ARE_ADDR_EQUAL( &m_SocketAddr.sin6_addr, &v6_noaddr );
356#else
41d93087 357 return 0xFFFFFFFF == m_SocketAddr.sin_addr.s_addr;
358#endif
359}
360
565b233e 361void IpAddress::SetNoAddr()
41d93087 362{
363#if USE_IPV6
c0248e14 364 memset(&m_SocketAddr.sin6_addr, 0xFF, sizeof(struct in6_addr) );
41d93087 365 m_SocketAddr.sin6_family = AF_INET6;
366#else
c0248e14 367 memset(&m_SocketAddr.sin_addr, 0xFF, sizeof(struct in_addr) );
41d93087 368 m_SocketAddr.sin_family = AF_INET;
369#endif
370}
371
372#if USE_IPV6
373
565b233e 374bool IpAddress::GetReverseString6(char buf[MAX_IPSTRLEN], const struct in6_addr &dat) const
41d93087 375{
376 char *p = buf;
377 unsigned char const *r = dat.s6_addr;
378
379 /* RFC1886 says: */
380 /* 4321:0:1:2:3:4:567:89ab */
381 /* must be sent */
382 /* 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. */
383
384 /* Work from the binary field. Anything else may have representation changes. */
385 /* The sin6_port and sin6_addr members shall be in network byte order. */
386
387 /* Compile Err: 'Too many arguments for format. */
388
26ac0430 389 for (int i = 15; i >= 0; i--, p+=4) {
41d93087 390 snprintf(p, 5, "%x.%x.", ((r[i])&0xf), (((r[i])>>4)&0xf) );
391 }
392
393 /* RFC3152 says: */
394 /* ip6.int is now deprecated TLD, use ip6.arpa instead. */
395 snprintf(p,10,"ip6.arpa.");
396
397 return true;
398}
399
400#endif
401
565b233e 402bool IpAddress::GetReverseString4(char buf[MAX_IPSTRLEN], const struct in_addr &dat) const
41d93087 403{
404 unsigned int i = (unsigned int) ntohl(dat.s_addr);
405 snprintf(buf, 32, "%u.%u.%u.%u.in-addr.arpa.",
406 i & 255,
407 (i >> 8) & 255,
408 (i >> 16) & 255,
409 (i >> 24) & 255);
410 return true;
411}
412
565b233e 413bool IpAddress::GetReverseString(char buf[MAX_IPSTRLEN], int show_type) const
41d93087 414{
415
26ac0430 416 if (show_type == AF_UNSPEC) {
41d93087 417#if USE_IPV6
418 show_type = IsIPv6() ? AF_INET6 : AF_INET ;
419#else
420 show_type = AF_INET;
421#endif
422 }
423
424 if (show_type == AF_INET && IsIPv4()) {
425#if USE_IPV6
2c8fff41
AJ
426 struct in_addr* tmp = (struct in_addr*)&m_SocketAddr.sin6_addr.s6_addr[12];
427 return GetReverseString4(buf, *tmp);
41d93087 428 } else if ( show_type == AF_INET6 && IsIPv6() ) {
429 return GetReverseString6(buf, m_SocketAddr.sin6_addr);
430#else
431 return GetReverseString4(buf, m_SocketAddr.sin_addr);
432#endif
433 }
434
435 debugs(14,0, "Unable to convert '" << NtoA(buf,MAX_IPSTRLEN) << "' to the rDNS type requested.");
436
437 buf[0] = '\0';
438
439 return false;
440}
441
9fb4efad 442IpAddress& IpAddress::operator =(const IpAddress &s)
41d93087 443{
565b233e 444 memcpy(this, &s, sizeof(IpAddress));
41d93087 445 return *this;
446};
447
23f6a720 448IpAddress::IpAddress(const char*s)
41d93087 449{
450 SetEmpty();
451 operator=(s);
452}
453
565b233e 454bool IpAddress::operator =(const char* s)
41d93087 455{
456 return LookupHostIP(s, true);
457}
458
565b233e 459bool IpAddress::GetHostByName(const char* s)
41d93087 460{
461 return LookupHostIP(s, false);
462}
463
565b233e 464bool IpAddress::LookupHostIP(const char *s, bool nodns)
41d93087 465{
466 int err = 0;
467
468 short port = 0;
469
470 struct addrinfo *res = NULL;
471
472 struct addrinfo want;
473
474 memset(&want, 0, sizeof(struct addrinfo));
26ac0430 475 if (nodns) {
41d93087 476 want.ai_flags = AI_NUMERICHOST; // prevent actual DNS lookups!
477 }
478#if !USE_IPV6
479 want.ai_family = AF_INET;
480#endif
481
482 if ( (err = xgetaddrinfo(s, NULL, &want, &res)) != 0) {
3f697f0d 483 debugs(14,3, HERE << "Given Bad IP '" << s << "': " << xgai_strerror(err) );
41d93087 484 /* free the memory xgetaddrinfo() dynamically allocated. */
26ac0430 485 if (res) {
41d93087 486 xfreeaddrinfo(res);
487 res = NULL;
488 }
489 return false;
490 }
491
492 /*
493 * NP: =(sockaddr_*) may alter the port. we don't want that.
494 * all we have been given as input was an IPA.
495 */
496 port = GetPort();
497 operator=(*res);
498 SetPort(port);
499
500 /* free the memory xgetaddrinfo() dynamically allocated. */
501 xfreeaddrinfo(res);
502
503 res = NULL;
504
505 return true;
506}
507
23f6a720 508IpAddress::IpAddress(struct sockaddr_in const &s)
41d93087 509{
510 SetEmpty();
511 operator=(s);
512};
513
23f6a720 514IpAddress& IpAddress::operator =(struct sockaddr_in const &s)
41d93087 515{
516#if USE_IPV6
517 Map4to6((const in_addr)s.sin_addr, m_SocketAddr.sin6_addr);
518 m_SocketAddr.sin6_port = s.sin_port;
519 m_SocketAddr.sin6_family = AF_INET6;
520#else
521
522 memcpy(&m_SocketAddr, &s, sizeof(struct sockaddr_in));
523#endif
524
b5587d15
AJ
525 /* maintain stored family values properly */
526 check4Mapped();
527
41d93087 528 return *this;
529};
530
23f6a720 531IpAddress& IpAddress::operator =(const struct sockaddr_storage &s)
0e1a47f0
AJ
532{
533#if USE_IPV6
534 /* some AF_* magic to tell socket types apart and what we need to do */
26ac0430 535 if (s.ss_family == AF_INET6) {
0e1a47f0 536 memcpy(&m_SocketAddr, &s, sizeof(struct sockaddr_in));
26ac0430 537 } else { // convert it to our storage mapping.
0e1a47f0
AJ
538 struct sockaddr_in *sin = (struct sockaddr_in*)&s;
539 m_SocketAddr.sin6_port = sin->sin_port;
540 Map4to6( sin->sin_addr, m_SocketAddr.sin6_addr);
541 }
542#else
543 memcpy(&m_SocketAddr, &s, sizeof(struct sockaddr_in));
544#endif
545 return *this;
546};
547
b5587d15
AJ
548void IpAddress::check4Mapped()
549{
550 // obsolete.
551 // TODO use this NOW to set the sin6_family properly on exporting. not on import.
552}
553
41d93087 554#if USE_IPV6
23f6a720 555IpAddress::IpAddress(struct sockaddr_in6 const &s)
41d93087 556{
557 SetEmpty();
558 operator=(s);
559};
560
23f6a720 561IpAddress& IpAddress::operator =(struct sockaddr_in6 const &s)
41d93087 562{
563 memcpy(&m_SocketAddr, &s, sizeof(struct sockaddr_in6));
b5587d15
AJ
564
565 /* maintain address family properly */
566 check4Mapped();
41d93087 567 return *this;
568};
569
570#endif
571
23f6a720 572IpAddress::IpAddress(struct in_addr const &s)
41d93087 573{
574 SetEmpty();
575 operator=(s);
576};
577
23f6a720 578IpAddress& IpAddress::operator =(struct in_addr const &s)
41d93087 579{
580#if USE_IPV6
581 Map4to6((const in_addr)s, m_SocketAddr.sin6_addr);
582 m_SocketAddr.sin6_family = AF_INET6;
b5587d15 583
41d93087 584#else
b5587d15 585
41d93087 586 memcpy(&m_SocketAddr.sin_addr, &s, sizeof(struct in_addr));
b5587d15 587
41d93087 588#endif
b5587d15
AJ
589
590 /* maintain stored family type properly */
591 check4Mapped();
592
41d93087 593 return *this;
594};
595
596#if USE_IPV6
597
23f6a720 598IpAddress::IpAddress(struct in6_addr const &s)
41d93087 599{
600 SetEmpty();
601 operator=(s);
602};
603
23f6a720 604IpAddress& IpAddress::operator =(struct in6_addr const &s)
41d93087 605{
b5587d15 606
41d93087 607 memcpy(&m_SocketAddr.sin6_addr, &s, sizeof(struct in6_addr));
608 m_SocketAddr.sin6_family = AF_INET6;
b5587d15
AJ
609
610 /* maintain address family type properly */
611 check4Mapped();
612
41d93087 613 return *this;
614};
615
616#endif
617
9fb4efad 618IpAddress::IpAddress(const IpAddress &s)
41d93087 619{
620 SetEmpty();
621 operator=(s);
622}
623
9fb4efad 624IpAddress::IpAddress(IpAddress *s)
41d93087 625{
626 SetEmpty();
1a1f4104 627 if (s)
af6a12ee 628 memcpy(this, s, sizeof(IpAddress));
41d93087 629}
630
23f6a720 631IpAddress::IpAddress(const struct hostent &s)
41d93087 632{
633 SetEmpty();
634 operator=(s);
635}
636
565b233e 637bool IpAddress::operator =(const struct hostent &s)
41d93087 638{
639
640 struct in_addr* ipv4 = NULL;
641
642 struct in6_addr* ipv6 = NULL;
643
644 //struct hostent {
645 // char *h_name; /* official name of host */
646 // char **h_aliases; /* alias list */
647 // int h_addrtype; /* host address type */
648 // int h_length; /* length of address */
649 // char **h_addr_list; /* list of addresses */
650 //}
651
26ac0430 652 switch (s.h_addrtype) {
41d93087 653
654 case AF_INET:
655 ipv4 = (in_addr*)(s.h_addr_list[0]);
656 /* this */
657 operator=(*ipv4);
658 break;
659
660 case AF_INET6:
661 ipv6 = (in6_addr*)(s.h_addr_list[0]);
662#if USE_IPV6
663 /* this */
664 operator=(*ipv6);
665#else
666
667 debugs(14,1, HERE << "Discarded IPv6 Address. Protocol disabled.");
668
669 // FIXME see if there is another address in the list that might be usable ??
670 return false;
671#endif
672
673 break;
674
675 default:
26ac0430
AJ
676 IASSERT("false",false);
677 return false;
41d93087 678 }
679
680 return true;
681}
682
23f6a720 683IpAddress::IpAddress(const struct addrinfo &s)
41d93087 684{
685 SetEmpty();
686 operator=(s);
687}
688
565b233e 689bool IpAddress::operator =(const struct addrinfo &s)
41d93087 690{
691
692 struct sockaddr_in* ipv4 = NULL;
693
694 struct sockaddr_in6* ipv6 = NULL;
695
696 //struct addrinfo {
697 // int ai_flags; /* input flags */
698 // int ai_family; /* protocol family for socket */
699 // int ai_socktype; /* socket type */
700 // int ai_protocol; /* protocol for socket */
701 // socklen_t ai_addrlen; /* length of socket-address */
702 // struct sockaddr *ai_addr; /* socket-address for socket */
703 // char *ai_canonname; /* canonical name for service location */
704 // struct addrinfo *ai_next; /* pointer to next in list */
705 //}
706
26ac0430 707 switch (s.ai_family) {
41d93087 708
709 case AF_INET:
710 ipv4 = (sockaddr_in*)(s.ai_addr);
711 /* this */
712 assert(ipv4);
713 operator=(*ipv4);
714 break;
715
716 case AF_INET6:
717 ipv6 = (sockaddr_in6*)(s.ai_addr);
718#if USE_IPV6
719 /* this */
720 assert(ipv6);
721 operator=(*ipv6);
722#else
723
724 debugs(14,1, HERE << "Discarded IPv6 Address. Protocol disabled.");
725
726 // see if there is another address in the list that might be usable ??
727
728 if (s.ai_next)
729 return operator=(*s.ai_next);
730 else
731 return false;
732
733#endif
734 break;
735
736 case AF_UNSPEC:
737 default:
738 // attempt to handle partially initialised addrinfo.
739 // such as those where data only comes from getsockopt()
26ac0430 740 if (s.ai_addr != NULL) {
41d93087 741#if USE_IPV6
26ac0430 742 if (s.ai_addrlen == sizeof(struct sockaddr_in6)) {
41d93087 743 operator=(*((struct sockaddr_in6*)s.ai_addr));
744 return true;
26ac0430 745 } else
41d93087 746#endif
26ac0430
AJ
747 if (s.ai_addrlen == sizeof(struct sockaddr_in)) {
748 operator=(*((struct sockaddr_in*)s.ai_addr));
749 return true;
750 }
41d93087 751 }
752 return false;
753 }
754
755 return true;
756}
757
565b233e 758void IpAddress::GetAddrInfo(struct addrinfo *&dst, int force) const
41d93087 759{
26ac0430 760 if (dst == NULL) {
41d93087 761 dst = new addrinfo;
762 }
763
764 memset(dst, 0, sizeof(struct addrinfo));
765
766 // set defaults
767 dst->ai_flags = AI_NUMERICHOST;
768
26ac0430 769 if (dst->ai_socktype == 0)
41d93087 770 dst->ai_socktype = SOCK_STREAM;
771
26ac0430 772 if (dst->ai_socktype == SOCK_STREAM // implies TCP
41d93087 773 && dst->ai_protocol == 0)
774 dst->ai_protocol = IPPROTO_TCP;
775
26ac0430 776 if (dst->ai_socktype == SOCK_DGRAM // implies UDP
41d93087 777 && dst->ai_protocol == 0)
778 dst->ai_protocol = IPPROTO_UDP;
779
780#if USE_IPV6
26ac0430 781 if ( force == AF_INET6 || (force == AF_UNSPEC && IsIPv6()) ) {
41d93087 782 dst->ai_addr = (struct sockaddr*)new sockaddr_in6;
783
784 memset(dst->ai_addr,0,sizeof(struct sockaddr_in6));
785
786 GetSockAddr(*((struct sockaddr_in6*)dst->ai_addr));
787
788 dst->ai_addrlen = sizeof(struct sockaddr_in6);
789
790 dst->ai_family = ((struct sockaddr_in6*)dst->ai_addr)->sin6_family;
9d92af86
AJ
791
792#if 0
793 /**
794 * Enable only if you must and please report to squid-dev if you find a need for this.
795 *
796 * Vista may need this to cope with dual-stack (unsetting IP6_V6ONLY).
797 * http://msdn.microsoft.com/en-us/library/ms738574(VS.85).aspx
798 * Linux appears to only do some things when its present.
799 * (93) Bad Protocol
800 * FreeBSD dies horribly when using dual-stack with it set.
801 * (43) Protocol not supported
802 */
41d93087 803 dst->ai_protocol = IPPROTO_IPV6;
9d92af86
AJ
804#endif
805
41d93087 806 } else
807#endif
26ac0430 808 if ( force == AF_INET || (force == AF_UNSPEC && IsIPv4()) ) {
41d93087 809
810 dst->ai_addr = (struct sockaddr*)new sockaddr_in;
811
812 memset(dst->ai_addr,0,sizeof(struct sockaddr_in));
813
814 GetSockAddr(*((struct sockaddr_in*)dst->ai_addr));
815
816 dst->ai_addrlen = sizeof(struct sockaddr_in);
817
818 dst->ai_family = ((struct sockaddr_in*)dst->ai_addr)->sin_family;
26ac0430 819 } else {
41d93087 820 IASSERT("false",false);
821 }
822}
823
565b233e 824void IpAddress::InitAddrInfo(struct addrinfo *&ai) const
41d93087 825{
26ac0430 826 if (ai == NULL) {
41d93087 827 ai = new addrinfo;
828 memset(ai,0,sizeof(struct addrinfo));
829 }
830
831 // remove any existing data.
26ac0430 832 if (ai->ai_addr) delete ai->ai_addr;
41d93087 833
834 ai->ai_addr = (struct sockaddr*)new sockaddr_in6;
835 memset(ai->ai_addr, 0, sizeof(struct sockaddr_in6));
836
837 ai->ai_addrlen = sizeof(struct sockaddr_in6);
838
839}
840
565b233e 841void IpAddress::FreeAddrInfo(struct addrinfo *&ai) const
41d93087 842{
26ac0430 843 if (ai == NULL) return;
41d93087 844
26ac0430 845 if (ai->ai_addr) delete ai->ai_addr;
41d93087 846
847 ai->ai_addr = NULL;
848
849 ai->ai_addrlen = 0;
850
851 // NP: name fields are NOT allocated at present.
852 delete ai;
853
854 ai = NULL;
855}
856
23f6a720 857int IpAddress::matchIPAddr(const IpAddress &rhs) const
41d93087 858{
859#if USE_IPV6
860 uint8_t *l = (uint8_t*)m_SocketAddr.sin6_addr.s6_addr;
861 uint8_t *r = (uint8_t*)rhs.m_SocketAddr.sin6_addr.s6_addr;
862#else
863 uint8_t *l = (uint8_t*)&m_SocketAddr.sin_addr.s_addr;
864 uint8_t *r = (uint8_t*)&rhs.m_SocketAddr.sin_addr.s_addr;
865#endif
866
867 // loop a byte-wise compare
868 // NP: match MUST be R-to-L : L-to-R produces inconsistent gt/lt results at varying CIDR
869 // expected difference on CIDR is gt/eq or lt/eq ONLY.
26ac0430 870 for (unsigned int i = 0 ; i < sizeof(m_SocketAddr.sin6_addr) ; i++) {
41d93087 871
26ac0430 872 if (l[i] < r[i])
41d93087 873 return -1;
874
26ac0430 875 if (l[i] > r[i])
41d93087 876 return 1;
877 }
878
879 return 0;
880}
881
23f6a720 882bool IpAddress::operator ==(const IpAddress &s) const
41d93087 883{
884 return (0 == matchIPAddr(s));
885}
886
23f6a720 887bool IpAddress::operator !=(const IpAddress &s) const
41d93087 888{
889 return ! ( operator==(s) );
890}
891
23f6a720 892bool IpAddress::operator <=(const IpAddress &rhs) const
41d93087 893{
26ac0430 894 if (IsAnyAddr() && !rhs.IsAnyAddr())
41d93087 895 return true;
896
897 return (matchIPAddr(rhs) <= 0);
898}
899
23f6a720 900bool IpAddress::operator >=(const IpAddress &rhs) const
41d93087 901{
26ac0430 902 if (IsNoAddr() && !rhs.IsNoAddr())
41d93087 903 return true;
904
905 return ( matchIPAddr(rhs) >= 0);
906}
907
23f6a720 908bool IpAddress::operator >(const IpAddress &rhs) const
41d93087 909{
26ac0430 910 if (IsNoAddr() && !rhs.IsNoAddr())
41d93087 911 return true;
912
913 return ( matchIPAddr(rhs) > 0);
914}
915
23f6a720 916bool IpAddress::operator <(const IpAddress &rhs) const
41d93087 917{
26ac0430 918 if (IsNoAddr() && !rhs.IsNoAddr())
41d93087 919 return true;
920
921 return ( matchIPAddr(rhs) < 0);
922}
923
565b233e 924u_short IpAddress::GetPort() const
41d93087 925{
926 return ntohs( m_SocketAddr.sin6_port );
927}
928
565b233e 929u_short IpAddress::SetPort(u_short prt)
41d93087 930{
931 m_SocketAddr.sin6_port = htons(prt);
932
933 return prt;
934}
935
936/**
937 * NtoA Given a buffer writes a readable ascii version of the IPA and/or port stored
938 *
939 * Buffer must be of a size large enough to hold the converted address.
940 * This size is provided in the form of a global defined variable MAX_IPSTRLEN
941 * Should a buffer shorter be provided the string result will be truncated
942 * at the length of the available buffer.
943 *
944 * A copy of the buffer is also returned for simple immediate display.
945 */
565b233e 946char* IpAddress::NtoA(char* buf, const unsigned int blen, int force) const
41d93087 947{
948 // Ensure we have a buffer.
26ac0430 949 if (buf == NULL) {
41d93087 950 return NULL;
951 }
952
953 /* some external code may have blindly memset a parent. */
954 /* thats okay, our default is known */
26ac0430 955 if ( IsAnyAddr() ) {
41d93087 956#if USE_IPV6
d85c3078 957 memcpy(buf,"::\0", min((const unsigned int)3,blen));
41d93087 958#else
d85c3078 959 memcpy(buf,"0.0.0.0\0", min((const unsigned int)8,blen));
41d93087 960#endif
961 return buf;
962 }
963
964 memset(buf,0,blen); // clear buffer before write
965
966 /* Pure-IPv6 CANNOT be displayed in IPv4 format. */
967 /* However IPv4 CAN. */
26ac0430
AJ
968 if ( force == AF_INET && !IsIPv4() ) {
969 if ( IsIPv6() ) {
d85c3078 970 memcpy(buf, "{!IPv4}\0", min((const unsigned int)8,blen));
41d93087 971 }
972 return buf;
973 }
974
975#if USE_IPV6
26ac0430 976 if ( force == AF_INET6 || (force == AF_UNSPEC && IsIPv6()) ) {
41d93087 977
978 xinet_ntop(AF_INET6, &m_SocketAddr.sin6_addr, buf, blen);
979
980 } else if ( force == AF_INET || (force == AF_UNSPEC && IsIPv4()) ) {
981
982 struct in_addr tmp;
983 GetInAddr(tmp);
984 xinet_ntop(AF_INET, &tmp, buf, blen);
985#else
26ac0430 986 if ( force == AF_UNSPEC || (force == AF_INET && IsIPv4()) ) {
41d93087 987 xinet_ntop(AF_INET, &m_SocketAddr.sin_addr, buf, blen);
988#endif
989 } else {
990 debugs(14,0,"WARNING: Corrupt IP Address details OR required to display in unknown format (" <<
26ac0430 991 force << "). accepted={" << AF_UNSPEC << "," << AF_INET << "," << AF_INET6 << "}");
41d93087 992 fprintf(stderr,"WARNING: Corrupt IP Address details OR required to display in unknown format (%d). accepted={%d,%d,%d} ",
993 force, AF_UNSPEC, AF_INET, AF_INET6);
d85c3078 994 memcpy(buf,"dead:beef::\0", min((const unsigned int)13,blen));
41d93087 995 assert(false);
996 }
997
998 return buf;
999}
1000
e1381638
AJ
1001unsigned int IpAddress::ToHostname(char *buf, const unsigned int blen) const
1002{
41d93087 1003 char *p = buf;
1004
26ac0430 1005 if (IsIPv6() && blen > 0) {
41d93087 1006 *p = '[';
1007 p++;
1008 }
1009
1010 /* 7 being space for [,], and port */
26ac0430 1011 if ( IsIPv6() )
41d93087 1012 NtoA(p, blen-7, AF_INET6);
1013 else
1014 NtoA(p, blen-7, AF_INET);
1015
1016 // find the end of the new string
26ac0430 1017 while (*p != '\0' && p < buf+blen)
41d93087 1018 p++;
1019
26ac0430 1020 if (IsIPv6() && p < (buf+blen-1) ) {
41d93087 1021 *p = ']';
1022 p++;
1023 }
1024
1025 /* terminate just in case. */
1026 *p = '\0';
1027
1028 /* return size of buffer now used */
1029 return (p - buf);
1030}
1031
e1381638
AJ
1032char* IpAddress::ToURL(char* buf, unsigned int blen) const
1033{
41d93087 1034 char *p = buf;
1035
1036 // Ensure we have a buffer.
1037
26ac0430 1038 if (buf == NULL) {
41d93087 1039 return NULL;
1040 }
1041
1042 p += ToHostname(p, blen);
1043
26ac0430 1044 if (m_SocketAddr.sin6_port > 0 && p < (buf+blen-6) ) {
41d93087 1045 /* 6 is max length of expected ':port' (short int) */
1046 snprintf(p, 6,":%d", GetPort() );
1047 }
1048
1049 // force a null-terminated string
303bfd76 1050 buf[blen-1] = '\0';
41d93087 1051
1052 return buf;
1053}
1054
e1381638
AJ
1055void IpAddress::GetSockAddr(struct sockaddr_storage &addr, const int family) const
1056{
52b694c2
AJ
1057 struct sockaddr_in *sin = NULL;
1058
26ac0430 1059 if ( family == AF_INET && !IsIPv4()) {
0e1a47f0 1060 // FIXME INET6: caller using the wrong socket type!
565b233e 1061 debugs(14, DBG_CRITICAL, HERE << "IpAddress::GetSockAddr : Cannot convert non-IPv4 to IPv4. from " << *this);
0e1a47f0
AJ
1062 assert(false);
1063 }
1064
1065#if USE_IPV6
26ac0430 1066 if ( family == AF_INET6 || (family == AF_UNSPEC && IsIPv6()) ) {
1ef0b9ce
AJ
1067 struct sockaddr_in6 *ss6 = (struct sockaddr_in6*)&addr;
1068 GetSockAddr(*ss6);
26ac0430 1069 } else if ( family == AF_INET || (family == AF_UNSPEC && IsIPv4()) ) {
52b694c2 1070 sin = (struct sockaddr_in*)&addr;
1ef0b9ce 1071 GetSockAddr(*sin);
52b694c2
AJ
1072 } else {
1073 IASSERT("false",false);
0e1a47f0 1074 }
8c37ea44 1075#else /* not USE_IPV6 */
52b694c2 1076 sin = (struct sockaddr_in*)&addr;
1ef0b9ce 1077 GetSockAddr(*sin);
8c37ea44 1078#endif /* USE_IPV6 */
0e1a47f0
AJ
1079}
1080
e1381638
AJ
1081void IpAddress::GetSockAddr(struct sockaddr_in &buf) const
1082{
41d93087 1083#if USE_IPV6
1084
26ac0430 1085 if ( IsIPv4() ) {
41d93087 1086 buf.sin_family = AF_INET;
1087 buf.sin_port = m_SocketAddr.sin6_port;
1088 Map6to4( m_SocketAddr.sin6_addr, buf.sin_addr);
26ac0430 1089 } else {
565b233e 1090 debugs(14, DBG_CRITICAL, HERE << "IpAddress::GetSockAddr : Cannot convert non-IPv4 to IPv4. from " << *this );
41d93087 1091
1092 memset(&buf,0xFFFFFFFF,sizeof(struct sockaddr_in));
1093 assert(false);
1094 }
1095
1096#else
1097
1098 memcpy(&buf, &m_SocketAddr, sizeof(struct sockaddr_in));
1099
26ac0430 1100 if (buf.sin_family == 0) {
41d93087 1101 buf.sin_family = AF_INET;
1102 }
1103
1104#endif
12f45551
AJ
1105
1106#if HAVE_SIN_LEN_IN_SAI
1107 /* not all OS have this field, BUT when they do it can be a problem if set wrong */
1ef0b9ce 1108 buf.sin_len = sizeof(struct sockaddr_in);
12f45551
AJ
1109#endif
1110
41d93087 1111}
1112
1113#if USE_IPV6
1114
e1381638
AJ
1115void IpAddress::GetSockAddr(struct sockaddr_in6 &buf) const
1116{
41d93087 1117 memcpy(&buf, &m_SocketAddr, sizeof(struct sockaddr_in6));
1118 /* maintain address family. It may have changed inside us. */
1119 buf.sin6_family = AF_INET6;
12f45551
AJ
1120
1121#if HAVE_SIN6_LEN_IN_SAI
1122 /* not all OS have this field, BUT when they do it can be a problem if set wrong */
1ef0b9ce 1123 buf.sin6_len = sizeof(struct sockaddr_in6);
12f45551 1124#endif
41d93087 1125}
1126
1127#endif
1128
1129#if USE_IPV6
1130
e1381638
AJ
1131void IpAddress::Map4to6(const struct in_addr &in, struct in6_addr &out) const
1132{
41d93087 1133 /* check for special cases */
1134
26ac0430 1135 if ( in.s_addr == 0x00000000) {
41d93087 1136 /* ANYADDR */
41d93087 1137 memset(&out, 0, sizeof(struct in6_addr));
26ac0430 1138 } else if ( in.s_addr == 0xFFFFFFFF) {
41d93087 1139 /* NOADDR */
2c8fff41 1140 memset(&out, 255, sizeof(struct in6_addr));
26ac0430 1141 } else {
41d93087 1142 /* general */
41d93087 1143 memset(&out, 0, sizeof(struct in6_addr));
2c8fff41
AJ
1144 out.s6_addr[10] = 0xFF;
1145 out.s6_addr[11] = 0xFF;
1146 out.s6_addr[12] = ((uint8_t *)&in.s_addr)[0];
1147 out.s6_addr[13] = ((uint8_t *)&in.s_addr)[1];
1148 out.s6_addr[14] = ((uint8_t *)&in.s_addr)[2];
1149 out.s6_addr[15] = ((uint8_t *)&in.s_addr)[3];
41d93087 1150 }
1151}
1152
e1381638
AJ
1153void IpAddress::Map6to4(const struct in6_addr &in, struct in_addr &out) const
1154{
41d93087 1155 /* ANYADDR */
1156 /* NOADDR */
1157 /* general */
1158
1159 memset(&out, 0, sizeof(struct in_addr));
2c8fff41
AJ
1160 ((uint8_t *)&out.s_addr)[0] = in.s6_addr[12];
1161 ((uint8_t *)&out.s_addr)[1] = in.s6_addr[13];
1162 ((uint8_t *)&out.s_addr)[2] = in.s6_addr[14];
1163 ((uint8_t *)&out.s_addr)[3] = in.s6_addr[15];
41d93087 1164}
1165
1166#endif
1167
1168#if USE_IPV6
e1381638
AJ
1169void IpAddress::GetInAddr(in6_addr &buf) const
1170{
41d93087 1171 memcpy(&buf, &m_SocketAddr.sin6_addr, sizeof(struct in6_addr));
1172}
1173
1174#endif
1175
e1381638
AJ
1176bool IpAddress::GetInAddr(struct in_addr &buf) const
1177{
41d93087 1178
1179#if USE_IPV6
26ac0430 1180 if ( IsIPv4() ) {
41d93087 1181 Map6to4((const in6_addr)m_SocketAddr.sin6_addr, buf);
1182 return true;
1183 }
1184#else
1185
26ac0430 1186 if ( IsIPv4() ) {
41d93087 1187 memcpy(&buf, &m_SocketAddr.sin_addr, sizeof(struct in_addr));
1188 return true;
1189 }
1190#endif
1191
1192 // default:
1193 // non-compatible IPv6 Pure Address
1194
565b233e 1195 debugs(14,1, HERE << "IpAddress::GetInAddr : Cannot convert non-IPv4 to IPv4. IPA=" << *this);
41d93087 1196 memset(&buf,0xFFFFFFFF,sizeof(struct in_addr));
1197 assert(false);
1198 return false;
1199}