]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/ip/Address.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / ip / Address.cc
index 6dbd1512e13cb99ec980c48e229027883cccaac7..95aa7323d5741bb7f18c4883d3c9812c5b83ead2 100644 (file)
@@ -1,41 +1,49 @@
 /*
- * DEBUG: section 14    IP Storage and Handling
- * AUTHOR: Amos Jeffries
- * COPYRIGHT: GPL version 2, (C)2007-2013 Treehouse Networks Ltd.
+ * 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/inet_ntop.h"
-#include "compat/getaddrinfo.h"
 #include "Debug.h"
 #include "ip/Address.h"
 #include "ip/tools.h"
 #include "util.h"
 
-#if HAVE_ASSERT_H
-#include <assert.h>
-#endif
-#if HAVE_STRING_H
-#include <string.h>
-#endif
+#include <cassert>
+#include <cstring>
 #if HAVE_ARPA_INET_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;
@@ -52,20 +60,20 @@ Ip::Address::cidr() const
     }
 
     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)
@@ -93,6 +101,13 @@ Ip::Address::applyMask(Ip::Address const &mask_addr)
     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)
 {
@@ -157,7 +172,7 @@ Ip::Address::isAnyAddr() const
     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()
 {
@@ -179,17 +194,29 @@ const struct in6_addr Ip::Address::v4_anyaddr = {{{ 0x00000000, 0x00000000, 0x00
 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
 
@@ -249,8 +276,8 @@ Ip::Address::isSiteLocal6() const
 bool
 Ip::Address::isSiteLocalAuto() const
 {
-    return mSocketAddr_.sin6_addr.s6_addr[10] == static_cast<uint8_t>(0xff) &&
-           mSocketAddr_.sin6_addr.s6_addr[11] == static_cast<uint8_t>(0xfe);
+    return mSocketAddr_.sin6_addr.s6_addr[11] == static_cast<uint8_t>(0xff) &&
+           mSocketAddr_.sin6_addr.s6_addr[12] == static_cast<uint8_t>(0xfe);
 }
 
 bool
@@ -329,13 +356,6 @@ Ip::Address::getReverseString(char buf[MAX_IPSTRLEN], int show_type) const
     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();
@@ -373,6 +393,20 @@ Ip::Address::lookupHostIP(const char *s, bool nodns)
         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.
@@ -382,7 +416,7 @@ Ip::Address::lookupHostIP(const char *s, bool nodns)
     port(portSaved);
 
     /* free the memory getaddrinfo() dynamically allocated. */
-    freeaddrinfo(res);
+    freeaddrinfo(resHead);
     return true;
 }
 
@@ -406,7 +440,7 @@ Ip::Address::operator =(const struct sockaddr_storage &s)
 {
     /* 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_in));
+        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;
@@ -424,8 +458,7 @@ Ip::Address::Address(struct sockaddr_in6 const &s)
 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;
 };
 
@@ -452,19 +485,12 @@ Ip::Address::Address(struct in6_addr const &s)
 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();
@@ -639,7 +665,7 @@ Ip::Address::getAddrInfo(struct addrinfo *&dst, int force) const
 }
 
 void
-Ip::Address::InitAddrInfo(struct addrinfo *&ai)
+Ip::Address::InitAddr(struct addrinfo *&ai)
 {
     if (ai == NULL) {
         ai = new addrinfo;
@@ -657,7 +683,7 @@ Ip::Address::InitAddrInfo(struct addrinfo *&ai)
 }
 
 void
-Ip::Address::FreeAddrInfo(struct addrinfo *&ai)
+Ip::Address::FreeAddr(struct addrinfo *&ai)
 {
     if (ai == NULL) return;
 
@@ -781,7 +807,7 @@ Ip::Address::toStr(char* buf, const unsigned int blen, int force) const
     }
 
     /* 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));
@@ -878,13 +904,39 @@ Ip::Address::toUrl(char* buf, unsigned int blen) const
     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);
     }
@@ -923,7 +975,7 @@ Ip::Address::getSockAddr(struct sockaddr_in &buf) const
 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;
 
@@ -969,16 +1021,16 @@ Ip::Address::map6to4(const struct in6_addr &in, struct in_addr &out) const
 }
 
 void
-Ip::Address::getInAddr(in6_addr &buf) const
+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
 Ip::Address::getInAddr(struct in_addr &buf) const
 {
     if ( isIPv4() ) {
-        map6to4((const in6_addr)mSocketAddr_.sin6_addr, buf);
+        map6to4(mSocketAddr_.sin6_addr, buf);
         return true;
     }
 
@@ -990,3 +1042,4 @@ Ip::Address::getInAddr(struct in_addr &buf) const
     assert(false);
     return false;
 }
+