Address.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2025 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  InitAddr(dst);
647  if (force == AF_INET6 || (force == AF_UNSPEC && isIPv6()) ) {
648  getSockAddr(*((struct sockaddr_in6*)dst->ai_addr));
649 
650  dst->ai_addrlen = sizeof(struct sockaddr_in6);
651 
652  dst->ai_family = ((struct sockaddr_in6*)dst->ai_addr)->sin6_family;
653 
654 #if 0
655 
665  dst->ai_protocol = IPPROTO_IPV6;
666 #endif
667 
668  } else if ( force == AF_INET || (force == AF_UNSPEC && isIPv4()) ) {
669  getSockAddr(*((struct sockaddr_in*)dst->ai_addr));
670 
671  dst->ai_addrlen = sizeof(struct sockaddr_in);
672 
673  dst->ai_family = ((struct sockaddr_in*)dst->ai_addr)->sin_family;
674  } else {
675  IASSERT("false",false);
676  }
677 }
678 
679 void
680 Ip::Address::InitAddr(struct addrinfo *&ai)
681 {
682  if (ai == nullptr) {
683  ai = new addrinfo;
684  memset(ai,0,sizeof(struct addrinfo));
685  }
686 
687  // remove any existing data.
688  delete reinterpret_cast<struct sockaddr_storage *>(ai->ai_addr);
689 
690  ai->ai_addr = reinterpret_cast<struct sockaddr *>(new sockaddr_storage);
691  memset(ai->ai_addr, 0, sizeof(struct sockaddr_storage));
692 
693  ai->ai_addrlen = sizeof(struct sockaddr_storage);
694 
695 }
696 
697 void
698 Ip::Address::FreeAddr(struct addrinfo *&ai)
699 {
700  if (ai == nullptr) return;
701 
702  delete reinterpret_cast<struct sockaddr_storage *>(ai->ai_addr);
703 
704  ai->ai_addr = nullptr;
705 
706  ai->ai_addrlen = 0;
707 
708  // NP: name fields are NOT allocated at present.
709  delete ai;
710 
711  ai = nullptr;
712 }
713 
714 int
716 {
717  uint8_t *l = (uint8_t*)mSocketAddr_.sin6_addr.s6_addr;
718  uint8_t *r = (uint8_t*)rhs.mSocketAddr_.sin6_addr.s6_addr;
719 
720  // loop a byte-wise compare
721  // NP: match MUST be R-to-L : L-to-R produces inconsistent gt/lt results at varying CIDR
722  // expected difference on CIDR is gt/eq or lt/eq ONLY.
723  for (unsigned int i = 0 ; i < sizeof(mSocketAddr_.sin6_addr) ; ++i) {
724 
725  if (l[i] < r[i])
726  return -1;
727 
728  if (l[i] > r[i])
729  return 1;
730  }
731 
732  return 0;
733 }
734 
735 int
737 {
738  return memcmp(this, &rhs, sizeof(*this));
739 }
740 
741 bool
743 {
744  return (0 == matchIPAddr(s));
745 }
746 
747 bool
749 {
750  return ! ( operator==(s) );
751 }
752 
753 bool
755 {
756  if (isAnyAddr() && !rhs.isAnyAddr())
757  return true;
758 
759  return (matchIPAddr(rhs) <= 0);
760 }
761 
762 bool
764 {
765  if (isNoAddr() && !rhs.isNoAddr())
766  return true;
767 
768  return ( matchIPAddr(rhs) >= 0);
769 }
770 
771 bool
773 {
774  if (isNoAddr() && !rhs.isNoAddr())
775  return true;
776 
777  return ( matchIPAddr(rhs) > 0);
778 }
779 
780 bool
782 {
783  if (isAnyAddr() && !rhs.isAnyAddr())
784  return true;
785 
786  return ( matchIPAddr(rhs) < 0);
787 }
788 
789 unsigned short
791 {
792  return ntohs( mSocketAddr_.sin6_port );
793 }
794 
795 unsigned short
796 Ip::Address::port(unsigned short prt)
797 {
798  mSocketAddr_.sin6_port = htons(prt);
799 
800  return prt;
801 }
802 
803 char *
804 Ip::Address::toStr(char* buf, const unsigned int blen, int force) const
805 {
806  // Ensure we have a buffer.
807  if (buf == nullptr) {
808  return nullptr;
809  }
810 
811  /* some external code may have blindly memset a parent. */
812  /* that's okay, our default is known */
813  if ( isAnyAddr() ) {
814  if (isIPv6())
815  memcpy(buf,"::\0", min(static_cast<unsigned int>(3),blen));
816  else if (isIPv4())
817  memcpy(buf,"0.0.0.0\0", min(static_cast<unsigned int>(8),blen));
818  return buf;
819  }
820 
821  memset(buf,0,blen); // clear buffer before write
822 
823  /* Pure-IPv6 CANNOT be displayed in IPv4 format. */
824  /* However IPv4 CAN. */
825  if ( force == AF_INET && !isIPv4() ) {
826  if ( isIPv6() ) {
827  memcpy(buf, "{!IPv4}\0", min(static_cast<unsigned int>(8),blen));
828  }
829  return buf;
830  }
831 
832  if ( force == AF_INET6 || (force == AF_UNSPEC && isIPv6()) ) {
833 
834  inet_ntop(AF_INET6, &mSocketAddr_.sin6_addr, buf, blen);
835 
836  } else if ( force == AF_INET || (force == AF_UNSPEC && isIPv4()) ) {
837 
838  struct in_addr tmp;
839  getInAddr(tmp);
840  inet_ntop(AF_INET, &tmp, buf, blen);
841  } else {
842  debugs(14, DBG_CRITICAL, "WARNING: Corrupt IP Address details OR required to display in unknown format (" <<
843  force << "). accepted={" << AF_UNSPEC << "," << AF_INET << "," << AF_INET6 << "}");
844  fprintf(stderr,"WARNING: Corrupt IP Address details OR required to display in unknown format (%d). accepted={%d,%d,%d} ",
845  force, AF_UNSPEC, AF_INET, AF_INET6);
846  memcpy(buf,"dead:beef::\0", min(static_cast<unsigned int>(13),blen));
847  assert(false);
848  }
849 
850  return buf;
851 }
852 
853 unsigned int
854 Ip::Address::toHostStr(char *buf, const unsigned int blen) const
855 {
856  char *p = buf;
857 
858  if (isIPv6() && blen > 0) {
859  *p = '[';
860  ++p;
861  }
862 
863  /* 8 being space for [ ] : and port digits */
864  if ( isIPv6() )
865  toStr(p, blen-8, AF_INET6);
866  else
867  toStr(p, blen-8, AF_INET);
868 
869  // find the end of the new string
870  while (*p != '\0' && p < buf+blen)
871  ++p;
872 
873  if (isIPv6() && p < (buf+blen-1) ) {
874  *p = ']';
875  ++p;
876  }
877 
878  /* terminate just in case. */
879  *p = '\0';
880 
881  /* return size of buffer now used */
882  return (p - buf);
883 }
884 
885 char *
886 Ip::Address::toUrl(char* buf, unsigned int blen) const
887 {
888  char *p = buf;
889 
890  // Ensure we have a buffer.
891 
892  if (buf == nullptr) {
893  return nullptr;
894  }
895 
896  p += toHostStr(p, blen);
897 
898  if (mSocketAddr_.sin6_port > 0 && p <= (buf+blen-7) ) {
899  // ':port' (short int) needs at most 6 bytes plus 1 for 0-terminator
900  snprintf(p, 7, ":%d", port() );
901  }
902 
903  // force a null-terminated string
904  buf[blen-1] = '\0';
905 
906  return buf;
907 }
908 
909 bool
910 Ip::Address::fromHost(const char *host)
911 {
912  setEmpty();
913 
914  if (!host)
915  return false;
916 
917  if (host[0] != '[')
918  return lookupHostIP(host, true); // no brackets
919 
920  /* unwrap a bracketed [presumably IPv6] address, presumably without port */
921 
922  const char *start = host + 1;
923  if (!*start)
924  return false; // missing address after an opening bracket
925 
926  // XXX: Check that there is a closing bracket and no trailing garbage.
927 
928  char *tmp = xstrdup(start); // XXX: Slow. TODO: Bail on huge strings and use an on-stack buffer.
929  tmp[strlen(tmp)-1] = '\0'; // XXX: Wasteful: xstrdup() just did strlen().
930  const bool result = lookupHostIP(tmp, true);
931  xfree(tmp);
932  return result;
933 }
934 
935 void
936 Ip::Address::getSockAddr(struct sockaddr_storage &addr, const int family) const
937 {
938  struct sockaddr_in *sin = nullptr;
939 
940  if ( family == AF_INET && !isIPv4()) {
941  // TODO INET6: caller using the wrong socket type!
942  debugs(14, DBG_CRITICAL, "ERROR: Ip::Address::getSockAddr : Cannot convert non-IPv4 to IPv4. from " << *this);
943  assert(false);
944  }
945 
946  if ( family == AF_INET6 || (family == AF_UNSPEC && isIPv6()) ) {
947  struct sockaddr_in6 *ss6 = (struct sockaddr_in6*)&addr;
948  getSockAddr(*ss6);
949  } else if ( family == AF_INET || (family == AF_UNSPEC && isIPv4()) ) {
950  sin = (struct sockaddr_in*)&addr;
951  getSockAddr(*sin);
952  } else {
953  IASSERT("false",false);
954  }
955 }
956 
957 void
958 Ip::Address::getSockAddr(struct sockaddr_in &buf) const
959 {
960  if ( isIPv4() ) {
961  buf.sin_family = AF_INET;
962  buf.sin_port = mSocketAddr_.sin6_port;
963  map6to4( mSocketAddr_.sin6_addr, buf.sin_addr);
964  } else {
965  debugs(14, DBG_CRITICAL, "ERROR: Ip::Address::getSockAddr : Cannot convert non-IPv4 to IPv4. from " << *this );
966 
967  memset(&buf,0xFFFFFFFF,sizeof(struct sockaddr_in));
968  assert(false);
969  }
970 
971 #if HAVE_SIN_LEN_IN_SAI
972  /* not all OS have this field, BUT when they do it can be a problem if set wrong */
973  buf.sin_len = sizeof(struct sockaddr_in);
974 #endif
975 }
976 
977 void
978 Ip::Address::getSockAddr(struct sockaddr_in6 &buf) const
979 {
980  memmove(&buf, &mSocketAddr_, sizeof(struct sockaddr_in6));
981  /* maintain address family. It may have changed inside us. */
982  buf.sin6_family = AF_INET6;
983 
984 #if HAVE_SIN6_LEN_IN_SAI
985  /* not all OS have this field, BUT when they do it can be a problem if set wrong */
986  buf.sin6_len = sizeof(struct sockaddr_in6);
987 #endif
988 }
989 
990 void
991 Ip::Address::map4to6(const struct in_addr &in, struct in6_addr &out) const
992 {
993  /* check for special cases */
994 
995  if ( in.s_addr == 0x00000000) {
996  /* ANYADDR */
997  out = v4_anyaddr;
998  } else if ( in.s_addr == 0xFFFFFFFF) {
999  /* NOADDR */
1000  out = v4_noaddr;
1001  } else {
1002  /* general */
1003  out = v4_anyaddr;
1004  out.s6_addr[12] = ((uint8_t *)&in.s_addr)[0];
1005  out.s6_addr[13] = ((uint8_t *)&in.s_addr)[1];
1006  out.s6_addr[14] = ((uint8_t *)&in.s_addr)[2];
1007  out.s6_addr[15] = ((uint8_t *)&in.s_addr)[3];
1008  }
1009 }
1010 
1011 void
1012 Ip::Address::map6to4(const struct in6_addr &in, struct in_addr &out) const
1013 {
1014  /* ANYADDR */
1015  /* NOADDR */
1016  /* general */
1017 
1018  memset(&out, 0, sizeof(struct in_addr));
1019  ((uint8_t *)&out.s_addr)[0] = in.s6_addr[12];
1020  ((uint8_t *)&out.s_addr)[1] = in.s6_addr[13];
1021  ((uint8_t *)&out.s_addr)[2] = in.s6_addr[14];
1022  ((uint8_t *)&out.s_addr)[3] = in.s6_addr[15];
1023 }
1024 
1025 void
1026 Ip::Address::getInAddr(struct in6_addr &buf) const
1027 {
1028  memmove(&buf, &mSocketAddr_.sin6_addr, sizeof(struct in6_addr));
1029 }
1030 
1031 bool
1032 Ip::Address::getInAddr(struct in_addr &buf) const
1033 {
1034  if ( isIPv4() ) {
1035  map6to4(mSocketAddr_.sin6_addr, buf);
1036  return true;
1037  }
1038 
1039  // default:
1040  // non-compatible IPv6 Pure Address
1041 
1042  debugs(14, DBG_IMPORTANT, "ERROR: Ip::Address::getInAddr : Cannot convert non-IPv4 to IPv4. IPA=" << *this);
1043  memset(&buf,0xFFFFFFFF,sizeof(struct in_addr));
1044  assert(false);
1045  return false;
1046 }
1047 
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:742
bool getInAddr(struct in_addr &) const
Definition: Address.cc:1032
bool fromHost(const char *hostWithoutPort)
Definition: Address.cc:910
static void FreeAddr(struct addrinfo *&ai)
Definition: Address.cc:698
bool operator>=(Address const &rhs) const
Definition: Address.cc:763
int compareWhole(const Ip::Address &rhs) const
Definition: Address.cc:736
char * toUrl(char *buf, unsigned int len) const
Definition: Address.cc:886
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:715
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:804
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:854
void applyClientMask(const Address &mask)
Definition: Address.cc:125
bool operator<=(Address const &rhs) const
Definition: Address.cc:754
bool isSiteLocal6() const
Definition: Address.cc:287
void setNoAddr()
Definition: Address.cc:312
unsigned short port() const
Definition: Address.cc:790
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:748
int applyMask(const Address &mask)
Definition: Address.cc:97
bool operator>(Address const &rhs) const
Definition: Address.cc:772
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:1012
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:991
bool operator<(Address const &rhs) const
Definition: Address.cc:781
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:936
#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:680
int unsigned int
Definition: stub_fd.cc:19

 

Introduction

Documentation

Support

Miscellaneous