/*
- * DEBUG: section 14 IP Storage and Handling
+ * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
*/
+
+/* DEBUG: section 14 IP Storage and Handling */
+
#include "squid.h"
-#include "compat/getaddrinfo.h"
-#include "compat/inet_ntop.h"
#include "Debug.h"
#include "ip/Address.h"
#include "ip/tools.h"
/* for inet_ntoa() */
#include <arpa/inet.h>
#endif
+#if HAVE_WS2TCPIP_H
+// Windows IPv6 definitions
+#include <ws2tcpip.h>
+#endif
+
+// some OS (ie WIndows) define IN6_ADDR_EQUAL instead
+#if !defined(IN6_ARE_ADDR_EQUAL) && _SQUID_WINDOWS_
+#define IN6_ARE_ADDR_EQUAL IN6_ADDR_EQUAL
+#endif
/* Debugging only. Dump the address content when a fatal assert is encountered. */
#define IASSERT(a,b) \
- if(!(b)){ printf("assert \"%s\" at line %d\n", a, __LINE__); \
- printf("Ip::Address invalid? with isIPv4()=%c, isIPv6()=%c\n",(isIPv4()?'T':'F'),(isIPv6()?'T':'F')); \
- printf("ADDRESS:"); \
- for(unsigned int i = 0; i < sizeof(mSocketAddr_.sin6_addr); ++i) { \
- printf(" %x", mSocketAddr_.sin6_addr.s6_addr[i]); \
- } printf("\n"); assert(b); \
- }
+ if(!(b)){ printf("assert \"%s\" at line %d\n", a, __LINE__); \
+ printf("Ip::Address invalid? with isIPv4()=%c, isIPv6()=%c\n",(isIPv4()?'T':'F'),(isIPv6()?'T':'F')); \
+ printf("ADDRESS:"); \
+ for(unsigned int i = 0; i < sizeof(mSocketAddr_.sin6_addr); ++i) { \
+ printf(" %x", mSocketAddr_.sin6_addr.s6_addr[i]); \
+ } printf("\n"); assert(b); \
+ }
int
Ip::Address::cidr() const
{
- uint8_t shift,byte;
+ uint8_t shift,ipbyte;
uint8_t bit,caught;
int len = 0;
const uint8_t *ptr= mSocketAddr_.sin6_addr.s6_addr;
}
for (; shift<sizeof(mSocketAddr_.sin6_addr) ; ++shift) {
- byte= *(ptr+shift);
+ ipbyte= *(ptr+shift);
- if (byte == 0xFF) {
+ if (ipbyte == 0xFF) {
len += 8;
continue ; /* A short-cut */
}
- for (caught = 0 , bit= 7 ; !caught && (bit <= 7); --bit) {
- caught = ((byte & 0x80) == 0x00); /* Found a '0' at 'bit' ? */
+ for (caught = 0, bit= 7 ; !caught && (bit <= 7); --bit) {
+ caught = ((ipbyte & 0x80) == 0x00); /* Found a '0' at 'bit' ? */
if (!caught)
++len;
- byte <<= 1;
+ ipbyte <<= 1;
}
if (caught)
return changes;
}
+void
+Ip::Address::applyClientMask(const Address &mask)
+{
+ if (!isLocalhost() && isIPv4())
+ (void)applyMask(mask);
+}
+
bool
Ip::Address::applyMask(const unsigned int cidrMask, int mtype)
{
return IN6_IS_ADDR_UNSPECIFIED(&mSocketAddr_.sin6_addr) || IN6_ARE_ADDR_EQUAL(&mSocketAddr_.sin6_addr, &v4_anyaddr);
}
-/// NOTE: Does NOT clear the Port stored. Ony the Address and Type.
+/// NOTE: Does NOT clear the Port stored. Only the Address and Type.
void
Ip::Address::setAnyAddr()
{
const struct in6_addr Ip::Address::v4_noaddr = {{{ 0x00000000, 0x00000000, 0x0000ffff, 0xffffffff }}};
const struct in6_addr Ip::Address::v6_noaddr = {{{ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }}};
#else
-const struct in6_addr Ip::Address::v4_localhost = {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01 }}
+const struct in6_addr Ip::Address::v4_localhost = {{{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01
+ }
+ }
};
-const struct in6_addr Ip::Address::v4_anyaddr = {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }}
+const struct in6_addr Ip::Address::v4_anyaddr = {{{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00
+ }
+ }
};
-const struct in6_addr Ip::Address::v4_noaddr = {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}
+const struct in6_addr Ip::Address::v4_noaddr = {{{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ }
+ }
};
-const struct in6_addr Ip::Address::v6_noaddr = {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}
+const struct in6_addr Ip::Address::v6_noaddr = {{{
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ }
+ }
};
#endif
return false;
}
-Ip::Address&
-Ip::Address::operator =(const Ip::Address &s)
-{
- memcpy(this, &s, sizeof(Ip::Address));
- return *this;
-};
-
Ip::Address::Address(const char*s)
{
setEmpty();
return false;
}
+ struct addrinfo *resHead = res; // we need to free the whole list later
+ if (!Ip::EnableIpv6) {
+ // if we are IPv6-disabled, use first-IPv4 instead of first-IP.
+ struct addrinfo *maybeIpv4 = res;
+ while (maybeIpv4) {
+ if (maybeIpv4->ai_family == AF_INET)
+ break;
+ maybeIpv4 = maybeIpv4->ai_next;
+ }
+ if (maybeIpv4 != NULL)
+ res = maybeIpv4;
+ // else IPv6-only host, let the caller deal with first-IP anyway.
+ }
+
/*
* NP: =(sockaddr_*) may alter the port. we don't want that.
* all we have been given as input was an IPA.
port(portSaved);
/* free the memory getaddrinfo() dynamically allocated. */
- freeaddrinfo(res);
+ freeaddrinfo(resHead);
return true;
}
{
/* some AF_* magic to tell socket types apart and what we need to do */
if (s.ss_family == AF_INET6) {
- memcpy(&mSocketAddr_, &s, sizeof(struct sockaddr_in6));
+ memmove(&mSocketAddr_, &s, sizeof(struct sockaddr_in6));
} else { // convert it to our storage mapping.
struct sockaddr_in *sin = (struct sockaddr_in*)&s;
mSocketAddr_.sin6_port = sin->sin_port;
Ip::Address &
Ip::Address::operator =(struct sockaddr_in6 const &s)
{
- memcpy(&mSocketAddr_, &s, sizeof(struct sockaddr_in6));
-
+ memmove(&mSocketAddr_, &s, sizeof(struct sockaddr_in6));
return *this;
};
Ip::Address &
Ip::Address::operator =(struct in6_addr const &s)
{
-
- memcpy(&mSocketAddr_.sin6_addr, &s, sizeof(struct in6_addr));
+ memmove(&mSocketAddr_.sin6_addr, &s, sizeof(struct in6_addr));
mSocketAddr_.sin6_family = AF_INET6;
return *this;
};
-Ip::Address::Address(const Ip::Address &s)
-{
- setEmpty();
- operator=(s);
-}
-
Ip::Address::Address(const struct hostent &s)
{
setEmpty();
}
void
-Ip::Address::InitAddrInfo(struct addrinfo *&ai)
+Ip::Address::InitAddr(struct addrinfo *&ai)
{
if (ai == NULL) {
ai = new addrinfo;
}
void
-Ip::Address::FreeAddrInfo(struct addrinfo *&ai)
+Ip::Address::FreeAddr(struct addrinfo *&ai)
{
if (ai == NULL) return;
}
/* some external code may have blindly memset a parent. */
- /* thats okay, our default is known */
+ /* that's okay, our default is known */
if ( isAnyAddr() ) {
if (isIPv6())
memcpy(buf,"::\0", min(static_cast<unsigned int>(3),blen));
return buf;
}
+bool
+Ip::Address::fromHost(const char *host)
+{
+ setEmpty();
+
+ if (!host)
+ return false;
+
+ if (host[0] != '[')
+ return lookupHostIP(host, true); // no brackets
+
+ /* unwrap a bracketed [presumably IPv6] address, presumably without port */
+
+ const char *start = host + 1;
+ if (!*start)
+ return false; // missing address after an opening bracket
+
+ // XXX: Check that there is a closing bracket and no trailing garbage.
+
+ char *tmp = xstrdup(start); // XXX: Slow. TODO: Bail on huge strings and use an on-stack buffer.
+ tmp[strlen(tmp)-1] = '\0'; // XXX: Wasteful: xstrdup() just did strlen().
+ const bool result = lookupHostIP(tmp, true);
+ xfree(tmp);
+ return result;
+}
+
void
Ip::Address::getSockAddr(struct sockaddr_storage &addr, const int family) const
{
struct sockaddr_in *sin = NULL;
if ( family == AF_INET && !isIPv4()) {
- // FIXME INET6: caller using the wrong socket type!
+ // TODO INET6: caller using the wrong socket type!
debugs(14, DBG_CRITICAL, HERE << "Ip::Address::getSockAddr : Cannot convert non-IPv4 to IPv4. from " << *this);
assert(false);
}
void
Ip::Address::getSockAddr(struct sockaddr_in6 &buf) const
{
- memcpy(&buf, &mSocketAddr_, sizeof(struct sockaddr_in6));
+ memmove(&buf, &mSocketAddr_, sizeof(struct sockaddr_in6));
/* maintain address family. It may have changed inside us. */
buf.sin6_family = AF_INET6;
void
Ip::Address::getInAddr(struct in6_addr &buf) const
{
- memcpy(&buf, &mSocketAddr_.sin6_addr, sizeof(struct in6_addr));
+ memmove(&buf, &mSocketAddr_.sin6_addr, sizeof(struct in6_addr));
}
bool
assert(false);
return false;
}
+