-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Raw Socket on Linux - Outbound data missing #26416
Comments
cc @wfurt |
https://www.linuxquestions.org/questions/programming-9/problem-sniffing-with-raw-sockets-222971/ You would need to use AF_PACKET(https://www.binarytides.com/packet-sniffer-code-in-c-using-linux-sockets-bsd-part-2/) However that addressFamily is currently not supported. Your best option may be invoking libpcap. |
@wfurt Thanks for confirming this is not currently supported. Is this something that’s on the roadmap for future versions? In the meantime I ended up doing what you suggested and leveraged SharpPcap to wrap libpcap but this introduces additional dependencies that I’d prefer to avoid. I am going to take a peek at System.IO.Sockets and see if it’s possible to accomplish this with extension methods as I assume it’s probably just configuring the driver. |
The difficulty is that that interface is Linux specific and it would be very difficult to support it cross platforms. If anything, I could possibly see generic packet capture API in NetworInfo class but I don't know if that would pass API review board. It would certainly needs some more thinking and preparation. Another path you can try to explore is using tcpdump. You can do something like |
Generic packet capture API seems like huge overkill. Given it is rare scenario, I would prioritize mainline scenarios first. |
We (Networking team) are in general fine with the API addition, assuming it solves the original problem - @wfurt will investigate. |
any plan or process for this ? |
This should now work with 3.0 Preview or daily builds. Note, that what we get is basic ability to create Socket with AddressFamily.Packet. If somebody wants to do anything fancy like setting BPF filter, you will need to get socket.Handle and pinvoke functions from libc or libpcap. By default, you will get all packets from all interfaces and that may or may not be what you want. using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
namespace Capture
{
class Program
{
/*
// from linux/if_packet.h
struct sockaddr_ll {
Int16 family;
Int16 protocol;
Int32 ifindex;
Int32 pad1;
Int32 pad2;
Int32 pad3;
}
*/
class LLEndPoint : EndPoint
{
private Int32 _ifIndex;
public LLEndPoint(int interfaceIndex)
{
_ifIndex = interfaceIndex;
}
public override SocketAddress Serialize()
{
var a = new SocketAddress(AddressFamily.Packet, 20);
byte[] asBytes = BitConverter.GetBytes(_ifIndex);
a[4] = asBytes[0];
a[5] = asBytes[1];
a[6] = asBytes[2];
a[7] = asBytes[3];
return a;
}
}
static void doBind(Socket s, int ifIndex)
{
var address = new LLEndPoint(ifIndex);
s.Bind(address);
}
static void Main(string[] args)
{
Int16 protocol = 0x800; // IP.
var _socket = new Socket(AddressFamily.Packet, SocketType.Raw, (ProtocolType)System.Net.IPAddress.HostToNetworkOrder(protocol));
if (args.Length > 0)
{
doBind(_socket, int.Parse(args[0]));
}
byte[] packet = new byte[1508];
int count = 10;
while (count > 0)
{
int packetLen = _socket.Receive(packet);
Console.WriteLine("got packet {0} {1} - {2}", packetLen, new IPAddress(packet.AsSpan().Slice(26, 4)), new IPAddress(packet.AsSpan().Slice(30,4)));
count--;
}
}
}
} |
@wfurt Thanks for working on this. I actually just grabbed preview6 and gave it a try using the example you posted, but it seems to have the same issue I originally had where the lo interface sees both in and outbound, but on an external interface it only sees the inbound data and doesn't see any of the outbound at all. |
do you have sample code? And of course you need to run it as root or you would get permission denied error. |
I’ll put a repro together and link it here as soon as I can. It will take a little bit before I can do it though because to test it I swapped out libpcap in my existing project with the sample you posted here and ran my normal traffic tests for that project against it |
I put together a quick repro of this at https://github.com/los93sol/RawSocketSample |
@wfurt Let me know if you want to see anything else, I just slammed that sample together pretty quickly to demo how eth0 is missing, just comment the block in PacketCapture that does the bind to the LLEndPoint and you can see it does see both inbound and outbound when the traffic is local. |
When socket is created, there should be no difference to libpcap/tcpdump or any direct use of the socket. Thanks for the repro but as I run directly on Linux I did quick check with my sample code. It seems like the problem is in the bind example. If I add
I can see packets in both directions.
it was mostly meant as guide how to use Bind() without introducing AF specific c# structure. You can always skip it and p/invoke bind from libc. If that does not work you can use 'strace -f -e trace=network xxx' to see what the difference is between your app and tcpdump. I may not be able to get back to this for a while as I need to focus on remaining 3.0 issues. |
@wfurt Thank you so much! Now that I'm taking another look at the man pages for the native structs I understand much better what's happening and how this is working. |
In case anyone comes across this thread and is looking for examples check my repo that was posted here, I have PACKET_FANOUT and BPF filters working now |
Sorry to continue on a closed thread, but the discussion here seems relevant. Looking at the source it looks like .NET Core is using a system call to recvmsg under the hood when reading from the socket. For a raw socket it seems it is probably more desirable to leverage SO_RX_RING to minimize the number of system calls and allocations. Is MemoryMappedFiles intended to be useful for these types of things or am I off down the wrong path completely? |
Hello @los93sol your example repo looks very interesting! Question: would it also be possible to send and receive Layer 2 packets (only MAC Source, MAC Destination, EtherType and Payload) without them having to be IPv4 for example? |
yes, that should work @smuellener. If you look at my sample code it gets first IP address fropm offset 26 -> the buffer contains whole payload including L2 header. |
I am using a raw socket on linux to capture all traffic on a specific interface and port. The issue I'm having is that on eth0 I see only the inbound traffic, but on the lo interface I can see both inbound and outbound. Is there a trick to getting the outbound data on the eth0 interface?
The text was updated successfully, but these errors were encountered: