Add upstream proxy auth support

This commit is contained in:
2026-04-09 20:13:53 +03:00
parent 6a945bb6ad
commit 70b2495ad6

View File

@@ -14,6 +14,9 @@ class Program
{
static string USER = "user";
static string PASS = "pass";
static readonly string UPSTREAM_USER = Environment.GetEnvironmentVariable("UPSTREAM_USER");
static readonly string UPSTREAM_PASS = Environment.GetEnvironmentVariable("UPSTREAM_PASS");
static readonly string UPSTREAM_PROXY_AUTH_HEADER = BuildUpstreamProxyAuthHeader();
static long _connectionSeq;
static async Task Main()
@@ -117,7 +120,8 @@ class Program
var upstreamStream = upstream.GetStream();
await upstreamStream.WriteAsync(req.RawBytes);
var outbound = BuildUpstreamHttpRequest(req);
await upstreamStream.WriteAsync(outbound);
await Pump(upstreamStream, clientStream, $"conn:{connectionId} HTTP upstream->client");
}
@@ -152,7 +156,7 @@ class Program
var upstreamStream = upstream.GetStream();
string connectReq =
$"CONNECT {host}:{port} HTTP/1.1\r\nHost: {host}:{port}\r\n\r\n";
$"CONNECT {host}:{port} HTTP/1.1\r\nHost: {host}:{port}\r\n{UPSTREAM_PROXY_AUTH_HEADER}\r\n";
await upstreamStream.WriteAsync(Encoding.ASCII.GetBytes(connectReq));
@@ -206,6 +210,7 @@ class Program
public string Url;
public string Raw;
public byte[] RawBytes;
public int HeaderLength;
}
static async Task<HttpRequest> ReadHeaders(Stream stream, string context)
@@ -232,7 +237,8 @@ class Program
Method = first[0],
Target = first[1],
Raw = raw,
RawBytes = buffer.Take(read).ToArray()
RawBytes = buffer.Take(read).ToArray(),
HeaderLength = GetHeaderLength(raw)
};
if (req.Method != "CONNECT")
@@ -309,6 +315,57 @@ class Program
return string.Empty;
return message.Replace("\r", " ").Replace("\n", " ").Trim();
}
static int GetHeaderLength(string raw)
{
int idx = raw.IndexOf("\r\n\r\n", StringComparison.Ordinal);
return idx >= 0 ? idx + 4 : raw.Length;
}
static byte[] BuildUpstreamHttpRequest(HttpRequest req)
{
var lines = req.Raw.Split("\r\n", StringSplitOptions.None);
var sb = new StringBuilder();
sb.Append(lines[0]).Append("\r\n");
for (int i = 1; i < lines.Length; i++)
{
var line = lines[i];
if (line.Length == 0)
break;
if (line.StartsWith("Proxy-Authorization:", StringComparison.OrdinalIgnoreCase))
continue; // local proxy auth, must not go upstream
if (line.StartsWith("Proxy-Connection:", StringComparison.OrdinalIgnoreCase))
continue;
sb.Append(line).Append("\r\n");
}
if (!string.IsNullOrEmpty(UPSTREAM_PROXY_AUTH_HEADER))
sb.Append(UPSTREAM_PROXY_AUTH_HEADER);
sb.Append("\r\n");
var headerBytes = Encoding.ASCII.GetBytes(sb.ToString());
if (req.HeaderLength >= req.RawBytes.Length)
return headerBytes;
int bodyLen = req.RawBytes.Length - req.HeaderLength;
var result = new byte[headerBytes.Length + bodyLen];
Buffer.BlockCopy(headerBytes, 0, result, 0, headerBytes.Length);
Buffer.BlockCopy(req.RawBytes, req.HeaderLength, result, headerBytes.Length, bodyLen);
return result;
}
static string BuildUpstreamProxyAuthHeader()
{
if (string.IsNullOrWhiteSpace(UPSTREAM_USER) || string.IsNullOrWhiteSpace(UPSTREAM_PASS))
return string.Empty;
string encoded = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{UPSTREAM_USER}:{UPSTREAM_PASS}"));
return $"Proxy-Authorization: Basic {encoded}\r\n";
}
}
// ================= WINHTTP =================