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

 

Introduction

Documentation

Support

Miscellaneous