PEASS-ng/winPEAS/winPEASexe/winPEAS/Info/NetworkInfo/InternetConnectivity.cs
2025-05-25 01:37:03 +02:00

237 lines
8.8 KiB
C#
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading;
namespace winPEAS.Info.NetworkInfo
{
// ───────────────────────────────────────────────────────────────
// POCO returned to the UI
// ───────────────────────────────────────────────────────────────
public class InternetConnectivityInfo
{
public bool HttpAccess { get; set; }
public bool HttpsAccess { get; set; }
public bool LambdaAccess { get; set; }
public bool DnsAccess { get; set; }
public bool IcmpAccess { get; set; }
public string HttpError { get; set; }
public string HttpsError { get; set; }
public string LambdaError { get; set; }
public string DnsError { get; set; }
public string IcmpError { get; set; }
public string SuccessfulHttpIp { get; set; }
public string SuccessfulHttpsIp { get; set; }
public string SuccessfulDnsIp { get; set; }
public string SuccessfulIcmpIp { get; set; }
}
// ───────────────────────────────────────────────────────────────
// Connectivity tester
// ───────────────────────────────────────────────────────────────
public static class InternetConnectivity
{
private const int HTTP_TIMEOUT_MS = 5000; // 5s
private const int ICMP_TIMEOUT_MS = 2000; // 2s
// IPs that answer on 80 & 443
private static readonly string[] WEB_TEST_IPS =
{ "93.184.216.34", "151.101.1.69" }; // example.com / Fastly
// Public DNS resolvers for DNS + ICMP checks
private static readonly string[] DNS_ICMP_IPS =
{ "1.1.1.1", "8.8.8.8" };
private const string LAMBDA_URL =
"https://2e6ppt7izvuv66qmx2r3et2ufi0mxwqs.lambda-url.us-east-1.on.aws/";
// Shared HttpClient (recommended pattern)
private static readonly HttpClient http = new HttpClient
{
Timeout = TimeSpan.FromMilliseconds(HTTP_TIMEOUT_MS)
};
// ─── Helpers ───────────────────────────────────────────────
private static bool TryHttpAccess(string ip, out string error) =>
TryWebRequest($"http://{ip}", out error);
private static bool TryHttpsAccess(string ip, out string error) =>
TryWebRequest($"https://{ip}", out error);
private static bool TryWebRequest(string url, out string error)
{
try
{
using var cts = new CancellationTokenSource(
TimeSpan.FromMilliseconds(HTTP_TIMEOUT_MS));
http.GetAsync(url, cts.Token).GetAwaiter().GetResult();
error = null;
return true; // any response = connectivity
}
catch (Exception ex)
{
error = ex.Message;
return false;
}
}
private static bool TryLambdaAccess(out string error)
{
try
{
using var cts = new CancellationTokenSource(
TimeSpan.FromMilliseconds(HTTP_TIMEOUT_MS));
var req = new HttpRequestMessage(HttpMethod.Get, LAMBDA_URL);
req.Headers.UserAgent.ParseAdd("winpeas");
req.Headers.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var resp = http.SendAsync(req, cts.Token).GetAwaiter().GetResult();
error = resp.IsSuccessStatusCode ? null :
$"HTTP {(int)resp.StatusCode}";
return error == null;
}
catch (Exception ex)
{
error = ex.Message;
return false;
}
}
private static bool TryDnsAccess(string ip, out string error)
{
try
{
using var udp = new UdpClient();
udp.Client.ReceiveTimeout = HTTP_TIMEOUT_MS;
udp.Client.SendTimeout = HTTP_TIMEOUT_MS;
var server = new IPEndPoint(IPAddress.Parse(ip), 53);
// minimal query for google.com Arecord
byte[] q = {
0x00,0x01, 0x01,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x00,0x00,
0x06,0x67,0x6f,0x6f,0x67,0x6c,0x65, 0x03,0x63,0x6f,0x6d, 0x00,
0x00,0x01, 0x00,0x01
};
udp.Send(q, q.Length, server);
IPEndPoint remote = new IPEndPoint(IPAddress.Any, 0);
byte[] resp = udp.Receive(ref remote);
error = resp?.Length > 0 ? null : "No DNS response";
return error == null;
}
catch (SocketException ex) { error = ex.Message; return false; }
catch (Exception ex) { error = ex.Message; return false; }
}
private static bool TryIcmpAccess(string ip, out string error)
{
try
{
using var ping = new Ping();
var reply = ping.Send(ip, ICMP_TIMEOUT_MS);
error = reply?.Status == IPStatus.Success
? null
: $"Ping failed: {reply?.Status}";
return error == null;
}
catch (Exception ex) { error = ex.Message; return false; }
}
// ─── Main entry ───────────────────────────────────────────
public static InternetConnectivityInfo CheckConnectivity()
{
var info = new InternetConnectivityInfo();
// -------- HTTP / HTTPS --------------------------------
foreach (var ip in WEB_TEST_IPS)
{
// HTTP
if (!info.HttpAccess)
{
string httpErr;
if (TryHttpAccess(ip, out httpErr))
{
info.HttpAccess = true;
info.SuccessfulHttpIp = ip;
}
else
{
info.HttpError = httpErr;
}
}
// HTTPS
if (!info.HttpsAccess)
{
string httpsErr;
if (TryHttpsAccess(ip, out httpsErr))
{
info.HttpsAccess = true;
info.SuccessfulHttpsIp = ip;
}
else
{
info.HttpsError = httpsErr;
}
}
if (info.HttpAccess && info.HttpsAccess) break;
}
// -------- Lambda --------------------------------------
info.LambdaAccess = TryLambdaAccess(out string lambdaErr);
if (!info.LambdaAccess) info.LambdaError = lambdaErr;
// -------- DNS / ICMP ----------------------------------
foreach (var ip in DNS_ICMP_IPS)
{
// DNS
if (!info.DnsAccess)
{
string dnsErr;
if (TryDnsAccess(ip, out dnsErr))
{
info.DnsAccess = true;
info.SuccessfulDnsIp = ip;
}
else
{
info.DnsError = dnsErr;
}
}
// ICMP
if (!info.IcmpAccess)
{
string pingErr;
if (TryIcmpAccess(ip, out pingErr))
{
info.IcmpAccess = true;
info.SuccessfulIcmpIp = ip;
}
else
{
info.IcmpError = pingErr;
}
}
if (info.DnsAccess && info.IcmpAccess) break;
}
return info;
}
}
}