/*
- * DEBUG: section 78 DNS lookups; interacts with lib/rfc1035.c
- * 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) 1996-2023 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 78 DNS lookups; interacts with dns/rfc1035.cc */
+
#include "squid.h"
+#include "base/CodeContext.h"
#include "base/InstanceId.h"
+#include "base/IoManip.h"
+#include "base/Random.h"
+#include "base/RunnersRegistry.h"
+#include "comm.h"
#include "comm/Connection.h"
#include "comm/ConnOpener.h"
-#include "comm.h"
#include "comm/Loops.h"
+#include "comm/Read.h"
#include "comm/Write.h"
+#include "debug/Messages.h"
#include "dlink.h"
+#include "dns/forward.h"
+#include "dns/rfc3596.h"
#include "event.h"
#include "fd.h"
#include "fde.h"
#include "ip/tools.h"
-#include "Mem.h"
#include "MemBuf.h"
#include "mgr/Registration.h"
-#include "rfc3596.h"
+#include "snmp_agent.h"
#include "SquidConfig.h"
-#include "SquidTime.h"
#include "Store.h"
#include "tools.h"
#include "util.h"
#if HAVE_ARPA_NAMESER_H
#include <arpa/nameser.h>
#endif
+#include <cerrno>
#if HAVE_RESOLV_H
#include <resolv.h>
#endif
-#if HAVE_ERRNO_H
-#include <errno.h>
-#endif
#if _SQUID_WINDOWS_
#define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
"Bad OPT Version or TSIG Signature Failure"
};
-typedef struct _idns_query idns_query;
-
-typedef struct _ns ns;
-
typedef struct _sp sp;
-typedef struct _nsvc nsvc;
+class idns_query
+{
+ CBDATA_CLASS(idns_query);
+
+public:
+ idns_query():
+ codeContext(CodeContext::Current())
+ {
+ callback = nullptr;
+ memset(&query, 0, sizeof(query));
+ *buf = 0;
+ *name = 0;
+ *orig = 0;
+ memset(&start_t, 0, sizeof(start_t));
+ memset(&sent_t, 0, sizeof(sent_t));
+ memset(&queue_t, 0, sizeof(queue_t));
+ }
+
+ ~idns_query() {
+ if (message)
+ rfc1035MessageDestroy(&message);
+ delete queue;
+ delete slave;
+ // master is just a back-reference
+ cbdataReferenceDone(callback_data);
+ }
-struct _idns_query {
hash_link hash;
rfc1035_query query;
char buf[RESOLV_BUFSZ];
char name[NS_MAXDNAME + 1];
char orig[NS_MAXDNAME + 1];
- ssize_t sz;
- unsigned short query_id; /// random query ID sent to server; changes with every query sent
- InstanceId<idns_query> xact_id; /// identifies our "transaction", stays constant when query is retried
+ ssize_t sz = 0;
+ unsigned short query_id = 0; ///< random query ID sent to server; changes with every query sent
+ InstanceId<idns_query> xact_id; ///< identifies our "transaction", stays constant when query is retried
- int nsends;
- int need_vc;
- bool permit_mdns;
- int pending;
+ int nsends = 0;
+ int need_vc = 0;
+ bool permit_mdns = false;
+ int pending = 0;
struct timeval start_t;
struct timeval sent_t;
struct timeval queue_t;
dlink_node lru;
+
IDNSCB *callback;
- void *callback_data;
- int attempt;
- int rcode;
- idns_query *queue;
- idns_query *slave; // single linked list
- idns_query *master; // single pointer to a shared master
- unsigned short domain;
- unsigned short do_searchpath;
- rfc1035_message *message;
- int ancount;
- const char *error;
+ void *callback_data = nullptr;
+ CodeContext::Pointer codeContext; ///< requestor's context
+
+ int attempt = 0;
+ int rcode = 0;
+ idns_query *queue = nullptr;
+ idns_query *slave = nullptr; // single linked list
+ idns_query *master = nullptr; // single pointer to a shared master
+ unsigned short domain = 0;
+ unsigned short do_searchpath = 0;
+ rfc1035_message *message = nullptr;
+ int ancount = 0;
+ const char *error = nullptr;
};
+
InstanceIdDefinitions(idns_query, "dns");
-struct _nsvc {
- int ns;
+CBDATA_CLASS_INIT(idns_query);
+
+class nsvc
+{
+ CBDATA_CLASS(nsvc);
+
+public:
+ explicit nsvc(size_t nsv) : ns(nsv), msg(new MemBuf()), queue(new MemBuf()) {}
+ ~nsvc();
+
+ size_t ns = 0;
Comm::ConnectionPointer conn;
- unsigned short msglen;
- int read_msglen;
- MemBuf *msg;
- MemBuf *queue;
- bool busy;
+ unsigned short msglen = 0;
+ int read_msglen = 0;
+ MemBuf *msg = nullptr;
+ MemBuf *queue = nullptr;
+ bool busy = true;
};
-struct _ns {
+CBDATA_CLASS_INIT(nsvc);
+
+class ns
+{
+public:
Ip::Address S;
- int nqueries;
- int nreplies;
+ int nqueries = 0;
+ int nreplies = 0;
#if WHEN_EDNS_RESPONSES_ARE_PARSED
- int last_seen_edns;
+ int last_seen_edns = 0;
#endif
- bool mDNSResolver;
- nsvc *vc;
+ bool mDNSResolver = false;
+ nsvc *vc = nullptr;
+};
+
+namespace Dns
+{
+
+/// manage DNS internal component
+class ConfigRr : public RegisteredRunner
+{
+public:
+ /* RegisteredRunner API */
+ void startReconfigure() override;
+ void endingShutdown() override;
};
+} // namespace Dns
+
+DefineRunnerRegistratorIn(Dns, ConfigRr);
+
struct _sp {
char domain[NS_MAXDNAME];
int queries;
};
-CBDATA_TYPE(nsvc);
-CBDATA_TYPE(idns_query);
-
-static ns *nameservers = NULL;
-static sp *searchpath = NULL;
-static int nns = 0;
-static int nns_alloc = 0;
+static std::vector<ns> nameservers;
+static sp *searchpath = nullptr;
static int nns_mdns_count = 0;
static int npc = 0;
static int npc_alloc = 0;
static int ndots = 1;
static dlink_list lru_list;
static int event_queued = 0;
-static hash_table *idns_lookup_hash = NULL;
+static hash_table *idns_lookup_hash = nullptr;
/*
* Notes on EDNS:
static void idnsAddNameserver(const char *buf);
static void idnsAddMDNSNameservers();
static void idnsAddPathComponent(const char *buf);
-static void idnsFreeNameservers(void);
static void idnsFreeSearchpath(void);
static bool idnsParseNameservers(void);
-#if _SQUID_WINDOWS_
static bool idnsParseResolvConf(void);
-#endif
#if _SQUID_WINDOWS_
static bool idnsParseWIN32Registry(void);
static void idnsParseWIN32SearchList(const char *);
static CLCB idnsVCClosed;
static unsigned short idnsQueryID(void);
static void idnsSendSlaveAAAAQuery(idns_query *q);
+static void idnsCallbackOnEarlyError(IDNSCB *callback, void *cbdata, const char *error);
static void
idnsCheckMDNS(idns_query *q)
// mDNS resolver addresses are explicit multicast group IPs
if (Ip::EnableIpv6) {
idnsAddNameserver("FF02::FB");
- nameservers[nns-1].S.port(5353);
- nameservers[nns-1].mDNSResolver = true;
+ nameservers.back().S.port(5353);
+ nameservers.back().mDNSResolver = true;
++nns_mdns_count;
}
idnsAddNameserver("224.0.0.251");
- nameservers[nns-1].S.port(5353);
- nameservers[nns-1].mDNSResolver = true;
+ nameservers.back().S.port(5353);
+ nameservers.back().mDNSResolver = true;
++nns_mdns_count;
}
return;
}
- if (nns == nns_alloc) {
- int oldalloc = nns_alloc;
- ns *oldptr = nameservers;
-
- if (nns_alloc == 0)
- nns_alloc = 2;
- else
- nns_alloc <<= 1;
-
- nameservers = (ns *)xcalloc(nns_alloc, sizeof(*nameservers));
-
- if (oldptr && oldalloc)
- memcpy(nameservers, oldptr, oldalloc * sizeof(*nameservers));
-
- if (oldptr)
- safe_free(oldptr);
- }
-
- assert(nns < nns_alloc);
+ auto &nameserver = nameservers.emplace_back(ns());
A.port(NS_DEFAULTPORT);
- nameservers[nns].S = A;
+ nameserver.S = A;
#if WHEN_EDNS_RESPONSES_ARE_PARSED
- nameservers[nns].last_seen_edns = RFC1035_DEFAULT_PACKET_SZ;
+ nameserver.last_seen_edns = RFC1035_DEFAULT_PACKET_SZ;
// TODO generate a test packet to probe this NS from EDNS size and ability.
#endif
- debugs(78, 3, "idnsAddNameserver: Added nameserver #" << nns << " (" << A << ")");
- ++nns;
+ debugs(78, 3, "Added nameserver #" << nameservers.size()-1 << " (" << A << ")");
}
static void
++npc;
}
-static void
-idnsFreeNameservers(void)
-{
- safe_free(nameservers);
- nns = nns_alloc = 0;
-}
-
static void
idnsFreeSearchpath(void)
{
idnsParseNameservers(void)
{
bool result = false;
- for (wordlist *w = Config.dns_nameservers; w; w = w->next) {
- debugs(78, DBG_IMPORTANT, "Adding nameserver " << w->key << " from squid.conf");
- idnsAddNameserver(w->key);
+ for (auto &i : Config.dns.nameservers) {
+ debugs(78, Important(15), "Adding nameserver " << i << " from squid.conf");
+ idnsAddNameserver(i.c_str());
result = true;
}
return result;
}
-#if !_SQUID_WINDOWS_
static bool
idnsParseResolvConf(void)
{
- FILE *fp;
- char buf[RESOLV_BUFSZ];
- const char *t;
bool result = false;
- fp = fopen(_PATH_RESCONF, "r");
+#if !_SQUID_WINDOWS_
+ FILE *fp = fopen(_PATH_RESCONF, "r");
- if (fp == NULL) {
- debugs(78, DBG_IMPORTANT, "" << _PATH_RESCONF << ": " << xstrerror());
+ if (!fp) {
+ int xerrno = errno;
+ debugs(78, DBG_IMPORTANT, "" << _PATH_RESCONF << ": " << xstrerr(xerrno));
return false;
}
-#if _SQUID_CYGWIN_
- setmode(fileno(fp), O_TEXT);
-#endif
-
+ char buf[RESOLV_BUFSZ];
+ const char *t = nullptr;
while (fgets(buf, RESOLV_BUFSZ, fp)) {
t = strtok(buf, w_space);
- if (NULL == t) {
+ if (nullptr == t) {
continue;
} else if (strcmp(t, "nameserver") == 0) {
- t = strtok(NULL, w_space);
+ t = strtok(nullptr, w_space);
- if (NULL == t)
+ if (nullptr == t)
continue;
debugs(78, DBG_IMPORTANT, "Adding nameserver " << t << " from " << _PATH_RESCONF);
result = true;
} else if (strcmp(t, "domain") == 0) {
idnsFreeSearchpath();
- t = strtok(NULL, w_space);
+ t = strtok(nullptr, w_space);
- if (NULL == t)
+ if (nullptr == t)
continue;
debugs(78, DBG_IMPORTANT, "Adding domain " << t << " from " << _PATH_RESCONF);
idnsAddPathComponent(t);
} else if (strcmp(t, "search") == 0) {
idnsFreeSearchpath();
- while (NULL != t) {
- t = strtok(NULL, w_space);
+ while (nullptr != t) {
+ t = strtok(nullptr, w_space);
- if (NULL == t)
+ if (nullptr == t)
continue;
debugs(78, DBG_IMPORTANT, "Adding domain " << t << " from " << _PATH_RESCONF);
idnsAddPathComponent(t);
}
} else if (strcmp(t, "options") == 0) {
- while (NULL != t) {
- t = strtok(NULL, w_space);
+ while (nullptr != t) {
+ t = strtok(nullptr, w_space);
- if (NULL == t)
+ if (nullptr == t)
continue;
if (strncmp(t, "ndots:", 6) == 0) {
}
fclose(fp);
+#endif
return result;
}
-#endif
-
#if _SQUID_WINDOWS_
static void
idnsParseWIN32SearchList(const char * Separator)
DWORD Type = 0;
DWORD Size = 0;
LONG Result;
- Result = RegQueryValueEx(hndKey, "Domain", NULL, &Type, NULL, &Size);
+ Result = RegQueryValueEx(hndKey, "Domain", nullptr, &Type, nullptr, &Size);
if (Result == ERROR_SUCCESS && Size) {
t = (char *) xmalloc(Size);
- RegQueryValueEx(hndKey, "Domain", NULL, &Type, (LPBYTE) t, &Size);
+ RegQueryValueEx(hndKey, "Domain", nullptr, &Type, (LPBYTE) t, &Size);
debugs(78, DBG_IMPORTANT, "Adding domain " << t << " from Registry");
idnsAddPathComponent(t);
xfree(t);
}
- Result = RegQueryValueEx(hndKey, "SearchList", NULL, &Type, NULL, &Size);
+ Result = RegQueryValueEx(hndKey, "SearchList", nullptr, &Type, nullptr, &Size);
if (Result == ERROR_SUCCESS && Size) {
t = (char *) xmalloc(Size);
- RegQueryValueEx(hndKey, "SearchList", NULL, &Type, (LPBYTE) t, &Size);
+ RegQueryValueEx(hndKey, "SearchList", nullptr, &Type, (LPBYTE) t, &Size);
token = strtok(t, Separator);
while (token) {
idnsAddPathComponent(token);
debugs(78, DBG_IMPORTANT, "Adding domain " << token << " from Registry");
- token = strtok(NULL, Separator);
+ token = strtok(nullptr, Separator);
}
xfree(t);
}
DWORD Type = 0;
DWORD Size = 0;
LONG Result;
- Result = RegQueryValueEx(hndKey, "DhcpNameServer", NULL, &Type, NULL, &Size);
+ Result = RegQueryValueEx(hndKey, "DhcpNameServer", nullptr, &Type, nullptr, &Size);
if (Result == ERROR_SUCCESS && Size) {
t = (char *) xmalloc(Size);
- RegQueryValueEx(hndKey, "DhcpNameServer", NULL, &Type, (LPBYTE) t, &Size);
+ RegQueryValueEx(hndKey, "DhcpNameServer", nullptr, &Type, (LPBYTE) t, &Size);
token = strtok(t, ", ");
while (token) {
idnsAddNameserver(token);
result = true;
debugs(78, DBG_IMPORTANT, "Adding DHCP nameserver " << token << " from Registry");
- token = strtok(NULL, ",");
+ token = strtok(nullptr, ",");
}
xfree(t);
}
- Result = RegQueryValueEx(hndKey, "NameServer", NULL, &Type, NULL, &Size);
+ Result = RegQueryValueEx(hndKey, "NameServer", nullptr, &Type, nullptr, &Size);
if (Result == ERROR_SUCCESS && Size) {
t = (char *) xmalloc(Size);
- RegQueryValueEx(hndKey, "NameServer", NULL, &Type, (LPBYTE) t, &Size);
+ RegQueryValueEx(hndKey, "NameServer", nullptr, &Type, (LPBYTE) t, &Size);
token = strtok(t, ", ");
while (token) {
debugs(78, DBG_IMPORTANT, "Adding nameserver " << token << " from Registry");
idnsAddNameserver(token);
result = true;
- token = strtok(NULL, ", ");
+ token = strtok(nullptr, ", ");
}
xfree(t);
}
char *keyname;
FILETIME ftLastWriteTime;
- if (RegQueryInfoKey(hndKey, NULL, NULL, NULL, &InterfacesCount, &MaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
+ if (RegQueryInfoKey(hndKey, nullptr, nullptr, nullptr, &InterfacesCount, &MaxSubkeyLen, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS) {
keyname = (char *) xmalloc(++MaxSubkeyLen);
for (i = 0; i < (int) InterfacesCount; ++i) {
DWORD j;
j = MaxSubkeyLen;
- if (RegEnumKeyEx(hndKey, i, keyname, &j, NULL, NULL, NULL, &ftLastWriteTime) == ERROR_SUCCESS) {
+ if (RegEnumKeyEx(hndKey, i, keyname, &j, nullptr, nullptr, nullptr, &ftLastWriteTime) == ERROR_SUCCESS) {
char *newkeyname;
newkeyname = (char *) xmalloc(sizeof(REG_TCPIP_PARA_INTERFACES) + j + 2);
strcpy(newkeyname, REG_TCPIP_PARA_INTERFACES);
DWORD Type = 0;
DWORD Size = 0;
LONG Result;
- Result = RegQueryValueEx(hndKey2, "DhcpNameServer", NULL, &Type, NULL, &Size);
+ Result = RegQueryValueEx(hndKey2, "DhcpNameServer", nullptr, &Type, nullptr, &Size);
if (Result == ERROR_SUCCESS && Size) {
t = (char *) xmalloc(Size);
- RegQueryValueEx(hndKey2, "DhcpNameServer", NULL, &Type, (LPBYTE)t, &Size);
+ RegQueryValueEx(hndKey2, "DhcpNameServer", nullptr, &Type, (LPBYTE)t, &Size);
token = strtok(t, ", ");
while (token) {
debugs(78, DBG_IMPORTANT, "Adding DHCP nameserver " << token << " from Registry");
idnsAddNameserver(token);
result = true;
- token = strtok(NULL, ", ");
+ token = strtok(nullptr, ", ");
}
xfree(t);
}
- Result = RegQueryValueEx(hndKey2, "NameServer", NULL, &Type, NULL, &Size);
+ Result = RegQueryValueEx(hndKey2, "NameServer", nullptr, &Type, nullptr, &Size);
if (Result == ERROR_SUCCESS && Size) {
t = (char *) xmalloc(Size);
- RegQueryValueEx(hndKey2, "NameServer", NULL, &Type, (LPBYTE)t, &Size);
+ RegQueryValueEx(hndKey2, "NameServer", nullptr, &Type, (LPBYTE)t, &Size);
token = strtok(t, ", ");
while (token) {
debugs(78, DBG_IMPORTANT, "Adding nameserver " << token << " from Registry");
idnsAddNameserver(token);
result = true;
- token = strtok(NULL, ", ");
+ token = strtok(nullptr, ", ");
}
xfree(t);
DWORD Type = 0;
DWORD Size = 0;
LONG Result;
- Result = RegQueryValueEx(hndKey, "NameServer", NULL, &Type, NULL, &Size);
+ Result = RegQueryValueEx(hndKey, "NameServer", nullptr, &Type, nullptr, &Size);
if (Result == ERROR_SUCCESS && Size) {
t = (char *) xmalloc(Size);
- RegQueryValueEx(hndKey, "NameServer", NULL, &Type, (LPBYTE) t, &Size);
+ RegQueryValueEx(hndKey, "NameServer", nullptr, &Type, (LPBYTE) t, &Size);
token = strtok(t, ", ");
while (token) {
debugs(78, DBG_IMPORTANT, "Adding nameserver " << token << " from Registry");
idnsAddNameserver(token);
result = true;
- token = strtok(NULL, ", ");
+ token = strtok(nullptr, ", ");
}
xfree(t);
}
break;
default:
- debugs(78, DBG_IMPORTANT, "Failed to read nameserver from Registry: Unknown System Type.");
+ debugs(78, DBG_IMPORTANT, "ERROR: Failed to read nameserver from Registry: Unknown System Type.");
}
return result;
storeAppendPrintf(sentry, "IP ADDRESS # QUERIES # REPLIES Type\n");
storeAppendPrintf(sentry, "---------------------------------------------- --------- --------- --------\n");
- for (i = 0; i < nns; ++i) {
+ for (const auto &server : nameservers) {
storeAppendPrintf(sentry, "%-45s %9d %9d %s\n", /* Let's take the maximum: (15 IPv4/45 IPv6) */
- nameservers[i].S.toStr(buf,MAX_IPSTRLEN),
- nameservers[i].nqueries,
- nameservers[i].nreplies,
- nameservers[i].mDNSResolver?"multicast":"recurse");
+ server.S.toStr(buf,MAX_IPSTRLEN),
+ server.nqueries,
+ server.nreplies,
+ server.mDNSResolver?"multicast":"recurse");
}
storeAppendPrintf(sentry, "\nRcode Matrix:\n");
if (event_queued)
return;
- if (NULL == lru_list.tail)
+ if (nullptr == lru_list.tail)
return;
const double when = min(Config.Timeout.idns_query, Config.Timeout.idns_retransmit)/1000.0;
- eventAdd("idnsCheckQueue", idnsCheckQueue, NULL, when, 1);
+ eventAdd("idnsCheckQueue", idnsCheckQueue, nullptr, when, 1);
event_queued = 1;
}
static void
-idnsSentQueryVC(const Comm::ConnectionPointer &conn, char *buf, size_t size, comm_err_t flag, int xerrno, void *data)
+idnsSentQueryVC(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag flag, int, void *data)
{
nsvc * vc = (nsvc *)data;
- if (flag == COMM_ERR_CLOSING)
+ if (flag == Comm::ERR_CLOSING)
return;
// XXX: irrelevant now that we have conn pointer?
if (!Comm::IsConnOpen(conn) || fd_table[conn->fd].closing())
return;
- if (flag != COMM_OK || size <= 0) {
+ if (flag != Comm::OK || size <= 0) {
conn->close();
return;
}
vc->busy = 1;
// Comm needs seconds but idnsCheckQueue() will check the exact timeout
- const int timeout = (Config.Timeout.idns_query % 1000 ?
- Config.Timeout.idns_query + 1000 : Config.Timeout.idns_query) / 1000;
+ const auto timeout = (Config.Timeout.idns_query % 1000 ?
+ Config.Timeout.idns_query + 1000 : Config.Timeout.idns_query) / 1000;
AsyncCall::Pointer nil;
commSetConnTimeout(vc->conn, timeout, nil);
}
static void
-idnsInitVCConnected(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data)
+idnsInitVCConnected(const Comm::ConnectionPointer &conn, Comm::Flag status, int, void *data)
{
nsvc * vc = (nsvc *)data;
- if (status != COMM_OK || !conn) {
+ if (status != Comm::OK || !conn) {
char buf[MAX_IPSTRLEN] = "";
- if (vc->ns < nns)
+ if (vc->ns < nameservers.size())
nameservers[vc->ns].S.toStr(buf,MAX_IPSTRLEN);
- debugs(78, DBG_IMPORTANT, HERE << "Failed to connect to nameserver " << buf << " using TCP.");
+ debugs(78, DBG_IMPORTANT, "ERROR: Failed to connect to nameserver " << buf << " using TCP.");
return;
}
idnsVCClosed(const CommCloseCbParams ¶ms)
{
nsvc * vc = (nsvc *)params.data;
- delete vc->queue;
- delete vc->msg;
- vc->conn = NULL;
- if (vc->ns < nns) // XXX: dnsShutdown may have freed nameservers[]
- nameservers[vc->ns].vc = NULL;
- cbdataFree(vc);
+ if (vc->conn) {
+ vc->conn->noteClosure();
+ vc->conn = nullptr;
+ }
+ delete vc;
+}
+
+nsvc::~nsvc()
+{
+ delete queue;
+ delete msg;
+ if (ns < nameservers.size()) // XXX: idnsShutdownAndFreeState may have freed nameservers[]
+ nameservers[ns].vc = nullptr;
}
static void
-idnsInitVC(int nsv)
+idnsInitVC(size_t nsv)
{
- nsvc *vc = cbdataAlloc(nsvc);
- assert(nsv < nns);
- assert(vc->conn == NULL); // MUST be NULL from the construction process!
+ assert(nsv < nameservers.size());
+ nsvc *vc = new nsvc(nsv);
+ assert(vc->conn == nullptr); // MUST be NULL from the construction process!
nameservers[nsv].vc = vc;
- vc->ns = nsv;
- vc->queue = new MemBuf;
- vc->msg = new MemBuf;
- vc->busy = 1;
Comm::ConnectionPointer conn = new Comm::Connection();
if (!Config.Addrs.udp_outgoing.isNoAddr())
- conn->local = Config.Addrs.udp_outgoing;
+ conn->setAddrs(Config.Addrs.udp_outgoing, nameservers[nsv].S);
else
- conn->local = Config.Addrs.udp_incoming;
-
- conn->remote = nameservers[nsv].S;
+ conn->setAddrs(Config.Addrs.udp_incoming, nameservers[nsv].S);
- if (conn->remote.isIPv4()) {
+ if (conn->remote.isIPv4())
conn->local.setIPv4();
- }
AsyncCall::Pointer call = commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected, vc));
}
static void
-idnsSendQueryVC(idns_query * q, int nsn)
+idnsSendQueryVC(idns_query * q, size_t nsn)
{
- assert(nsn < nns);
- if (nameservers[nsn].vc == NULL)
+ assert(nsn < nameservers.size());
+ if (nameservers[nsn].vc == nullptr)
idnsInitVC(nsn);
nsvc *vc = nameservers[nsn].vc;
if (!vc) {
char buf[MAX_IPSTRLEN];
- debugs(78, DBG_IMPORTANT, "idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers[nsn].S.toStr(buf,MAX_IPSTRLEN) << "!");
+ debugs(78, DBG_IMPORTANT, "ERROR: idnsSendQuery: Failed to initiate TCP connection to nameserver " << nameservers[nsn].S.toStr(buf,MAX_IPSTRLEN) << "!");
return;
}
static void
idnsSendQuery(idns_query * q)
{
+ // XXX: DNS sockets get closed during reconfigure produces a race between
+ // any already active connections (or ones received between closing DNS
+ // sockets and server listening sockets) and the reconfigure completing
+ // (Runner syncConfig() being run). Transactions which loose this race will
+ // produce DNS timeouts (or whatever the caller set) as their queries never
+ // get queued to be re-tried after the DNS socekts are re-opened.
+
if (DnsSocketA < 0 && DnsSocketB < 0) {
debugs(78, DBG_IMPORTANT, "WARNING: idnsSendQuery: Can't send query, no DNS socket!");
return;
}
- if (nns <= 0) {
+ if (nameservers.empty()) {
debugs(78, DBG_IMPORTANT, "WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
return;
}
- assert(q->lru.next == NULL);
+ assert(q->lru.next == nullptr);
- assert(q->lru.prev == NULL);
+ assert(q->lru.prev == nullptr);
int x = -1, y = -1;
- int nsn;
+ size_t nsn;
+ const auto nsCount = nameservers.size();
do {
// only use mDNS resolvers for mDNS compatible queries
if (!q->permit_mdns)
- nsn = nns_mdns_count + q->nsends % (nns-nns_mdns_count);
+ nsn = nns_mdns_count + q->nsends % (nsCount - nns_mdns_count);
else
- nsn = q->nsends % nns;
+ nsn = q->nsends % nsCount;
if (q->need_vc) {
idnsSendQueryVC(q, nsn);
else if (DnsSocketA >= 0)
x = comm_udp_sendto(DnsSocketA, nameservers[nsn].S, q->buf, q->sz);
}
+ int xerrno = errno;
++ q->nsends;
q->sent_t = current_time;
if (y < 0 && nameservers[nsn].S.isIPv6())
- debugs(50, DBG_IMPORTANT, "idnsSendQuery: FD " << DnsSocketB << ": sendto: " << xstrerror());
+ debugs(50, DBG_IMPORTANT, MYNAME << "FD " << DnsSocketB << ": sendto: " << xstrerr(xerrno));
if (x < 0 && nameservers[nsn].S.isIPv4())
- debugs(50, DBG_IMPORTANT, "idnsSendQuery: FD " << DnsSocketA << ": sendto: " << xstrerror());
+ debugs(50, DBG_IMPORTANT, MYNAME << "FD " << DnsSocketA << ": sendto: " << xstrerr(xerrno));
- } while ( (x<0 && y<0) && q->nsends % nns != 0);
+ } while ( (x<0 && y<0) && q->nsends % nsCount != 0);
if (y > 0) {
- fd_bytes(DnsSocketB, y, FD_WRITE);
+ fd_bytes(DnsSocketB, y, IoDirection::Write);
}
if (x > 0) {
- fd_bytes(DnsSocketA, x, FD_WRITE);
+ fd_bytes(DnsSocketA, x, IoDirection::Write);
}
++ nameservers[nsn].nqueries;
static int
idnsFromKnownNameserver(Ip::Address const &from)
{
- int i;
-
- for (i = 0; i < nns; ++i) {
+ for (int i = 0; static_cast<size_t>(i) < nameservers.size(); ++i) {
if (nameservers[i].S != from)
continue;
return q;
}
- return NULL;
+ return nullptr;
}
static unsigned short
-idnsQueryID(void)
+idnsQueryID()
{
- unsigned short id = squid_random() & 0xFFFF;
+ // NP: apparently ranlux are faster, but not quite as "proven"
+ static std::mt19937 mt(RandomSeed32());
+ unsigned short id = mt() & 0xFFFF;
unsigned short first_id = id;
+ // ensure temporal uniqueness by looking for an existing use
while (idnsFindQuery(id)) {
++id;
if (id == first_id) {
- debugs(78, DBG_IMPORTANT, "idnsQueryID: Warning, too many pending DNS requests");
+ debugs(78, DBG_IMPORTANT, "WARNING: idnsQueryID: too many pending DNS requests");
break;
}
}
return id;
}
-static void
-idnsCallback(idns_query *q, const char *error)
+/// \returns whether master or associated queries are still waiting for replies
+static bool
+idnsStillPending(const idns_query *master)
{
- IDNSCB *callback;
- void *cbdata;
+ assert(!master->master); // we were given the master transaction
+ for (const idns_query *qi = master; qi; qi = qi->slave) {
+ if (qi->pending)
+ return true;
+ }
+ return false;
+}
- if (error)
- q->error = error;
+static std::ostream &
+operator <<(std::ostream &os, const idns_query &answered)
+{
+ if (answered.error)
+ os << "error \"" << answered.error << "\"";
+ else
+ os << answered.ancount << " records";
+ return os;
+}
- if (q->master)
- q = q->master;
+static void
+idnsCallbackOnEarlyError(IDNSCB *callback, void *cbdata, const char *error)
+{
+ // A cbdataReferenceValid() check asserts on unlocked cbdata: Early errors,
+ // by definition, happen before we store/cbdataReference() cbdata.
+ debugs(78, 6, "\"" << error << "\" for " << cbdata);
+ callback(cbdata, nullptr, 0, "Internal error", true); // hide error details
+}
- // If any of our subqueries are still pending then wait for them to complete before continuing
- for (idns_query *q2 = q; q2; q2 = q2->slave) {
- if (q2->pending) {
- return;
- }
- }
+/// safely sends one set of DNS records (or an error) to the caller
+static bool
+idnsCallbackOneWithAnswer(IDNSCB *callback, void *cbdata, const idns_query &answered, const bool lastAnswer)
+{
+ if (!cbdataReferenceValid(cbdata))
+ return false;
+ const rfc1035_rr *records = answered.message ? answered.message->answer : nullptr;
+ debugs(78, 6, (lastAnswer ? "last " : "") << answered << " for " << cbdata);
+ callback(cbdata, records, answered.ancount, answered.error, lastAnswer);
+ return true;
+}
- /* Merge results */
- rfc1035_message *message = q->message;
- q->message = NULL;
- int n = q->ancount;
- error = q->error;
-
- while ( idns_query *q2 = q->slave ) {
- debugs(78, 6, HERE << "Merging DNS results " << q->name << " A has " << n << " RR, AAAA has " << q2->ancount << " RR");
- q->slave = q2->slave;
- if ( !q2->error ) {
- if (n > 0) {
- // two sets of RR need merging
- rfc1035_rr *result = (rfc1035_rr*) xmalloc( sizeof(rfc1035_rr)*(n + q2->ancount) );
- if (Config.dns.v4_first) {
- memcpy(result, message->answer, (sizeof(rfc1035_rr)*n) );
- memcpy(result+n, q2->message->answer, (sizeof(rfc1035_rr)*q2->ancount) );
- } else {
- memcpy(result, q2->message->answer, (sizeof(rfc1035_rr)*q2->ancount) );
- memcpy(result+q2->ancount, message->answer, (sizeof(rfc1035_rr)*n) );
- }
- n += q2->ancount;
- // HACK WARNING, the answer rr:s have been copied in-place to
- // result, do not free them here
- safe_free(message->answer);
- safe_free(q2->message->answer);
- message->answer = result;
- message->ancount += q2->message->ancount;
- } else {
- // first response empty or failed, just use the second
- rfc1035MessageDestroy(&message);
- message = q2->message;
- q2->message = NULL;
- n = q2->ancount;
- error = NULL;
- }
- }
- rfc1035MessageDestroy(&q2->message);
- cbdataFree(q2);
+static void
+idnsCallbackNewCallerWithOldAnswers(IDNSCB *callback, void *cbdata, const idns_query * const master)
+{
+ const bool lastAnswer = false;
+ // iterate all queries to act on answered ones
+ for (auto query = master; query; query = query->slave) {
+ if (query->pending)
+ continue; // no answer yet
+ // no CallBack(CodeContext...) -- we always run in requestor's context
+ if (!idnsCallbackOneWithAnswer(callback, cbdata, *query, lastAnswer))
+ break; // the caller disappeared
}
+}
- debugs(78, 6, HERE << "Sending " << n << " (" << (error ? error : "OK") << ") DNS results to caller.");
-
- callback = q->callback;
- q->callback = NULL;
- const rfc1035_rr *answers = message ? message->answer : NULL;
+static void
+idnsCallbackAllCallersWithNewAnswer(const idns_query * const answered, const bool lastAnswer)
+{
+ debugs(78, 8, (lastAnswer ? "last " : "") << *answered);
+ const auto master = answered->master ? answered->master : answered;
+ // iterate all queued lookup callers
+ for (auto looker = master; looker; looker = looker->queue) {
+ CallBack(looker->codeContext, [&] {
+ (void)idnsCallbackOneWithAnswer(looker->callback, looker->callback_data,
+ *answered, lastAnswer);
+ });
+ }
+}
- if (cbdataReferenceValidDone(q->callback_data, &cbdata))
- callback(cbdata, answers, n, error);
+static void
+idnsCallback(idns_query *q, const char *error)
+{
+ if (error)
+ q->error = error;
- while (q->queue) {
- idns_query *q2 = q->queue;
- q->queue = q2->queue;
- callback = q2->callback;
- q2->callback = NULL;
+ auto master = q->master ? q->master : q;
- if (cbdataReferenceValidDone(q2->callback_data, &cbdata))
- callback(cbdata, answers, n, error);
+ const bool lastAnswer = !idnsStillPending(master);
+ idnsCallbackAllCallersWithNewAnswer(q, lastAnswer);
- cbdataFree(q2);
- }
+ if (!lastAnswer)
+ return; // wait for more answers
- if (q->hash.key) {
- hash_remove_link(idns_lookup_hash, &q->hash);
- q->hash.key = NULL;
+ if (master->hash.key) {
+ hash_remove_link(idns_lookup_hash, &master->hash);
+ master->hash.key = nullptr;
}
- rfc1035MessageDestroy(&message);
- cbdataFree(q);
+ delete master;
}
static void
-idnsGrokReply(const char *buf, size_t sz, int from_ns)
+idnsGrokReply(const char *buf, size_t sz, int /*from_ns*/)
{
- int n;
- rfc1035_message *message = NULL;
- idns_query *q;
+ rfc1035_message *message = nullptr;
- n = rfc1035MessageUnpack(buf, sz, &message);
+ int n = rfc1035MessageUnpack(buf, sz, &message);
- if (message == NULL) {
- debugs(78, DBG_IMPORTANT, "idnsGrokReply: Malformed DNS response");
+ if (message == nullptr) {
+ debugs(78, DBG_IMPORTANT, "ERROR: idnsGrokReply: Malformed DNS response");
return;
}
- debugs(78, 3, "idnsGrokReply: QID 0x" << std::hex << message->id << ", " << std::dec << n << " answers");
+ debugs(78, 3, "idnsGrokReply: QID 0x" << asHex(message->id) << ", " << n << " answers");
- q = idnsFindQuery(message->id);
+ idns_query *q = idnsFindQuery(message->id);
- if (q == NULL) {
+ if (q == nullptr) {
debugs(78, 3, "idnsGrokReply: Late response");
rfc1035MessageDestroy(&message);
return;
#if WHEN_EDNS_RESPONSES_ARE_PARSED
// TODO: actually gr the message right here.
-// pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
-// this is overall better than force-feeding A response with AAAA an section later anyway.
-// AND allows us to merge AN+AR sections from both responses (one day)
+// pull out the DNS meta data we need (A records, AAAA records and EDNS OPT) and store in q
+// this is overall better than force-feeding A response with AAAA an section later anyway.
+// AND allows us to merge AN+AR sections from both responses (one day)
if (q->edns_seen >= 0) {
if (max_shared_edns == nameservers[from_ns].last_seen_edns && max_shared_edns < q->edns_seen) {
// the altered NS was limiting the whole group.
max_shared_edns = q->edns_seen;
// may be limited by one of the others still
- for (int i = 0; i < nns; ++i)
- max_shared_edns = min(max_shared_edns, nameservers[i].last_seen_edns);
+ for (const auto &server : nameservers)
+ max_shared_edns = min(max_shared_edns, server.last_seen_edns);
} else {
nameservers[from_ns].last_seen_edns = q->edns_seen;
- // maybe reduce the global limit downwards to accomodate this NS
+ // maybe reduce the global limit downwards to accommodate this NS
max_shared_edns = min(max_shared_edns, q->edns_seen);
}
if (max_shared_edns < RFC1035_DEFAULT_PACKET_SZ)
q->pending = 0;
if (message->tc) {
- debugs(78, 3, HERE << "Resolver requested TC (" << q->query.name << ")");
+ debugs(78, 3, "Resolver requested TC (" << q->query.name << ")");
rfc1035MessageDestroy(&message);
if (!q->need_vc) {
} else {
// Strange: A TCP DNS response with the truncation bit (TC) set.
// Return an error and cleanup; no point in trying TCP again.
- debugs(78, 3, HERE << "TCP DNS response");
+ debugs(78, 3, "TCP DNS response");
idnsCallback(q, "Truncated TCP DNS response");
}
}
// Do searchpath processing on the master A query only to keep
- // things simple. NXDOMAIN is authorative for the label, not
+ // things simple. NXDOMAIN is authoritative for the label, not
// the record type.
if (q->rcode == 3 && !q->master && q->do_searchpath && q->attempt < MAX_ATTEMPT) {
- assert(NULL == message->answer);
+ assert(nullptr == message->answer);
strcpy(q->name, q->orig);
debugs(78, 3, "idnsGrokReply: Query result: NXDOMAIN - " << q->name );
while (idns_query *slave = q->slave) {
dlinkDelete(&slave->lru, &lru_list);
q->slave = slave->slave;
- rfc1035MessageDestroy(&slave->message);
- cbdataFree(slave);
+ slave->slave = nullptr;
+ delete slave;
}
// Build new query
q->ancount = n;
if (n >= 0)
- idnsCallback(q, NULL);
+ idnsCallback(q, nullptr);
else
idnsCallback(q, rfc1035ErrorMessage(q->rcode));
}
static void
-idnsRead(int fd, void *data)
+idnsRead(int fd, void *)
{
int *N = &incoming_sockets_accepted;
int len;
// Always keep reading. This stops (or at least makes harder) several
// attacks on the DNS client.
- Comm::SetSelect(fd, COMM_SELECT_READ, idnsRead, NULL, 0);
+ Comm::SetSelect(fd, COMM_SELECT_READ, idnsRead, nullptr, 0);
/* BUG (UNRESOLVED)
* two code lines after returning from comm_udprecvfrom()
break;
if (len < 0) {
- if (ignoreErrno(errno))
+ int xerrno = errno;
+ if (ignoreErrno(xerrno))
break;
#if _SQUID_LINUX_
* return ECONNREFUSED when sendto() fails and generates an ICMP
* port unreachable message. */
/* or maybe an EHOSTUNREACH "No route to host" message */
- if (errno != ECONNREFUSED && errno != EHOSTUNREACH)
+ if (xerrno != ECONNREFUSED && xerrno != EHOSTUNREACH)
#endif
-
- debugs(50, DBG_IMPORTANT, "idnsRead: FD " << fd << " recvfrom: " << xstrerror());
+ debugs(50, DBG_IMPORTANT, MYNAME << "FD " << fd << " recvfrom: " << xstrerr(xerrno));
break;
}
- fd_bytes(fd, len, FD_READ);
+ fd_bytes(fd, len, IoDirection::Read);
assert(N);
++(*N);
}
static void
-idnsCheckQueue(void *unused)
+idnsCheckQueue(void *)
{
dlink_node *n;
- dlink_node *p = NULL;
+ dlink_node *p = nullptr;
idns_query *q;
event_queued = 0;
- if (0 == nns)
+ if (nameservers.empty())
/* name servers went away; reconfiguring or shutting down */
return;
+ const auto nsCount = nameservers.size();
for (n = lru_list.tail; n; n = p) {
p = n->prev;
break;
/* Query timer still running? */
- if ((time_msec_t)tvSubMsec(q->sent_t, current_time) < (Config.Timeout.idns_retransmit * 1 << ((q->nsends - 1) / nns))) {
+ if ((time_msec_t)tvSubMsec(q->sent_t, current_time) < (Config.Timeout.idns_retransmit * 1 << ((q->nsends - 1) / nsCount))) {
dlinkDelete(&q->lru, &lru_list);
q->queue_t = current_time;
dlinkAdd(q, &q->lru, &lru_list);
}
debugs(78, 3, "idnsCheckQueue: ID " << q->xact_id <<
- " QID 0x" << std::hex << std::setfill('0') <<
- std::setw(4) << q->query_id << ": timeout" );
+ " QID 0x" << asHex(q->query_id).minDigits(4) << ": timeout");
dlinkDelete(&q->lru, &lru_list);
q->pending = 0;
idnsSendQuery(q);
} else {
debugs(78, 2, "idnsCheckQueue: ID " << q->xact_id <<
- " QID 0x" << std::hex << q->query_id <<
- " : giving up after " << std::dec << q->nsends << " tries and " <<
+ " QID 0x" << asHex(q->query_id) <<
+ ": giving up after " << q->nsends << " tries and " <<
std::setw(5)<< std::setprecision(2) << tvSubDsec(q->start_t, current_time) << " seconds");
if (q->rcode != 0)
}
static void
-idnsReadVC(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
+idnsReadVC(const Comm::ConnectionPointer &conn, char *buf, size_t len, Comm::Flag flag, int, void *data)
{
nsvc * vc = (nsvc *)data;
- if (flag == COMM_ERR_CLOSING)
+ if (flag == Comm::ERR_CLOSING)
return;
- if (flag != COMM_OK || len <= 0) {
+ if (flag != Comm::OK || len <= 0) {
if (Comm::IsConnOpen(conn))
conn->close();
return;
return;
}
- assert(vc->ns < nns);
- debugs(78, 3, HERE << conn << ": received " << vc->msg->contentSize() << " bytes via TCP from " << nameservers[vc->ns].S << ".");
+ assert(vc->ns < nameservers.size());
+ debugs(78, 3, conn << ": received " << vc->msg->contentSize() << " bytes via TCP from " << nameservers[vc->ns].S << ".");
idnsGrokReply(vc->msg->buf, vc->msg->contentSize(), vc->ns);
vc->msg->clean();
}
static void
-idnsReadVCHeader(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
+idnsReadVCHeader(const Comm::ConnectionPointer &conn, char *buf, size_t len, Comm::Flag flag, int, void *data)
{
nsvc * vc = (nsvc *)data;
- if (flag == COMM_ERR_CLOSING)
+ if (flag == Comm::ERR_CLOSING)
return;
- if (flag != COMM_OK || len <= 0) {
+ if (flag != Comm::OK || len <= 0) {
if (Comm::IsConnOpen(conn))
conn->close();
return;
vc->msglen = ntohs(vc->msglen);
+ if (!vc->msglen) {
+ if (Comm::IsConnOpen(conn))
+ conn->close();
+ return;
+ }
+
vc->msg->init(vc->msglen, vc->msglen);
AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVC",
CommIoCbPtrFun(idnsReadVC, vc));
++ RcodeMatrix[rcode][attempt];
}
-/* ====================================================================== */
-
-static void
-idnsRegisterWithCacheManager(void)
-{
- Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats, 0, 1);
-}
-
void
-dnsInit(void)
+Dns::Init(void)
{
static int init = 0;
- CBDATA_INIT_TYPE(nsvc);
- CBDATA_INIT_TYPE(idns_query);
-
if (DnsSocketA < 0 && DnsSocketB < 0) {
- Ip::Address addrV6; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
+ Ip::Address addrV6; // since we do not want to alter Config.Addrs.udp_* and do not have one of our own.
if (!Config.Addrs.udp_outgoing.isNoAddr())
addrV6 = Config.Addrs.udp_outgoing;
*/
if (DnsSocketB >= 0) {
comm_local_port(DnsSocketB);
- debugs(78, DBG_IMPORTANT, "DNS Socket created at " << addrV6 << ", FD " << DnsSocketB);
- Comm::SetSelect(DnsSocketB, COMM_SELECT_READ, idnsRead, NULL, 0);
+ debugs(78, Important(16), "DNS IPv6 socket created at " << addrV6 << ", FD " << DnsSocketB);
+ Comm::SetSelect(DnsSocketB, COMM_SELECT_READ, idnsRead, nullptr, 0);
}
if (DnsSocketA >= 0) {
comm_local_port(DnsSocketA);
- debugs(78, DBG_IMPORTANT, "DNS Socket created at " << addrV4 << ", FD " << DnsSocketA);
- Comm::SetSelect(DnsSocketA, COMM_SELECT_READ, idnsRead, NULL, 0);
+ debugs(78, Important(64), "DNS IPv4 socket created at " << addrV4 << ", FD " << DnsSocketA);
+ Comm::SetSelect(DnsSocketA, COMM_SELECT_READ, idnsRead, nullptr, 0);
}
}
- assert(0 == nns);
+ assert(nameservers.empty());
idnsAddMDNSNameservers();
bool nsFound = idnsParseNameservers();
-#if !_SQUID_WINDOWS_
if (!nsFound)
nsFound = idnsParseResolvConf();
-#endif
#if _SQUID_WINDOWS_
if (!nsFound)
nsFound = idnsParseWIN32Registry();
#endif
if (!nsFound) {
- debugs(78, DBG_IMPORTANT, "Warning: Could not find any nameservers. Trying to use localhost");
+ debugs(78, DBG_IMPORTANT, "WARNING: Could not find any nameservers. Trying to use localhost");
#if _SQUID_WINDOWS_
debugs(78, DBG_IMPORTANT, "Please check your TCP-IP settings or /etc/resolv.conf file");
#else
}
if (!init) {
- memDataInit(MEM_IDNS_QUERY, "idns_query", sizeof(idns_query), 0);
memset(RcodeMatrix, '\0', sizeof(RcodeMatrix));
idns_lookup_hash = hash_create((HASHCMP *) strcmp, 103, hash_string);
++init;
}
#endif
- idnsRegisterWithCacheManager();
+ Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats, 0, 1);
}
-void
-dnsShutdown(void)
+static void
+idnsShutdownAndFreeState(const char *reason)
{
if (DnsSocketA < 0 && DnsSocketB < 0)
return;
+ debugs(78, 2, reason << ": Closing DNS sockets");
+
if (DnsSocketA >= 0 ) {
comm_close(DnsSocketA);
DnsSocketA = -1;
DnsSocketB = -1;
}
- for (int i = 0; i < nns; ++i) {
- if (nsvc *vc = nameservers[i].vc) {
+ for (const auto &server : nameservers) {
+ if (const auto vc = server.vc) {
if (Comm::IsConnOpen(vc->conn))
vc->conn->close();
}
}
// XXX: vcs are not closed/freed yet and may try to access nameservers[]
- idnsFreeNameservers();
+ nameservers.clear();
idnsFreeSearchpath();
}
+void
+Dns::ConfigRr::endingShutdown()
+{
+ idnsShutdownAndFreeState("Shutdown");
+}
+
+void
+Dns::ConfigRr::startReconfigure()
+{
+ idnsShutdownAndFreeState("Reconfigure");
+}
+
static int
idnsCachedLookup(const char *key, IDNSCB * callback, void *data)
{
- idns_query *q;
-
idns_query *old = (idns_query *) hash_lookup(idns_lookup_hash, key);
if (!old)
return 0;
- q = cbdataAlloc(idns_query);
- // idns_query is POD so no constructors are called after allocation
- q->xact_id.change();
+ // XXX: We are collapsing this DNS query (B) onto another one (A), but there
+ // is no code to later send B if the A answer has unshareable 0 TTL records.
+
+ idns_query *q = new idns_query;
// no query_id on this instance.
q->callback = callback;
-
q->callback_data = cbdataReference(data);
q->queue = old->queue;
-
old->queue = q;
+ // This check must follow cbdataReference() above because our callback code
+ // needs a locked cbdata to call cbdataReferenceValid().
+ if (idnsStillPending(old))
+ idnsCallbackNewCallerWithOldAnswers(callback, data, old);
+ // else: idns_lookup_hash is not a cache so no pending lookups means we are
+ // in a reentrant lookup and will be called back when dequeued.
+
return 1;
}
static void
idnsSendSlaveAAAAQuery(idns_query *master)
{
- idns_query *q = cbdataAlloc(idns_query);
+ idns_query *q = new idns_query;
memcpy(q->name, master->name, sizeof(q->name));
memcpy(q->orig, master->orig, sizeof(q->orig));
q->master = master;
q->query_id = idnsQueryID();
q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query, Config.dns.packet_max);
- q->start_t = master->start_t;
- q->slave = master->slave;
- debugs(78, 3, HERE << "buf is " << q->sz << " bytes for " << q->name <<
- ", id = 0x" << std::hex << q->query_id);
+ debugs(78, 3, "buf is " << q->sz << " bytes for " << q->name <<
+ ", id = 0x" << asHex(q->query_id));
if (!q->sz) {
- cbdataFree(q);
+ delete q;
return;
}
+
+ q->start_t = master->start_t;
+ q->slave = master->slave;
+
idnsCheckMDNS(q);
master->slave = q;
idnsSendQuery(q);
// Prevent buffer overflow on q->name
if (nameLength > NS_MAXDNAME) {
debugs(23, DBG_IMPORTANT, "SECURITY ALERT: DNS name too long to perform lookup: '" << name << "'. see access.log for details.");
- callback(data, NULL, 0, "Internal error");
+ idnsCallbackOnEarlyError(callback, data, "huge name");
return;
}
if (idnsCachedLookup(name, callback, data))
return;
- idns_query *q = cbdataAlloc(idns_query);
- // idns_query is POD so no constructors are called after allocation
- q->xact_id.change();
+ idns_query *q = new idns_query;
q->query_id = idnsQueryID();
int nd = 0;
- for (unsigned int i = 0; i < nameLength; ++i)
+ for (size_t i = 0; i < nameLength; ++i)
if (name[i] == '.')
++nd;
if (q->sz < 0) {
/* problem with query data -- query not sent */
- callback(data, NULL, 0, "Internal error");
- cbdataFree(q);
+ idnsCallbackOnEarlyError(callback, data, "rfc3596BuildAQuery error");
+ delete q;
return;
}
debugs(78, 3, "idnsALookup: buf is " << q->sz << " bytes for " << q->name <<
- ", id = 0x" << std::hex << q->query_id);
+ ", id = 0x" << asHex(q->query_id));
idnsCheckMDNS(q);
idnsStartQuery(q, callback, data);
if (Ip::EnableIpv6)
idnsSendSlaveAAAAQuery(q);
-
}
void
idnsPTRLookup(const Ip::Address &addr, IDNSCB * callback, void *data)
{
- idns_query *q;
-
char ip[MAX_IPSTRLEN];
addr.toStr(ip,MAX_IPSTRLEN);
- q = cbdataAlloc(idns_query);
-
- // idns_query is POD so no constructors are called after allocation
- q->xact_id.change();
+ idns_query *q = new idns_query;
q->query_id = idnsQueryID();
if (addr.isIPv6()) {
if (q->sz < 0) {
/* problem with query data -- query not sent */
- callback(data, NULL, 0, "Internal error");
- cbdataFree(q);
+ idnsCallbackOnEarlyError(callback, data, "rfc3596BuildPTRQuery error");
+ delete q;
return;
}
if (idnsCachedLookup(q->query.name, callback, data)) {
- cbdataFree(q);
+ delete q;
return;
}
debugs(78, 3, "idnsPTRLookup: buf is " << q->sz << " bytes for " << ip <<
- ", id = 0x" << std::hex << q->query_id);
+ ", id = 0x" << asHex(q->query_id));
q->permit_mdns = Config.onoff.dns_mdns;
idnsStartQuery(q, callback, data);
variable_list *
snmp_netDnsFn(variable_list * Var, snint * ErrP)
{
- int i, n = 0;
- variable_list *Answer = NULL;
+ int n = 0;
+ variable_list *Answer = nullptr;
MemBuf tmp;
debugs(49, 5, "snmp_netDnsFn: Processing request: " << snmpDebugOid(Var->name, Var->name_length, tmp));
*ErrP = SNMP_ERR_NOERROR;
case DNS_REQ:
- for (i = 0; i < nns; ++i)
- n += nameservers[i].nqueries;
+ for (const auto &server : nameservers)
+ n += server.nqueries;
Answer = snmp_var_new_integer(Var->name, Var->name_length,
n,
break;
case DNS_REP:
- for (i = 0; i < nns; ++i)
- n += nameservers[i].nreplies;
+ for (const auto &server : nameservers)
+ n += server.nreplies;
Answer = snmp_var_new_integer(Var->name, Var->name_length,
n,
case DNS_SERVERS:
Answer = snmp_var_new_integer(Var->name, Var->name_length,
- nns,
+ nameservers.size(),
SMI_COUNTER32);
break;
}
#endif /*SQUID_SNMP */
+