TechnikEmpire / WinDivertSharp

A minimal .NET binding over WinDivert
Other
106 stars 27 forks source link

Update sample code #6

Open TechnikEmpire opened 5 years ago

TechnikEmpire commented 5 years ago

Sandbox code is out of sync with the latest version.

jjxtra commented 5 years ago

Trying this new code in the sandbox, getting error 87 every time...

public static void ReadThread()
{
            var packet = new WinDivertBuffer();
            WinDivertAddress addr = new WinDivertAddress();
            uint readLen = 0;
            WinDivertParseResult result;
            Span<byte> packetData = null;
            NativeOverlapped recvOverlapped;
            IntPtr recvEvent = IntPtr.Zero;
            uint recvAsyncIoLen = 0;

            recvOverlapped = new NativeOverlapped();
            recvEvent = Kernel32.CreateEvent(IntPtr.Zero, false, false, IntPtr.Zero);
            recvOverlapped.EventHandle = recvEvent;

            try
            {
                while (!Disposed)
                {
                    packetData = null;
                    readLen = 0;
                    recvAsyncIoLen = 0;
                    addr.Reset();

                    Console.WriteLine("Read");

                    if (!WinDivert.WinDivertRecvEx(winDivertHandle, packet, 0, ref addr, ref readLen, ref recvOverlapped))
                    {
                        var error = Marshal.GetLastWin32Error();

                        // 997 == ERROR_IO_PENDING
                        if (error != 997)
                        {
                            Console.WriteLine(string.Format("Unknown IO error ID {0} while awaiting overlapped result.", error));
                            continue;
                        }

                        while (Kernel32.WaitForSingleObject(recvEvent, 1000) == (uint)WaitForSingleObjectResult.WaitTimeout)
                        {
                        }

                        if (!Kernel32.GetOverlappedResult(winDivertHandle, ref recvOverlapped, ref recvAsyncIoLen, false))
                        {
                            Console.WriteLine("Failed to get overlapped result.");
                            continue;
                        }

                        readLen = recvAsyncIoLen;
                    }

                    Console.WriteLine("Read packet {0}", readLen);

                    result = WinDivert.WinDivertHelperParsePacket(packet, readLen);

                    if (addr.Direction == WinDivertDirection.Inbound)
                    {
                        Console.WriteLine("inbound!");
                    }

                    if (result.IPv4Header != null && result.TcpHeader != null)
                    {
                        Console.WriteLine($"V4 TCP packet {addr.Direction} from {result.IPv4Header->SrcAddr}:{result.TcpHeader->SrcPort} to {result.IPv4Header->DstAddr}:{result.TcpHeader->DstPort}");
                    }
                    else if (result.IPv6Header != null && result.TcpHeader != null)
                    {
                        Console.WriteLine($"V4 TCP packet {addr.Direction} from {result.IPv6Header->SrcAddr}:{result.TcpHeader->SrcPort} to {result.IPv6Header->DstAddr}:{result.TcpHeader->DstPort}");
                    }

                    if (packetData != null)
                    {
                        Console.WriteLine("Packet has {0} byte payload.", packetData.Length);
                    }

                    Console.WriteLine($"{nameof(addr.Direction)} - {addr.Direction}");
                    Console.WriteLine($"{nameof(addr.Impostor)} - {addr.Impostor}");
                    Console.WriteLine($"{nameof(addr.Loopback)} - {addr.Loopback}");
                    Console.WriteLine($"{nameof(addr.IfIdx)} - {addr.IfIdx}");
                    Console.WriteLine($"{nameof(addr.SubIfIdx)} - {addr.SubIfIdx}");
                    Console.WriteLine($"{nameof(addr.Timestamp)} - {addr.Timestamp}");
                    Console.WriteLine($"{nameof(addr.PseudoIPChecksum)} - {addr.PseudoIPChecksum}");
                    Console.WriteLine($"{nameof(addr.PseudoTCPChecksum)} - {addr.PseudoTCPChecksum}");
                    Console.WriteLine($"{nameof(addr.PseudoUDPChecksum)} - {addr.PseudoUDPChecksum}");

                    // Console.WriteLine(WinDivert.WinDivertHelperCalcChecksums(packet, ref addr, WinDivertChecksumHelperParam.All));

                    if (!WinDivert.WinDivertSendEx(winDivertHandle, packet, readLen, 0, ref addr))
                    {
                        Console.WriteLine("Write Err: {0}", Marshal.GetLastWin32Error());
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Fatal error in read thread: {0}", ex);
            }
            finally
            {
                WinDivert.WinDivertClose(winDivertHandle);
                Kernel32.CloseHandle(recvEvent);
            }
}

public static void RunSandbox()
{
            winDivertHandle = WinDivert.WinDivertOpen("inbound and tcp", WinDivertLayer.Network, 0, 
                WinDivertOpenFlags.None);
            WinDivert.WinDivertSetParam(winDivertHandle, WinDivertParam.QueueLen, 16384);
            WinDivert.WinDivertSetParam(winDivertHandle, WinDivertParam.QueueTime, 8000);
            WinDivert.WinDivertSetParam(winDivertHandle, WinDivertParam.QueueSize, 33554432);
            Task.Run(FirewallThread);
}
TechnikEmpire commented 5 years ago

87 on which line?

TechnikEmpire commented 5 years ago

87 is invalid param. Right off the bat I don't see you resetting your overlapped event. Error codes are standard win api errors fyi to help you debug.

jjxtra commented 5 years ago

Never mind I am binding against windivert 2.0, I am guessing the params are not an exact match.

TechnikEmpire commented 5 years ago

Windivert doesn't use semver even between minor versions the api is generally not backward compatible. 2.0 might as well be version 9000. A 2.0 update is in progress but the struct are now really ugly and hard to emulate.

jjxtra commented 5 years ago

I tried using the pinvoke binder application on the 2.0 windivert.h file but it crashed, do you know of any other tools that auto-generate the pinvoke?

jjxtra commented 5 years ago

I have 2.0 recv ex working in a fork, will post example code in a bit

jjxtra commented 5 years ago

Well I am having trouble getting send ex working. It gets 997 io pending error but then attempting to read the overlapped data after the send event has signalled always gives error 87...

I have recv ex working. Care to compare code and see if we can figure it out? My branch is here: https://github.com/DigitalRuby/WinDivertSharp/tree/2.0

jjxtra commented 5 years ago

I've got 2.0 working with receive and send with batching now, see the latest commits on my fork.

TechnikEmpire commented 5 years ago

Yeah I already have all that working but I want to have accurate structs that are modifiable.

Lemorz56 commented 3 years ago

Yeah I already have all that working but I want to have accurate structs that are modifiable.

Sorry for bumping an old issue, did not want to create a new. I've seen some comments about you making your own driver, is it Open source? Thanks.

TechnikEmpire commented 3 years ago

@Lemorz56 No problem. My driver is not open source. It doesn't even work like WinDivert anyway, as in, it's not a general purpose driver.

illumen commented 3 years ago

How would we modify a packet's payload content?

Lemorz56 commented 3 years ago

How would we modify a packet's payload content?

I ended up using the original C++ but im guessing you will need skip sending the one you want to change and then making your own using the old one, and sending that instead.

TechnikEmpire commented 3 years ago

I'm probably going to archive this repo.

Lemorz56 commented 3 years ago

I'm probably going to archive this repo.

Yeah that's probably for the best