I don't think I've ever encountered a bug in the .NET framework and as such, its the last thing I would ever suspect when something is not working. That is, until now.
A system I am working on contains a section that may only be accessed from within a corporate network. We achieve this by filtering by the user's IP address. We're also using Node as a reverse proxy which adds the user's IP as a header (otherwise our API thinks all requests are coming from the proxy as the source IP gets lost on the way).
Node interprets the IP using IPv6, even though our internal network and restricted ranges are IPv4. This means we need to convert from IPv6 to v4 before checking if the IP is in range. We use this library to do the range checking.
using System.Net; var ipHeader = request.Headers[ForwardingIPHeader]; var userIP = IPAddress.Parse(ipHeader); var ipv4 = userIP.MapToIPv4(); //Check that IP is in range
So we rolled out the feature, it was working well on developers machines. It passed QA and worked for most production users, except when it didn't. We confirmed the users were in the correct IP range and that they had the correct rights. What made it even stranger, was that it worked sometimes for those same users.
Inspecting the log files showed that we were getting an
ArgumentOutOfRangeExcpetion when mapping the IP.
Being the good clean coder that I am :) I wrote some extra unit tests using the actual IPs that were failing. To my dismay, they all passed.
After adding some more logging, and managing to reproduce on our QA environment, I Googled my heart out and found 1 lone StackOverflow question with the same problem.
Turns our, there is a bug in the parse method that causes an overflow for 1 part of the address. The conversion is done using bit shifting, and the last part of the IP is cast to a byte, which only supports 0-255. So IPs with anything over 127 in the last section (i.e. 192.168.2.132) would cause the exception.
This explains the seemingly random occurrence of the failure.
My PC also has .NET 4.7 installed, whereas the other environments were on 4.5.2. It seems the bug was fixed in 4.6 onwards.
The StackOverflow post contains the correct code, but that doesn't help much when its contained in the framework. I toyed with the idea of getting the IPAdress source from GitHub and adding my own custom implementation, but that wasn't as trivial as it sounds.
But the obvious solution would be to upgrade the .NET version which we ended up doing in the end.
Don't trust the .NET framework ... kidding :) But also, don't rule it out completely that there may be bugs in it.