Updated
This commit is contained in:
parent
41a3f72560
commit
16c642dd20
|
@ -1,8 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
@ -11,10 +11,12 @@ namespace EonaCat.DnsTester.Helpers
|
||||||
class DnsHelper
|
class DnsHelper
|
||||||
{
|
{
|
||||||
public static event EventHandler<string> OnLog;
|
public static event EventHandler<string> OnLog;
|
||||||
|
|
||||||
|
private static readonly Random random = new Random();
|
||||||
|
|
||||||
public static async Task<DnsResponse> SendDnsQueryPacket(string dnsId, string server, int port, byte[] queryBytes)
|
public static async Task<DnsResponse> SendDnsQueryPacket(string dnsId, string server, int port, byte[] queryBytes)
|
||||||
{
|
{
|
||||||
// Start the clock
|
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
|
||||||
var startTime = DateTime.Now.Ticks;
|
|
||||||
|
|
||||||
var endPoint = new IPEndPoint(IPAddress.Parse(server), port);
|
var endPoint = new IPEndPoint(IPAddress.Parse(server), port);
|
||||||
using (var client = new UdpClient(endPoint.AddressFamily))
|
using (var client = new UdpClient(endPoint.AddressFamily))
|
||||||
|
@ -23,10 +25,11 @@ namespace EonaCat.DnsTester.Helpers
|
||||||
client.EnableBroadcast = false;
|
client.EnableBroadcast = false;
|
||||||
client.Client.SendTimeout = DnsSendTimeout;
|
client.Client.SendTimeout = DnsSendTimeout;
|
||||||
client.Client.ReceiveTimeout = DnsReceiveTimeout;
|
client.Client.ReceiveTimeout = DnsReceiveTimeout;
|
||||||
byte[] responseBytes = null;
|
|
||||||
|
byte[] responseBytes;
|
||||||
if (FakeResponse)
|
if (FakeResponse)
|
||||||
{
|
{
|
||||||
responseBytes = DnsHelper.GetExampleResponse();
|
responseBytes = GetExampleResponse();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -35,94 +38,55 @@ namespace EonaCat.DnsTester.Helpers
|
||||||
responseBytes = responseResult.Buffer;
|
responseBytes = responseResult.Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
DnsResponse response = ParseDnsResponsePacket(dnsId, startTime, server, responseBytes);
|
var response = ParseDnsResponsePacket(dnsId, stopwatch.ElapsedTicks, server, responseBytes);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For testing purposes
|
// For testing purposes
|
||||||
public static bool FakeResponse { get; set; }
|
public static bool FakeResponse { get; set; }
|
||||||
|
|
||||||
public static int DnsSendTimeout { get; set; } = 5;
|
public static int DnsSendTimeout { get; set; } = 5;
|
||||||
public static int DnsReceiveTimeout { get; set; } = 5;
|
public static int DnsReceiveTimeout { get; set; } = 5;
|
||||||
|
|
||||||
|
|
||||||
public static byte[] CreateDnsQueryPacket(string domainName, DnsRecordType recordType)
|
public static byte[] CreateDnsQueryPacket(string domainName, DnsRecordType recordType)
|
||||||
{
|
{
|
||||||
Random random = new Random();
|
var id = (ushort)random.Next(0, 65536);
|
||||||
|
var flags = (ushort)0x0100; // recursion desired
|
||||||
|
var qdcount = (ushort)1;
|
||||||
|
var ancount = (ushort)0;
|
||||||
|
var nscount = (ushort)0;
|
||||||
|
var arcount = (ushort)0;
|
||||||
|
|
||||||
// DNS header
|
using (var stream = new MemoryStream())
|
||||||
ushort id = (ushort)random.Next(0, 65536);
|
using (var writer = new BinaryWriter(stream))
|
||||||
ushort flags = (ushort)0x0100; // recursion desired
|
|
||||||
ushort qdcount = 1;
|
|
||||||
ushort ancount = 0;
|
|
||||||
ushort nscount = 0;
|
|
||||||
ushort arcount = 0;
|
|
||||||
byte[] headerBytes = new byte[]
|
|
||||||
{
|
{
|
||||||
(byte)(id >> 8), (byte)(id & 0xff),
|
writer.Write(id);
|
||||||
(byte)(flags >> 8), (byte)(flags & 0xff),
|
writer.Write(flags);
|
||||||
(byte)(qdcount >> 8), (byte)(qdcount & 0xff),
|
writer.Write(qdcount);
|
||||||
(byte)(ancount >> 8), (byte)(ancount & 0xff),
|
writer.Write(ancount);
|
||||||
(byte)(nscount >> 8), (byte)(nscount & 0xff),
|
writer.Write(nscount);
|
||||||
(byte)(arcount >> 8), (byte)(arcount & 0xff),
|
writer.Write(arcount);
|
||||||
};
|
|
||||||
|
|
||||||
// DNS question
|
var labels = domainName.Split('.');
|
||||||
string[] labels = domainName.Split('.');
|
foreach (var label in labels)
|
||||||
byte[] qnameBytes = new byte[domainName.Length + 2];
|
|
||||||
int qnameIndex = 0;
|
|
||||||
foreach (string label in labels)
|
|
||||||
{
|
{
|
||||||
qnameBytes[qnameIndex++] = (byte)label.Length;
|
writer.Write((byte)label.Length);
|
||||||
foreach (char c in label)
|
writer.Write(Encoding.ASCII.GetBytes(label));
|
||||||
{
|
|
||||||
qnameBytes[qnameIndex++] = (byte)c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qnameBytes[qnameIndex++] = 0;
|
|
||||||
|
|
||||||
byte[] qtypeBytes = new byte[] { (byte)((ushort)recordType >> 8), (byte)((ushort)recordType & 0xff) };
|
|
||||||
byte[] qclassBytes = new byte[] { 0, 1 }; // internet class
|
|
||||||
byte[] questionBytes = new byte[qnameBytes.Length + qtypeBytes.Length + qclassBytes.Length];
|
|
||||||
qnameBytes.CopyTo(questionBytes, 0);
|
|
||||||
qtypeBytes.CopyTo(questionBytes, qnameBytes.Length);
|
|
||||||
qclassBytes.CopyTo(questionBytes, qnameBytes.Length + qtypeBytes.Length);
|
|
||||||
|
|
||||||
// Combine the header and question to form the DNS query packet
|
|
||||||
byte[] queryBytes = new byte[headerBytes.Length + questionBytes.Length];
|
|
||||||
headerBytes.CopyTo(queryBytes, 0);
|
|
||||||
questionBytes.CopyTo(queryBytes, headerBytes.Length);
|
|
||||||
|
|
||||||
return queryBytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static DnsQuestion ParseDnsQuestionRecord(byte[] queryBytes, ref int offset)
|
writer.Write((byte)0); // Null terminator
|
||||||
{
|
writer.Write((ushort)recordType);
|
||||||
// Parse the DNS name
|
writer.Write((ushort)1); // Record class: IN (Internet)
|
||||||
string name = DnsNameParser.ParseName(queryBytes, ref offset);
|
|
||||||
if (name == null)
|
return stream.ToArray();
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the DNS type and class
|
|
||||||
ushort type = (ushort)((queryBytes[offset] << 8) | queryBytes[offset + 1]);
|
|
||||||
ushort qclass = (ushort)((queryBytes[offset + 2] << 8) | queryBytes[offset + 3]);
|
|
||||||
offset += 4;
|
|
||||||
|
|
||||||
return new DnsQuestion
|
|
||||||
{
|
|
||||||
Name = name,
|
|
||||||
Type = (DnsRecordType)type,
|
|
||||||
Class = (DnsRecordClass)qclass,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] GetExampleResponse()
|
public static byte[] GetExampleResponse()
|
||||||
{
|
{
|
||||||
// Example response bytes for the A record of google.com
|
// Example response bytes for the A record of google.com
|
||||||
byte[] response = {
|
return new byte[]
|
||||||
|
{
|
||||||
0x9d, 0xa9, // Query ID
|
0x9d, 0xa9, // Query ID
|
||||||
0x81, 0x80, // Flags
|
0x81, 0x80, // Flags
|
||||||
0x00, 0x01, // Questions: 1
|
0x00, 0x01, // Questions: 1
|
||||||
|
@ -141,58 +105,45 @@ namespace EonaCat.DnsTester.Helpers
|
||||||
0x00, 0x04, // Data length: 4 bytes
|
0x00, 0x04, // Data length: 4 bytes
|
||||||
0xac, 0xd9, 0x03, 0x3d // Data: 172.217.3.61
|
0xac, 0xd9, 0x03, 0x3d // Data: 172.217.3.61
|
||||||
};
|
};
|
||||||
return response;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static DnsResponse ParseDnsResponsePacket(string dnsId, long startTime, string server, byte[] responseBytes)
|
private static DnsResponse ParseDnsResponsePacket(string dnsId, long startTime, string server, byte[] responseBytes)
|
||||||
{
|
{
|
||||||
Console.WriteLine("new byte[] { " + responseBytes + " }");
|
|
||||||
|
|
||||||
// Check if response is valid
|
|
||||||
if (responseBytes.Length < 12)
|
if (responseBytes.Length < 12)
|
||||||
{
|
{
|
||||||
throw new Exception("Invalid DNS response");
|
throw new Exception("Invalid DNS response");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the offset to the start
|
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
|
var id = (ushort)((responseBytes[offset++] << 8) | responseBytes[offset++]);
|
||||||
// Parse the DNS header
|
var flags = (ushort)((responseBytes[offset++] << 8) | responseBytes[offset++]);
|
||||||
ushort id = (ushort)((responseBytes[0] << 8) | responseBytes[1]);
|
var isResponse = (flags & 0x8000) != 0;
|
||||||
ushort flags = (ushort)((responseBytes[2] << 8) | responseBytes[3]);
|
var qdcount = (ushort)((responseBytes[offset++] << 8) | responseBytes[offset++]);
|
||||||
bool isResponse = (flags & 0x8000) != 0;
|
|
||||||
ushort qdcount = (ushort)((responseBytes[4] << 8) | responseBytes[5]);
|
|
||||||
ushort ancount = (ushort)((responseBytes[6] << 8) | responseBytes[7]);
|
|
||||||
|
|
||||||
if (!isResponse)
|
if (!isResponse)
|
||||||
{
|
{
|
||||||
throw new Exception("Invalid DNS response");
|
throw new Exception("Invalid DNS response");
|
||||||
}
|
}
|
||||||
|
|
||||||
ushort nscount = (ushort)((responseBytes[8] << 8) | responseBytes[9]);
|
var nscount = (ushort)((responseBytes[offset++] << 8) | responseBytes[offset++]);
|
||||||
ushort arcount = (ushort)((responseBytes[10] << 8) | responseBytes[11]);
|
var arcount = (ushort)((responseBytes[offset++] << 8) | responseBytes[offset++]);
|
||||||
|
|
||||||
// We parsed the header set the offset past the header
|
|
||||||
offset = 12;
|
|
||||||
|
|
||||||
List<DnsQuestion> questions = new List<DnsQuestion>();
|
|
||||||
|
|
||||||
|
var questions = new List<DnsQuestion>();
|
||||||
for (int i = 0; i < qdcount; i++)
|
for (int i = 0; i < qdcount; i++)
|
||||||
{
|
{
|
||||||
DnsQuestion question = ParseDnsQuestionRecord(responseBytes, ref offset);
|
var question = ParseDnsQuestionRecord(responseBytes, ref offset);
|
||||||
if (question != null)
|
if (question != null)
|
||||||
{
|
{
|
||||||
questions.Add(question);
|
questions.Add(question);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the DNS answer records
|
var answers = new List<ResourceRecord>();
|
||||||
List<ResourceRecord> answers = new List<ResourceRecord>();
|
for (int i = 0; i < qdcount; i++)
|
||||||
for (int i = 0; i < ancount; i++)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ResourceRecord answer = ParseDnsAnswerRecord(responseBytes, ref offset);
|
var answer = ParseDnsAnswerRecord(responseBytes, ref offset);
|
||||||
if (answer != null)
|
if (answer != null)
|
||||||
{
|
{
|
||||||
answers.Add(answer);
|
answers.Add(answer);
|
||||||
|
@ -200,17 +151,17 @@ namespace EonaCat.DnsTester.Helpers
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
OnLog?.Invoke(null, $"Answer exception: " + exception.Message);
|
OnLog?.Invoke(null, $"Answer exception: {exception.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the DNS authority records
|
// Parse the DNS authority records
|
||||||
List<ResourceRecord> authorities = new List<ResourceRecord>();
|
var authorities = new List<ResourceRecord>();
|
||||||
for (int i = 0; i < nscount; i++)
|
for (int i = 0; i < nscount; i++)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ResourceRecord authority = ParseDnsAnswerRecord(responseBytes, ref offset);
|
var authority = ParseDnsAnswerRecord(responseBytes, ref offset);
|
||||||
if (authority != null)
|
if (authority != null)
|
||||||
{
|
{
|
||||||
authorities.Add(authority);
|
authorities.Add(authority);
|
||||||
|
@ -218,17 +169,17 @@ namespace EonaCat.DnsTester.Helpers
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
OnLog?.Invoke(null, $"Authority answer exception: " + exception.Message);
|
OnLog?.Invoke(null, $"Authority answer exception: {exception.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the DNS additional records
|
// Parse the DNS additional records
|
||||||
List<ResourceRecord> additionals = new List<ResourceRecord>();
|
var additionals = new List<ResourceRecord>();
|
||||||
for (int i = 0; i < arcount; i++)
|
for (int i = 0; i < arcount; i++)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ResourceRecord additional = ParseDnsAnswerRecord(responseBytes, ref offset);
|
var additional = ParseDnsAnswerRecord(responseBytes, ref offset);
|
||||||
if (additional != null)
|
if (additional != null)
|
||||||
{
|
{
|
||||||
additionals.Add(additional);
|
additionals.Add(additional);
|
||||||
|
@ -236,7 +187,7 @@ namespace EonaCat.DnsTester.Helpers
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
OnLog?.Invoke(null, $"Additional answer exception: " + exception.Message);
|
OnLog?.Invoke(null, $"Additional answer exception: {exception.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,53 +206,61 @@ namespace EonaCat.DnsTester.Helpers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResourceRecord ParseDnsAnswerRecord(byte[] responseBytes, ref int offset)
|
private static DnsQuestion ParseDnsQuestionRecord(byte[] queryBytes, ref int offset)
|
||||||
{
|
{
|
||||||
// Parse the DNS name
|
var name = DnsNameParser.ParseName(queryBytes, ref offset);
|
||||||
string name = DnsNameParser.ExtractDomainName(responseBytes, ref offset);
|
|
||||||
if (name == null)
|
if (name == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the DNS type, class, ttl, and data length
|
var type = (DnsRecordType)((queryBytes[offset++] << 8) | queryBytes[offset++]);
|
||||||
DnsRecordType type = (DnsRecordType)((responseBytes[offset++] << 8) + responseBytes[offset++]);
|
var qclass = (DnsRecordClass)((queryBytes[offset++] << 8) | queryBytes[offset++]);
|
||||||
DnsRecordClass klass = (DnsRecordClass)((responseBytes[offset++] << 8) + responseBytes[offset++]);
|
|
||||||
int ttl = (responseBytes[offset++] << 24) + (responseBytes[offset++] << 16) + (responseBytes[offset++] << 8) + responseBytes[offset++];
|
|
||||||
|
|
||||||
// Extract record data length
|
return new DnsQuestion
|
||||||
int dataLength = (responseBytes[offset] << 8) + responseBytes[offset + 1];
|
{
|
||||||
offset += 2;
|
Name = name,
|
||||||
|
Type = type,
|
||||||
|
Class = qclass,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Extract record data
|
private static ResourceRecord ParseDnsAnswerRecord(byte[] responseBytes, ref int offset)
|
||||||
byte[] recordData = new byte[dataLength];
|
{
|
||||||
Buffer.BlockCopy(responseBytes, offset, recordData, 0, dataLength);
|
var name = DnsNameParser.ExtractDomainName(responseBytes, ref offset);
|
||||||
|
if (name == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
string recordDataAsString = null;
|
var type = (DnsRecordType)((responseBytes[offset++] << 8) + responseBytes[offset++]);
|
||||||
switch ((DnsRecordType)type)
|
var klass = (DnsRecordClass)((responseBytes[offset++] << 8) + responseBytes[offset++]);
|
||||||
|
var ttl = (responseBytes[offset++] << 24) + (responseBytes[offset++] << 16) + (responseBytes[offset++] << 8) + responseBytes[offset++];
|
||||||
|
var dataLength = (responseBytes[offset++] << 8) + responseBytes[offset++];
|
||||||
|
|
||||||
|
string dataAsString = null;
|
||||||
|
switch (type)
|
||||||
{
|
{
|
||||||
case DnsRecordType.A:
|
case DnsRecordType.A:
|
||||||
if (dataLength != 4)
|
if (dataLength != 4)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
recordDataAsString = new IPAddress(recordData).ToString();
|
dataAsString = new IPAddress(responseBytes, offset).ToString();
|
||||||
offset += recordData.Length;
|
offset += dataLength;
|
||||||
break;
|
break;
|
||||||
case DnsRecordType.CNAME:
|
case DnsRecordType.CNAME:
|
||||||
recordDataAsString = DnsNameParser.ExtractDomainName(responseBytes, ref offset);
|
|
||||||
break;
|
|
||||||
case DnsRecordType.NS:
|
case DnsRecordType.NS:
|
||||||
recordDataAsString = DnsNameParser.ExtractDomainName(responseBytes, ref offset);
|
dataAsString = DnsNameParser.ExtractDomainName(responseBytes, ref offset);
|
||||||
break;
|
break;
|
||||||
case DnsRecordType.MX:
|
case DnsRecordType.MX:
|
||||||
int preference = (responseBytes[0] << 8) + responseBytes[1];
|
var preference = (responseBytes[offset++] << 8) + responseBytes[offset++];
|
||||||
offset += 2;
|
var exchange = DnsNameParser.ExtractDomainName(responseBytes, ref offset);
|
||||||
string exchange = DnsNameParser.ExtractDomainName(responseBytes, ref offset);
|
dataAsString = $"{preference} {exchange}";
|
||||||
recordDataAsString = $"{preference} {exchange}";
|
|
||||||
break;
|
break;
|
||||||
case DnsRecordType.TXT:
|
case DnsRecordType.TXT:
|
||||||
recordDataAsString = Encoding.ASCII.GetString(recordData);
|
dataAsString = Encoding.ASCII.GetString(responseBytes, offset, dataLength);
|
||||||
|
offset += dataLength;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
offset += dataLength;
|
offset += dataLength;
|
||||||
|
@ -314,19 +273,10 @@ namespace EonaCat.DnsTester.Helpers
|
||||||
Type = type,
|
Type = type,
|
||||||
Class = klass,
|
Class = klass,
|
||||||
Ttl = TimeSpan.FromSeconds(ttl),
|
Ttl = TimeSpan.FromSeconds(ttl),
|
||||||
Data = recordDataAsString,
|
Data = dataAsString,
|
||||||
|
DataLength = (ushort)dataLength,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static string GetString(byte[] bytes, ref int index, int length)
|
|
||||||
{
|
|
||||||
string str = "";
|
|
||||||
for (int i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
str += (char)bytes[index++];
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DnsQuestion
|
public class DnsQuestion
|
||||||
|
@ -372,35 +322,11 @@ namespace EonaCat.DnsTester.Helpers
|
||||||
|
|
||||||
public enum DnsRecordClass : ushort
|
public enum DnsRecordClass : ushort
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The Internet.
|
|
||||||
/// </summary>
|
|
||||||
Internet = 1,
|
Internet = 1,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The CSNET class (Obsolete - used only for examples insome obsolete RFCs).
|
|
||||||
/// </summary>
|
|
||||||
CS = 2,
|
CS = 2,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The CHAOS class.
|
|
||||||
/// </summary>
|
|
||||||
CH = 3,
|
CH = 3,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hesiod[Dyer 87].
|
|
||||||
/// </summary>
|
|
||||||
HS = 4,
|
HS = 4,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Used in UPDATE message to signify no class.
|
|
||||||
/// </summary>
|
|
||||||
None = 254,
|
None = 254,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Only used in QCLASS.
|
|
||||||
/// </summary>
|
|
||||||
/// <seealso cref="Question.Class"/>
|
|
||||||
ANY = 255
|
ANY = 255
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,19 +21,17 @@ namespace EonaCat.DnsTester.Helpers
|
||||||
public static bool UseSearchEngineStartPage { get; set; }
|
public static bool UseSearchEngineStartPage { get; set; }
|
||||||
public static bool UseSearchEngineYandex { get; set; }
|
public static bool UseSearchEngineYandex { get; set; }
|
||||||
|
|
||||||
private static async Task<List<string>> GetRandomUrls(int totalUrls)
|
private static List<string> GetRandomUrls(int totalUrls)
|
||||||
{
|
{
|
||||||
var letters = GetRandomLetters();
|
var letters = GetRandomLetters();
|
||||||
|
|
||||||
var searchEngineUrls = GetSearchEngines();
|
var searchEngineUrls = GetSearchEngines();
|
||||||
|
|
||||||
Random rand = new Random();
|
|
||||||
|
|
||||||
List<string> urls = new List<string>();
|
List<string> urls = new List<string>();
|
||||||
while (urls.Count < totalUrls)
|
|
||||||
|
Parallel.ForEach(searchEngineUrls, searchEngine =>
|
||||||
{
|
{
|
||||||
int index = rand.Next(searchEngineUrls.Count);
|
if (urls.Count >= totalUrls)
|
||||||
KeyValuePair<string, string> searchEngine = searchEngineUrls.ElementAt(index);
|
return;
|
||||||
|
|
||||||
string url = searchEngine.Value + letters;
|
string url = searchEngine.Value + letters;
|
||||||
|
|
||||||
|
@ -51,9 +49,7 @@ namespace EonaCat.DnsTester.Helpers
|
||||||
}
|
}
|
||||||
|
|
||||||
if (responseString == null)
|
if (responseString == null)
|
||||||
{
|
return;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find all .xxx.com addresses
|
// find all .xxx.com addresses
|
||||||
MatchCollection hostNames = Regex.Matches(responseString, @"[.](\w+[.]com)");
|
MatchCollection hostNames = Regex.Matches(responseString, @"[.](\w+[.]com)");
|
||||||
|
@ -69,24 +65,20 @@ namespace EonaCat.DnsTester.Helpers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock (urls)
|
||||||
|
{
|
||||||
// Add the names to the list
|
// Add the names to the list
|
||||||
foreach (string name in uniqueNames)
|
foreach (string name in uniqueNames)
|
||||||
{
|
{
|
||||||
if (urls.Count >= totalUrls)
|
if (urls.Count >= totalUrls)
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (!urls.Contains(name))
|
if (!urls.Contains(name))
|
||||||
{
|
|
||||||
urls.Add(name);
|
urls.Add(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
letters = GetRandomLetters();
|
|
||||||
await Task.Delay(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
var urlText = "url" + (urls.Count > 1 ? "'s" : string.Empty);
|
var urlText = "url" + (urls.Count > 1 ? "'s" : string.Empty);
|
||||||
SetStatus($"{urls.Count} random {urlText} found");
|
SetStatus($"{urls.Count} random {urlText} found");
|
||||||
|
@ -139,20 +131,18 @@ namespace EonaCat.DnsTester.Helpers
|
||||||
return searchEngineUrls;
|
return searchEngineUrls;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<List<string>> RetrieveUrls(int numThreads, int numUrlsPerThread)
|
public static List<string> RetrieveUrls(int numThreads, int numUrlsPerThread)
|
||||||
{
|
{
|
||||||
Task[] tasks = new Task[numThreads];
|
|
||||||
|
|
||||||
List<string> urlList = new List<string>();
|
List<string> urlList = new List<string>();
|
||||||
|
|
||||||
// start each thread to retrieve a subset of unique URLs
|
Parallel.For(0, numThreads, _ =>
|
||||||
for (int i = 0; i < numThreads; i++)
|
|
||||||
{
|
{
|
||||||
tasks[i] = Task.Run(async () => urlList.AddRange(await GetRandomUrls(numUrlsPerThread)));
|
var threadUrls = GetRandomUrls(numUrlsPerThread);
|
||||||
|
lock (urlList)
|
||||||
|
{
|
||||||
|
urlList.AddRange(threadUrls);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
// wait for all threads to complete
|
|
||||||
await Task.WhenAll(tasks);
|
|
||||||
|
|
||||||
return urlList;
|
return urlList;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using EonaCat.DnsTester.Helpers;
|
using EonaCat.DnsTester.Helpers;
|
||||||
|
@ -57,11 +58,11 @@ namespace EonaCat.DnsTester
|
||||||
}
|
}
|
||||||
|
|
||||||
SetSearchEngines();
|
SetSearchEngines();
|
||||||
urls = await UrlHelper.RetrieveUrls(numThreads, numUrlsPerThread);
|
urls = UrlHelper.RetrieveUrls(numThreads, numUrlsPerThread);
|
||||||
AddUrlToView(urls);
|
AddUrlToView(urls);
|
||||||
|
|
||||||
IsRunning = true;
|
IsRunning = true;
|
||||||
await Process(_recordType, urls.ToArray(), _dnsServer1, _dnsServer2);
|
await Process(_recordType, urls.ToArray(), _dnsServer1, _dnsServer2).ConfigureAwait(false);
|
||||||
IsRunning = false;
|
IsRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,21 +351,7 @@ namespace EonaCat.DnsTester
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Run(() =>
|
await ResolveIP().ConfigureAwait(false);
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var dnsEntry = Dns.GetHostEntry(iPAddress);
|
|
||||||
txtResolveHost.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)
|
private async void btnResolveHost_Click(object sender, EventArgs e)
|
||||||
|
@ -374,38 +361,75 @@ namespace EonaCat.DnsTester
|
||||||
MessageBox.Show("Please enter a hostname to resolve");
|
MessageBox.Show("Please enter a hostname to resolve");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
await ResolveHost().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ResolveIP()
|
||||||
await Task.Run(() =>
|
|
||||||
{
|
{
|
||||||
|
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
|
try
|
||||||
{
|
{
|
||||||
var dnsEntry = Dns.GetHostEntry(txtResolveHost.Text);
|
var dnsEntry = await Dns.GetHostEntryAsync(iPAddress);
|
||||||
|
txtResolveHost.Text = dnsEntry.HostName;
|
||||||
txtResolveHost.Invoke(() =>
|
}
|
||||||
|
catch (Exception)
|
||||||
{
|
{
|
||||||
txtResolveIP.Text = dnsEntry.AddressList.Where(x => x.AddressFamily == AddressFamily.InterNetwork).FirstOrDefault().Address.ToString();
|
MessageBox.Show($"Could not get hostname for IP address '{txtResolveIP.Text}'");
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ResolveHost()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(txtResolveHost.Text))
|
||||||
|
{
|
||||||
|
MessageBox.Show("Please enter a hostname to resolve");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var dnsEntry = await Dns.GetHostEntryAsync(txtResolveHost.Text);
|
||||||
|
var ipAddress = dnsEntry.AddressList.FirstOrDefault(x => x.AddressFamily == AddressFamily.InterNetwork);
|
||||||
|
if (ipAddress != null)
|
||||||
|
{
|
||||||
|
txtResolveIP.Text = ipAddress.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MessageBox.Show($"Could not get IP address for hostname '{txtResolveHost.Text}'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
MessageBox.Show($"Could not get IP address for hostname '{txtResolveHost.Text}'");
|
MessageBox.Show($"Could not get IP address for hostname '{txtResolveHost.Text}'");
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetStatus(string text)
|
private void SetStatus(string text)
|
||||||
{
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(StatusBox.Items.Count + 1);
|
||||||
|
sb.AppendLine($"{DateTime.Now} {text}");
|
||||||
|
|
||||||
StatusBox.Invoke(() =>
|
StatusBox.Invoke(() =>
|
||||||
{
|
{
|
||||||
StatusBox.Items.Add($"{DateTime.Now} {text}");
|
StatusBox.Items.Add(sb.ToString());
|
||||||
StatusBox.TopIndex = StatusBox.Items.Count - 1;
|
StatusBox.TopIndex = StatusBox.Items.Count - 1;
|
||||||
|
|
||||||
if (StatusBox.Items.Count > STATUS_BAR_SIZE)
|
if (StatusBox.Items.Count > STATUS_BAR_SIZE)
|
||||||
{
|
{
|
||||||
StatusBox.Items.RemoveAt(0);
|
StatusBox.Items.RemoveAt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusBox.Update();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue