From 4afe9153ed21ffd153b910f7c49e2e740d1fda19 Mon Sep 17 00:00:00 2001 From: EonaCat Date: Thu, 2 Mar 2023 10:02:06 +0100 Subject: [PATCH] Updated --- EonaCat.DnsTester/Helpers/DnsHelper.cs | 74 ++++++++++++---------- EonaCat.DnsTester/Helpers/DnsNameParser.cs | 30 +++++++++ EonaCat.DnsTester/MainForm.Designer.cs | 30 ++++----- EonaCat.DnsTester/MainForm.cs | 65 +++++++++++-------- 4 files changed, 122 insertions(+), 77 deletions(-) diff --git a/EonaCat.DnsTester/Helpers/DnsHelper.cs b/EonaCat.DnsTester/Helpers/DnsHelper.cs index 58fa434..c4c823e 100644 --- a/EonaCat.DnsTester/Helpers/DnsHelper.cs +++ b/EonaCat.DnsTester/Helpers/DnsHelper.cs @@ -146,14 +146,27 @@ namespace EonaCat.DnsTester.Helpers { Console.WriteLine("new byte[] { " + responseBytes + " }"); + // Check if response is valid + if (responseBytes.Length < 12) + { + throw new Exception("Invalid DNS response"); + } + // Set the offset to the start var offset = 0; // Parse the DNS header ushort id = (ushort)((responseBytes[0] << 8) | responseBytes[1]); ushort flags = (ushort)((responseBytes[2] << 8) | responseBytes[3]); + bool isResponse = (flags & 0x8000) != 0; ushort qdcount = (ushort)((responseBytes[4] << 8) | responseBytes[5]); ushort ancount = (ushort)((responseBytes[6] << 8) | responseBytes[7]); + + if (!isResponse) + { + throw new Exception("Invalid DNS response"); + } + ushort nscount = (ushort)((responseBytes[8] << 8) | responseBytes[9]); ushort arcount = (ushort)((responseBytes[10] << 8) | responseBytes[11]); @@ -243,62 +256,53 @@ namespace EonaCat.DnsTester.Helpers static ResourceRecord ParseDnsAnswerRecord(byte[] responseBytes, ref int offset) { // Parse the DNS name - string name = DnsNameParser.ParseName(responseBytes, ref offset); + string name = DnsNameParser.ExtractDomainName(responseBytes, ref offset); if (name == null) { return null; } // Parse the DNS type, class, ttl, and data length - DnsRecordType type = (DnsRecordType)((responseBytes[offset] << 8) | responseBytes[offset++]); - DnsRecordClass klass = (DnsRecordClass)((responseBytes[offset] << 8) | responseBytes[offset++]); - uint ttl = (uint)((responseBytes[offset] << 24) | (responseBytes[offset++] << 16) | (responseBytes[offset++] << 8) | responseBytes[offset++]); - ushort rdlen = (ushort)((responseBytes[offset] << 8) + responseBytes[offset++]); - offset += 10; + DnsRecordType type = (DnsRecordType)((responseBytes[offset++] << 8) + responseBytes[offset++]); + DnsRecordClass klass = (DnsRecordClass)((responseBytes[offset++] << 8) + responseBytes[offset++]); + int ttl = (responseBytes[offset++] << 24) + (responseBytes[offset++] << 16) + (responseBytes[offset++] << 8) + responseBytes[offset++]; - // Parse the DNS data - string data = null; + // Extract record data length + int dataLength = (responseBytes[offset] << 8) + responseBytes[offset + 1]; + offset += 2; + + // Extract record data + byte[] recordData = new byte[dataLength]; + Buffer.BlockCopy(responseBytes, offset, recordData, 0, dataLength); + + string recordDataAsString = null; switch ((DnsRecordType)type) { case DnsRecordType.A: - if (rdlen != 4) + if (dataLength != 4) { return null; } - - data = new IPAddress(new byte[] - { - responseBytes[offset], responseBytes[offset + 1], responseBytes[offset + 2], - responseBytes[offset + 3] - }).ToString(); - offset += rdlen; + recordDataAsString = new IPAddress(recordData).ToString(); + offset += recordData.Length; break; case DnsRecordType.CNAME: + recordDataAsString = DnsNameParser.ExtractDomainName(responseBytes, ref offset); + break; case DnsRecordType.NS: - data = DnsNameParser.ParseName(responseBytes, ref offset); - if (data == null) - { - return null; - } - + recordDataAsString = DnsNameParser.ExtractDomainName(responseBytes, ref offset); break; case DnsRecordType.MX: - ushort preference = (ushort)((responseBytes[offset] << 8) | responseBytes[offset + 1]); + int preference = (responseBytes[0] << 8) + responseBytes[1]; offset += 2; - string exchange = DnsNameParser.ParseName(responseBytes, ref offset); - if (exchange == null) - { - return null; - } - - data = $"{preference} {exchange}"; + string exchange = DnsNameParser.ExtractDomainName(responseBytes, ref offset); + recordDataAsString = $"{preference} {exchange}"; break; case DnsRecordType.TXT: - data = Encoding.ASCII.GetString(responseBytes, offset, rdlen); - offset += rdlen; + recordDataAsString = Encoding.ASCII.GetString(recordData); break; default: - offset += rdlen; + offset += dataLength; break; } @@ -308,7 +312,7 @@ namespace EonaCat.DnsTester.Helpers Type = type, Class = klass, Ttl = TimeSpan.FromSeconds(ttl), - Data = data, + Data = recordDataAsString, }; } @@ -358,7 +362,7 @@ namespace EonaCat.DnsTester.Helpers { A = 1, NS = 2, - CNAME = 5, + CNAME = 6, MX = 15, TXT = 16, AAAA = 28, diff --git a/EonaCat.DnsTester/Helpers/DnsNameParser.cs b/EonaCat.DnsTester/Helpers/DnsNameParser.cs index f41a8c1..984688e 100644 --- a/EonaCat.DnsTester/Helpers/DnsNameParser.cs +++ b/EonaCat.DnsTester/Helpers/DnsNameParser.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Text; namespace EonaCat.DnsTester.Helpers { @@ -29,5 +30,34 @@ namespace EonaCat.DnsTester.Helpers return string.Join(".", labels); } + + public static string ExtractDomainName(byte[] buffer, ref int offset) + { + List labels = new List(); + + while (true) + { + byte labelLength = buffer[offset++]; + + if (labelLength == 0) + { + break; + } + + if ((labelLength & 0xC0) == 0xC0) + { + // Compressed domain name + int pointer = (int)(((labelLength & 0x3F) << 8) + buffer[offset++]); + labels.Add(ExtractDomainName(buffer, ref pointer)); + break; + } + + string label = Encoding.ASCII.GetString(buffer, offset, labelLength); + labels.Add(label); + offset += labelLength; + } + + return string.Join(".", labels); + } } } diff --git a/EonaCat.DnsTester/MainForm.Designer.cs b/EonaCat.DnsTester/MainForm.Designer.cs index 318cb67..0b9605c 100644 --- a/EonaCat.DnsTester/MainForm.Designer.cs +++ b/EonaCat.DnsTester/MainForm.Designer.cs @@ -49,9 +49,9 @@ StatusBox = new System.Windows.Forms.ListBox(); ResultView = new System.Windows.Forms.ListView(); Url = new System.Windows.Forms.ColumnHeader(); - DNS1IP = new System.Windows.Forms.ColumnHeader(); + DNS1DATA = new System.Windows.Forms.ColumnHeader(); DNS1Performance = new System.Windows.Forms.ColumnHeader(); - DNS2IP = new System.Windows.Forms.ColumnHeader(); + DNS2DATA = new System.Windows.Forms.ColumnHeader(); DNS2Performance = new System.Windows.Forms.ColumnHeader(); panel3 = new System.Windows.Forms.Panel(); btnResolveHost = new System.Windows.Forms.Button(); @@ -273,7 +273,7 @@ // // ResultView // - ResultView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { Url, DNS1IP, DNS1Performance, DNS2IP, DNS2Performance }); + ResultView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { Url, DNS1DATA, DNS1Performance, DNS2DATA, DNS2Performance }); ResultView.GridLines = true; ResultView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; ResultView.Location = new System.Drawing.Point(56, 49); @@ -290,27 +290,27 @@ Url.Text = "URL"; Url.Width = 160; // - // DNS1IP + // DNS1DATA // - DNS1IP.Text = "IP Address from DNS 1"; - DNS1IP.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; - DNS1IP.Width = 140; + DNS1DATA.Text = "Data"; + DNS1DATA.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + DNS1DATA.Width = 140; // // DNS1Performance // - DNS1Performance.Text = "DNS 1 Performance"; + DNS1Performance.Text = "Performance"; DNS1Performance.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; DNS1Performance.Width = 120; // - // DNS2IP + // DNS2DATA // - DNS2IP.Text = "IP Address from DNS 2"; - DNS2IP.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; - DNS2IP.Width = 140; + DNS2DATA.Text = "Data"; + DNS2DATA.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + DNS2DATA.Width = 140; // // DNS2Performance // - DNS2Performance.Text = "DNS 2 Performance"; + DNS2Performance.Text = "Performance"; DNS2Performance.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; DNS2Performance.Width = 120; // @@ -428,9 +428,9 @@ private System.Windows.Forms.ListBox StatusBox; private System.Windows.Forms.ListView ResultView; private System.Windows.Forms.ColumnHeader Url; - private System.Windows.Forms.ColumnHeader DNS1IP; + private System.Windows.Forms.ColumnHeader DNS1DATA; private System.Windows.Forms.ColumnHeader DNS1Performance; - private System.Windows.Forms.ColumnHeader DNS2IP; + private System.Windows.Forms.ColumnHeader DNS2DATA; private System.Windows.Forms.ColumnHeader DNS2Performance; private System.Windows.Forms.Panel panel3; private System.Windows.Forms.Button btnResolveHost; diff --git a/EonaCat.DnsTester/MainForm.cs b/EonaCat.DnsTester/MainForm.cs index 17300ae..3c591a1 100644 --- a/EonaCat.DnsTester/MainForm.cs +++ b/EonaCat.DnsTester/MainForm.cs @@ -273,38 +273,49 @@ namespace EonaCat.DnsTester var stopTime = DateTime.Now.Ticks; var deltaTime = Convert.ToString((double)(stopTime - dnsResponse.StartTime) / 10000000, CultureInfo.InvariantCulture); - SetStatus($"ResourceRecord: Name: {dnsResponse.Answers.FirstOrDefault().Name} : Type : {dnsResponse.Answers.FirstOrDefault().Type} : Data : {dnsResponse.Answers.FirstOrDefault().Data}"); + foreach (var answer in dnsResponse.Answers) + { + SetStatus( + $"ResourceRecord: Name: {answer.Name} : Type : {answer.Type} : Data : {answer.Data}"); + } + for (int i = 0; i < ResultView.Items.Count; i++) { - if (ResultView.Items[i].Text != $"{dnsResponse.Answers.FirstOrDefault().Name.TrimEnd('.')}") continue; - - string sDeltaTime; - switch (dnsResponse.DnsId) + foreach (var answer in dnsResponse.Answers) { - case "Dns1": - ResultView.Items[i].SubItems[1].Text = Convert.ToString(dnsResponse.Answers.FirstOrDefault().Data); - sDeltaTime = Convert.ToString(deltaTime); - ResultView.Items[i].SubItems[2].Text = - sDeltaTime.Length > 5 ? sDeltaTime.Substring(0, 5) : 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; + if (ResultView.Items[i].Text != $"{answer.Name.TrimEnd('.')}") + continue; - case "Dns2": - ResultView.Items[i].SubItems[3].Text = Convert.ToString(dnsResponse.Answers.FirstOrDefault().Data); - sDeltaTime = Convert.ToString(deltaTime); - ResultView.Items[i].SubItems[4].Text = - sDeltaTime.Length > 5 ? sDeltaTime.Substring(0, 5) : 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; + string sDeltaTime; + switch (dnsResponse.DnsId) + { + case "Dns1": + ResultView.Items[i].SubItems[1].Text = + Convert.ToString(answer.Data); + sDeltaTime = Convert.ToString(deltaTime); + ResultView.Items[i].SubItems[2].Text = + sDeltaTime.Length > 5 ? sDeltaTime.Substring(0, 5) : 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 "Dns2": + ResultView.Items[i].SubItems[3].Text = + Convert.ToString(answer.Data); + sDeltaTime = Convert.ToString(deltaTime); + ResultView.Items[i].SubItems[4].Text = + sDeltaTime.Length > 5 ? sDeltaTime.Substring(0, 5) : 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; + } } } }