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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors