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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors