dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.98k stars 4.66k forks source link

IP protocol implementations which work in Windows do not work in Linux #67303

Closed mikebromwich closed 2 years ago

mikebromwich commented 2 years ago

Description

Our platform includes an implementation of SCTP (RFC4960) implemented natively in C# (since SCTP is not supported by Windows). We use raw sockets to send/receive SCTP packets using the appropriate protocol number (132):

RawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, (ProtocolType)132);

We construct and interpret the SCTP L4 header within our code.

This works fine in Windows, but we now need to port this to Linux. Unfortunately there is code in runtime/src/native/libs/System.Native/pal_networking.c (Line 2274) which means that this cannot work. Any L4 protocols not specifically listed (and known to .NET) result in an error.

This is inconsistent with the Windows implementation which works as expected and allows arbitrary L4 protocol numbers to be used.

Reproduction Steps

using System;
using System.Net.Sockets;

var s = new Socket(AddressFamily.InterNetwork, SocketType.Raw, (ProtocolType)132);
Console.WriteLine(s);

Expected behavior

Successful execution - displaying the socket.

Actual behavior

Unhandled exception. System.Net.Sockets.SocketException (93): Protocol not supported

Regression?

This works on Windows, not on Linux

Known Workarounds

No response

Configuration

.NET 6.0 Works on Windows 10 (x64) Fails on Ubuntu 20.04 (x64)

Other information

Perhaps runtime/src/native/libs/System.Native/pal_networking.c (Line 2274) should return true rather than false?

ghost commented 2 years ago

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

Issue Details
### Description Our platform includes an implementation of SCTP (RFC4960) implemented natively in C# (since SCTP is not supported by Windows). We use raw sockets to send/receive SCTP packets using the appropriate protocol number (132): `RawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, (ProtocolType)132);` We construct and interpret the SCTP L4 header within our code. This works fine in Windows, but we now need to port this to Linux. Unfortunately there is code in runtime/src/native/libs/System.Native/pal_networking.c (Line 2274) which means that this cannot work. Any L4 protocols not specifically listed (and known to .NET) result in an error. This is inconsistent with the Windows implementation which works as expected and allows arbitrary L4 protocol numbers to be used. ### Reproduction Steps ``` using System; using System.Net.Sockets; var s = new Socket(AddressFamily.InterNetwork, SocketType.Raw, (ProtocolType)132); Console.WriteLine(s); ``` ### Expected behavior Successful execution - displaying the socket. ### Actual behavior `Unhandled exception. System.Net.Sockets.SocketException (93): Protocol not supported` ### Regression? This works on Windows, not on Linux ### Known Workarounds _No response_ ### Configuration .NET 6.0 Works on Windows 10 (x64) Fails on Ubuntu 20.04 (x64) ### Other information Perhaps runtime/src/native/libs/System.Native/pal_networking.c (Line 2274) should return true rather than false?
Author: mikebromwich
Assignees: -
Labels: `area-System.Net.Sockets`, `untriaged`
Milestone: -
wfurt commented 2 years ago

This works because .NET enums are copies from Windows and there is no PAL. I think the solution would be to open the socket via p/invoke and create Socket instance from the handle.

mikebromwich commented 2 years ago

Thanks @wfurt. The P/Invoke approach works.

I think, however, that if a developer is passing a specific protocol number (byte) to be matched against that in the IP header then no mapping is required? The code is already copying the value directly in line 2273 (which I think would resolve the issue) - but then returning false (which triggers the error).

The existing cases in the switch statement seem to cover circumstances where mapping is required.

wfurt commented 2 years ago

It is more tricky. The last parameter is ProtocolType not int. So you can pass same number on all platforms and the PAL code will make it work as needed. The difficult part is to know when not to do it and pass it raw. We had quite a few discussions about it and we decided to provide constructor for description for rare cases like this.

cc: @stephentoub for any additional thoughts.

mikebromwich commented 2 years ago

Understood. Perhaps another option would be to expand the ProtocolType enum to include more well-known protocol entries. The current list seems reasonably arbitrary - but excludes protocols like SCTP, GRE, OSPF, EIGRP etc. This wouldn't imply wider support within .NET - but would allow developers to implement as required without resorting to platform-specific work-arounds.

Maybe too the cases in the PAL could be expanded to cover all those (relevant) entries in the ProtocolType enum.

Thanks for the feedback anyway - I'll continue with the P/Invoke method as per your suggestion.

karelz commented 2 years ago

Triage:

Alternatives discussed:

@antonfirsov @stephentoub please speak up if you disagree

Closing for now, we can reopen if there is more interest in future.