Fixed DNS query leaks and increased defense against DNS cache poisoning.
We were leaking (i.e. forgetting about) DNS queries under several conditions.
The most realistic leak case would go like this:
- We send UDP query1.
No response.
- We send UDP query2.
The response for query1 comes, with TC bit.
- We try to connect over TCP, sending TCP query3.
The response for query2 comes, with TC bit, matching TCP query3 ID.
Since we are waiting a response over TCP, we drop the UDP response,
and delete the query from the queue. We leak.
This change avoids forgetting the query under the above scenario.
Moreover, the above steps are hiding another problem: we are accepting responses
to timed out queries, making DNS cache poisoning easier. This change avoids
that by using unique query ID for each sent query. We have also added an
instance ID so that we still can track/identify a single "transaction" from
Squid point of view, even when that transaction involves many DNS query
messages.
When we forget about a DNS query, the caller may get stuck, holding a cbdata
lock. This is typical for ACLs that require domain name resolution, for example.
On a busy server with a long ACL list, the lock counter keeps growing due to
forgotten requests and may overflow, causing a "c->locks < 65535" assertion.
This change fixes the assertion unless there are more DNS leaks or different
lock leaks present.