44#if HAVE_ARPA_NAMESER_H
45#include <arpa/nameser.h>
53#define REG_TCPIP_PARA_INTERFACES "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"
54#define REG_TCPIP_PARA "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
55#define REG_VXD_MSTCP "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP"
58#define _PATH_RESCONF "/etc/resolv.conf"
61#define NS_DEFAULTPORT 53
65#define NS_MAXDNAME 1025
74#define RESOLV_BUFSZ NS_MAXDNAME * MAXDNSRCH + sizeof("search ") + 1
77#define IDNS_MAX_TRIES 20
85 "Packet Format Error",
87 "Non-Existent Domain",
91 "Name Exists when it should not",
92 "RR Set Exists when it should not",
93 "RR Set that should exist does not",
94 "Server Not Authoritative for zone",
95 "Name not contained in zone",
99 "Bad OPT Version or TSIG Signature Failure"
195#if WHEN_EDNS_RESPONSES_ARE_PARSED
196 int last_seen_edns = 0;
250#if WHEN_EDNS_RESPONSES_ARE_PARSED
262static bool idnsParseWIN32Registry(
void);
263static void idnsParseWIN32SearchList(
const char *);
275static void idnsGrokReply(
const char *buf,
size_t sz,
int from_ns);
291 size_t slen = strlen(q->
name);
292 if (slen > 6 && memcmp(q->
name +(slen-6),
".local", 6) == 0) {
307 if (Ip::EnableIpv6) {
327 debugs(78,
DBG_CRITICAL,
"WARNING: rejecting '" << buf <<
"' as a name server, because it is not a numeric IP address");
332 debugs(78,
DBG_CRITICAL,
"WARNING: Squid does not accept " << A <<
" in DNS server specifications.");
334 debugs(78,
DBG_CRITICAL,
"Will be using " << A <<
" instead, assuming you meant that DNS is running on the same machine");
337 if (!Ip::EnableIpv6 && !A.
setIPv4()) {
338 debugs(78,
DBG_IMPORTANT,
"WARNING: IPv6 is disabled. Discarding " << A <<
" in DNS server specifications.");
345#if WHEN_EDNS_RESPONSES_ARE_PARSED
366 if (oldptr && oldalloc)
393 debugs(78,
Important(15),
"Adding nameserver " << i <<
" from squid.conf");
414 const char *t =
nullptr;
420 }
else if (strcmp(t,
"nameserver") == 0) {
430 }
else if (strcmp(t,
"domain") == 0) {
440 }
else if (strcmp(t,
"search") == 0) {
442 while (
nullptr != t) {
452 }
else if (strcmp(t,
"options") == 0) {
453 while (
nullptr != t) {
459 if (strncmp(t,
"ndots:", 6) == 0) {
483idnsParseWIN32SearchList(
const char * Separator)
489 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_TCPIP_PARA, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
493 Result = RegQueryValueEx(hndKey,
"Domain",
nullptr, &
Type,
nullptr, &Size);
495 if (Result == ERROR_SUCCESS && Size) {
497 RegQueryValueEx(hndKey,
"Domain",
nullptr, &
Type, (LPBYTE) t, &Size);
502 Result = RegQueryValueEx(hndKey,
"SearchList",
nullptr, &
Type,
nullptr, &Size);
504 if (Result == ERROR_SUCCESS && Size) {
506 RegQueryValueEx(hndKey,
"SearchList",
nullptr, &
Type, (LPBYTE) t, &Size);
507 token = strtok(t, Separator);
512 token = strtok(
nullptr, Separator);
527idnsParseWIN32Registry(
void)
531 HKEY hndKey, hndKey2;
534 switch (WIN32_OS_version) {
539 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_TCPIP_PARA, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
543 Result = RegQueryValueEx(hndKey,
"DhcpNameServer",
nullptr, &
Type,
nullptr, &Size);
545 if (Result == ERROR_SUCCESS && Size) {
547 RegQueryValueEx(hndKey,
"DhcpNameServer",
nullptr, &
Type, (LPBYTE) t, &Size);
548 token = strtok(t,
", ");
554 token = strtok(
nullptr,
",");
559 Result = RegQueryValueEx(hndKey,
"NameServer",
nullptr, &
Type,
nullptr, &Size);
561 if (Result == ERROR_SUCCESS && Size) {
563 RegQueryValueEx(hndKey,
"NameServer",
nullptr, &
Type, (LPBYTE) t, &Size);
564 token = strtok(t,
", ");
570 token = strtok(
nullptr,
", ");
578 idnsParseWIN32SearchList(
" ");
594 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_TCPIP_PARA_INTERFACES, 0, KEY_READ, &hndKey) == ERROR_SUCCESS) {
596 DWORD MaxSubkeyLen, InterfacesCount;
598 FILETIME ftLastWriteTime;
600 if (RegQueryInfoKey(hndKey,
nullptr,
nullptr,
nullptr, &InterfacesCount, &MaxSubkeyLen,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr) == ERROR_SUCCESS) {
601 keyname = (
char *)
xmalloc(++MaxSubkeyLen);
602 for (i = 0; i < (
int) InterfacesCount; ++i) {
605 if (RegEnumKeyEx(hndKey, i, keyname, &j,
nullptr,
nullptr,
nullptr, &ftLastWriteTime) == ERROR_SUCCESS) {
607 newkeyname = (
char *)
xmalloc(
sizeof(REG_TCPIP_PARA_INTERFACES) + j + 2);
608 strcpy(newkeyname, REG_TCPIP_PARA_INTERFACES);
609 strcat(newkeyname,
"\\");
610 strcat(newkeyname, keyname);
611 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, newkeyname, 0, KEY_QUERY_VALUE, &hndKey2) == ERROR_SUCCESS) {
615 Result = RegQueryValueEx(hndKey2,
"DhcpNameServer",
nullptr, &
Type,
nullptr, &Size);
616 if (Result == ERROR_SUCCESS && Size) {
618 RegQueryValueEx(hndKey2,
"DhcpNameServer",
nullptr, &
Type, (LPBYTE)t, &Size);
619 token = strtok(t,
", ");
624 token = strtok(
nullptr,
", ");
629 Result = RegQueryValueEx(hndKey2,
"NameServer",
nullptr, &
Type,
nullptr, &Size);
630 if (Result == ERROR_SUCCESS && Size) {
632 RegQueryValueEx(hndKey2,
"NameServer",
nullptr, &
Type, (LPBYTE)t, &Size);
633 token = strtok(t,
", ");
638 token = strtok(
nullptr,
", ");
644 RegCloseKey(hndKey2);
657 idnsParseWIN32SearchList(
", ");
668 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_VXD_MSTCP, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
672 Result = RegQueryValueEx(hndKey,
"NameServer",
nullptr, &
Type,
nullptr, &Size);
674 if (Result == ERROR_SUCCESS && Size) {
676 RegQueryValueEx(hndKey,
"NameServer",
nullptr, &
Type, (LPBYTE) t, &Size);
677 token = strtok(t,
", ");
683 token = strtok(
nullptr,
", ");
694 debugs(78,
DBG_IMPORTANT,
"ERROR: Failed to read nameserver from Registry: Unknown System Type.");
733 storeAppendPrintf(sentry,
"---------------------------------------------- --------- --------- --------\n");
740 server.mDNSResolver?
"multicast":
"recurse");
752 if (j > 10 && j < 16)
766 for (i=0; i <
npc; ++i)
852 debugs(78,
DBG_IMPORTANT,
"ERROR: Failed to connect to nameserver " << buf <<
" using TCP.");
932 const auto serialiedQuerySize = 2 + q->
sz + 1;
935 debugs(78,
DBG_IMPORTANT,
"ERROR: Dropping DNS query due to insufficient buffer space for DNS over TCP query queue" <<
940 Debug::Extra <<
"required space: " << serialiedQuerySize);
944 short head = htons(q->
sz);
969 debugs(78,
DBG_IMPORTANT,
"WARNING: idnsSendQuery: Can't send query, no DNS nameservers known!");
986 nsn = q->
nsends % nsCount;
1008 }
while ( (x<0 && y<0) && q->
nsends % nsCount != 0);
1027 for (
int i = 0;
static_cast<size_t>(i) <
nameservers.size(); ++i) {
1056static unsigned short
1061 unsigned short id = mt() & 0xFFFF;
1062 unsigned short first_id = id;
1068 if (
id == first_id) {
1089static std::ostream &
1093 os <<
"error \"" << answered.
error <<
"\"";
1095 os << answered.
ancount <<
" records";
1105 callback(
cbdata,
nullptr, 0,
"Internal error",
true);
1115 debugs(78, 6, (lastAnswer ?
"last " :
"") << answered <<
" for " <<
cbdata);
1123 const bool lastAnswer =
false;
1125 for (
auto query = master; query; query = query->
slave) {
1137 debugs(78, 8, (lastAnswer ?
"last " :
"") << *answered);
1138 const auto master = answered->
master ? answered->
master : answered;
1140 for (
auto looker = master; looker; looker = looker->queue) {
1141 CallBack(looker->codeContext, [&] {
1142 (void)idnsCallbackOneWithAnswer(looker->callback, looker->callback_data,
1143 *answered, lastAnswer);
1162 if (master->hash.key) {
1164 master->hash.key =
nullptr;
1177 if (message ==
nullptr) {
1182 debugs(78, 3,
"idnsGrokReply: QID 0x" <<
asHex(message->
id) <<
", " << n <<
" answers");
1187 debugs(78, 3,
"idnsGrokReply: Late response");
1198#if WHEN_EDNS_RESPONSES_ARE_PARSED
1204 if (q->edns_seen >= 0) {
1205 if (max_shared_edns ==
nameservers[from_ns].last_seen_edns && max_shared_edns < q->edns_seen) {
1206 nameservers[from_ns].last_seen_edns = q->edns_seen;
1208 max_shared_edns = q->edns_seen;
1211 max_shared_edns =
min(max_shared_edns,
server.last_seen_edns);
1213 nameservers[from_ns].last_seen_edns = q->edns_seen;
1215 max_shared_edns =
min(max_shared_edns, q->edns_seen);
1218 max_shared_edns = -1;
1236 debugs(78, 3,
"TCP DNS response");
1255 debugs(78, 3,
"idnsGrokReply: Query result: SERV_FAIL");
1268 debugs(78, 3,
"idnsGrokReply: Query result: NXDOMAIN - " << q->
name );
1271 strcat(q->
name,
".");
1273 debugs(78, 3,
"idnsGrokReply: searchpath used for " << q->
name);
1285 slave->
slave =
nullptr;
1291 debugs(78, 3,
"idnsGrokReply: Trying A Query for " << q->
name);
1328 debugs(78, 3,
"idnsRead: starting with FD " << fd);
1362 if (xerrno != ECONNREFUSED && xerrno != EHOSTUNREACH)
1374 debugs(78, 3,
"idnsRead: FD " << fd <<
": received " << len <<
" bytes from " << from);
1389 static time_t last_warning = 0;
1435 " QID 0x" <<
asHex(q->
query_id).minDigits(4) <<
": timeout");
1445 ": giving up after " << q->
nsends <<
" tries and " <<
1466 if (flag !=
Comm::OK || len <= 0) {
1499 if (flag !=
Comm::OK || len <= 0) {
1551 static int init = 0;
1564 if (Ip::EnableIpv6 && addrV6.
isIPv6()) {
1565 debugs(78, 2,
"idnsInit: attempt open DNS socket to: " << addrV6);
1574 debugs(78, 2,
"idnsInit: attempt open DNS socket to: " << addrV4);
1583 fatal(
"Could not create a DNS socket");
1609 nsFound = idnsParseWIN32Registry();
1613 debugs(78,
DBG_IMPORTANT,
"WARNING: Could not find any nameservers. Trying to use localhost");
1632#if WHEN_EDNS_RESPONSES_ARE_PARSED
1634 debugs(0,
DBG_IMPORTANT,
"ERROR: cannot negotiate EDNS with unknown nameservers. Disabling");
1635 max_shared_edns = -1;
1648 debugs(78, 2, reason <<
": Closing DNS sockets");
1661 if (
const auto vc =
server.vc) {
1737 debugs(78, 3,
"buf is " << q->
sz <<
" bytes for " << q->
name <<
1755 size_t nameLength = strlen(name);
1759 debugs(23,
DBG_IMPORTANT,
"SECURITY ALERT: DNS name too long to perform lookup: '" << name <<
"'. see access.log for details.");
1771 for (
size_t i = 0; i < nameLength; ++i)
1781 strcpy(q->
orig, name);
1786 strcat(q->
name,
".");
1788 debugs(78, 3,
"idnsALookup: searchpath used for " << q->
name);
1800 debugs(78, 3,
"idnsALookup: buf is " << q->
sz <<
" bytes for " << q->
name <<
1821 struct in6_addr addr6;
1825 struct in_addr addr4;
1842 debugs(78, 3,
"idnsPTRLookup: buf is " << q->
sz <<
" bytes for " << ip <<
void CallBack(const CodeContext::Pointer &callbackContext, Fun &&callback)
CommCbFunPtrCallT< Dialer > * commCbCall(int debugSection, int debugLevel, const char *callName, const Dialer &dialer)
void IOCB(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag flag, int xerrno, void *data)
void CLCB(const CommCloseCbParams ¶ms)
void CNCB(const Comm::ConnectionPointer &conn, Comm::Flag status, int xerrno, void *data)
#define InstanceIdDefinitions(...)
convenience macro to instantiate Class-specific stuff in .cc files
AsHex< Integer > asHex(const Integer n)
a helper to ease AsHex object creation
void comm_read(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer &callback)
#define DefineRunnerRegistratorIn(Namespace, ClassName)
void error(char *format,...)
squidaio_request_t * head
std::mt19937::result_type RandomSeed32()
static char server[MAXLINE]
int cbdataReferenceValid(const void *p)
#define cbdataReferenceDone(var)
#define cbdataReference(var)
#define CBDATA_CLASS_INIT(type)
#define CBDATA_CLASS(type)
static void Start(const Pointer &job)
void setHost(const char *)
set the hostname note for this connection
void setAddrs(const Ip::Address &aLocal, const Ip::Address &aRemote)
static std::ostream & Extra(std::ostream &)
manage DNS internal component
void startReconfigure() override
void endingShutdown() override
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
bool getInAddr(struct in_addr &) const
unsigned short port() const
void append(const char *c, int sz) override
void init(mb_size_t szInit, mb_size_t szMax)
mb_size_t contentSize() const
available data size
mb_size_t potentialSpaceSize() const
time_msec_t idns_retransmit
struct SquidConfig::@77 Timeout
struct SquidConfig::@85 Addrs
ssize_t packet_max
maximum size EDNS advertised for DNS replies.
struct SquidConfig::@90 onoff
struct SquidConfig::@100 dns
int ignore_unknown_nameservers
unsigned short do_searchpath
rfc1035_message * message
CodeContext::Pointer codeContext
requestor's context
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
Comm::ConnectionPointer conn
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
unsigned short comm_local_port(int fd)
void commSetConnTimeout(const Comm::ConnectionPointer &conn, time_t timeout, AsyncCall::Pointer &callback)
int ignoreErrno(int ierrno)
int comm_udp_sendto(int fd, const Ip::Address &to_addr, const void *buf, int len)
void comm_open_listener(int sock_type, int proto, Comm::ConnectionPointer &conn, const char *note)
int comm_udp_recvfrom(int fd, void *buf, size_t len, int flags, Ip::Address &from)
A const & max(A const &lhs, A const &rhs)
A const & min(A const &lhs, A const &rhs)
#define debugs(SECTION, LEVEL, CONTENT)
void dlinkDelete(dlink_node *m, dlink_list *list)
void dlinkAdd(void *data, dlink_node *m, dlink_list *list)
void IDNSCB(void *cbdata, const rfc1035_rr *answer, const int recordsInAnswer, const char *error, bool lastAnswer)
void idnsPTRLookup(const Ip::Address &, IDNSCB *, void *)
void idnsALookup(const char *, IDNSCB *, void *)
static void idnsCheckMDNS(idns_query *q)
static void idnsAddMDNSNameservers()
static int idnsCachedLookup(const char *key, IDNSCB *callback, void *data)
static void idnsCallbackAllCallersWithNewAnswer(const idns_query *const answered, const bool lastAnswer)
static void idnsCallback(idns_query *q, const char *error)
static void idnsSendQuery(idns_query *q)
static bool idnsParseResolvConf(void)
static void idnsFreeSearchpath(void)
static void idnsGrokReply(const char *buf, size_t sz, int from_ns)
static int RcodeMatrix[MAX_RCODE][MAX_ATTEMPT]
static void idnsAddPathComponent(const char *buf)
static const char * Rcodes[]
static IOCB idnsReadVCHeader
static int nns_mdns_count
static void idnsSendQueryVC(idns_query *q, size_t nsn)
variable_list * snmp_netDnsFn(variable_list *Var, snint *ErrP)
static void idnsCallbackOnEarlyError(IDNSCB *callback, void *cbdata, const char *error)
static hash_table * idns_lookup_hash
static bool idnsCallbackOneWithAnswer(IDNSCB *callback, void *cbdata, const idns_query &answered, const bool lastAnswer)
safely sends one set of DNS records (or an error) to the caller
static void idnsInitVC(size_t nsv)
static unsigned short idnsQueryID(void)
static IOCB idnsSentQueryVC
static void idnsShutdownAndFreeState(const char *reason)
static void idnsDoSendQueryVC(nsvc *vc)
static void idnsTickleQueue(void)
static std::vector< ns > nameservers
static std::ostream & operator<<(std::ostream &os, const idns_query &answered)
static dlink_list lru_list
static EVH idnsCheckQueue
static bool idnsParseNameservers(void)
static void idnsRcodeCount(int, int)
static void idnsAddNameserver(const char *buf)
static CNCB idnsInitVCConnected
static void idnsCallbackNewCallerWithOldAnswers(IDNSCB *callback, void *cbdata, const idns_query *const master)
static bool idnsStillPending(const idns_query *master)
static void idnsSendSlaveAAAAQuery(idns_query *q)
static idns_query * idnsFindQuery(unsigned short id)
static void idnsStartQuery(idns_query *q, IDNSCB *callback, void *data)
static int idnsFromKnownNameserver(Ip::Address const &from)
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
void fatal(const char *message)
void fd_bytes(const int fd, const int len, const IoDirection direction)
int incoming_sockets_accepted
hash_link * hash_lookup(hash_table *, const void *)
hash_table * hash_create(HASHCMP *, int, HASHHASH *)
int HASHCMP(const void *, const void *)
void hash_join(hash_table *, hash_link *)
void hash_remove_link(hash_table *, hash_link *)
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
bool IsConnOpen(const Comm::ConnectionPointer &conn)
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
void SetSelect(int, unsigned int, PF *, void *, time_t)
Mark an FD to be watched for its IO status.
void RegisterAction(char const *action, char const *desc, OBJH *handler, Protected, Atomic, Format)
int rfc1035MessageUnpack(const char *buf, size_t sz, rfc1035_message **answer)
int rfc1035QueryCompare(const rfc1035_query *a, const rfc1035_query *b)
const char * rfc1035ErrorMessage(int n)
void rfc1035MessageDestroy(rfc1035_message **msg)
#define RFC1035_DEFAULT_PACKET_SZ
ssize_t rfc3596BuildAAAAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query *query)
ssize_t rfc3596BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query *query)
ssize_t rfc3596BuildPTRQuery6(const struct in6_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query *query)
ssize_t rfc3596BuildPTRQuery4(const struct in_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query *query)
const char * snmpDebugOid(oid *Name, snint Len, MemBuf &outbuf)
#define SNMP_ERR_NOSUCHNAME
struct variable_list * snmp_var_new_integer(oid *, int, int, unsigned char)
#define SQUID_UDP_SO_RCVBUF
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
char name[RFC1035_MAXHOSTNAMESZ]
double tvSubDsec(struct timeval t1, struct timeval t2)
struct timeval current_time
the current UNIX time in timeval {seconds, microseconds} format
int tvSubMsec(struct timeval t1, struct timeval t2)
void * xcalloc(size_t n, size_t sz)
const char * xstrerr(int error)