EonaCat.DnsTester/EonaCat.DnsTester/MainForm.cs

527 lines
16 KiB
C#

using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Threading;
namespace EonaCat.DnsTester
{
public partial class MainForm : Form
{
private bool UseCustomDnsServers = false;
public string DNS1, DNS2;
public bool IsRunning { get; private set; }
public MainForm()
{
InitializeComponent();
}
private void RunTest_Click(object sender, EventArgs e)
{
int i;
List<string> CleanNames = new List<string>();
if (this.UseCustomDnsServers)
{
if (chkDns1.Checked)
{
DNS1 = CustomDns1.Text;
}
if (chkDns2.Checked)
{
DNS2 = CustomDns2.Text;
}
}
else
{
if (chkDns1.Checked)
{
DNS1 = DnsList1.SelectedValue.ToString();
}
if (chkDns2.Checked)
{
DNS2 = DnsList2.SelectedValue.ToString();
}
}
ResultView.Items.Clear();
ResultView.Update();
Application.DoEvents();
GetWebAddresses(ref CleanNames, (int)numericUpDown1.Value);
for (i = 0; i < CleanNames.Count; i++)
{
ListViewItem listURL = new ListViewItem(CleanNames[i]);
listURL.SubItems.Add(" ");
listURL.SubItems.Add(" ");
listURL.SubItems.Add(" ");
listURL.SubItems.Add(" ");
ResultView.Items.Add(listURL);
}
if (ResultView.Items.Count > 1)
{
ResultView.EnsureVisible(ResultView.Items.Count - 1);
}
ResultView.Update();
Application.DoEvents();
if (IsRunning)
{
return;
}
IsRunning = true;
CheckDNS(CleanNames.ToArray(), CleanNames.Count, DNS1, DNS2);
IsRunning = false;
}
private void TesterUI_Load(object sender, EventArgs e)
{
FillDnsList();
}
private void FillDnsList()
{
DnsList1.ValueMember = "ip";
DnsList1.DisplayMember = "name";
DnsList2.ValueMember = "ip";
DnsList2.DisplayMember = "name";
DataSet servers1 = new DataSet();
DataSet servers2 = new DataSet();
servers1.ReadXml(Path.Combine(Application.StartupPath, "Servers.xml"));
servers2.ReadXml(Path.Combine(Application.StartupPath, "Servers.xml"));
DataTable ns1 = servers1.Tables[0];
DataTable ns2 = servers2.Tables[0];
DnsList1.DataSource = ns1;
DnsList2.DataSource = ns2;
}
private void UseCustomServers_CheckedChanged(object sender, EventArgs e)
{
this.UseCustomDnsServers = UseCustomServers.Checked;
SetUI();
}
private void SetUI()
{
if (this.UseCustomDnsServers)
{
this.DnsList1.Enabled = false;
this.DnsList2.Enabled = false;
this.CustomDns1.Enabled = true;
this.CustomDns2.Enabled = true;
this.CustomDns1.Visible = true;
this.CustomDns2.Visible = true;
this.lblCustom1.Visible = true;
this.lblCustom2.Visible = true;
}
else
{
this.DnsList1.Enabled = true;
this.DnsList2.Enabled = true;
this.CustomDns1.Enabled = false; ;
this.CustomDns2.Enabled = false;
this.CustomDns1.Visible = false;
this.CustomDns2.Visible = false;
this.lblCustom1.Visible = false;
this.lblCustom2.Visible = false;
}
}
private void GetWebAddresses(ref List<string> CleanNames, int totalUrls)
{
int i, j;
byte[] random = new Byte[256];
string Letters = "";
// Make a 3 letter random string
//RNGCryptoServiceProvider is an implementation of a random number generator.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(random); // The array is now filled with cryptographically strong random bytes.
for (i = 1; i < 256; i++)
{
// Just take the first three letters
if (random[i] > 0x40 && random[i] < 0x5b) Letters = Letters + Convert.ToChar(random[i]);
if (Letters.Length == 3) break;
}
KeyValuePair<string, string> searchEngine = new KeyValuePair<string, string>();
Random rand = new Random();
// Create a list of search engine URLs to query
Dictionary<string, string> searchEngineUrls = new Dictionary<string, string>
{
{ "DuckDuckGo", "https://duckduckgo.com/html/?q=" },
{ "Yahoo", "https://search.yahoo.com/search?p=" },
{ "Bing", "https://www.bing.com/search?q=" },
{ "Google", "https://www.google.com/search?q=" },
{ "Ask", "https://www.ask.com/web?q=" },
{ "AOL", "https://www.aol.com/search?q=" },
{ "WolframAlpha", "https://www.wolframalpha.com/input/?i=" },
{ "StartPage", "https://www.startpage.com/do/dsearch?query=" },
{ "Yandex", "https://www.yandex.com/search/?text=" },
{ "Qwant", "https://www.qwant.com/?q=" }
};
try
{
while (CleanNames.Count < totalUrls)
{
int index = rand.Next(searchEngineUrls.Count);
searchEngine = searchEngineUrls.ElementAt(index);
WebRequest Request = WebRequest.Create(searchEngine.Value + Letters); //Letters);
WebResponse Response = Request.GetResponse();
Application.DoEvents();
// Get the response stream.
Stream Stream = Response.GetResponseStream();
StatusBoxPrint(searchEngine.Key + " response received");
StreamReader StreamReader = new StreamReader(Stream, Encoding.ASCII);
string ResponseString = StreamReader.ReadToEnd();
// Close the response stream and response to free resources.
Stream.Close();
Response.Close();
Application.DoEvents();
// find all .xxx.com addresses
MatchCollection HostNames;
string[] Names = new string[totalUrls + 1000];
// Create a new Regex object and define the regular expression.
Regex Dotcom = new Regex("[.]([A-Za-z]*)[.]com");
// Use the Matches method to find all matches in the input string.
HostNames = Dotcom.Matches(ResponseString);
Application.DoEvents();
// Loop through the match collection to retrieve all
// matches and delete the leading "."
for (i = 0; i < HostNames.Count; i++)
{
Names[i] = HostNames[i].Value.Remove(0, 1);
}
// eliminate its own search engine names and repeated entries
for (i = 0; i < HostNames.Count - 1; i++)
{
if (Names[i] == searchEngine.Key.ToLower() + ".com") Names[i] = "";
for (j = i + 1; j < HostNames.Count; j++)
{
if (Names[i] == Names[j]) Names[j] = "";
}
}
Shuffle(Names);
// Add the names to the list
for (i = 0; i < HostNames.Count; i++)
{
if (CleanNames.Count >= totalUrls)
{
break;
}
if (!string.IsNullOrEmpty(Names[i]) && !CleanNames.Contains(Names[i]))
{
CleanNames.Add(Names[i]);
}
}
}
StatusBoxPrint(CleanNames.Count + " Random URL's found");
}
catch(Exception exception)
{
StatusBoxPrint(searchEngine.Key + ": " ?? string.Empty + exception.Message);
}
}
public static void Shuffle<T>(T[] array)
{
Random rng = new Random();
int n = array.Length;
while (n > 1)
{
n--;
int k = rng.Next(n + 1);
T value = array[k];
array[k] = array[n];
array[n] = value;
}
}
private void CheckDNS(string[] URLNames, int URLNamescount, string DNSAddress1, string DNSAddress2)
{
int i;
const int IPPort = 53;
const string TransactionID1 = "Q1"; // Use transaction ID of Q1 and Q2 to identify our packet and DNS
const string TransactionID2 = "Q2";
const string TypeString = "\u0001" + "\u0000" + "\u0000" + "\u0001" + "\u0000" + "\u0000" + "\u0000" + "\u0000" + "\u0000" + "\u0000";
const string TrailerString = "\u0000" + "\u0000" + "\u0001" + "\u0000" + "\u0001";
const int DNSReceiveTimeout = 5000;
string URLNameStart, DomainName, QueryString, ReceiveString, IPResponse, sDeltaTime;
int URLNameStartLength, DomainNameLength, index, TransactionDNS;
byte[] Sendbytes = new byte[256];
long StartTime, StopTime;
string DeltaTime;
Socket DNSsocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
DNSsocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, DNSReceiveTimeout);
IPEndPoint dnsEP1 = null;
if (chkDns1.Checked && !string.IsNullOrWhiteSpace(DNSAddress1))
{
dnsEP1 = new IPEndPoint(IPAddress.Parse(DNSAddress1), IPPort);
}
IPEndPoint dnsEP2 = null;
if (chkDns2.Checked && !string.IsNullOrWhiteSpace(DNSAddress2))
{
dnsEP2 = new IPEndPoint(IPAddress.Parse(DNSAddress2), IPPort);
}
// Start the clock
StartTime = DateTime.Now.Ticks;
for (i = 0; i < URLNamescount; i++)
{
URLNameStart = URLNames[i].Substring(0, URLNames[i].IndexOf("."));
DomainName = URLNames[i].Substring(URLNames[i].IndexOf(".") + 1, URLNames[i].Length - URLNames[i].IndexOf(".") - 1);
if (chkDns1.Checked)
{
QueryString = TransactionID1 + TypeString + (char)URLNameStart.Length + URLNameStart + (char)DomainName.Length + DomainName + TrailerString;
Sendbytes = Encoding.ASCII.GetBytes(QueryString);
if (dnsEP1 != null)
{
DNSsocket.SendTo(Sendbytes, Sendbytes.Length, SocketFlags.None, dnsEP1);
}
}
if (chkDns2.Checked)
{
QueryString = TransactionID2 + TypeString + (char)URLNameStart.Length + URLNameStart + (char)DomainName.Length + DomainName + TrailerString;
Sendbytes = Encoding.ASCII.GetBytes(QueryString);
if (dnsEP2 != null)
{
DNSsocket.SendTo(Sendbytes, Sendbytes.Length, SocketFlags.None, dnsEP2);
}
}
}
byte[] Receivebytes = new byte[512];
int totalReceived = 0;
try
{
// wait for a response up to timeout
more:
DNSsocket.Receive(Receivebytes);
// make sure the message returned is ours
if (Receivebytes[0] == Sendbytes[0] && (Receivebytes[1] == 0x31) || (Receivebytes[1] == 0x32))
{
if (Receivebytes[2] == 0x81 && Receivebytes[3] == 0x80)
{
// Get the time now
StopTime = DateTime.Now.Ticks;
DeltaTime = Convert.ToString((double)(StopTime - StartTime) / 10000000);
// Decode the answers
// Find the URL that was returned
TransactionDNS = Receivebytes[1];
ReceiveString = Encoding.ASCII.GetString(Receivebytes);
index = 12;
URLNameStartLength = Receivebytes[index];
index++;
URLNameStart = ReceiveString.Substring(index, URLNameStartLength);
index = index + URLNameStartLength;
DomainNameLength = Receivebytes[index];
index++;
DomainName = ReceiveString.Substring(index, DomainNameLength);
index = index + DomainNameLength;
index = index + 8;
// Get the record type
int ResponseType = Receivebytes[index];
index = index + 9;
// Get the IP address if applicable
IPResponse = "";
switch (ResponseType)
{
case 1:
IPResponse = Convert.ToString(Receivebytes[index]) + "."
+ Convert.ToString(Receivebytes[index + 1]) + "."
+ Convert.ToString(Receivebytes[index + 2]) + "."
+ Convert.ToString(Receivebytes[index + 3]); break;
case 5: IPResponse = "CNAME"; break;
case 6: IPResponse = "SOA"; break;
}
StatusBoxPrint("DNS Answer: " + URLNameStart + "." + DomainName + " = " + IPResponse);
// Find the URL entry in the list
for (i = 0; i < ResultView.Items.Count; i++)
{
if (ResultView.Items[i].Text == URLNameStart + "." + DomainName)
{
switch (TransactionDNS)
{
case 0x31:
ResultView.Items[i].SubItems[1].Text = Convert.ToString(IPResponse);
sDeltaTime = Convert.ToString(DeltaTime);
if (sDeltaTime.Length > 5) ResultView.Items[i].SubItems[2].Text = sDeltaTime.Substring(0, 5);
else ResultView.Items[i].SubItems[2].Text = sDeltaTime;
ResultView.Items[i].ForeColor = System.Drawing.Color.Red;
ResultView.EnsureVisible(i);
ResultView.Update();
Application.DoEvents();
ResultView.Items[i].ForeColor = System.Drawing.Color.Black;
break;
case 0x32:
ResultView.Items[i].SubItems[3].Text = Convert.ToString(IPResponse);
sDeltaTime = Convert.ToString(DeltaTime);
if (sDeltaTime.Length > 5) ResultView.Items[i].SubItems[4].Text = sDeltaTime.Substring(0, 5);
else ResultView.Items[i].SubItems[4].Text = sDeltaTime;
ResultView.Items[i].ForeColor = System.Drawing.Color.Red;
ResultView.EnsureVisible(i);
ResultView.Update();
Application.DoEvents();
ResultView.Items[i].ForeColor = System.Drawing.Color.Black;
break;
}
totalReceived++;
}
}
}
if (totalReceived < URLNamescount)
{
goto more;
}
}
}
catch (SocketException e)
{
if (Convert.ToString(e).IndexOf("time") > 0)
{
StatusBoxPrint("Timeout - No response received for " + Convert.ToString(DNSReceiveTimeout / 1000) + " seconds");
}
else
{
StatusBoxPrint(Convert.ToString(e)); // for testing
}
}
finally
{
// close the socket
DNSsocket.Close();
}
}
private async void btnResolveIP_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(txtResolveIP.Text))
{
MessageBox.Show("Please enter an IP address to resolve");
return;
}
if (!IPAddress.TryParse(txtResolveIP.Text , out IPAddress iPAddress))
{
MessageBox.Show("Please enter a valid IP address");
return;
}
try
{
await Task.Run(() =>
{
var dnsEntry = Dns.GetHostEntry(iPAddress);
Dispatcher.CurrentDispatcher.Invoke(() =>
{
txtResolveHost.Text = dnsEntry.HostName;
});
});
}
catch (Exception)
{
MessageBox.Show($"Could not get hostname for IP address '{txtResolveIP.Text}'");
}
}
private async void btnResolveHost_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(txtResolveHost.Text))
{
MessageBox.Show("Please enter an hostname to resolve");
return;
}
try
{
await Task.Run(() =>
{
var dnsEntry = Dns.GetHostEntry(txtResolveHost.Text);
Dispatcher.CurrentDispatcher.Invoke(() =>
{
txtResolveIP.Text = dnsEntry.AddressList.Where(x => x.AddressFamily == AddressFamily.InterNetwork).FirstOrDefault().Address.ToString();
});
});
}
catch (Exception)
{
MessageBox.Show($"Could not get hostname for IP address '{txtResolveIP.Text}'");
}
}
private void StatusBoxPrint(string LogText)
{
StatusBox.Items.Add(DateTime.Now + " " + LogText);
StatusBox.TopIndex = StatusBox.Items.Count - 1;
if (StatusBox.Items.Count > 5000)
{
StatusBox.Items.RemoveAt(0);
}
StatusBox.Update();
}
}
}