Обновить Program.cs

This commit is contained in:
2026-04-09 18:32:01 +02:00
parent 3f34f06cd5
commit 2d8f3d07e1

View File

@@ -63,6 +63,7 @@ class Program
static async Task HandleHttp(NetworkStream clientStream, HttpRequestData req)
{
DefaultProxyCredentials = CredentialCache.DefaultCredentials
var handler = new SocketsHttpHandler
{
UseProxy = true,
@@ -111,8 +112,8 @@ class Program
// ================= CONNECT =================
static async Task HandleConnect(NetworkStream clientStream, string target)
{
static async Task HandleConnect(NetworkStream clientStream, string target)
{
var parts = target.Split(':');
string host = parts[0];
int port = int.Parse(parts[1]);
@@ -125,25 +126,32 @@ class Program
var upstreamStream = upstream.GetStream();
// CONNECT к upstream
// CONNECT к upstream proxy
string connectReq =
$"CONNECT {host}:{port} HTTP/1.1\r\nHost: {host}:{port}\r\n\r\n";
$"CONNECT {host}:{port} HTTP/1.1\r\n" +
$"Host: {host}:{port}\r\n" +
$"Proxy-Connection: Keep-Alive\r\n\r\n";
await upstreamStream.WriteAsync(Encoding.ASCII.GetBytes(connectReq));
// читаем ответ от upstream
var buffer = new byte[8192];
int read = await upstreamStream.ReadAsync(buffer);
// читаем ответ upstream полностью до \r\n\r\n
var resp = await ReadHeaders(upstreamStream);
// отвечаем клиенту что туннель открыт
if (!resp.HeadersRaw.Contains("200"))
{
await clientStream.WriteAsync(Encoding.ASCII.GetBytes("HTTP/1.1 502 Bad Gateway\r\n\r\n"));
return;
}
// говорим клиенту ОК
await clientStream.WriteAsync(Encoding.ASCII.GetBytes("HTTP/1.1 200 Connection Established\r\n\r\n"));
// двунаправленный туннель
var t1 = upstreamStream.CopyToAsync(clientStream);
var t2 = clientStream.CopyToAsync(upstreamStream);
// туннель
var t1 = Pump(upstreamStream, clientStream);
var t2 = Pump(clientStream, upstreamStream);
await Task.WhenAny(t1, t2);
}
}
// ================= AUTH =================
@@ -233,80 +241,96 @@ class WinHttpProxy : IWebProxy
public bool IsBypassed(Uri host) => false;
}
using System.Runtime.InteropServices;
static class WinHttpHelper
{
[DllImport("winhttp.dll", SetLastError = true)]
static extern bool WinHttpGetIEProxyConfigForCurrentUser(
out WINHTTP_CURRENT_USER_IE_PROXY_CONFIG config);
static extern IntPtr WinHttpOpen(string agent, int accessType, string proxy, string bypass, int flags);
[DllImport("winhttp.dll", SetLastError = true)]
static extern bool WinHttpGetProxyForUrl(
IntPtr hSession,
string url,
ref WINHTTP_AUTOPROXY_OPTIONS options,
out WINHTTP_PROXY_INFO proxyInfo);
[DllImport("winhttp.dll")]
static extern bool WinHttpCloseHandle(IntPtr handle);
public static Uri GetProxyForUrl(Uri url)
{
if (!WinHttpGetIEProxyConfigForCurrentUser(out var cfg))
return url;
IntPtr session = WinHttpOpen("proxy", 0, null, null, 0);
string proxy = PtrToString(cfg.lpszProxy);
var options = new WINHTTP_AUTOPROXY_OPTIONS
{
dwFlags = 0x00000001 | 0x00000002, // AUTO_DETECT + CONFIG_URL
dwAutoDetectFlags = 0x00000001 | 0x00000002 // DHCP + DNS_A
};
if (string.IsNullOrWhiteSpace(proxy))
return url;
if (WinHttpGetProxyForUrl(session, url.ToString(), ref options, out var info))
{
string proxy = PtrToString(info.lpszProxy);
string selectedProxy = ParseProxy(proxy, url.Scheme);
if (string.IsNullOrEmpty(selectedProxy))
return url;
return new Uri(NormalizeProxy(selectedProxy));
if (!string.IsNullOrEmpty(proxy))
{
var first = proxy.Split(';')[0];
return new Uri(Normalize(first));
}
}
// ===== helpers =====
WinHttpCloseHandle(session);
return url; // direct fallback
}
static string PtrToString(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
return null;
if (ptr == IntPtr.Zero) return null;
return Marshal.PtrToStringUni(ptr);
}
static string ParseProxy(string proxy, string scheme)
static string Normalize(string proxy)
{
// варианты:
// "proxy:8080"
// "http=proxy:8080;https=proxy2:8080"
if (!proxy.Contains("="))
return proxy;
var entries = proxy.Split(';', StringSplitOptions.RemoveEmptyEntries);
foreach (var entry in entries)
{
var parts = entry.Split('=', 2);
if (parts.Length != 2)
continue;
if (parts[0].Equals(scheme, StringComparison.OrdinalIgnoreCase))
return parts[1];
}
// fallback — берём первый
return entries[0].Split('=')[1];
}
static string NormalizeProxy(string proxy)
{
if (!proxy.StartsWith("http://") && !proxy.StartsWith("https://"))
if (!proxy.StartsWith("http"))
return "http://" + proxy;
return proxy;
}
// ===== struct =====
struct WINHTTP_CURRENT_USER_IE_PROXY_CONFIG
struct WINHTTP_AUTOPROXY_OPTIONS
{
public bool fAutoDetect;
public int dwFlags;
public int dwAutoDetectFlags;
public IntPtr lpszAutoConfigUrl;
public IntPtr lpvReserved;
public int dwReserved;
public bool fAutoLogonIfChallenged;
}
struct WINHTTP_PROXY_INFO
{
public int dwAccessType;
public IntPtr lpszProxy;
public IntPtr lpszProxyBypass;
}
}
static async Task Pump(Stream from, Stream to)
{
var buffer = ArrayPool<byte>.Shared.Rent(8192);
try
{
while (true)
{
int read = await from.ReadAsync(buffer);
if (read <= 0) break;
await to.WriteAsync(buffer.AsMemory(0, read));
}
}
catch { }
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
}