狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

C#開發完整的Socks5代理客戶端與服務端——客戶端

freeflydom
2025年5月12日 9:11 本文熱度 120

本機流量劫持

通過系統開啟手動代理

通過c#程序打開Windows的手動代理, 并且設置端口號和IP地址,這樣只要客戶端監聽該端口就可以獲取到本機的Http的流量數據。

通過對注冊表的修改,來開啟本機的手動代理,并且設置端口,Ip設置為本機,因為客戶端是本機啟動的,端口設置不沖突的即可。

黑名單則是設置哪些域名或者IP段不走代理,我們這里先把局域網的排除掉。

// 引入Windows API
[DllImport("wininet.dll")]
public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);
public const int INTERNET_OPTION_SETTINGS_CHANGED = 39;
public const int INTERNET_OPTION_REFRESH = 37;
// 設置系統代理
public static void SetProxy(string proxyServer, bool enable)
{
    const string userRoot = "HKEY_CURRENT_USER";
    const string subkey = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
    const string keyName = userRoot + "\\" + subkey;
    // 設置代理服務器地址和端口
    Microsoft.Win32.Registry.SetValue(keyName, "ProxyServer", proxyServer);
    // 啟用或禁用代理
    Microsoft.Win32.Registry.SetValue(keyName, "ProxyEnable", enable ? 1 : 0);
    // 通知系統設置已更改
    InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0);
    InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
}
/// <summary>
/// 黑名單
/// </summary>
/// <param name="exceptions"></param>
public static void SetProxyExceptions(string exceptions)
{
    const string userRoot = "HKEY_CURRENT_USER";
    const string subkey = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
    const string keyName = userRoot + "\\" + subkey;
    Microsoft.Win32.Registry.SetValue(keyName, "ProxyOverride", exceptions);
}
 SystemProxy.SetProxy($"127.0.0.1:{App.SettingsModel.LocalPort}", true);
 SystemProxy.SetProxyExceptions("localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*;<local>");
客戶端開啟對應TCP服務
 _tcpListener = new TcpListener(IPAddress.Any, _httpProxyPort);
 _tcpListener.Start();

主要就是開啟一個監聽服務,讓操作系統將對應的流量轉發到我們的Socks5客戶端。

將http報文進行解析,獲取到請求的targetHost和Port,這樣才能后面在和Socks5服務端握手的時候才能告知對方需要代理的遠端信息。

解析系統的Http請求
    
    /// <summary>
    /// 解析http請求報文,提取關鍵信息
    /// </summary>
    /// <param name="request">http請求</param>
    /// <param name="host">請求主機</param>
    /// <param name="port">請求主機端口號</param>
    /// <returns>是否解析成功</returns>
    private bool TryParseHttpRequest(string request, out string host, out int port)
    {
        host = null;
        port = 0;
        // 解析 CONNECT 請求(如 CONNECT example.com:443 HTTP/1.1)
        if (request.StartsWith("CONNECT"))
        {
            var parts = request.Split(' ')[1].Split(':');
            host = parts[0];
            port = int.Parse(parts[1]);
            return true;
        }
        // 2. 處理 GET/POST 請求(HTTP)
        using (var reader = new StringReader(request))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                // 從 Host 頭提取目標
                if (line.StartsWith("Host:", StringComparison.OrdinalIgnoreCase))
                {
                    var hostParts = line.Substring(5).Trim().Split(':');
                    host = hostParts[0];
                    if (hostParts.Length > 1)
                        port = int.Parse(hostParts[1]);
                    return true;
                }
                // 空行表示頭結束
                if (string.IsNullOrWhiteSpace(line))
                    break;
            }
        }
        // 3. 舊式HTTP/1.0請求可能沒有Host頭,從URL解析
        if (request.StartsWith("GET ") || request.StartsWith("POST "))
        {
            var url = request.Split(' ')[1];
            if (Uri.TryCreate(url, UriKind.Absolute, out var uri))
            {
                host = uri.Host;
                port = uri.Port;
                return true;
            }
        }
        return false;
    }
遠程Socks5服務端握手

這里我們采用的是帶有認證的握手,需要服務端也開啟認證配置,這里對于握手協議和認證還不清楚的可以看我集合的上面一篇文章

將http的遠程信息作為握手信息與服務端建立連接,讓服務端建立與目標的連接代理。

    /// <summary>
    /// 帶有身份驗證的登錄
    /// </summary>
    /// <param name="socks5Stream"></param>
    /// <param name="targetHost"></param>
    /// <param name="targetPort"></param>
    /// <param name="username"></param>
    /// <param name="password"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    private async Task PerformSocks5Handshake(NetworkStream socks5Stream,
                                              string targetHost,
                                              int targetPort,
                                              string username,
                                              string password)
    {
        // === 1. 協商認證方法 ===
        // 發送支持的認證方法:無認證(0x00) 和 用戶名/密碼(0x02)
        var authMethods = new byte[] { 0x05, 0x02, 0x00, 0x02 };
        await socks5Stream.WriteAsync(authMethods, 0, authMethods.Length);
        // 讀取服務器選擇的認證方法
        var authResponse = new byte[2];
        await socks5Stream.ReadAsync(authResponse, 0, 2);
        if (authResponse[1] == 0xFF)
            throw new Exception("SOCKS5服務器不支持任何提供的認證方法");
        // === 2. 用戶名/密碼認證 ===
        if (authResponse[1] == 0x02)
        {
            // 構建認證請求包
            var authRequest = new byte[3 + username.Length + password.Length];
            authRequest[0] = 0x01; // 認證子協商版本
            authRequest[1] = (byte)username.Length;
            Encoding.ASCII.GetBytes(username).CopyTo(authRequest, 2);
            authRequest[2 + username.Length] = (byte)password.Length;
            Encoding.ASCII.GetBytes(password).CopyTo(authRequest, 3 + username.Length);
            await socks5Stream.WriteAsync(authRequest, 0, authRequest.Length);
            // 讀取認證響應
            var authResult = new byte[2];
            await socks5Stream.ReadAsync(authResult, 0, 2);
            if (authResult[1] != 0x00)
                throw new Exception("SOCKS5用戶名/密碼認證失敗");
        }
        // === 3. 發送連接請求 ===
        var request = new byte[7 + targetHost.Length];
        request[0] = 0x05; // VER
        request[1] = 0x01; // CMD=CONNECT
        request[2] = 0x00; // RSV
        request[3] = 0x03; // ATYP=域名
        request[4] = (byte)targetHost.Length;
        Encoding.ASCII.GetBytes(targetHost).CopyTo(request, 5);
        BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)targetPort)).CopyTo(request, 5 + targetHost.Length);
        await socks5Stream.WriteAsync(request, 0, request.Length);
        // === 4. 讀取連接響應 ===
        var response = new byte[10];
        await socks5Stream.ReadAsync(response, 0, 10);
        if (response[1] != 0x00)
            throw new Exception($"SOCKS5連接失敗 (狀態碼: {response[1]})");
    }
交換流量

所謂的交換流量就是把遠程代理的流量和本機的請求流量通過客戶端作為中間人來轉發

    private async Task ForwardDataAsync(NetworkStream src, NetworkStream dest)
    {
        var buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = await src.ReadAsync(buffer, 0, buffer.Length)) > 0)
        {
            await dest.WriteAsync(buffer, 0, bytesRead);
        }
    }
await Task.WhenAny(ForwardDataAsync(httpStream, socks5Stream),ForwardDataAsync(socks5Stream, httpStream)
代理流量顯示

客戶端也需要顯示上傳和下載流量的一些顯示,我們這里簡單點,因為我們之前開發的服務端是有基于用戶的流量統計的,所以只需要把數據獲取到就行,一般情況下為了性能,也可以做雙端統計減少壓力。

我們這里通過SSE將用戶的流量信息基于用戶名推送到客戶端。

public async Task ConnectAsync(string remoteAddress, string userName)
{
    _httpClient = new HttpClient(new HttpClientHandler
    {
        Proxy = new WebProxy($"http://{remoteAddress}:5000"), // 明確指定代理
    });
    _cts = new CancellationTokenSource();
    try
    {
        using var response = await _httpClient
            .GetAsync($"http://{remoteAddress}:5000/account/flow/{userName}", HttpCompletionOption.ResponseHeadersRead,_cts.Token);
        if (response.IsSuccessStatusCode)
        {
            using var stream = await response.Content.ReadAsStreamAsync();
            using var reader = new StreamReader(stream);
            while (!_cts.Token.IsCancellationRequested)
            {
                var line = await reader.ReadLineAsync();
                if (!string.IsNullOrEmpty(line))
                {
                    MessageReceived?.Invoke(line);
                }
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"SSE連接錯誤: {ex.Message}");
    }
}

驗證

遠端開啟服務端

開啟客戶端

添加一些配置
包括:服務端IP,服務端Port,本地代理Port,用戶名密碼

開啟客戶端

可以看到代理成功,走的是本機的代理和服務端的代理請求

結尾

因為本身代理采用的修改系統代理設置是一種基礎設置,所謂可能存在下面影響:
僅影響支持系統代理的應用(部分UWP應用、游戲等會繞過
無法代理非HTTP/HTTPS流量(如DNS、UDP

源碼地址

https://github.com/BruceQiu1996/Socks5Server

?轉自https://www.cnblogs.com/qwqwQAQ/p/18867762


該文章在 2025/5/12 9:12:31 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved