Handle `RCode::ServFail` from nameserver response
Fixes #23
Try next nameserver if current nameserver response is RCode::ServFail
@hsbt how can we get this merged?
Can you add test for this at least?
Sure i will do so (or at least will give it a try - I am not a ruby pro 😉)
@hsbt please have a look at the added test case.
@hsbt did you had a chance to look into this?
@hanazuki, @hsbt anything else I can add/update here?
I have examined the logic but don't know if this works with TCP fallback.
I'm thinking of a situation as follows:
- The Resolv::DNS instance is configured with two nameservers NS1 and NS2 in this order.
- NS1's TCP listener is somehow broken and returns ServFail.
- The requested resource records are large and don't fit in a UDP response.
In this case, it is expected that:
- Resolv first queries NS1 with UDP. NS1 will respond with NoError with TC=1.
- Resolv then falls back to TCP and queries NS1 with TCP. NS1 will respond with ServFail.
- Resolv tries the next nameserver with TCP. NS2 will respond with NoError. This answer is returned to the caller.
IIUC, the proposed implementation will:
- changes the variable
requestertomake_tcp_requester(nameserver, port)when it receives a UDP message with TC=1 (so this host/port pair is NS1's), - queries the same server (NS1) and gets a ServFail, and then
- uses the same
requesterto query NS2, which results in an error due to the unmatched host/port pair.
To make this work properly, maybe we have to reset the requester before next.
when RCode::ServFail
if Requester::TCP === requester
requester.close
requester = nil # next iteration assigns new TCP requester
end
next
Sorry if I'm wrong. I feel confused 😵 .
To make this work properly, maybe we have to reset the requester before
next.when RCode::ServFail if Requester::TCP === requester requester.close requester = nil # next iteration assigns new TCP requester end next
I found this was not a sufficient solution. Please forget about it.
We also need to think of what should happen if all of the nameservers return ServFail (This is the expected result when the record set has a bogus DNSSEC signature).
In that case, the control goes to https://github.com/ruby/resolv/blob/22153c2a45ecc73232bad89ead5bce3e1b660c9a/lib/resolv.rb#L1149 and a timeout error is raised, which might not be a desired behavior. This means that to handle ServFail correctly, the error needs to be notified to Resolv::DNS::Config#resolv, which conducts retrying.