Prevent idnsVCClosed segfaults during shutdown or reconfiguration.

idnsShutdown() schedules comm_close and then frees nameservers[] by calling
idnsFreeNameservers. The closing handler tried to access freed nameservers[].
The patch prevents access to the freed nameservers[] array in idnsVCClosed and
other functions.

TODO: Nameservers[] array management should be rewritten. The array should not
be freed while there are nameservers using it. It should be freed when the
last entry is gone.

=== modified file 'src/dns_internal.cc'
--- src/dns_internal.cc	2009-12-14 18:53:50 +0000
+++ src/dns_internal.cc	2010-01-08 17:46:12 +0000
@@ -699,13 +699,15 @@
 }
 
 static void
-idnsInitVCConnected(int fd, const DnsLookupDetails &, comm_err_t status, int xerrno, void *data)
+idnsInitVCConnected(int fd, const DnsLookupDetails &details, comm_err_t status, int xerrno, void *data)
 {
     nsvc * vc = (nsvc *)data;
 
     if (status != COMM_OK) {
-        char buf[MAX_IPSTRLEN];
-        debugs(78, 1, "idnsInitVCConnected: Failed to connect to nameserver " << nameservers[vc->ns].S.NtoA(buf,MAX_IPSTRLEN) << " using TCP!");
+        char buf[MAX_IPSTRLEN] = "";
+        if (vc->ns < nns)
+            nameservers[vc->ns].S.NtoA(buf,MAX_IPSTRLEN);
+        debugs(78, 1, HERE << "Failed to connect to nameserver " << buf << " using TCP: " << details);
         comm_close(fd);
         return;
     }
@@ -721,7 +723,8 @@
     nsvc * vc = (nsvc *)data;
     delete vc->queue;
     delete vc->msg;
-    nameservers[vc->ns].vc = NULL;
+    if (vc->ns < nns) // XXX: idnsShutdown may have freed nameservers[]
+        nameservers[vc->ns].vc = NULL;
     cbdataFree(vc);
 }
 
@@ -731,6 +734,7 @@
     char buf[MAX_IPSTRLEN];
 
     nsvc *vc = cbdataAlloc(nsvc);
+    assert(ns < nns);
     nameservers[ns].vc = vc;
     vc->ns = ns;
 
@@ -764,6 +768,7 @@
 static void
 idnsSendQueryVC(idns_query * q, int ns)
 {
+    assert(ns < nns);
     if (nameservers[ns].vc == NULL)
         idnsInitVC(ns);
 
@@ -1254,6 +1259,7 @@
         return;
     }
 
+    assert(vc->ns < nns);
     debugs(78, 3, "idnsReadVC: FD " << fd << ": received " <<
            (int) vc->msg->contentSize() << " bytes via tcp from " <<
            nameservers[vc->ns].S << ".");
@@ -1410,6 +1416,7 @@
         }
     }
 
+    // XXX: vcs are not closed/freed yet and may try to access nameservers[]
     idnsFreeNameservers();
 
     idnsFreeSearchpath();


