From: hno <> Date: Sun, 10 Oct 2004 08:53:26 +0000 (+0000) Subject: Bug #852: A large number of queued DNS lookups for the same domain X-Git-Tag: SQUID_3_0_PRE4~1028 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3074b9d1c9690355ead0e0ba2d08c654c7b045cd;p=thirdparty%2Fsquid.git Bug #852: A large number of queued DNS lookups for the same domain --- diff --git a/src/dns_internal.cc b/src/dns_internal.cc index a73efbac5a..e666674366 100644 --- a/src/dns_internal.cc +++ b/src/dns_internal.cc @@ -1,6 +1,6 @@ /* - * $Id: dns_internal.cc,v 1.63 2004/04/10 13:10:17 hno Exp $ + * $Id: dns_internal.cc,v 1.64 2004/10/10 02:53:26 hno Exp $ * * DEBUG: section 78 DNS lookups; interacts with lib/rfc1035.c * AUTHOR: Duane Wessels @@ -63,6 +63,8 @@ typedef struct _ns ns; struct _idns_query { + hash_link hash; + char query[RFC1035_MAXHOSTNAMESZ+1]; char buf[512]; size_t sz; unsigned short id; @@ -77,6 +79,7 @@ struct _idns_query int attempt; const char *error; int rcode; + idns_query *queue; }; struct _ns @@ -93,6 +96,7 @@ static int nns = 0; static int nns_alloc = 0; static dlink_list lru_list; static int event_queued = 0; +static hash_table *idns_lookup_hash = NULL; static OBJH idnsStats; static void idnsAddNameserver(const char *buf); @@ -544,6 +548,36 @@ idnsFindQuery(unsigned short id) return NULL; } +static void +idnsCallback(idns_query *q, rfc1035_rr *answers, int n, const char *error) +{ + IDNSCB *callback; + void *cbdata; + + callback = q->callback; + q->callback = NULL; + + if (cbdataReferenceValidDone(q->callback_data, &cbdata)) + callback(cbdata, answers, n, error); + + while(q->queue) { + idns_query *q2 = q->queue; + q->queue = q2->queue; + callback = q2->callback; + q2->callback = NULL; + + if (cbdataReferenceValidDone(q2->callback_data, &cbdata)) + callback(cbdata, answers, n, error); + + memFree(q2, MEM_IDNS_QUERY); + } + + if (q->hash.key) { + hash_remove_link(idns_lookup_hash, &q->hash); + q->hash.key = NULL; + } +} + static void idnsGrokReply(const char *buf, size_t sz) { @@ -551,8 +585,7 @@ idnsGrokReply(const char *buf, size_t sz) rfc1035_rr *answers = NULL; unsigned short rid = 0xFFFF; idns_query *q; - IDNSCB *callback; - void *cbdata; + n = rfc1035AnswersUnpack(buf, sz, &answers, @@ -597,12 +630,7 @@ idnsGrokReply(const char *buf, size_t sz) } } - callback = q->callback; - q->callback = NULL; - - if (cbdataReferenceValidDone(q->callback_data, &cbdata)) - callback(cbdata, answers, n, q->error); - + idnsCallback(q, answers, n, q->error); rfc1035RRDestroy(answers, n); memFree(q, MEM_IDNS_QUERY); @@ -725,20 +753,14 @@ idnsCheckQueue(void *unused) if (tvSubDsec(q->start_t, current_time) < Config.Timeout.idns_query) { idnsSendQuery(q); } else { - IDNSCB *callback; - void *cbdata; debug(78, 2) ("idnsCheckQueue: ID %x: giving up after %d tries and %5.1f seconds\n", (int) q->id, q->nsends, tvSubDsec(q->start_t, current_time)); - callback = q->callback; - q->callback = NULL; - - if (cbdataReferenceValidDone(q->callback_data, &cbdata)) { - if (q->rcode != 0) - callback(cbdata, NULL, -q->rcode, q->error); - else - callback(cbdata, NULL, -16, "Timeout"); - } + + if (q->rcode != 0) + idnsCallback(q, NULL, -q->rcode, q->error); + else + idnsCallback(q, NULL, -16, "Timeout"); memFree(q, MEM_IDNS_QUERY); } @@ -830,6 +852,7 @@ idnsInit(void) "Internal DNS Statistics", idnsStats, 0, 1); memset(RcodeMatrix, '\0', sizeof(RcodeMatrix)); + idns_lookup_hash = hash_create((HASHCMP *) strcmp, 103, hash_string); init++; } } @@ -847,11 +870,49 @@ idnsShutdown(void) idnsFreeNameservers(); } +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 = (idns_query *)memAllocate(MEM_IDNS_QUERY); + + q->callback = callback; + + q->callback_data = cbdataReference(data); + + q->queue = old->queue; + + old->queue = q; + + return 1; +} + +static void +idnsCacheQuery(idns_query *q, const char *key) +{ + xstrncpy(q->query, key, sizeof(q->query)); + q->hash.key = q->query; + hash_join(idns_lookup_hash, &q->hash); +} + void idnsALookup(const char *name, IDNSCB * callback, void *data) { - idns_query *q = (idns_query *)memAllocate(MEM_IDNS_QUERY); + idns_query *q; + + if (idnsCachedLookup(name, callback, data)) + return; + + q = (idns_query *)memAllocate(MEM_IDNS_QUERY); + q->sz = sizeof(q->buf); + q->id = rfc1035BuildAQuery(name, q->buf, &q->sz); if (0 == q->id) { @@ -866,6 +927,7 @@ idnsALookup(const char *name, IDNSCB * callback, void *data) q->callback = callback; q->callback_data = cbdataReference(data); q->start_t = current_time; + idnsCacheQuery(q, name); idnsSendQuery(q); } @@ -873,14 +935,30 @@ void idnsPTRLookup(const struct in_addr addr, IDNSCB * callback, void *data) { - idns_query *q = (idns_query *)memAllocate(MEM_IDNS_QUERY); + idns_query *q; + + const char *ip = inet_ntoa(addr); + + if (idnsCachedLookup(ip, callback, data)) + return; + + q = (idns_query *)memAllocate(MEM_IDNS_QUERY); + q->sz = sizeof(q->buf); + q->id = rfc1035BuildPTRQuery(addr, q->buf, &q->sz); + debug(78, 3) ("idnsPTRLookup: buf is %d bytes for %s, id = %#hx\n", - (int) q->sz, inet_ntoa(addr), q->id); + (int) q->sz, ip, q->id); + q->callback = callback; + q->callback_data = cbdataReference(data); + q->start_t = current_time; + + idnsCacheQuery(q, ip); + idnsSendQuery(q); }