diff --git a/CheckProxy.csproj b/CheckProxy.csproj
index 9a3020c..c775d0e 100644
--- a/CheckProxy.csproj
+++ b/CheckProxy.csproj
@@ -15,6 +15,7 @@
+
diff --git a/Program.cs b/Program.cs
index dda05cf..5b6f02f 100644
--- a/Program.cs
+++ b/Program.cs
@@ -1,7 +1,5 @@
using Spectre.Console;
using System.Net;
-using System.Net.NetworkInformation;
-using System.Net.Sockets;
using System.CommandLine;
///
@@ -53,21 +51,26 @@ public static async Task Main(string[] args)
/// The timeout in milliseconds for each check.
static async Task CheckSingleProxy(string proxyAddress, int timeout)
{
- if (IPEndPoint.TryParse(proxyAddress, out var proxyEndPoint))
+ if (IPEndPoint.TryParse(proxyAddress, out _))
{
var webProxy = new WebProxy(proxyAddress);
- AnsiConsole.MarkupLine("Target: [bold]" + proxyAddress + "[/]");
-
- var columns = new List
- {
- new Markup("[bold]Ping Check[/]"),
- new Markup("[bold]TCP Connection[/]"),
- new Markup("[bold]HTTP Proxy Check[/]"),
- };
- AnsiConsole.Write(new Columns(columns));
-
- var results = await RunChecksInParallel(webProxy, proxyEndPoint, timeout);
- AnsiConsole.Write(new Columns(results.Select(r => new Markup(r.ToString()))));
+ var checker = new ProxyChecker(webProxy);
+ var proxyInfo = await checker.CheckProxyAsync();
+
+ var table = new Table();
+ table.AddColumn("Property");
+ table.AddColumn("Value");
+
+ table.AddRow("Address", proxyInfo.Address ?? "N/A");
+ table.AddRow("Type", proxyInfo.Type ?? "N/A");
+ table.AddRow("Anonymity", proxyInfo.Anonymity ?? "N/A");
+ table.AddRow("Country", proxyInfo.Country ?? "N/A");
+ table.AddRow("ASN", proxyInfo.Asn ?? "N/A");
+ table.AddRow("Outgoing IP", proxyInfo.OutgoingIp ?? "N/A");
+ table.AddRow("Alive", proxyInfo.IsAlive ? "[green]Yes[/]" : "[red]No[/]");
+ table.AddRow("Additional Headers", proxyInfo.AdditionalHeaders ?? "N/A");
+
+ AnsiConsole.Write(table);
}
else
{
@@ -91,14 +94,14 @@ static async Task CheckProxiesFromFile(FileInfo file, int timeout)
var proxies = await File.ReadAllLinesAsync(file.FullName);
AnsiConsole.MarkupLine($"[yellow]Found {proxies.Length} proxies in {file.Name}. Starting checks...[/]");
- var columns = new List
- {
- new Markup("[bold]Proxy[/]"),
- new Markup("[bold]Ping[/]"),
- new Markup("[bold]TCP[/]"),
- new Markup("[bold]HTTP[/]"),
- };
- AnsiConsole.Write(new Columns(columns));
+ var table = new Table();
+ table.AddColumn("Address");
+ table.AddColumn("Type");
+ table.AddColumn("Anonymity");
+ table.AddColumn("Country");
+ table.AddColumn("ASN");
+ table.AddColumn("Outgoing IP");
+ table.AddColumn("Alive");
var tasks = new List();
var semaphore = new SemaphoreSlim(10); // Limit to 10 concurrent checks
@@ -111,25 +114,25 @@ static async Task CheckProxiesFromFile(FileInfo file, int timeout)
{
try
{
- if (IPEndPoint.TryParse(proxyAddress, out var proxyEndPoint))
+ if (IPEndPoint.TryParse(proxyAddress, out _))
{
var webProxy = new WebProxy(proxyAddress);
- var results = await RunChecksInParallel(webProxy, proxyEndPoint, timeout);
- AnsiConsole.Write(new Columns(
- new Markup(proxyAddress),
- new Markup(results[0].ToString()),
- new Markup(results[1].ToString()),
- new Markup(results[2].ToString())
- ));
+ var checker = new ProxyChecker(webProxy);
+ var proxyInfo = await checker.CheckProxyAsync();
+
+ table.AddRow(
+ proxyInfo.Address ?? "N/A",
+ proxyInfo.Type ?? "N/A",
+ proxyInfo.Anonymity ?? "N/A",
+ proxyInfo.Country ?? "N/A",
+ proxyInfo.Asn ?? "N/A",
+ proxyInfo.OutgoingIp ?? "N/A",
+ proxyInfo.IsAlive ? "[green]Yes[/]" : "[red]No[/]"
+ );
}
else
{
- AnsiConsole.Write(new Columns(
- new Markup(proxyAddress),
- new Markup("[red]Invalid[/]"),
- new Markup("[red]Invalid[/]"),
- new Markup("[red]Invalid[/]")
- ));
+ table.AddRow(proxyAddress, "[red]Invalid[/]", "[red]Invalid[/]", "[red]Invalid[/]", "[red]Invalid[/]", "[red]Invalid[/]", "[red]No[/]");
}
}
finally
@@ -140,118 +143,7 @@ static async Task CheckProxiesFromFile(FileInfo file, int timeout)
}
await Task.WhenAll(tasks);
+ AnsiConsole.Write(table);
AnsiConsole.MarkupLine("[green]All proxy checks complete.[/]");
}
-
- ///
- /// Runs a series of checks for a given proxy in parallel.
- ///
- /// The WebProxy object for the proxy.
- /// The IPEndPoint for the proxy.
- /// The timeout in milliseconds for each check.
- /// A boolean array indicating the result of each check.
- static async Task RunChecksInParallel(WebProxy wp, IPEndPoint proxyEp, int timeout)
- {
- var pingCheckTask = PingCheckAsync(proxyEp.Address.ToString(), timeout);
- var tcpConnectionTask = TcpConnectionCheckAsync(wp.Address.Host, wp.Address.Port, timeout);
- var httpProxyCheckTask = HttpProxyCheckAsync(wp, timeout);
-
- await Task.WhenAll(
- pingCheckTask,
- tcpConnectionTask,
- httpProxyCheckTask);
-
- return new[]
- {
- pingCheckTask.Result,
- tcpConnectionTask.Result,
- httpProxyCheckTask.Result,
- };
- }
-
- ///
- /// Performs an HTTP GET request through the proxy to check its functionality.
- ///
- /// The WebProxy to use for the request.
- /// The timeout in milliseconds for the request.
- /// True if the request is successful; otherwise, false.
- static async Task HttpProxyCheckAsync(WebProxy wp, int timeout)
- {
- var handler = new HttpClientHandler
- {
- Proxy = wp,
- UseProxy = true,
- };
-
- using var client = new HttpClient(handler);
- client.Timeout = TimeSpan.FromMilliseconds(timeout);
-
- try
- {
- using var response = await client.GetAsync("http://www.google.com/generate_204");
- return response.IsSuccessStatusCode;
- }
- catch
- {
- return false;
- }
- }
-
- ///
- /// Pings the specified address to check for reachability.
- ///
- /// The IP address or hostname to ping.
- /// The timeout in milliseconds for the ping.
- /// True if the ping is successful; otherwise, false.
- static async Task PingCheckAsync(string address, int timeout)
- {
- using var ping = new Ping();
- try
- {
- var reply = await ping.SendPingAsync(address, timeout);
- return reply?.Status == IPStatus.Success;
- }
- catch (PingException)
- {
- return false;
- }
- }
-
- ///
- /// Attempts to open a TCP socket to the specified host and port.
- ///
- /// The target host.
- /// The target port.
- /// The timeout in milliseconds for the connection attempt.
- /// True if the connection is successful; otherwise, false.
- static async Task TcpConnectionCheckAsync(string host, int port, int timeout)
- {
- using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- try
- {
- var connectTask = socket.ConnectAsync(host, port);
- var timeoutTask = Task.Delay(TimeSpan.FromMilliseconds(timeout));
-
- var completedTask = await Task.WhenAny(connectTask, timeoutTask);
-
- if (completedTask == timeoutTask)
- {
- return false;
- }
-
- await connectTask;
- return socket.Connected;
- }
- catch
- {
- return false;
- }
- finally
- {
- if (socket.Connected)
- {
- socket.Disconnect(false);
- }
- }
- }
-}
\ No newline at end of file
+}
diff --git a/ProxyChecker.cs b/ProxyChecker.cs
new file mode 100644
index 0000000..91fc3b0
--- /dev/null
+++ b/ProxyChecker.cs
@@ -0,0 +1,223 @@
+using Newtonsoft.Json;
+using System.Net;
+using System.Net.Http.Headers;
+
+///
+/// A class to check the validity of a proxy server.
+///
+public class ProxyChecker
+{
+ private readonly HttpClient _httpClient;
+ private readonly WebProxy _proxy;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The proxy to use for the checks.
+ public ProxyChecker(WebProxy proxy)
+ {
+ _proxy = proxy;
+ var handler = new HttpClientHandler
+ {
+ Proxy = proxy,
+ UseProxy = true,
+ };
+
+ _httpClient = new HttpClient(handler);
+ _httpClient.Timeout = TimeSpan.FromMilliseconds(5000);
+ }
+
+ ///
+ /// Checks the proxy and returns a object with the results.
+ ///
+ /// A object with the results of the check.
+ public async Task CheckProxyAsync()
+ {
+ var proxyInfo = new ProxyInfo
+ {
+ Address = _proxy.Address.ToString(),
+ IsAlive = false,
+ };
+
+ try
+ {
+ var response = await _httpClient.GetStringAsync("http://httpbin.org/headers");
+ var headers = JsonConvert.DeserializeObject(response);
+
+ var publicIpAddress = headers.Origin;
+ var headerDictionary = headers.Headers;
+
+ proxyInfo.IsAlive = true;
+ proxyInfo.OutgoingIp = publicIpAddress;
+
+ var ipInfo = await GetIpInfoAsync(publicIpAddress);
+ if (ipInfo != null)
+ {
+ proxyInfo.Country = ipInfo.Country;
+ proxyInfo.Asn = ipInfo.Asn;
+ }
+
+ proxyInfo.Type = await GetProxyTypeAsync();
+ proxyInfo.Anonymity = GetAnonymity(publicIpAddress, headerDictionary);
+ proxyInfo.AdditionalHeaders = string.Join(", ", headerDictionary.Keys);
+ }
+ catch
+ {
+ // Ignore exceptions
+ }
+
+ return proxyInfo;
+ }
+
+ ///
+ /// Gets the public IP address of the system.
+ ///
+ /// Whether to use the proxy to get the public IP address.
+ /// The public IP address of the system.
+ private async Task GetPublicIpAddressAsync(bool useProxy)
+ {
+ try
+ {
+ var httpClient = useProxy ? _httpClient : new HttpClient();
+ var response = await httpClient.GetStringAsync("https://api.ipify.org");
+ return response.Trim();
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// Gets the geolocation and ASN information for the specified IP address.
+ ///
+ /// The IP address to get the information for.
+ /// A object with the geolocation and ASN information.
+ private async Task GetIpInfoAsync(string ipAddress)
+ {
+ try
+ {
+ var response = await new HttpClient().GetStringAsync($"http://ip-api.com/json/{ipAddress}");
+ return JsonConvert.DeserializeObject(response);
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// Gets the proxy type.
+ ///
+ /// The proxy type.
+ private async Task GetProxyTypeAsync()
+ {
+ if (await IsSocks5ProxyAsync())
+ {
+ return "SOCKS5";
+ }
+
+ if (await IsHttpsProxyAsync())
+ {
+ return "HTTPS";
+ }
+
+ return "HTTP";
+ }
+
+ ///
+ /// Checks if the proxy is a SOCKS5 proxy.
+ ///
+ /// True if the proxy is a SOCKS5 proxy; otherwise, false.
+ private async Task IsSocks5ProxyAsync()
+ {
+ try
+ {
+ var socket = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
+ await socket.ConnectAsync(_proxy.Address.Host, _proxy.Address.Port);
+ var buffer = new byte[] { 5, 1, 0 };
+ await socket.SendAsync(buffer, System.Net.Sockets.SocketFlags.None);
+ var response = new byte[2];
+ await socket.ReceiveAsync(response, System.Net.Sockets.SocketFlags.None);
+ return response[0] == 5 && response[1] == 0;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Checks if the proxy is an HTTPS proxy.
+ ///
+ /// True if the proxy is an HTTPS proxy; otherwise, false.
+ private async Task IsHttpsProxyAsync()
+ {
+ try
+ {
+ var response = await _httpClient.GetAsync("https://www.google.com");
+ return response.IsSuccessStatusCode;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Gets the anonymity level of the proxy.
+ ///
+ /// The public IP address of the system.
+ /// The headers from the proxy.
+ /// The anonymity level of the proxy.
+ private string GetAnonymity(string publicIpAddress, Dictionary headers)
+ {
+ if (headers.ContainsKey("X-Forwarded-For") || headers.ContainsKey("Via"))
+ {
+ var forwardedFor = headers.ContainsKey("X-Forwarded-For") ? headers["X-Forwarded-For"] : "";
+ if (forwardedFor.Contains(publicIpAddress))
+ {
+ return "Transparent";
+ }
+ return "Anonymous";
+ }
+
+ return "Elite";
+ }
+}
+
+///
+/// Represents the headers returned by httpbin.org/headers.
+///
+public class HttpBinHeaders
+{
+ ///
+ /// Gets or sets the origin IP address.
+ ///
+ [JsonProperty("origin")]
+ public string Origin { get; set; }
+
+ ///
+ /// Gets or sets the headers.
+ ///
+ [JsonProperty("headers")]
+ public Dictionary Headers { get; set; }
+}
+
+///
+/// Represents the geolocation and ASN information for an IP address.
+///
+public class IpInfo
+{
+ ///
+ /// Gets or sets the country of the IP address.
+ ///
+ [JsonProperty("country")]
+ public string Country { get; set; }
+
+ ///
+ /// Gets or sets the Autonomous System Number (ASN) of the IP address.
+ ///
+ [JsonProperty("as")]
+ public string Asn { get; set; }
+}
diff --git a/ProxyInfo.cs b/ProxyInfo.cs
new file mode 100644
index 0000000..69e51fa
--- /dev/null
+++ b/ProxyInfo.cs
@@ -0,0 +1,46 @@
+///
+/// Represents the information about a proxy server.
+///
+public class ProxyInfo
+{
+ ///
+ /// Gets or sets the proxy address.
+ ///
+ public string Address { get; set; }
+
+ ///
+ /// Gets or sets the proxy type (e.g., HTTP, HTTPS, SOCKS5).
+ ///
+ public string Type { get; set; }
+
+ ///
+ /// Gets or sets the anonymity level (e.g., Elite, Anonymous, Transparent).
+ ///
+ public string Anonymity { get; set; }
+
+ ///
+ /// Gets or sets the country of the proxy.
+ ///
+ public string Country { get; set; }
+
+ ///
+ /// Gets or sets the Autonomous System Number (ASN) of the proxy.
+ ///
+ public string Asn { get; set; }
+
+ ///
+ /// Gets or sets the outgoing IP address of the proxy.
+ ///
+ public string OutgoingIp { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the proxy is alive.
+ ///
+ public bool IsAlive { get; set; }
+
+ ///
+ summary>
+ /// Gets or sets any additional headers added by the proxy.
+ ///
+ public string AdditionalHeaders { get; set; }
+}