New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Critical issue with response poisoning #132
Comments
Hi @DejanPelzel I never had any issues running things on Windows, so that at least lines up with your findings it seems. I might just remove that feature from on Linux based systems and always throw away the UdpClient. Would be pretty unfortsh though because that costs a lot of performance. |
Hi, It was Ubuntu 18.04 LTS on a physical server. |
Hi, I suppose we've got the same issue in production on Windows Server. We are using DnsClient to get the addresses of all instances of a service, and then we choose a random instance and call it. |
We're seeing a similar issue on a Windows Server. We recently updated our software to .NET 4.8 and upgraded from DnsClient 1.3.2 to 1.5.0. We also use the DnsUdpMessageHandler to perform MXLookup queries and we started seeing results from previous request show up in the responses. After running for a few hours and making hundreds of requests we'll eventually run into the problem. We pulled 1.5.0 locally and added the fix "if (request.Header.Id != response.Header.Id)" suggested by @DejanPelzel and it seems to have resolved the issue. We've been running this fix for a couple of days now and have not received results from previous DNS queries. It looks like that IF check used to be in 1.3.2 so maybe that's why we've never ran into this before. |
The if check does not solve anything. It just compares the headers. In 1.5 the only change was to not throw a hard error If the Id doesnt match. Regarding an actual fix for this. I'll probably disable any reuse of sockets until I can reliably fix and reproduce that problem, which I still cannot. |
Throwing the Exception causes the updClient to dispose. So I'm guessing it gets recreated on the next query and why it seems to fix for us. |
It does not solve the source of the issue itself, but it solves the issue of getting the wrong response since it makes sure that the ID of the response matches the request. I guess I'd call it a workaround, not a fix, but it should be in regardless in some form. Otherwise someone can send fake packets back and just feed whatever data due to the ID not being checked. |
I will remove the pooling mechansim I had for UDP traffic in 1.6 |
It seems there is an issue going on with the responses being poisoned by old packets due to UdpClient reuse. I'm not sure what exactly causes this to happen, but it seems that the DNS server sends multiple packets for whatever reason or if we receive a broken packet of sorts I assume, the next query might receive the response from the query before itself.
Additionally, s_random is a singleton used between multiple threads, which can also create cross-thread issues and result in identical numbers returned. See: https://stackoverflow.com/questions/3049467/is-c-sharp-random-number-generator-thread-safe
This is a critical flaw, making the client potentially dangerous given the scale on which it is used.
Digging deeper, by modifying the DnsUdpMessageHandler's QueryAsync, we are able to read multiple queries in a single QueryAsync call.
The sample code to reproduce is below. Semaphores are used just to simulate tight concurrency, especially with random generation, but I'm not sure that's even necessary here to replicate. Test environment was on Ubuntu 18, not able to reproduce on Windows locally however.
The text was updated successfully, but these errors were encountered: