Runtime: Unsupported raw socket programming

Created on 8 Nov 2017  路  6Comments  路  Source: dotnet/runtime

@jakubaleksanderpolkowski commented on Thu Nov 02 2017

Unsupported raw socket programming

Unable to create new raw socket using .net core and C# on armhf hardware under linux

As above i can't create raw socket in any way.
It seems like .net core does not support raw socket programming yet.

Hardware: Raspberry Pi3
CPU: armhf
OS: Raspbian
Runtime: 2.0.0-preview1-001887-00

Language: C#

Published on x64 Linux with sdk 2.0.0

Received error:

" Unhandled Exception: System.Net.Sockets.SocketException: Protocol not supported
at System.Net.Sockets.Socket..ctor(AddressFamily addressFamily, SocketType socketType, ProtocolType > protocolType) "

Code that whrows error:
mainSocket = new Socket(AddressFamily.InterNetwork,SocketType.Raw, ProtocolType.IP);


@stephentoub commented on Thu Nov 02 2017

What happens if you run with sudo?

Are you able to write/run a C program that creates a raw socket successfully?


@jakubaleksanderpolkowski commented on Fri Nov 03 2017

I all ready run this as sudo, I even gave CAP_NET_RAW capability to this program


@stephentoub commented on Fri Nov 03 2017

And what about a C program... you have a program in C that runs successfully opening a raw socket on the same machine?


@wfurt commented on Fri Nov 03 2017

https://stackoverflow.com/questions/19732145/python-raw-socket-protocol-not-supported

You need to use AF_PACKET (17 on Linux) but that does not seems to be defined for .net.
Try Cprogram as @stephentoub suggested and check it with strace.

area-System.Net.Sockets os-linux

Most helpful comment

Ok... I'm interested in this as well.

I am writing a Cisco CDP client for Linux that can be used from C#. There are a few solutions to this.

1) Use AF_LLC which would be the best solution but would require A LOT of research to simply read the packet and frankly, it's not particularly exciting to do so. I believe I will do this at some point though. I'm not excited about this solution because AF_LLC is poorly documented and the code seems unmaintained and there has been historically double-delete issues on the memory. This scares the hell out of me because I simply don't trust unmaintained C code.

2) Write a kernel module and implement the protocol family. It's been done before. It wouldn't be overly difficult, but this is a very poor choice since it would require maintaining a kernel module which has a lot of parsing in it. I refuse to pollute society with more unmanaged memory. That's how we did it in the 90's. In the 21st century we put dynamic code into userland in languages which have relocatable memory.

3) Use AF_PACKET.

So, here's my testing.

#include<net/if_packet.h>
#include<linux/if_ether.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>

int main(int argc, char **argv)
{
    int sd;

    sd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_802_2));

    if(sd == -1)
        printf("Error -> %s\n", strerror(errno));

    printf("sd = %d\n", sd);

    return 1;
}

When run as me the output is as follows :

Error -> Operation not permitted
sd = -1

When run as root, the output is as follows :

sd = 3

A program which should do similar things in C#

using System;
using System.Net.Sockets;

namespace cdpclient
{
    class Program
    {
        static void Main(string[] args)
        {
            var socket = new Socket((AddressFamily)17, SocketType.Dgram, (ProtocolType)0x0004);
        }
    }
}

This is a truly horrible example... but I've been digging in the CoreFX code base hoping it would work. Then I realized there are some troubles to be worked with.

  • System.Net.Primitives.cs and System.Net.Sockets.cs define AddressFamily.NetBIOS as 17 but on Linux from /usr/include we find :
me@LinuxServer7:/usr/include$ grep -r PF_PACKET
x86_64-linux-gnu/bits/socket.h:#define PF_PACKET    17  /* Packet family.  */
x86_64-linux-gnu/bits/socket.h:#define AF_PACKET    PF_PACKET
  • InnerSafeCloseSocket.Create in the unix safe close socket code says the following :
public static unsafe InnerSafeCloseSocket CreateSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, out SocketError errorCode)
{
    IntPtr fd;
    Interop.Error error = Interop.Sys.Socket(addressFamily, socketType, protocolType, &fd);

Interop.Sys.Socket is as follows :

[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Socket")]
internal static extern unsafe Error Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, IntPtr* socket);

The C native system code in pal_networking.c gives us the bug/problem :

SystemNative_Socket calls TryConvertAddressFamilyPalToPlatform() which in turn runs a select statement for the protocols which .NET Core understands. But for the default there is the following :

    default:
            *platformAddressFamily = (sa_family_t)palAddressFamily;
            return false;

which causes SystemNative_Socket to do the following :

{
    *createdSocket = -1;
    return Error_EAFNOSUPPORT;
}

The problems as I see is a case where some form of security should be applied. Of course, this code can't be run unless as root or suid, but supporting all the nifty protocols in the whole UNIX world could be a problem to secure properly. As such, if exposing this without the "Error_EAFNOSUPPORT" thing, it might be interesting to make a case on systems like UWP that restricts access to anything but the approved protocols unless the user clicks "I agree I didn't read this warning".

All 6 comments

I don't believe this is a .NET issue. The OS is simply reporting that it doesn't support the combination of inputs you provided. For example, on my Ubuntu 17.10 install, when I sudo dotnet run this:
```C#
using System;
using System.Net.Sockets;

public class Repro
{
static void Main()
{
var s = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
Console.WriteLine(s);
}
}

I get an error, but when I `sudo dotnet run` this:
```C#
using System;
using System.Net.Sockets;

public class Repro
{
    static void Main()
    {
        var s = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Udp);
        Console.WriteLine(s);
    }
}

it runs successfully and prints out the socket object.

Similarly, if I compile this program (gcc -o test test.c):

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/ip.h>

int main(int argc, char** argv)
{
    int fd = socket(PF_INET, SOCK_RAW, IPPROTO_IP);
    if (fd == -1)
        perror("socket");
    else
        printf("%d\n", fd);
}

and run it with sudo ./test, I get:

stoub@SToubUbuntu17102:~/tmpapp$ sudo ./test
socket: Protocol not supported

but if I instead compile this program:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/ip.h>

int main(int argc, char** argv)
{
    int fd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
    if (fd == -1)
        perror("socket");
    else
        printf("%d\n", fd);
}

it runs fine and I get the file descriptor output, e.g.

stoub@SToubUbuntu17102:~/tmpapp$ sudo ./test
3

If you find evidence that this is a .NET issue, please share and re-open the issue. Thanks.

This problem was fixed on 2.1 ?

what exactly are you trying to do @nim? As @stephentoub mentioned in some cases the error is coming from OS and there is not much we can do about it at dotnet.

Ok... I'm interested in this as well.

I am writing a Cisco CDP client for Linux that can be used from C#. There are a few solutions to this.

1) Use AF_LLC which would be the best solution but would require A LOT of research to simply read the packet and frankly, it's not particularly exciting to do so. I believe I will do this at some point though. I'm not excited about this solution because AF_LLC is poorly documented and the code seems unmaintained and there has been historically double-delete issues on the memory. This scares the hell out of me because I simply don't trust unmaintained C code.

2) Write a kernel module and implement the protocol family. It's been done before. It wouldn't be overly difficult, but this is a very poor choice since it would require maintaining a kernel module which has a lot of parsing in it. I refuse to pollute society with more unmanaged memory. That's how we did it in the 90's. In the 21st century we put dynamic code into userland in languages which have relocatable memory.

3) Use AF_PACKET.

So, here's my testing.

#include<net/if_packet.h>
#include<linux/if_ether.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>

int main(int argc, char **argv)
{
    int sd;

    sd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_802_2));

    if(sd == -1)
        printf("Error -> %s\n", strerror(errno));

    printf("sd = %d\n", sd);

    return 1;
}

When run as me the output is as follows :

Error -> Operation not permitted
sd = -1

When run as root, the output is as follows :

sd = 3

A program which should do similar things in C#

using System;
using System.Net.Sockets;

namespace cdpclient
{
    class Program
    {
        static void Main(string[] args)
        {
            var socket = new Socket((AddressFamily)17, SocketType.Dgram, (ProtocolType)0x0004);
        }
    }
}

This is a truly horrible example... but I've been digging in the CoreFX code base hoping it would work. Then I realized there are some troubles to be worked with.

  • System.Net.Primitives.cs and System.Net.Sockets.cs define AddressFamily.NetBIOS as 17 but on Linux from /usr/include we find :
me@LinuxServer7:/usr/include$ grep -r PF_PACKET
x86_64-linux-gnu/bits/socket.h:#define PF_PACKET    17  /* Packet family.  */
x86_64-linux-gnu/bits/socket.h:#define AF_PACKET    PF_PACKET
  • InnerSafeCloseSocket.Create in the unix safe close socket code says the following :
public static unsafe InnerSafeCloseSocket CreateSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, out SocketError errorCode)
{
    IntPtr fd;
    Interop.Error error = Interop.Sys.Socket(addressFamily, socketType, protocolType, &fd);

Interop.Sys.Socket is as follows :

[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Socket")]
internal static extern unsafe Error Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, IntPtr* socket);

The C native system code in pal_networking.c gives us the bug/problem :

SystemNative_Socket calls TryConvertAddressFamilyPalToPlatform() which in turn runs a select statement for the protocols which .NET Core understands. But for the default there is the following :

    default:
            *platformAddressFamily = (sa_family_t)palAddressFamily;
            return false;

which causes SystemNative_Socket to do the following :

{
    *createdSocket = -1;
    return Error_EAFNOSUPPORT;
}

The problems as I see is a case where some form of security should be applied. Of course, this code can't be run unless as root or suid, but supporting all the nifty protocols in the whole UNIX world could be a problem to secure properly. As such, if exposing this without the "Error_EAFNOSUPPORT" thing, it might be interesting to make a case on systems like UWP that restricts access to anything but the approved protocols unless the user clicks "I agree I didn't read this warning".

There is discussion in dotnet/corefx#30197 about adding AF_PACKET and possibly AF_NETLINK to supported address family.

dotnet/corefx#30197 is resolved. This should work now with 3.0

Was this page helpful?
0 / 5 - 0 ratings

Related issues

GitAntoinee picture GitAntoinee  路  3Comments

bencz picture bencz  路  3Comments

v0l picture v0l  路  3Comments

nalywa picture nalywa  路  3Comments

omajid picture omajid  路  3Comments