/// <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;
        }
        /// <summary>
        /// Handles the process of inspecting a new TCP connection, seeking the user's decision on
        /// what to do with the connection, and then applying that decision in code in such a way as
        /// to cause the packet filtering loop to apply the user's decision.
        /// </summary>
        /// <param name="connInfo">
        /// The state of the appropriate TCP table at the time of the new connectio.
        /// </param>
        /// <param name="tcpHeader">
        /// The TCP header from the first packet in the new connection/flow.
        /// </param>
        /// <param name="isIpv6">
        /// Whether or not this is from an IPV6 connection.
        /// </param>
        private unsafe void HandleNewTcpConnection(ITcpConnectionInfo connInfo, TcpHeader *tcpHeader, bool isIpv6)
        {
            if (tcpHeader == null)
            {
            }

            if (connInfo != null && connInfo.OwnerPid == m_thisPid)
            {
                // This is our process.
                switch (isIpv6)
                {
                case true:
                {
                    Volatile.Write(ref m_v6ShouldFilter[tcpHeader->SrcPort], (int)FirewallAction.DontFilterApplication);
                }
                break;

                case false:
                {
                    Volatile.Write(ref m_v4ShouldFilter[tcpHeader->SrcPort], (int)FirewallAction.DontFilterApplication);
                }
                break;
                }
            }
            else
            {
                FirewallResponse response = null;
                if (connInfo == null || connInfo.OwnerPid == 4 || connInfo.OwnerPid == 0)
                {
                    var firewallRequest = new FirewallRequest("SYSTEM", tcpHeader->SrcPort, tcpHeader->DstPort, connInfo == null ? 0L : connInfo.OwnerPid);
                    response = ConfirmDenyFirewallAccess?.Invoke(firewallRequest);
                }
                else
                {
                    if (IsInternalIp(connInfo.RemoteAddress))
                    {
                        response = new FirewallResponse(FirewallAction.DontFilterApplication);

                        m_logger.Info("Don't filter internal IPs.");
                    }
                    else
                    {
                        // No need to null check here, because the above IF catches whenever connInfo
                        // is null.
                        var procPath        = connInfo.OwnerProcessPath.Length > 0 ? connInfo.OwnerProcessPath : "SYSTEM";
                        var firewallRequest = new FirewallRequest(procPath, tcpHeader->SrcPort, tcpHeader->DstPort, connInfo.OwnerPid);
                        response = ConfirmDenyFirewallAccess?.Invoke(firewallRequest);
                    }
                }


                if (response == null)
                {
                    // The user couldn't be bothered to give us an answer, so just go ahead and
                    // let the packet through.

                    switch (isIpv6)
                    {
                    case true:
                    {
                        Volatile.Write(ref m_v6ShouldFilter[tcpHeader->SrcPort], (byte)FirewallAction.DontFilterApplication);

                        Volatile.Write(ref m_v6EncryptionHints[tcpHeader->SrcPort], (tcpHeader->DstPort == m_httpsStandardPort || tcpHeader->DstPort == m_httpsAltPort));
                    }
                    break;

                    case false:
                    {
                        Volatile.Write(ref m_v4ShouldFilter[tcpHeader->SrcPort], (byte)FirewallAction.DontFilterApplication);

                        Volatile.Write(ref m_v4EncryptionHints[tcpHeader->SrcPort], (tcpHeader->DstPort == m_httpsStandardPort || tcpHeader->DstPort == m_httpsAltPort));
                    }
                    break;
                    }
                }
                else
                {
                    switch (isIpv6)
                    {
                    case true:
                    {
                        Volatile.Write(ref m_v6ShouldFilter[tcpHeader->SrcPort], (byte)response.Action);

                        Volatile.Write(ref m_v6EncryptionHints[tcpHeader->SrcPort], response.EncryptedHint ?? (tcpHeader->DstPort == m_httpsStandardPort || tcpHeader->DstPort == m_httpsAltPort));
                    }
                    break;

                    case false:
                    {
                        Volatile.Write(ref m_v4ShouldFilter[tcpHeader->SrcPort], (byte)response.Action);

                        Volatile.Write(ref m_v4EncryptionHints[tcpHeader->SrcPort], response.EncryptedHint ?? (tcpHeader->DstPort == m_httpsStandardPort || tcpHeader->DstPort == m_httpsAltPort));
                    }
                    break;
                    }
                }
            }
        }
Exemplo n.º 3
0
        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);
        }