Closed trudyhood closed 3 years ago
Thanks for the report. Normally the ICMP Fragmentation Needed message should "pass through" the passthru
program without change, allowing for normal pMTU discovery. What happens if you run passthru
without diverting ICMP? E.g.:
passthru.exe "not icmp"
Applications usually send "DONT Fragment" to find MTU. By the way, with [passthru.exe "not icmp"] the result is still the same and unexpected. Without [passthru.exe "not icmp"], I receive the packet is too big error, but after running it, no error is return by windows, UDP packets just get lost without indicating any error. I think it causes unexpected behavior in some applications.
The more strange part is that Windows cache results from MTU error for each destination about a few minutes. When I choose a new destination, the first big packet gets lost, but the next call immediately receives the error indicating that packet is too big. But it looks like Windows bypass its cache result immediately as soon as I run passthru.
with [passthru.exe "not icmp"] the result is still the same and unexpected.
This means the problem is not because passthru.exe
is failing to reinject the ICMP packets.
I think maybe the problem is the original large packet. Perhaps, if the packet is too big, the underlying miniport/ethernet driver would normally return an error (e.g., NDIS_STATUS_INVALID_LENGTH
) or it is handled by NDIS itself, rather than using ICMP internally. But, by using passthru.exe
, the original packet is effectively discarded and a copy takes the original's place, meaning that the length error no longer flows back to the original application. This is just speculation though.
You are right, the test packet was too big and dropped by WinDivert before sending to the destination. Perhaps windows handle the error or maybe NDIS generate the ICMP reply itself. I wish WinDivert replied the "ICMP fragment needed" after dropping it.
The packet is not dropped by WinDivert itself, but is likely dropped by the underlying Miniport (ethernet) driver.
To fix this issue, WinDivert ought to translate internal errors into corresponding ICMP packets. I think this would be a useful feature to add, but would need to investigate how to implement it & the complexity.
I tried but could not reproduce this issue. Can you please post a minimal example to exercise this issue?
I tried but could not reproduce this issue. Can you please post a minimal example to exercise this issue?
Try this before and after "passthru true"
ping 142.250.217.143 -l 1700 -f
Sometimes I change IP to prevent windows cache the result. before running passthru you should see this:
Pinging 142.250.217.143 with 1700 bytes of data:
Packet needs to be fragmented but DF set.
after that you just get time out.
Pinging 142.250.217.143 with 1700 bytes of data:
Request timed out.
I think maybe the problem is the original large packet. Perhaps, if the packet is too big, the underlying miniport/ethernet driver would normally return an error (e.g., NDIS_STATUS_INVALID_LENGTH) or it is handled by NDIS itself, rather than using ICMP internally.
After some experimentation, it seems this theory is correct. I think it will be possible for the WinDivert driver to automatically translate the error code into an ICMP message, and maybe this will fix the PMTU problem.
One problem is that the ICMP message should report the next hop MTU. However, the WinDivert driver does not have this information. It may be possible to map the interface index to the next hop MTU somehow.
An alternative would be for WinDivert to try and guess the MTU using the current packet size and common MTU values. If the guess is too low, then the connection will still work, albeit with a sub-optimal MTU. Else if the guess is too high, then the next send will fail, causing a new ICMP message to be generated with an even lower MTU value. Eventually, a working MTU value should be found.
Sorry, but If the underlying miniport/ethernet driver notify a high-level app like C# that packet is too big, then how WinDivert can interfere with this notification! If it is something in Windows API socket API. then how WinDivert intercepts that error!
Because the error flows to WinDivertSend
rather than the WSASend
from the original application. In fact, WinDivertSend
even ignores errors, since the "correct" error handling turned out to be a major bottleneck.
Now I think about it, generating an ICMP message may not help, since the original WSASend
will successfully complete before the ICMP message arrives.
I think WSASend returns immediately but windows cache the ICMP result for few minutes as far as it arrives, then throws an error message in the subsequent calls.
By the way, I guess due to the unreliability of ICMP over the internet, many applications use a timeout in addition to ICMP's packet too big message.
Injecting an ICMP message fixes the ping example at least. I will likely add this change to WinDivert, but it requires a mini-refactoring, so needs more testing first.
@basil00 - Do you plan to release a new version of WinDivert with this fix in it anytime soon?
Version 2.3.0 will be released next year hopefully. There are a few other fixes that still need to be implemented, as well as a lot of testing.
Thanks!
I am wondering why the behavior of C# UdpClient changes while WinDivert is running. I test it with passthru. When I send a UDP more than MTU with DontFragment, I receive FragmentationNeeded error, but after running passthru, I don't receive this error, of course the packets never reach to destination too. It causes problem for some apps to find a proper MTU. It this normal?