Fri 18 Mar 2016 07:45:53 PM UTC, original submission:
dns_recv() is not resilient to unexpected, malformed or forged DNS responses.
While parsing the response, the function ends with a 'goto responseerr' when an inconsistency is detected and finally calls dns_call_found() with NULL, hence notifies the caller of a resolution error.
For example, when a DNS response coming from an unexpected IP address is received, the following check will fail:
/* Check whether response comes from the same network address to which the
question was sent. (RFC 5452) */
if (!ip_addr_cmp(addr, &dns_servers[entry->server_idx])) {
/* call callback to indicate error, clean up memory and return */
goto responseerr;
}
and the user will be notified of a DNS resolution error.
This probably applies to the other checks performed in dns_recv().
When an inconsistency is detected, the packet should be ignored, but it should not trigger a resolution error: I think a 'goto memerr' is more appropriate.
A possible approach to solve this would be:
- first, ensure the packets is coming from a 'good looking' DNS server (as explained in RFC 5452) ; silently drop erroneous packets ('goto memerr')
- then, check the answer content to determine the resolution status and notify the user of success or failure
I'm not a DNS expert, so I'm not sure which check should trigger a packet drop or a resolution error.
For the record, I spotted this when two DNS servers are configured and DNS_MAX_RETRIES = 1 :
- the query is sent to the 1st server
- timeout occurs while no answer has been received; the query is sent to the 2nd server
- the answer from the 1st server is finally received and triggers the error described above
I attach the patch related to this specific issue, but I think it could be generalized.
|