コード例 #1
0
        /// <summary>
        /// Driver thread. If the hotkey is activated, it will drop the incoming packets.
        /// </summary>
        public unsafe void watchTraffic(object param)
        {
            string filter = (string)param;

            if (filter == "")
            {
                Debug.WriteLine("empty filter");
                goto Cleanup;
            }
            filter = "icmp or " + filter;
            Debug.WriteLine(filter);
            IntPtr driver = WinDivert.WinDivertOpen(filter, WinDivertLayer.Network, 0, WinDivertOpenFlags.None);

            if (driver == new IntPtr(-1))
            {
                Debug.WriteLine("Driver open failed");
                goto Cleanup;
            }
            IPAddress            terminateAddress = new IPAddress(new byte[] { 127, 0, 0, 2 });
            WinDivertBuffer      packet           = new WinDivertBuffer(0xFFFF);
            uint                 packetLen        = 0;
            WinDivertAddress     address          = new WinDivertAddress();
            WinDivertParseResult parsed           = new WinDivertParseResult();

            while (true)
            {
                WinDivert.WinDivertRecv(driver, packet, ref address, ref packetLen);
                parsed = WinDivert.WinDivertHelperParsePacket(packet, packetLen);
                if (parsed.IPv4Header->DstAddr.Equals(terminateAddress))
                {
                    Debug.WriteLine("ICMP signalled termination");
                    break;
                }
                if (!packetsBlocked)
                {
                    WinDivert.WinDivertSend(driver, packet, packetLen, ref address);
                }
            }
            WinDivert.WinDivertClose(driver);

Cleanup:
            driverThread = null;
            Debug.WriteLine("Driver terminated");
        }
コード例 #2
0
        private unsafe void RunDiversion()
        {
            var packet = new WinDivertBuffer();

            var addr = new WinDivertAddress();

            uint recvLength = 0;

            NativeOverlapped recvOverlapped;

            IntPtr recvEvent = IntPtr.Zero;

            recvEvent = WinDivertSharp.WinAPI.Kernel32.CreateEvent(IntPtr.Zero, false, false, IntPtr.Zero);

            if (recvEvent == IntPtr.Zero || recvEvent == new IntPtr(-1))
            {
                m_logger.Error("Failed to initialize receive IO event.");
                return;
            }

            uint recvAsyncIoLen = 0;

            bool isLocalIpv4    = false;
            bool modifiedPacket = false;
            bool dropPacket     = false;

            Span <byte> payloadBufferPtr = null;

            while (m_running)
            {
                try
                {
                    payloadBufferPtr = null;

                    recvLength = 0;
                    addr.Reset();
                    modifiedPacket = false;
                    dropPacket     = false;
                    isLocalIpv4    = false;
                    recvAsyncIoLen = 0;

                    recvOverlapped = new NativeOverlapped();
                    WinAPI.Kernel32.ResetEvent(recvEvent);

                    recvOverlapped.EventHandle = recvEvent;

                    #region Packet Reading Code

                    uint addrLen = (uint)sizeof(WinDivertAddress);
                    if (!WinDivert.WinDivertRecvEx(m_diversionHandle, packet, 0, out recvLength, out addr, ref addrLen, ref recvOverlapped))
                    {
                        var error = Marshal.GetLastWin32Error();

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

                        // 258 == WAIT_TIMEOUT
                        while (m_running && WinDivertSharp.WinAPI.Kernel32.WaitForSingleObject(recvEvent, 1000) == (uint)WaitForSingleObjectResult.WaitTimeout)
                        {
                        }

                        if (!WinDivertSharp.WinAPI.Kernel32.GetOverlappedResult(m_diversionHandle, ref recvOverlapped, ref recvAsyncIoLen, false))
                        {
                            m_logger.Warn("Failed to get overlapped result.");
                            continue;
                        }

                        recvLength = recvAsyncIoLen;
                    }

                    #endregion Packet Reading Code

                    WinDivertParseResult parseResult = null;
                    if (addr.Outbound)
                    {
                        parseResult = WinDivert.WinDivertHelperParsePacket(packet, recvLength);

                        #region New TCP Connection Detection

                        if (parseResult.TcpHeader != null && parseResult.TcpHeader->Syn > 0)
                        {
                            // Brand new outbound connection. Grab the PID of the process holding this
                            // port and map it.
                            if (parseResult.IPv4Header != null)
                            {
                                var connInfo = GetLocalPacketInfo(parseResult.TcpHeader->SrcPort, parseResult.IPv4Header->SrcAddr);

                                HandleNewTcpConnection(connInfo, parseResult.TcpHeader, false);

                                // Handle the special case of entirely blocking internet for this application/port.
                                if (Volatile.Read(ref m_v4ShouldFilter[parseResult.TcpHeader->SrcPort]) == (int)FirewallAction.BlockInternetForApplication)
                                {
                                    dropPacket = true;
                                }
                            }

                            if (parseResult.IPv6Header != null)
                            {
                                var connInfo = GetLocalPacketInfo(parseResult.TcpHeader->SrcPort, parseResult.IPv6Header->SrcAddr);

                                HandleNewTcpConnection(connInfo, parseResult.TcpHeader, true);

                                // Handle the special case of entirely blocking internet for this application/port.
                                if (Volatile.Read(ref m_v6ShouldFilter[parseResult.TcpHeader->SrcPort]) == (int)FirewallAction.BlockInternetForApplication)
                                {
                                    dropPacket = true;
                                }
                            }
                        }

                        // Now that we've processed any potentially new connections, let's see if the
                        // packet belongs to an existing flow that was marked to be blocked.

                        // Check if this packet belongs to an IPV4 flow marked for blocking.
                        if (parseResult.IPv4Header != null)
                        {
                            int srcPortAction = Volatile.Read(ref m_v4ShouldFilter[parseResult.TcpHeader->SrcPort]);

                            // Handle the special case of entirely blocking internet for this application/port.
                            if (srcPortAction == (int)FirewallAction.BlockInternetForApplication)
                            {
                                dropPacket = true;
                            }
                        }

                        // Check if this packet belongs to an IPV6 flow marked for blocking.
                        if (!dropPacket && parseResult.IPv6Header != null)
                        {
                            int srcPortAction = Volatile.Read(ref m_v6ShouldFilter[parseResult.TcpHeader->SrcPort]);

                            // Handle the special case of entirely blocking internet for this application/port.
                            if (srcPortAction == (int)FirewallAction.BlockInternetForApplication)
                            {
                                dropPacket = true;
                            }
                        }

                        #endregion New TCP Connection Detection

                        // I put the checks for ipv4 and ipv6 as a double if statement rather than an
                        // else if because I'm not sure how that would affect dual-mode sockets. Perhaps
                        // it's possible for both headers to be defined. Probably not, but since I don't
                        // know, I err on the side of awesome, or uhh, something like that.

                        // We check local packets for TOR/SOCKS packets here. However, if we don't find
                        // something we want to block on local addresses, then we want to skip these for
                        // the rest of the filtering and just let them through.

                        if (dropPacket == false && parseResult.IPv4Header != null && parseResult.TcpHeader != null)
                        {
                            // Let's explain the weird arcane logic here. First, we check if the current
                            // flow should even be filtered. We do this, because there's a good chance
                            // that this flow belongs to our proxy's connections, which we never want to
                            // filter. If we didn't check this, then we would end up setting the
                            // isLocalIpv4 flag to true on every single one of our proxy's connections,
                            // and clients would never get packets ever because with that flag set, the
                            // direction of the packets wouldn't be sorted.
                            //
                            // So, we check this, ensure it's actually something we want to filter. Then,
                            // we check if the packet is destined for a local address. We set the flag
                            // accordingly, and if true, then we will allow these packets to go out uninterrupted.
                            //
                            // If false, who cares. Regardless of true or false, we check to see if this
                            // is a TOR/SOCKS4/5 proxy CONNECT, and drop it if it is.
                            //
                            // Also note, by letting local/private address destined packets go, we also
                            // solve the problem of private TLS connections using private TLS self signed
                            // certs, such as logging into one's router. If we didn't do this check and
                            // let these through, we would break such connections.

                            if (Volatile.Read(ref m_v4ShouldFilter[parseResult.TcpHeader->SrcPort]) == (int)FirewallAction.FilterApplication)
                            {
                                isLocalIpv4 = parseResult.IPv4Header->DstAddr.IsPrivateIpv4Address();

                                if (isLocalIpv4)
                                {
#if !ENGINE_NO_BLOCK_TOR
                                    byte[] payload = null;
                                    if (payloadBufferPtr != null && payloadBufferPtr.Length > 0)
                                    {
                                        payload = payloadBufferPtr.ToArray();

                                        if (payload.IsSocksProxyConnect())
                                        {
                                            m_logger.Info("Blocking SOCKS proxy connect.");
                                            continue;
                                        }
                                    }
#endif
                                }
                            }
                        }

                        if (dropPacket == false && !isLocalIpv4)
                        {
                            if (parseResult.IPv4Header != null && parseResult.TcpHeader != null)
                            {
                                if (parseResult.TcpHeader->SrcPort == m_v4HttpProxyPort || parseResult.TcpHeader->SrcPort == m_v4HttpsProxyPort)
                                {
                                    // Means that the data is originating from our proxy in response to a
                                    // client's request, which means it was originally meant to go
                                    // somewhere else. We need to reorder the data such as the src and
                                    // destination ports and addresses and divert it back inbound, so it
                                    // appears to be an inbound response from the original external server.

                                    modifiedPacket = true;

                                    parseResult.TcpHeader->SrcPort = Volatile.Read(ref m_v4ReturnPorts[parseResult.TcpHeader->DstPort]);
                                    addr.Outbound = false;

                                    var dstIp = parseResult.IPv4Header->DstAddr;
                                    parseResult.IPv4Header->DstAddr = parseResult.IPv4Header->SrcAddr;
                                    parseResult.IPv4Header->SrcAddr = dstIp;
                                }
                                else
                                {
                                    // This means outbound traffic has been captured that we know for
                                    // sure is not coming from our proxy in response to a client, but we
                                    // don't know that it isn't the upstream portion of our proxy trying
                                    // to fetch a response on behalf of a connected client. So, we need
                                    // to check if we have a cached result for information about the
                                    // binary generating the outbound traffic for two reasons.
                                    //
                                    // First, we need to ensure that it's not us, obviously. Secondly, we
                                    // need to ensure that the binary has been granted firewall access to
                                    // generate outbound traffic.

                                    if (Volatile.Read(ref m_v4ShouldFilter[parseResult.TcpHeader->SrcPort]) == (int)FirewallAction.FilterApplication)
                                    {
                                        modifiedPacket = true;

                                        // If the process was identified as a process that is permitted
                                        // to access the internet, and is not a system process or
                                        // ourselves, then we divert its packets back inbound to the
                                        // local machine, changing the destination port appropriately.
                                        var dstAddress = parseResult.IPv4Header->DstAddr;

                                        parseResult.IPv4Header->DstAddr = parseResult.IPv4Header->SrcAddr;
                                        parseResult.IPv4Header->SrcAddr = dstAddress;

                                        addr.Outbound = false;

                                        Volatile.Write(ref m_v4ReturnPorts[parseResult.TcpHeader->SrcPort], parseResult.TcpHeader->DstPort);


                                        GoproxyWrapper.GoProxy.Instance.SetDestPortForLocalPort(parseResult.TcpHeader->SrcPort, parseResult.TcpHeader->DstPort);

                                        // Unless we know for sure this is an encrypted connection via
                                        // the HTTP port, we should always default to sending to the
                                        // non-encrypted listener.
                                        var encrypted = Volatile.Read(ref m_v4EncryptionHints[parseResult.TcpHeader->SrcPort]);

                                        parseResult.TcpHeader->DstPort = encrypted ? m_v4HttpsProxyPort : m_v4HttpProxyPort;
                                    }
                                }
                            }

                            // The ipV6 version works exactly the same, just with larger storage for the
                            // larger addresses. Look at the ipv4 version notes for clarification on anything.
                            if (parseResult.IPv6Header != null && parseResult.TcpHeader != null)
                            {
                                if (parseResult.TcpHeader->SrcPort == m_v6HttpProxyPort || parseResult.TcpHeader->SrcPort == m_v6HttpsProxyPort)
                                {
                                    modifiedPacket = true;

                                    parseResult.TcpHeader->SrcPort = Volatile.Read(ref m_v6ReturnPorts[parseResult.TcpHeader->DstPort]);
                                    addr.Outbound = false;

                                    var dstIp = parseResult.IPv6Header->DstAddr;
                                    parseResult.IPv6Header->DstAddr = parseResult.IPv6Header->SrcAddr;
                                    parseResult.IPv6Header->SrcAddr = dstIp;
                                }
                                else
                                {
                                    if (Volatile.Read(ref m_v6ShouldFilter[parseResult.TcpHeader->SrcPort]) == (int)FirewallAction.FilterApplication)
                                    {
                                        modifiedPacket = true;

                                        // If the process was identified as a process that is permitted
                                        // to access the internet, and is not a system process or
                                        // ourselves, then we divert its packets back inbound to the
                                        // local machine, changing the destination port appropriately.
                                        var dstAddress = parseResult.IPv6Header->DstAddr;

                                        parseResult.IPv6Header->DstAddr = parseResult.IPv6Header->SrcAddr;
                                        parseResult.IPv6Header->SrcAddr = dstAddress;
                                        addr.Outbound = false;

                                        Volatile.Write(ref m_v6ReturnPorts[parseResult.TcpHeader->SrcPort], parseResult.TcpHeader->DstPort);

                                        GoproxyWrapper.GoProxy.Instance.SetDestPortForLocalPort(parseResult.TcpHeader->SrcPort, parseResult.TcpHeader->DstPort);
                                        // Unless we know for sure this is an encrypted connection via
                                        // the HTTP port, we should always default to sending to the
                                        // non-encrypted listener.
                                        var encrypted = Volatile.Read(ref m_v6EncryptionHints[parseResult.TcpHeader->SrcPort]);

                                        parseResult.TcpHeader->DstPort = encrypted ? m_v6HttpsProxyPort : m_v6HttpProxyPort;
                                    }
                                }
                            }
                        } // if(!isLocalIpv4)
                    }     // if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND)

                    if (!dropPacket)
                    {
                        if (modifiedPacket)
                        {
                            var sumsCalculated = WinDivert.WinDivertHelperCalcChecksums(packet, recvLength, ref addr, WinDivertChecksumHelperParam.All);

                            if (sumsCalculated <= 0)
                            {
                                m_logger.Warn("Modified packet reported that no checksums were calculated");
                            }
                        }

                        WinDivert.WinDivertSendEx(m_diversionHandle, packet, recvLength, 0, ref addr);
                    }
                    else
                    {
                        Console.WriteLine("dropping a packet");
                    }
                }
                catch (Exception loopException)
                {
                    m_logger.Error(loopException);
                }
            } // while (m_running)
        }
コード例 #3
0
ファイル: Device.cs プロジェクト: sgf/SCTP
        private async ValueTask FilterPackets(PipeWriter writer)
        {
            var workspace         = writer.GetMemory(8192);
            var pack              = new WinDivertBuffer(workspace.ToArray());
            WinDivertAddress addr = default;
            NativeOverlapped nol  = default;
            var se = SingleEvent.Create();

            nol.EventHandle = se.Event;
            WinDivertParseResult result = new WinDivertParseResult();
            uint readLen = 0;

            //writer.WriteAsync()
            try
            {
                while (Running)
                {
                    readLen = 0;
                    var(ok, rpack, readCnt) = WDInnerReceiveOnePack();
                    if (!ok)
                    {
                        goto end;
                    }
                    writer.Advance((int)readLen);
                    await writer.FlushAsync();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Fatal error in read thread: {0}", ex);
            }
            finally
            {
                wd.WinDivertClose(WDHandle);
                se.Close();
            }
            end :;

            (bool ok, WinDivertParseResult pack, uint readLen) WDInnerReceiveOnePack()
            {
                try
                {
                    //var sp = writer.GetSpan();
                    addr.Reset();
again:
                    if (!Running)
                    {
                        goto end_sub;
                    }
                    if (!wd.WinDivertRecvEx(WDHandle, pack, 0, ref addr, ref readLen, ref nol))
                    {
                        if (!Win32.LasErr(ERROR_IO_PENDING, "Unknown IO error ID while awaiting overlapped result."))
                        {
                            goto again;
                        }
                        if (!se.Wait(existsAction: () => Running))
                        {
                            goto end_sub;
                        }

                        if (!Kernel32.GetOverlappedResult(WDHandle, ref nol, ref readLen, false))
                        {
                            Debug.WriteLine($"Failed to get overlapped result.");
                            se.Close();
                            goto again;
                        }
                    }
                    se.Close();//这个可能位置不太对?关掉是否影响下一轮的接收
                    Debug.WriteLine("Read packet {0}", readLen);
                    result = WinDivert.WinDivertHelperParsePacket(pack, readLen);
                    if (addr.Direction == WinDivertDirection.Inbound)
                    {
                        Debug.WriteLine("inbound");
                    }
                    DisplayPackInfo(result);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Fatal error in read thread: {0}", ex);
                    goto end_sub;
                }
                finally
                {
                    wd.WinDivertClose(WDHandle);
                    se.Close();
                }

                return(true, result, readLen);

end_sub:
                return(false, result, readLen);
            }

            unsafe void DisplayPackInfo(WinDivertParseResult pack)
            {
                if (result.IPv4Header != null && result.TcpHeader != null)
                {
                    Debug.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)
                {
                    Debug.WriteLine($"V4 TCP packet {addr.Direction} from {result.IPv6Header->SrcAddr}:{result.TcpHeader->SrcPort} to {result.IPv6Header->DstAddr}:{result.TcpHeader->DstPort}");
                }
            }
        }