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 USER = "user";
|
||||||
static string PASS = "pass";
|
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 long _connectionSeq;
|
||||||
|
|
||||||
static async Task Main()
|
static async Task Main()
|
||||||
@@ -117,7 +120,8 @@ class Program
|
|||||||
|
|
||||||
var upstreamStream = upstream.GetStream();
|
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");
|
await Pump(upstreamStream, clientStream, $"conn:{connectionId} HTTP upstream->client");
|
||||||
}
|
}
|
||||||
@@ -152,7 +156,7 @@ class Program
|
|||||||
var upstreamStream = upstream.GetStream();
|
var upstreamStream = upstream.GetStream();
|
||||||
|
|
||||||
string connectReq =
|
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));
|
await upstreamStream.WriteAsync(Encoding.ASCII.GetBytes(connectReq));
|
||||||
|
|
||||||
@@ -206,6 +210,7 @@ class Program
|
|||||||
public string Url;
|
public string Url;
|
||||||
public string Raw;
|
public string Raw;
|
||||||
public byte[] RawBytes;
|
public byte[] RawBytes;
|
||||||
|
public int HeaderLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async Task<HttpRequest> ReadHeaders(Stream stream, string context)
|
static async Task<HttpRequest> ReadHeaders(Stream stream, string context)
|
||||||
@@ -232,7 +237,8 @@ class Program
|
|||||||
Method = first[0],
|
Method = first[0],
|
||||||
Target = first[1],
|
Target = first[1],
|
||||||
Raw = raw,
|
Raw = raw,
|
||||||
RawBytes = buffer.Take(read).ToArray()
|
RawBytes = buffer.Take(read).ToArray(),
|
||||||
|
HeaderLength = GetHeaderLength(raw)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (req.Method != "CONNECT")
|
if (req.Method != "CONNECT")
|
||||||
@@ -309,6 +315,57 @@ class Program
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
return message.Replace("\r", " ").Replace("\n", " ").Trim();
|
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 =================
|
// ================= WINHTTP =================
|
||||||
|
|||||||
Reference in New Issue
Block a user