Closed PJB3005 closed 5 months ago
Tagging subscribers to this area: @dotnet/ncl See info in area-owners.md if you want to be subscribed.
Author: | PJB3005 |
---|---|
Assignees: | - |
Labels: | `area-System.Net.Sockets`, `untriaged` |
Milestone: | - |
How did you test it @PJB3005? Using the Socket.SetRawSocketOption
? It seems reasonable to relax the checks if DualMode is enabled and if it works on majority of OSes.
@wfurt Just SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment, true);
. It lines up on Windows and PAL maps it to IP_PMTUDISC_DONT
/IP_PMTUDISC_DO
on Linux. This is basically just one call down from Socket.DontFragment
, with one protocol check removed.
It doesn't work on mac, but that's because macOS outright doesn't support setting don't-fragment in the first place. Socket.DontFragment
doesn't work there ever, so it's not really dependent on dual-mode or whatever. (Big Sur apparently finally has a flag for it, but somebody who was helping me test this couldn't get it to work I don't think.)
I have no idea about BSD.
For reference, here are some bits of code you can use to verify that it works:
// Test sending IPv4 packets from IPv6.
using var s = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
s.DualMode = true;
s.Bind(IPEndPoint.Parse("[::]:1212"));
var targetEP = IPEndPoint.Parse("[::ffff:1.1.1.1]:1212");
s.SendTo(new byte[1234], targetEP);
s.SendTo(new byte[9000], targetEP);
s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment, true);
s.SendTo(new byte[1234], targetEP);
s.SendTo(new byte[9000], targetEP);
// Just plain IPv4.
using var s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
s.Bind(IPEndPoint.Parse("0.0.0.0:1212"));
var targetEP = IPEndPoint.Parse("1.1.1.1:1212");
s.SendTo(new byte[1234], targetEP);
s.SendTo(new byte[9000], targetEP);
s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment, true);
s.SendTo(new byte[1234], targetEP);
s.SendTo(new byte[9000], targetEP);
Triage: Makes sense to allow the flag on IPv6 for cases when it encapsulated IPv4. Should be easy to do. But not a priority -> Future. We would welcome a contribution though!
Description
While
DontFragment
doesn't make much sense on IPv6 itself, it is still useful for dual-stack sockets (an IPv6 socket that can handle IPv4 traffic too, through::FFFF:x.x.x.x
IPv6 addresses).Manually setting it via
SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment, true)
does work. The problem appears to be a rough top-level check in theDontFragment
property itself, nothing lower-level: https://github.com/dotnet/runtime/blob/8ff1bd04dfce1ca7e80401053b8983e22798a29d/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs#L652On both Windows and Linux, the flags are correctly respected when sending IPv4 traffic out of the IPv6 socket (at least, if my Wireshark isn't lying).
Reproduction Steps
Expected behavior
Don't fragment to be set on IPv4 sockets sent from the dual-stack socket.
Actual behavior
Regression?
No response
Known Workarounds
SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment, true);
works great.Configuration
No response
Other information
No response