Add upstream proxy auth support
This commit is contained in:
63
Program.cs
63
Program.cs
@@ -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 =================
|
||||
|
||||
Reference in New Issue
Block a user