/*
- * DEBUG: section 28 Access Control
- * AUTHOR: Duane Wessels
+ * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
*
- * 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 "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,
* 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 );
int a1 = 0;
/* default is a mask that doesn't change any IP */
- mask.SetNoAddr();
+ mask.setNoAddr();
if (!asc || !*asc) {
return true;
if ((sscanf(asc, "%d%c", &a1, &junk)==1) &&
(a1 <= 128) && (a1 >= 0)
) {
- return mask.ApplyMask(a1, ctype);
+ return mask.applyMask(a1, ctype);
}
/* dotted notation */
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;
}
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;
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.
/* 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 ... */
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;
}
*/
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 */
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;
}
if ( iptype == AF_INET6 && !Ip::EnableIpv6) {
debugs(28, DBG_IMPORTANT, "aclIpParseIpData: IPv6 has not been enabled.");
delete q;
- return NULL;
+ 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) */
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;
}
}
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;
/*
* 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) {}