/// <summary> /// Parses a raw packet (e.g. from /// <seealso cref="WinDivertRecv(IntPtr, WinDivertBuffer, ref WinDivertAddress, ref uint)" />) /// into the various packet headers and/or payloads that may or may not be present. /// </summary> /// <param name="packet"> /// The packet to be parsed. /// </param> /// <param name="packetDataLength"> /// The total length of the packet pPacket. /// </param> /// <returns> /// TRUE if all expected (non-NULL) outputs were present, FALSE otherwise. Note that FALSE /// may sometimes be a legitimate return value, e.g., when both ppIpHdr and ppIpv6Hdr are non-NULL. /// </returns> /// <remarks> /// Each output parameter may be NULL or non-NULL. For non-NULL parameters, this function /// will write the pointer to the corresponding header/payload if it exists, or will write /// NULL otherwise. Any non-NULL pointer that is returned Is pointer into the original /// pPacket packet, and, there is enough space in pPacket to fit the header. This function /// does not do any verification of the header/payload contents beyond checking the header /// length and any other minimal information required for parsing. /// </remarks> public static WinDivertParseResult WinDivertHelperParsePacket(WinDivertBuffer packet, uint packetDataLength) { IPv4Header* _pip4Header = null; IPv6Header* _pip6Header = null; IcmpV4Header* _picmp4Header = null; IcmpV6Header* _picmp6Header = null; TcpHeader* _ptcpHdr = null; UdpHeader* _pudpHdr = null; byte* _pdataPtr; uint _dataLen = 0; var retVal = new WinDivertParseResult(); WinDivertNative.WinDivertHelperParsePacket(packet.BufferPointer, packetDataLength, &_pip4Header, &_pip6Header, &_picmp4Header, &_picmp6Header, &_ptcpHdr, &_pudpHdr, &_pdataPtr, ref _dataLen); retVal._pip4Header = _pip4Header; retVal._pip6Header = _pip6Header; retVal._picmp4Header = _picmp4Header; retVal._picmp6Header = _picmp6Header; retVal._ptcpHdr = _ptcpHdr; retVal._pudpHdr = _pudpHdr; retVal._pdataPtr = _pdataPtr; retVal._dataLen = _dataLen; return retVal; }
private static unsafe void RunDiversion(IntPtr handle) { var packet = new WinDivertBuffer(); var addr = new WinDivertAddress(); uint readLen = 0; IPv4Header * ipv4Header = null; IPv6Header * ipv6Header = null; IcmpV4Header *icmpV4Header = null; IcmpV6Header *icmpV6Header = null; TcpHeader * tcpHeader = null; UdpHeader * udpHeader = null; Span <byte> packetData = null; NativeOverlapped recvOverlapped; IntPtr recvEvent = IntPtr.Zero; uint recvAsyncIoLen = 0; do { if (s_running) { packetData = null; readLen = 0; recvAsyncIoLen = 0; recvOverlapped = new NativeOverlapped(); recvEvent = Kernel32.CreateEvent(IntPtr.Zero, false, false, IntPtr.Zero); if (recvEvent == IntPtr.Zero) { Console.WriteLine("Failed to initialize receive IO event."); continue; } addr.Reset(); recvOverlapped.EventHandle = recvEvent; Console.WriteLine("Read"); if (!WinDivert.WinDivertRecvEx(handle, 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)); Kernel32.CloseHandle(recvEvent); continue; } while (Kernel32.WaitForSingleObject(recvEvent, 1000) == (uint)WaitForSingleObjectResult.WaitTimeout) { ; } if (!Kernel32.GetOverlappedResult(handle, ref recvOverlapped, ref recvAsyncIoLen, false)) { Console.WriteLine("Failed to get overlapped result."); Kernel32.CloseHandle(recvEvent); continue; } readLen = recvAsyncIoLen; } Kernel32.CloseHandle(recvEvent); Console.WriteLine("Read packet {0}", readLen); var parseResult = WinDivert.WinDivertHelperParsePacket(packet, readLen); ipv4Header = parseResult.IPv4Header; ipv6Header = parseResult.IPv6Header; icmpV4Header = parseResult.IcmpV4Header; icmpV6Header = parseResult.IcmpV6Header; tcpHeader = parseResult.TcpHeader; udpHeader = parseResult.UdpHeader; if (addr.Direction == WinDivertDirection.Inbound) { Console.WriteLine("inbound!"); } if (ipv4Header != null && tcpHeader != null) { Console.WriteLine($"V4 TCP packet {addr.Direction} from {ipv4Header->SrcAddr}:{tcpHeader->SrcPort.ReverseBytes()} to {ipv4Header->DstAddr}:{tcpHeader->DstPort.ReverseBytes()}"); } else if (ipv6Header != null && tcpHeader != null) { Console.WriteLine($"V4 TCP packet {addr.Direction} from {ipv6Header->SrcAddr}:{tcpHeader->SrcPort.ReverseBytes()} to {ipv6Header->DstAddr}:{tcpHeader->DstPort.ReverseBytes()}"); } 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(handle, packet, readLen, 0, ref addr)) { Console.WriteLine("Write Err: {0}", Marshal.GetLastWin32Error()); } } }while (s_running); }