Refactored DnsHelper and added DNS testing for the public config hostname instead of a hardcoded URL
Refactored DnsHelper for maintainability and added automatic DNS testing for the public config hostname after creation/update of vrp-public.json to automatically enable fallback DNS and proxy if system DNS fails for that
This commit is contained in:
@@ -348,6 +348,9 @@ namespace AndroidSideloader
|
||||
{
|
||||
PublicConfigFile = config;
|
||||
hasPublicConfig = true;
|
||||
|
||||
// Test DNS for the public config hostname after it's been created/updated
|
||||
DnsHelper.TestPublicConfigDns();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace AndroidSideloader.Utilities
|
||||
{
|
||||
@@ -20,49 +22,161 @@ namespace AndroidSideloader.Utilities
|
||||
"raw.githubusercontent.com",
|
||||
"downloads.rclone.org",
|
||||
"vrpirates.wiki",
|
||||
"go.vrpyourself.online",
|
||||
"github.com"
|
||||
};
|
||||
|
||||
private static readonly ConcurrentDictionary<string, IPAddress> _dnsCache =
|
||||
new ConcurrentDictionary<string, IPAddress>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private static bool _initialized;
|
||||
private static bool _useFallbackDns;
|
||||
private static readonly object _lock = new object();
|
||||
|
||||
// Local proxy for rclone
|
||||
private static TcpListener _proxyListener;
|
||||
private static CancellationTokenSource _proxyCts;
|
||||
private static int _proxyPort;
|
||||
private static bool _initialized;
|
||||
private static bool _proxyRunning;
|
||||
|
||||
public static bool UseFallbackDns
|
||||
{
|
||||
get { if (!_initialized) Initialize(); return _useFallbackDns; }
|
||||
}
|
||||
public static bool UseFallbackDns { get; private set; }
|
||||
|
||||
// Gets the proxy URL for rclone to use, or empty string if not needed
|
||||
public static string ProxyUrl => _proxyRunning ? $"http://127.0.0.1:{_proxyPort}" : string.Empty;
|
||||
|
||||
// Called after vrp-public.json is created/updated to test the hostname
|
||||
// Enable fallback DNS if the hostname fails on system DNS but works with fallback DNS
|
||||
public static void TestPublicConfigDns()
|
||||
{
|
||||
string hostname = GetPublicConfigHostname();
|
||||
if (string.IsNullOrEmpty(hostname))
|
||||
return;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
// If already using fallback, just pre-resolve the new hostname
|
||||
if (UseFallbackDns)
|
||||
{
|
||||
var ip = ResolveWithFallbackDns(hostname);
|
||||
if (ip != null)
|
||||
{
|
||||
_dnsCache[hostname] = ip;
|
||||
Logger.Log($"Pre-resolved public config hostname {hostname} -> {ip}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Test if system DNS can resolve the public config hostname
|
||||
bool systemDnsWorks = TestHostnameWithSystemDns(hostname);
|
||||
|
||||
if (!systemDnsWorks)
|
||||
{
|
||||
Logger.Log($"System DNS failed for {hostname}. Testing fallback...", LogLevel.WARNING);
|
||||
|
||||
// Test if fallback DNS works for this hostname
|
||||
var ip = ResolveWithFallbackDns(hostname);
|
||||
if (ip != null)
|
||||
{
|
||||
UseFallbackDns = true;
|
||||
_dnsCache[hostname] = ip;
|
||||
Logger.Log($"Enabled fallback DNS for {hostname} -> {ip}", LogLevel.INFO);
|
||||
ServicePointManager.DnsRefreshTimeout = 0;
|
||||
|
||||
// Pre-resolve base hostnames too
|
||||
PreResolveHostnames(CriticalHostnames);
|
||||
|
||||
// Start proxy if not already running
|
||||
if (!_proxyRunning)
|
||||
{
|
||||
StartProxy();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log($"Both system and fallback DNS failed for {hostname}", LogLevel.ERROR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log($"System DNS works for public config hostname: {hostname}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetPublicConfigHostname()
|
||||
{
|
||||
try
|
||||
{
|
||||
string configPath = Path.Combine(Environment.CurrentDirectory, "vrp-public.json");
|
||||
if (!File.Exists(configPath))
|
||||
return null;
|
||||
|
||||
var config = JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(configPath));
|
||||
if (config != null && config.TryGetValue("baseUri", out string baseUri))
|
||||
{
|
||||
return ExtractHostname(baseUri);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log($"Failed to get hostname from vrp-public.json: {ex.Message}", LogLevel.WARNING);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string[] GetCriticalHostnames()
|
||||
{
|
||||
var hostnames = new List<string>(CriticalHostnames);
|
||||
|
||||
string host = GetPublicConfigHostname();
|
||||
if (!string.IsNullOrWhiteSpace(host) && !hostnames.Contains(host))
|
||||
{
|
||||
hostnames.Add(host);
|
||||
Logger.Log($"Added {host} from vrp-public.json to critical hostnames");
|
||||
}
|
||||
|
||||
return hostnames.ToArray();
|
||||
}
|
||||
|
||||
private static string ExtractHostname(string uriString)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(uriString)) return null;
|
||||
|
||||
if (!uriString.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
|
||||
!uriString.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
uriString = "https://" + uriString;
|
||||
}
|
||||
|
||||
if (Uri.TryCreate(uriString, UriKind.Absolute, out Uri uri))
|
||||
return uri.Host;
|
||||
|
||||
// Fallback: manual extraction
|
||||
string hostname = uriString.Replace("https://", "").Replace("http://", "");
|
||||
int idx = hostname.IndexOfAny(new[] { '/', ':' });
|
||||
return idx > 0 ? hostname.Substring(0, idx) : hostname;
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_initialized) return;
|
||||
Logger.Log("Testing DNS resolution for critical hostnames...");
|
||||
|
||||
if (!TestSystemDns())
|
||||
Logger.Log("Testing DNS resolution for critical hostnames...");
|
||||
var hostnames = GetCriticalHostnames();
|
||||
|
||||
if (TestDns(hostnames, useSystem: true))
|
||||
{
|
||||
Logger.Log("System DNS is working correctly.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log("System DNS failed. Testing Cloudflare DNS fallback...", LogLevel.WARNING);
|
||||
if (TestFallbackDns())
|
||||
if (TestDns(hostnames, useSystem: false))
|
||||
{
|
||||
_useFallbackDns = true;
|
||||
UseFallbackDns = true;
|
||||
Logger.Log("Using Cloudflare DNS fallback.", LogLevel.INFO);
|
||||
PreResolveHostnames();
|
||||
PreResolveHostnames(hostnames);
|
||||
ServicePointManager.DnsRefreshTimeout = 0;
|
||||
|
||||
// Start local proxy for rclone
|
||||
StartProxy();
|
||||
}
|
||||
else
|
||||
@@ -70,77 +184,65 @@ namespace AndroidSideloader.Utilities
|
||||
Logger.Log("Both system and fallback DNS failed.", LogLevel.ERROR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Log("System DNS is working correctly.");
|
||||
}
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleans up resources. Called on application exit
|
||||
public static void Cleanup()
|
||||
{
|
||||
StopProxy();
|
||||
}
|
||||
public static void Cleanup() => StopProxy();
|
||||
|
||||
private static void PreResolveHostnames()
|
||||
private static bool TestHostnameWithSystemDns(string hostname)
|
||||
{
|
||||
foreach (string hostname in CriticalHostnames)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
var ip = ResolveWithFallbackDns(hostname);
|
||||
if (ip != null)
|
||||
{
|
||||
_dnsCache[hostname] = ip;
|
||||
Logger.Log($"Pre-resolved {hostname} -> {ip}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log($"Failed to pre-resolve {hostname}: {ex.Message}", LogLevel.WARNING);
|
||||
}
|
||||
var addresses = Dns.GetHostAddresses(hostname);
|
||||
return addresses?.Length > 0;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TestSystemDns()
|
||||
private static bool TestDns(string[] hostnames, bool useSystem)
|
||||
{
|
||||
foreach (string hostname in CriticalHostnames)
|
||||
if (useSystem)
|
||||
{
|
||||
try
|
||||
return hostnames.All(h =>
|
||||
{
|
||||
var addresses = Dns.GetHostAddresses(hostname);
|
||||
if (addresses == null || addresses.Length == 0) return false;
|
||||
}
|
||||
try { return Dns.GetHostAddresses(h)?.Length > 0; }
|
||||
catch { return false; }
|
||||
});
|
||||
}
|
||||
|
||||
return FallbackDnsServers.Any(server =>
|
||||
{
|
||||
try { return ResolveWithDns(hostnames[0], server)?.Count > 0; }
|
||||
catch { return false; }
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private static bool TestFallbackDns()
|
||||
private static void PreResolveHostnames(string[] hostnames)
|
||||
{
|
||||
foreach (string dnsServer in FallbackDnsServers)
|
||||
foreach (string hostname in hostnames)
|
||||
{
|
||||
try
|
||||
var ip = ResolveWithFallbackDns(hostname);
|
||||
if (ip != null)
|
||||
{
|
||||
var addresses = ResolveWithDns(CriticalHostnames[0], dnsServer);
|
||||
if (addresses != null && addresses.Count > 0) return true;
|
||||
_dnsCache[hostname] = ip;
|
||||
Logger.Log($"Pre-resolved {hostname} -> {ip}");
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static IPAddress ResolveWithFallbackDns(string hostname)
|
||||
{
|
||||
foreach (string dnsServer in FallbackDnsServers)
|
||||
foreach (string server in FallbackDnsServers)
|
||||
{
|
||||
try
|
||||
{
|
||||
var addresses = ResolveWithDns(hostname, dnsServer);
|
||||
if (addresses != null && addresses.Count > 0)
|
||||
return addresses[0];
|
||||
var addresses = ResolveWithDns(hostname, server);
|
||||
if (addresses?.Count > 0) return addresses[0];
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
@@ -149,56 +251,57 @@ namespace AndroidSideloader.Utilities
|
||||
|
||||
private static List<IPAddress> ResolveWithDns(string hostname, string dnsServer, int timeoutMs = 5000)
|
||||
{
|
||||
byte[] query = BuildDnsQuery(hostname);
|
||||
using (var udp = new UdpClient())
|
||||
using (var udp = new UdpClient { Client = { ReceiveTimeout = timeoutMs, SendTimeout = timeoutMs } })
|
||||
{
|
||||
udp.Client.ReceiveTimeout = timeoutMs;
|
||||
udp.Client.SendTimeout = timeoutMs;
|
||||
byte[] query = BuildDnsQuery(hostname);
|
||||
udp.Send(query, query.Length, new IPEndPoint(IPAddress.Parse(dnsServer), 53));
|
||||
IPEndPoint remoteEp = null;
|
||||
byte[] response = udp.Receive(ref remoteEp);
|
||||
return ParseDnsResponse(response);
|
||||
return ParseDnsResponse(udp.Receive(ref remoteEp));
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] BuildDnsQuery(string hostname)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
var writer = new BinaryWriter(ms);
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)new Random().Next(0, ushort.MaxValue)));
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)0x0100));
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)1));
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)0));
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)0));
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)0));
|
||||
foreach (string label in hostname.Split('.'))
|
||||
using (var ms = new MemoryStream())
|
||||
using (var writer = new BinaryWriter(ms))
|
||||
{
|
||||
writer.Write((byte)label.Length);
|
||||
writer.Write(Encoding.ASCII.GetBytes(label));
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)new Random().Next(0, ushort.MaxValue)));
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)0x0100)); // Flags
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)1)); // Questions
|
||||
writer.Write(new byte[6]); // Answer/Authority/Additional counts
|
||||
|
||||
foreach (string label in hostname.Split('.'))
|
||||
{
|
||||
writer.Write((byte)label.Length);
|
||||
writer.Write(Encoding.ASCII.GetBytes(label));
|
||||
}
|
||||
writer.Write((byte)0);
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)1)); // Type A
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)1)); // Class IN
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
writer.Write((byte)0);
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)1));
|
||||
writer.Write(IPAddress.HostToNetworkOrder((short)1));
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
private static List<IPAddress> ParseDnsResponse(byte[] response)
|
||||
{
|
||||
var addresses = new List<IPAddress>();
|
||||
if (response.Length < 12) return addresses;
|
||||
|
||||
int pos = 12;
|
||||
while (pos < response.Length && response[pos] != 0) pos += response[pos] + 1;
|
||||
pos += 5;
|
||||
|
||||
int answerCount = (response[6] << 8) | response[7];
|
||||
for (int i = 0; i < answerCount && pos + 12 <= response.Length; i++)
|
||||
{
|
||||
if ((response[pos] & 0xC0) == 0xC0) pos += 2;
|
||||
else { while (pos < response.Length && response[pos] != 0) pos += response[pos] + 1; pos++; }
|
||||
pos += (response[pos] & 0xC0) == 0xC0 ? 2 : SkipName(response, pos);
|
||||
if (pos + 10 > response.Length) break;
|
||||
|
||||
ushort type = (ushort)((response[pos] << 8) | response[pos + 1]);
|
||||
pos += 8;
|
||||
ushort rdLength = (ushort)((response[pos] << 8) | response[pos + 1]);
|
||||
pos += 2;
|
||||
ushort rdLength = (ushort)((response[pos + 8] << 8) | response[pos + 9]);
|
||||
pos += 10;
|
||||
|
||||
if (pos + rdLength > response.Length) break;
|
||||
if (type == 1 && rdLength == 4)
|
||||
addresses.Add(new IPAddress(new[] { response[pos], response[pos + 1], response[pos + 2], response[pos + 3] }));
|
||||
@@ -207,7 +310,73 @@ namespace AndroidSideloader.Utilities
|
||||
return addresses;
|
||||
}
|
||||
|
||||
#region Local HTTP CONNECT Proxy for rclone
|
||||
private static int SkipName(byte[] data, int pos)
|
||||
{
|
||||
int start = pos;
|
||||
while (pos < data.Length && data[pos] != 0) pos += data[pos] + 1;
|
||||
return pos - start + 1;
|
||||
}
|
||||
|
||||
public static IPAddress ResolveHostname(string hostname, bool alwaysTryFallback = false)
|
||||
{
|
||||
if (_dnsCache.TryGetValue(hostname, out IPAddress cached))
|
||||
return cached;
|
||||
|
||||
try
|
||||
{
|
||||
var addresses = Dns.GetHostAddresses(hostname);
|
||||
if (addresses?.Length > 0)
|
||||
{
|
||||
_dnsCache[hostname] = addresses[0];
|
||||
return addresses[0];
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (alwaysTryFallback || UseFallbackDns || !_initialized)
|
||||
{
|
||||
var ip = ResolveWithFallbackDns(hostname);
|
||||
if (ip != null)
|
||||
{
|
||||
_dnsCache[hostname] = ip;
|
||||
return ip;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static HttpWebRequest CreateWebRequest(string url)
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
|
||||
if (!UseFallbackDns)
|
||||
{
|
||||
try
|
||||
{
|
||||
Dns.GetHostAddresses(uri.Host);
|
||||
return (HttpWebRequest)WebRequest.Create(url);
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (!_initialized) Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
if (UseFallbackDns)
|
||||
{
|
||||
var ip = ResolveHostname(uri.Host, alwaysTryFallback: true);
|
||||
if (ip != null)
|
||||
{
|
||||
var builder = new UriBuilder(uri) { Host = ip.ToString() };
|
||||
var request = (HttpWebRequest)WebRequest.Create(builder.Uri);
|
||||
request.Host = uri.Host;
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
||||
return (HttpWebRequest)WebRequest.Create(url);
|
||||
}
|
||||
|
||||
private static void StartProxy()
|
||||
{
|
||||
@@ -246,7 +415,7 @@ namespace AndroidSideloader.Utilities
|
||||
try
|
||||
{
|
||||
var client = await _proxyListener.AcceptTcpClientAsync();
|
||||
_ = Task.Run(() => HandleProxyClient(client, ct));
|
||||
_ = HandleProxyClient(client, ct);
|
||||
}
|
||||
catch (ObjectDisposedException) { break; }
|
||||
catch (Exception ex)
|
||||
@@ -264,10 +433,8 @@ namespace AndroidSideloader.Utilities
|
||||
using (client)
|
||||
using (var stream = client.GetStream())
|
||||
{
|
||||
client.ReceiveTimeout = 30000;
|
||||
client.SendTimeout = 30000;
|
||||
client.ReceiveTimeout = client.SendTimeout = 30000;
|
||||
|
||||
// Read the HTTP request
|
||||
var buffer = new byte[8192];
|
||||
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, ct);
|
||||
if (bytesRead == 0) return;
|
||||
@@ -279,19 +446,12 @@ namespace AndroidSideloader.Utilities
|
||||
string[] requestLine = lines[0].Split(' ');
|
||||
if (requestLine.Length < 2) return;
|
||||
|
||||
string method = requestLine[0];
|
||||
string target = requestLine[1];
|
||||
|
||||
if (method == "CONNECT")
|
||||
{
|
||||
if (requestLine[0] == "CONNECT")
|
||||
// HTTPS proxy - tunnel mode
|
||||
await HandleConnectRequest(stream, target, ct);
|
||||
}
|
||||
await HandleConnectRequest(stream, requestLine[1], ct);
|
||||
else
|
||||
{
|
||||
// HTTP proxy - forward mode
|
||||
await HandleHttpRequest(stream, request, target, ct);
|
||||
}
|
||||
await HandleHttpRequest(stream, request, requestLine[1], ct);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -306,14 +466,13 @@ namespace AndroidSideloader.Utilities
|
||||
// Parse host:port
|
||||
string[] parts = target.Split(':');
|
||||
string host = parts[0];
|
||||
int port = parts.Length > 1 ? int.Parse(parts[1]) : 443;
|
||||
int port = parts.Length > 1 && int.TryParse(parts[1], out int p) ? p : 443;
|
||||
|
||||
// Resolve hostname using our DNS
|
||||
IPAddress ip = ResolveAnyHostname(host);
|
||||
// Resolve hostname
|
||||
IPAddress ip = ResolveHostname(host, alwaysTryFallback: true);
|
||||
if (ip == null)
|
||||
{
|
||||
byte[] errorResponse = Encoding.ASCII.GetBytes("HTTP/1.1 502 Bad Gateway\r\n\r\n");
|
||||
await clientStream.WriteAsync(errorResponse, 0, errorResponse.Length, ct);
|
||||
await SendResponse(clientStream, "HTTP/1.1 502 Bad Gateway\r\n\r\n", ct);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -326,21 +485,16 @@ namespace AndroidSideloader.Utilities
|
||||
using (var targetStream = targetClient.GetStream())
|
||||
{
|
||||
// Send 200 OK to client
|
||||
byte[] okResponse = Encoding.ASCII.GetBytes("HTTP/1.1 200 Connection Established\r\n\r\n");
|
||||
await clientStream.WriteAsync(okResponse, 0, okResponse.Length, ct);
|
||||
|
||||
await SendResponse(clientStream, "HTTP/1.1 200 Connection Established\r\n\r\n", ct);
|
||||
// Tunnel data bidirectionally
|
||||
var clientToTarget = RelayData(clientStream, targetStream, ct);
|
||||
var targetToClient = RelayData(targetStream, clientStream, ct);
|
||||
await Task.WhenAny(clientToTarget, targetToClient);
|
||||
await Task.WhenAny(RelayData(clientStream, targetStream, ct), RelayData(targetStream, clientStream, ct));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log($"CONNECT tunnel error to {host}: {ex.Message}", LogLevel.WARNING);
|
||||
byte[] errorResponse = Encoding.ASCII.GetBytes("HTTP/1.1 502 Bad Gateway\r\n\r\n");
|
||||
try { await clientStream.WriteAsync(errorResponse, 0, errorResponse.Length, ct); } catch { }
|
||||
await SendResponse(clientStream, "HTTP/1.1 502 Bad Gateway\r\n\r\n", ct);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,19 +503,16 @@ namespace AndroidSideloader.Utilities
|
||||
try
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
IPAddress ip = ResolveAnyHostname(uri.Host);
|
||||
IPAddress ip = ResolveHostname(uri.Host, alwaysTryFallback: true);
|
||||
if (ip == null)
|
||||
{
|
||||
byte[] errorResponse = Encoding.ASCII.GetBytes("HTTP/1.1 502 Bad Gateway\r\n\r\n");
|
||||
await clientStream.WriteAsync(errorResponse, 0, errorResponse.Length, ct);
|
||||
await SendResponse(clientStream, "HTTP/1.1 502 Bad Gateway\r\n\r\n", ct);
|
||||
return;
|
||||
}
|
||||
|
||||
int port = uri.Port > 0 ? uri.Port : 80;
|
||||
|
||||
using (var targetClient = new TcpClient())
|
||||
{
|
||||
await targetClient.ConnectAsync(ip, port);
|
||||
await targetClient.ConnectAsync(ip, uri.Port > 0 ? uri.Port : 80);
|
||||
using (var targetStream = targetClient.GetStream())
|
||||
{
|
||||
// Modify request to use relative path
|
||||
@@ -380,6 +531,12 @@ namespace AndroidSideloader.Utilities
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task SendResponse(NetworkStream stream, string response, CancellationToken ct)
|
||||
{
|
||||
byte[] bytes = Encoding.ASCII.GetBytes(response);
|
||||
try { await stream.WriteAsync(bytes, 0, bytes.Length, ct); } catch { }
|
||||
}
|
||||
|
||||
private static async Task RelayData(NetworkStream from, NetworkStream to, CancellationToken ct)
|
||||
{
|
||||
byte[] buffer = new byte[8192];
|
||||
@@ -387,105 +544,9 @@ namespace AndroidSideloader.Utilities
|
||||
{
|
||||
int bytesRead;
|
||||
while ((bytesRead = await from.ReadAsync(buffer, 0, buffer.Length, ct)) > 0)
|
||||
{
|
||||
await to.WriteAsync(buffer, 0, bytesRead, ct);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static IPAddress ResolveHostname(string hostname)
|
||||
{
|
||||
if (_dnsCache.TryGetValue(hostname, out IPAddress cached))
|
||||
return cached;
|
||||
|
||||
try
|
||||
{
|
||||
var addresses = Dns.GetHostAddresses(hostname);
|
||||
if (addresses != null && addresses.Length > 0)
|
||||
{
|
||||
_dnsCache[hostname] = addresses[0];
|
||||
return addresses[0];
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (_useFallbackDns || !_initialized)
|
||||
{
|
||||
var ip = ResolveWithFallbackDns(hostname);
|
||||
if (ip != null)
|
||||
{
|
||||
_dnsCache[hostname] = ip;
|
||||
return ip;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IPAddress ResolveAnyHostname(string hostname)
|
||||
{
|
||||
if (_dnsCache.TryGetValue(hostname, out IPAddress cached))
|
||||
return cached;
|
||||
|
||||
try
|
||||
{
|
||||
var addresses = Dns.GetHostAddresses(hostname);
|
||||
if (addresses != null && addresses.Length > 0)
|
||||
{
|
||||
_dnsCache[hostname] = addresses[0];
|
||||
return addresses[0];
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
var ip = ResolveWithFallbackDns(hostname);
|
||||
if (ip != null)
|
||||
{
|
||||
_dnsCache[hostname] = ip;
|
||||
return ip;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static HttpWebRequest CreateWebRequest(string url)
|
||||
{
|
||||
var uri = new Uri(url);
|
||||
|
||||
if (!_useFallbackDns)
|
||||
{
|
||||
try
|
||||
{
|
||||
Dns.GetHostAddresses(uri.Host);
|
||||
return (HttpWebRequest)WebRequest.Create(url);
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (!_initialized) Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
if (_useFallbackDns)
|
||||
{
|
||||
var ip = ResolveHostname(uri.Host);
|
||||
if (ip == null)
|
||||
{
|
||||
ip = ResolveAnyHostname(uri.Host);
|
||||
}
|
||||
|
||||
if (ip != null)
|
||||
{
|
||||
var builder = new UriBuilder(uri) { Host = ip.ToString() };
|
||||
var request = (HttpWebRequest)WebRequest.Create(builder.Uri);
|
||||
request.Host = uri.Host;
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
||||
return (HttpWebRequest)WebRequest.Create(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user