Skip to content

Conversation

@wfurt
Copy link
Member

@wfurt wfurt commented Jun 7, 2023

contributes to #82262

note that on Linux there are two different modes of IPv6 not available.
One can pass ipv6.disable=1 to boot loader. With that, Socket.OSSupportsIPv6 is false and Quic fails to function even for IPv4 as MsQuic fails to create socket.

3863  socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_UDP) = -1 EAFNOSUPPORT (Address family not supported by protocol)

That mode is generally not applicable to Windows see microsoft/msquic#3093 (comment)

One can also set sysctl -w net.ipv6.conf.all.disable_ipv6=1 on Linux or HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters\DisabledComponents=0xffffffff on Windows. That efectively disables IPv6 on all interfaces, Socket.OSSupportsIPv6 is true, IPv4 works but attempt to bind on IPv6 ANY or connect to IPv6 destination fails with error described in #74053

@wfurt wfurt added this to the 8.0.0 milestone Jun 7, 2023
@wfurt wfurt requested review from CarnaViire, ManickaP and rzikm June 7, 2023 08:12
@wfurt wfurt self-assigned this Jun 7, 2023
@ghost
Copy link

ghost commented Jun 7, 2023

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

contributes to #82262

note that on Linux there are two different modes of IPv6 not available.
One can pass ipv6.disable=1 to boot loader. With that, Socket.OSSupportsIPv6 is false and Quic fails to function even for IPv4 as MsQuic fails to create socket.

3863  socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_UDP) = -1 EAFNOSUPPORT (Address family not supported by protocol)

That mode is generally not applicable to Windows see microsoft/msquic#3093 (comment)

One can also set sysctl -w net.ipv6.conf.all.disable_ipv6=1 on Linux or HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters\DisabledComponents=0xffffffff on Windows. That efectively disables IPv6 on all interfaces, Socket.OSSupportsIPv6 is true, IPv4 works but attempt to bind on IPv6 ANY or connect to IPv6 destination fails with error described in #74053

Author: wfurt
Assignees: wfurt
Labels:

area-System.Net.Quic

Milestone: 8.0.0

throw new ArgumentNullException(SR.Format(SR.net_quic_not_null_open_connection, nameof(QuicClientConnectionOptions.RemoteEndPoint)), argumentName);
}

// MsQuic is using DualMode sockets and that will faill even for IPv4 if AF_INET6 is not available.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this should be part of options Validation. Can you move this to connect itself? It also should not be thrown synchronously from ConnectAsync, but rather exposed as stored exception in the task.

General guidance is that only Argument validation exceptions should be thrown synchronously from async methods. What socket does is not 100% in line with this guidance, but we keep these inconsistencies for historical reasons.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can move it but I felt it would be better to keep everything together. And I also feel that throwing synchronously is better for cases when we even cannot start the operation. Is the guidance written somewhere?
cc: @stephentoub for more insight.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If quic can't work without OSSupportsIPv6, shouldn't that instead be part of QuicConnection.IsSupported, e.g.

public static bool IsSupported => MsQuicApi.IsQuicSupported && Socket.OSSupportsIPv6;

And for RemoteEndPoint, shouldn't that validation be done as part of setting the RemoteEndPoint, e.g. move the validation of its AddressFamily into the property setter?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can update IsSupported. I realized that only after writing tests and testing various setups. The only caveat is that when 'IsSupportedisfalse` it is very difficult IMHO to figure out why. But I guess we can document it in remarks.

As far as validation in setter: AFAIK we don't do that or anything else - neither in Quic nor SslStream e.g. for property bags we validate when applied to some action now when they are created. We could go down that route but then I would expect same for other properties.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I think moving Socket.OSSupportsIPv6 to IsSupported makes the most sense. AFAICT, it cannot change during app run and is essential for MsQuic to work.
But I'd suggest to make it part of MsQuicApi.IsQuicSupported as this might be MsQuic specific behavior and it will also give us opportunity to log this as we do with missing libmsquic etc. This should also answer the problem of diagnosing this as it would be evident from the logs what's going on. WDYT?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sense. How about the IPv4 check? It seems like less likely but sill possible. And than the question if it is ok to throw synchronously, store exception or do it when somebody is manipulating the option object.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not put it into the setter, we intentionally postpone all validations until the options are used.

We do other IP related and other checks afterwards, e.g.:

if (!options.RemoteEndPoint.TryParse(out string? host, out IPAddress? address, out int port))
{
throw new ArgumentException(SR.Format(SR.net_quic_unsupported_endpoint_type, options.RemoteEndPoint.GetType()), nameof(options));
}
int addressFamily = QUIC_ADDRESS_FAMILY_UNSPEC;

if (addresses.Length == 0)
{
throw new SocketException((int)SocketError.HostNotFound);
}

I still personally think this fits there better.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved the IPv6 check to IsSupported as suggested. As fas as the other check I'm still not convinced. The link you posted spawns task to figure out if something is going to work. But for the address family we can tell upfront it is going to fail (without any additional work)

From my prospective if something is going to fail the sooner we surface error and we stop doing extra work the better. Throwing in validation avoids creation of the task and and executing more code. But I can move it if that is consensus.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left IPv6 check as part of the IsSupported and I took out IPv4 check. I'll make plan and I'll put it up together with fixes for #74053.

@wfurt wfurt merged commit e5ddc6c into dotnet:main Jun 27, 2023
@wfurt wfurt deleted the QE branch June 27, 2023 09:06
@ghost ghost locked as resolved and limited conversation to collaborators Jul 27, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants