]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/acl/Ip.cc
Source Format Enforcement (#1234)
[thirdparty/squid.git] / src / acl / Ip.cc
index e323856170514416c1170df103b2a74e3954682c..6d2d202db72049ae48cd42305616dc80718421f8 100644 (file)
 /*
- * $Id$
+ * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
  *
- * DEBUG: section 28    Access Control
- * AUTHOR: Duane Wessels
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
+ * 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 28    Access Control */
+
 #include "squid.h"
-#include "acl/Ip.h"
 #include "acl/Checklist.h"
+#include "acl/Ip.h"
 #include "cache_cf.h"
-#include "Debug.h"
+#include "ConfigParser.h"
+#include "debug/Stream.h"
 #include "ip/tools.h"
 #include "MemBuf.h"
-#include "protos.h"
 #include "wordlist.h"
 
 void *
-ACLIP::operator new (size_t byteCount)
+ACLIP::operator new (size_t)
 {
     fatal ("ACLIP::operator new: unused");
     return (void *)1;
 }
 
 void
-ACLIP::operator delete (void *address)
+ACLIP::operator delete (void *)
 {
     fatal ("ACLIP::operator delete: unused");
 }
 
-/**
- * Writes an IP ACL data into a buffer, then copies the buffer into the wordlist given
- *
- \param ip     ACL data structure to display
- \param state  wordlist structure which is being generated
- */
-void
-ACLIP::DumpIpListWalkee(acl_ip_data * const & ip, void *state)
-{
-    char tmpbuf[ ((MAX_IPSTRLEN*2)+6) ]; // space for 2 IPs and a CIDR mask(3) and seperators(3).
-    MemBuf mb;
-    wordlist **W = static_cast<wordlist **>(state);
-    tmpbuf[0] = '\0';
-
-    mb.init();
-    assert(mb.max_capacity > 0 && 1==1 );
-
-    ip->toStr(tmpbuf, sizeof(tmpbuf) );
-    assert(mb.max_capacity > 0 && 2==2 );
-    mb.append(tmpbuf, strlen(tmpbuf) );
-    assert(mb.max_capacity > 0 && 3==3);
-    wordlistAdd(W, mb.buf);
-    mb.clean();
-}
-
 /**
  * print/format an acl_ip_data structure for debugging output.
  *
- \param buf    string buffer to write to
- \param len    size of the buffer available
+ \param buf string buffer to write to
+ \param len size of the buffer available
  */
 void
 acl_ip_data::toStr(char *buf, int len) const
 {
     char *b1 = buf;
-    char *b2 = NULL;
-    char *b3 = NULL;
+    char *b2 = nullptr;
+    char *b3 = nullptr;
     int rlen = 0;
 
-    addr1.NtoA(b1, len - rlen );
+    addr1.toStr(b1, len - rlen );
     rlen = strlen(buf);
     b2 = buf + rlen;
 
-    if (!addr2.IsAnyAddr()) {
+    if (!addr2.isAnyAddr()) {
         b2[0] = '-';
         ++rlen;
-        addr2.NtoA(&(b2[1]), len - rlen );
+        addr2.toStr(&(b2[1]), len - rlen );
         rlen = strlen(buf);
     } else
         b2[0] = '\0';
 
     b3 = buf + rlen;
 
-    if (!mask.IsNoAddr()) {
+    if (!mask.isNoAddr()) {
         b3[0] = '/';
         ++rlen;
-        int cidr =  mask.GetCIDR() - (addr1.IsIPv4()?96:0);
+        int cidr =  mask.cidr() - (addr1.isIPv4()?96:0);
         snprintf(&(b3[1]), (len-rlen), "%u", (unsigned int)(cidr<0?0:cidr) );
     } else
         b3[0] = '\0';
 }
 
+SBuf
+acl_ip_data::toSBuf() const
+{
+    const int bufsz = MAX_IPSTRLEN*2+6;
+    static char tmpbuf[ bufsz ];
+    toStr(tmpbuf,bufsz);
+    return SBuf(tmpbuf);
+}
+
 /*
  * aclIpAddrNetworkCompare - The guts of the comparison for IP ACLs
  * matching checks.  The first argument (p) is a "host" address,
@@ -125,18 +84,18 @@ acl_ip_data::toStr(char *buf, int len) const
  * is an entry in some address-based access control element.  This
  * function is called via ACLIP::match() and the splay library.
  */
-int
+static int
 aclIpAddrNetworkCompare(acl_ip_data * const &p, acl_ip_data * const &q)
 {
     Ip::Address A = p->addr1;
 
     /* apply netmask */
-    A.ApplyMask(q->mask);
+    A.applyMask(q->mask);
 
     debugs(28,9, "aclIpAddrNetworkCompare: compare: " << p->addr1 << "/" << q->mask << " (" << A << ")  vs " <<
            q->addr1 << "-" << q->addr2 << "/" << q->mask);
 
-    if (q->addr2.IsAnyAddr()) {       /* single address check */
+    if (q->addr2.isAnyAddr()) {       /* single address check */
 
         return A.matchIPAddr( q->addr1 );
 
@@ -200,7 +159,7 @@ acl_ip_data::DecodeMask(const char *asc, Ip::Address &mask, int ctype)
     int a1 = 0;
 
     /* default is a mask that doesn't change any IP */
-    mask.SetNoAddr();
+    mask.setNoAddr();
 
     if (!asc || !*asc) {
         return true;
@@ -210,7 +169,7 @@ acl_ip_data::DecodeMask(const char *asc, Ip::Address &mask, int ctype)
     if ((sscanf(asc, "%d%c", &a1, &junk)==1) &&
             (a1 <= 128) && (a1  >= 0)
        ) {
-        return mask.ApplyMask(a1, ctype);
+        return mask.applyMask(a1, ctype);
     }
 
     /* dotted notation */
@@ -218,16 +177,16 @@ acl_ip_data::DecodeMask(const char *asc, Ip::Address &mask, int ctype)
     if ((mask = asc)) {
         /* HACK: IPv4 netmasks don't cleanly map to IPv6 masks. */
         debugs(28, DBG_CRITICAL, "WARNING: Netmasks are deprecated. Please use CIDR masks instead.");
-        if (mask.IsIPv4()) {
+        if (mask.isIPv4()) {
             /* locate what CIDR mask was _probably_ meant to be in its native protocol format. */
             /* this will completely crap out with a security fail-open if the admin is playing mask tricks */
-            /* however, thats their fault, and we do warn. see bug 2601 for the effects if we don't do this. */
-            unsigned int m = mask.GetCIDR();
+            /* however, that's their fault, and we do warn. see bug 2601 for the effects if we don't do this. */
+            unsigned int m = mask.cidr();
             debugs(28, DBG_CRITICAL, "WARNING: IPv4 netmasks are particularly nasty when used to compare IPv6 to IPv4 ranges.");
             debugs(28, DBG_CRITICAL, "WARNING: For now we will assume you meant to write /" << m);
             /* reset the mask completely, and crop to the CIDR boundary back properly. */
-            mask.SetNoAddr();
-            return mask.ApplyMask(m,AF_INET);
+            mask.setNoAddr();
+            return mask.applyMask(m,AF_INET);
         }
         return true;
     }
@@ -252,8 +211,8 @@ acl_ip_data::FactoryParse(const char *t)
     LOCAL_ARRAY(char, addr1, 256);
     LOCAL_ARRAY(char, addr2, 256);
     LOCAL_ARRAY(char, mask, 256);
-    acl_ip_data *r = NULL;
-    acl_ip_data **Q = NULL;
+    acl_ip_data *r = nullptr;
+    acl_ip_data **Q = nullptr;
     Ip::Address temp;
     char c;
     unsigned int changed;
@@ -263,38 +222,38 @@ acl_ip_data::FactoryParse(const char *t)
     debugs(28, 5, "aclIpParseIpData: " << t);
 
     /* Special ACL RHS "all" matches entire Internet */
-    if (strcasecmp(t, "all") == 0) {
+    if (strcmp(t, "all") == 0) {
         debugs(28, 9, "aclIpParseIpData: magic 'all' found.");
-        q->addr1.SetAnyAddr();
-        q->addr2.SetEmpty();
-        q->mask.SetAnyAddr();
+        q->addr1.setAnyAddr();
+        q->addr2.setEmpty();
+        q->mask.setAnyAddr();
         return q;
     }
 
     /* Detect some old broken strings equivalent to 'all'.
      * treat them nicely. But be loud until its fixed.  */
-    if (strcasecmp(t, "0/0") == 0 || strcasecmp(t, "0.0.0.0/0") == 0 || strcasecmp(t, "0.0.0.0/0.0.0.0") == 0 ||
-            strcasecmp(t, "0.0.0.0-255.255.255.255") == 0 || strcasecmp(t, "0.0.0.0-0.0.0.0/0") == 0) {
+    if (strcmp(t, "0/0") == 0 || strcmp(t, "0.0.0.0/0") == 0 || strcmp(t, "0.0.0.0/0.0.0.0") == 0 ||
+            strcmp(t, "0.0.0.0-255.255.255.255") == 0 || strcmp(t, "0.0.0.0-0.0.0.0/0") == 0) {
 
         debugs(28,DBG_CRITICAL, "ERROR: '" << t << "' needs to be replaced by the term 'all'.");
         debugs(28,DBG_CRITICAL, "SECURITY NOTICE: Overriding config setting. Using 'all' instead.");
-        q->addr1.SetAnyAddr();
-        q->addr2.SetEmpty();
-        q->mask.SetAnyAddr();
+        q->addr1.setAnyAddr();
+        q->addr2.setEmpty();
+        q->mask.setAnyAddr();
         return q;
     }
 
     /* Special ACL RHS "ipv4" matches IPv4 Internet
      * A nod to IANA; we include the entire class space in case
      * they manage to find a way to recover and use it */
-    if (strcasecmp(t, "ipv4") == 0) {
-        q->mask.SetNoAddr();
-        q->mask.ApplyMask(0, AF_INET);
+    if (strcmp(t, "ipv4") == 0) {
+        q->mask.setNoAddr();
+        q->mask.applyMask(0, AF_INET);
         return q;
     }
 
     /* Special ACL RHS "ipv6" matches IPv6-Unicast Internet */
-    if (strcasecmp(t, "ipv6") == 0) {
+    if (strcmp(t, "ipv6") == 0) {
         debugs(28, 9, "aclIpParseIpData: magic 'ipv6' found.");
         r = q; // save head of the list for result.
 
@@ -302,43 +261,43 @@ acl_ip_data::FactoryParse(const char *t)
 
         /* Future global unicast space: 1000::/4 */
         q->addr1 = "1000::";
-        q->mask.SetNoAddr();
-        q->mask.ApplyMask(4, AF_INET6);
+        q->mask.setNoAddr();
+        q->mask.applyMask(4, AF_INET6);
 
         /* Current global unicast space: 2000::/4 = (2000::/4 - 3000::/4) */
         q->next = new acl_ip_data;
         q = q->next;
         q->addr1 = "2000::";
-        q->mask.SetNoAddr();
-        q->mask.ApplyMask(3, AF_INET6);
+        q->mask.setNoAddr();
+        q->mask.applyMask(3, AF_INET6);
 
         /* Future global unicast space: 4000::/2 = (4000::/4 - 7000::/4) */
         q->next = new acl_ip_data;
         q = q->next;
         q->addr1 = "4000::";
-        q->mask.SetNoAddr();
-        q->mask.ApplyMask(2, AF_INET6);
+        q->mask.setNoAddr();
+        q->mask.applyMask(2, AF_INET6);
 
         /* Future global unicast space: 8000::/2 = (8000::/4 - B000::/4) */
         q->next = new acl_ip_data;
         q = q->next;
         q->addr1 = "8000::";
-        q->mask.SetNoAddr();
-        q->mask.ApplyMask(2, AF_INET6);
+        q->mask.setNoAddr();
+        q->mask.applyMask(2, AF_INET6);
 
         /* Future global unicast space: C000::/3 = (C000::/4 - D000::/4) */
         q->next = new acl_ip_data;
         q = q->next;
         q->addr1 = "C000::";
-        q->mask.SetNoAddr();
-        q->mask.ApplyMask(3, AF_INET6);
+        q->mask.setNoAddr();
+        q->mask.applyMask(3, AF_INET6);
 
         /* Future global unicast space: E000::/4 */
         q->next = new acl_ip_data;
         q = q->next;
         q->addr1 = "E000::";
-        q->mask.SetNoAddr();
-        q->mask.ApplyMask(4, AF_INET6);
+        q->mask.setNoAddr();
+        q->mask.applyMask(4, AF_INET6);
 
         /* F000::/4 is mostly reserved non-unicast. With some exceptions ... */
 
@@ -346,15 +305,15 @@ acl_ip_data::FactoryParse(const char *t)
         q->next = new acl_ip_data;
         q = q->next;
         q->addr1 = "FC00::";
-        q->mask.SetNoAddr();
-        q->mask.ApplyMask(7, AF_INET6);
+        q->mask.setNoAddr();
+        q->mask.applyMask(7, AF_INET6);
 
         /* Link-Local unicast space: FE80::/10 */
         q->next = new acl_ip_data;
         q = q->next;
         q->addr1 = "FE80::";
-        q->mask.SetNoAddr();
-        q->mask.ApplyMask(10, AF_INET6);
+        q->mask.setNoAddr();
+        q->mask.applyMask(10, AF_INET6);
 
         return r;
     }
@@ -406,34 +365,30 @@ acl_ip_data::FactoryParse(const char *t)
          */
 
         debugs(28, 5, "aclIpParseIpData: Lookup Host/IP " << addr1);
-        struct addrinfo *hp = NULL, *x = NULL;
+        struct addrinfo *hp = nullptr, *x = nullptr;
         struct addrinfo hints;
-        Ip::Address *prev_addr = NULL;
+        Ip::Address *prev_addr = nullptr;
 
         memset(&hints, 0, sizeof(struct addrinfo));
 
-        if ( iptype != AF_UNSPEC ) {
-            hints.ai_flags |= AI_NUMERICHOST;
-        }
-
-#if 0
-        if (Ip::EnableIpv6&IPV6_SPECIAL_V4MAPPING)
-            hints.ai_flags |= AI_V4MAPPED | AI_ALL;
-#endif
-
-        int errcode = getaddrinfo(addr1,NULL,&hints,&hp);
-        if (hp == NULL) {
-            debugs(28, DBG_CRITICAL, "aclIpParseIpData: Bad host/IP: '" << addr1 <<
-                   "' in '" << t << "', flags=" << hints.ai_flags <<
-                   " : (" << errcode << ") " << gai_strerror(errcode) );
-            self_destruct();
-            return NULL;
+        int errcode = getaddrinfo(addr1,nullptr,&hints,&hp);
+        if (hp == nullptr) {
+            delete q;
+            if (strcmp(addr1, "::1") == 0) {
+                debugs(28, DBG_IMPORTANT, "aclIpParseIpData: IPv6 has not been enabled in host DNS resolver.");
+            } else {
+                debugs(28, DBG_CRITICAL, "ERROR: aclIpParseIpData: Bad host/IP: '" << addr1 <<
+                       "' in '" << t << "', flags=" << hints.ai_flags <<
+                       " : (" << errcode << ") " << gai_strerror(errcode) );
+                self_destruct();
+            }
+            return nullptr;
         }
 
         Q = &q;
 
-        for (x = hp; x != NULL;) {
-            if ((r = *Q) == NULL)
+        for (x = hp; x != nullptr;) {
+            if ((r = *Q) == nullptr)
                 r = *Q = new acl_ip_data;
 
             /* getaddrinfo given a host has a nasty tendency to return duplicate addr's */
@@ -443,72 +398,73 @@ acl_ip_data::FactoryParse(const char *t)
             if ( prev_addr && r->addr1 == *prev_addr) {
                 debugs(28, 3, "aclIpParseIpData: Duplicate host/IP: '" << r->addr1 << "' dropped.");
                 delete r;
-                *Q = NULL;
+                *Q = nullptr;
                 continue;
             } else
                 prev_addr = &r->addr1;
 
             debugs(28, 3, "aclIpParseIpData: Located host/IP: '" << r->addr1 << "'");
 
-            r->addr2.SetAnyAddr();
-            r->mask.SetNoAddr();
+            r->addr2.setAnyAddr();
+            r->mask.setNoAddr();
 
             Q = &r->next;
 
             debugs(28, 3, "" << addr1 << " --> " << r->addr1 );
         }
 
-        if (*Q != NULL) {
-            debugs(28, DBG_CRITICAL, "aclIpParseIpData: Bad host/IP: '" << t << "'");
+        freeaddrinfo(hp);
+
+        if (*Q != nullptr) {
+            debugs(28, DBG_CRITICAL, "ERROR: aclIpParseIpData: Bad host/IP: '" << t << "'");
             self_destruct();
-            return NULL;
+            return nullptr;
         }
 
-        freeaddrinfo(hp);
-
         return q;
     }
 
     /* ignore IPv6 addresses when built with IPv4-only */
     if ( iptype == AF_INET6 && !Ip::EnableIpv6) {
         debugs(28, DBG_IMPORTANT, "aclIpParseIpData: IPv6 has not been enabled.");
-        return NULL;
+        delete q;
+        return nullptr;
     }
 
     /* Decode addr1 */
     if (!*addr1 || !(q->addr1 = addr1)) {
-        debugs(28, DBG_CRITICAL, "aclIpParseIpData: unknown first address in '" << t << "'");
+        debugs(28, DBG_CRITICAL, "ERROR: aclIpParseIpData: unknown first address in '" << t << "'");
         delete q;
         self_destruct();
-        return NULL;
+        return nullptr;
     }
 
     /* Decode addr2 */
     if (!*addr2)
-        q->addr2.SetAnyAddr();
+        q->addr2.setAnyAddr();
     else if (!(q->addr2=addr2) ) {
-        debugs(28, DBG_CRITICAL, "aclIpParseIpData: unknown second address in '" << t << "'");
+        debugs(28, DBG_CRITICAL, "ERROR: aclIpParseIpData: unknown second address in '" << t << "'");
         delete q;
         self_destruct();
-        return NULL;
+        return nullptr;
     }
 
     /* Decode mask (NULL or empty means a exact host mask) */
     if (!DecodeMask(mask, q->mask, iptype)) {
-        debugs(28, DBG_CRITICAL, "aclParseIpData: unknown netmask '" << mask << "' in '" << t << "'");
+        debugs(28, DBG_CRITICAL, "ERROR: aclParseIpData: unknown netmask '" << mask << "' in '" << t << "'");
         delete q;
         self_destruct();
-        return NULL;
+        return nullptr;
     }
 
     changed = 0;
-    changed += q->addr1.ApplyMask(q->mask);
-    changed += q->addr2.ApplyMask(q->mask);
+    changed += q->addr1.applyMask(q->mask);
+    changed += q->addr2.applyMask(q->mask);
 
     if (changed)
-        debugs(28, DBG_CRITICAL, "aclIpParseIpData: WARNING: Netmask masks away part of the specified IP in '" << t << "'");
+        debugs(28, DBG_CRITICAL, "WARNING: aclIpParseIpData: Netmask masks away part of the specified IP in '" << t << "'");
 
-    debugs(28,9, HERE << "Parsed: " << q->addr1 << "-" << q->addr2 << "/" << q->mask << "(/" << q->mask.GetCIDR() <<")");
+    debugs(28,9, "Parsed: " << q->addr1 << "-" << q->addr2 << "/" << q->mask << "(/" << q->mask.cidr() <<")");
 
     /* 1.2.3.4/255.255.255.0  --> 1.2.3.0 */
     /* Same as IPv6 (not so trivial to depict) */
@@ -518,16 +474,18 @@ acl_ip_data::FactoryParse(const char *t)
 void
 ACLIP::parse()
 {
-    char *t = NULL;
+    if (data == nullptr)
+        data = new IPSplay();
 
-    while ((t = strtokFile())) {
+    while (char *t = ConfigParser::strtokFile()) {
         acl_ip_data *q = acl_ip_data::FactoryParse(t);
 
-        while (q != NULL) {
+        while (q != nullptr) {
             /* pop each result off the list and add it to the data tree individually */
             acl_ip_data *next_node = q->next;
-            q->next = NULL;
-            data = data->insert(q, acl_ip_data::NetworkCompare);
+            q->next = nullptr;
+            if (!data->find(q,acl_ip_data::NetworkCompare))
+                data->insert(q, acl_ip_data::NetworkCompare);
             q = next_node;
         }
     }
@@ -535,26 +493,35 @@ ACLIP::parse()
 
 ACLIP::~ACLIP()
 {
-    if (data)
-        data->destroy(IPSplay::DefaultFree);
+    if (data) {
+        data->destroy();
+        delete data;
+    }
 }
 
-wordlist *
+struct IpAclDumpVisitor {
+    SBufList contents;
+    void operator() (acl_ip_data * const & ip) {
+        contents.push_back(ip->toSBuf());
+    }
+};
+
+SBufList
 ACLIP::dump() const
 {
-    wordlist *w = NULL;
-    data->walk (DumpIpListWalkee, &w);
-    return w;
+    IpAclDumpVisitor visitor;
+    data->visit(visitor);
+    return visitor.contents;
 }
 
 bool
-ACLIP::empty () const
+ACLIP::empty() const
 {
     return data->empty();
 }
 
 int
-ACLIP::match(Ip::Address &clientip)
+ACLIP::match(const Ip::Address &clientip)
 {
     static acl_ip_data ClientAddress;
     /*
@@ -564,14 +531,15 @@ ACLIP::match(Ip::Address &clientip)
      * MUST be set to empty.
      */
     ClientAddress.addr1 = clientip;
-    ClientAddress.addr2.SetEmpty();
-    ClientAddress.mask.SetEmpty();
+    ClientAddress.addr2.setEmpty();
+    ClientAddress.mask.setEmpty();
 
-    data = data->splay(&ClientAddress, aclIpAddrNetworkCompare);
-    debugs(28, 3, "aclIpMatchIp: '" << clientip << "' " << (splayLastResult ? "NOT found" : "found"));
-    return !splayLastResult;
+    const acl_ip_data * const * result =  data->find(&ClientAddress, aclIpAddrNetworkCompare);
+    debugs(28, 3, "aclIpMatchIp: '" << clientip << "' " << (result ? "found" : "NOT found"));
+    return (result != nullptr);
 }
 
-acl_ip_data::acl_ip_data () :addr1(), addr2(), mask(), next (NULL) {}
+acl_ip_data::acl_ip_data() :addr1(), addr2(), mask(), next (nullptr) {}
+
+acl_ip_data::acl_ip_data(Ip::Address const &anAddress1, Ip::Address const &anAddress2, Ip::Address const &aMask, acl_ip_data *aNext) : addr1(anAddress1), addr2(anAddress2), mask(aMask), next(aNext) {}
 
-acl_ip_data::acl_ip_data (Ip::Address const &anAddress1, Ip::Address const &anAddress2, Ip::Address const &aMask, acl_ip_data *aNext) : addr1(anAddress1), addr2(anAddress2), mask(aMask), next(aNext) {}