commit 2daee199b525dbf10e50ece94dca4461fd22f23d
Author: dong <1278815766@qq.com>
Date: Fri Apr 11 01:14:08 2025 +0800
first commit
diff --git a/App.config b/App.config
new file mode 100644
index 0000000..f8f2a4c
--- /dev/null
+++ b/App.config
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DnsClientForm.Designer.cs b/DnsClientForm.Designer.cs
new file mode 100644
index 0000000..4ebc19f
--- /dev/null
+++ b/DnsClientForm.Designer.cs
@@ -0,0 +1,143 @@
+namespace DnsClient
+{
+ partial class DnsClientForm
+ {
+ ///
+ /// 必需的设计器变量。
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// 清理所有正在使用的资源。
+ ///
+ /// 如果应释放托管资源,为 true;否则为 false。
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows 窗体设计器生成的代码
+
+ ///
+ /// 设计器支持所需的方法 - 不要修改
+ /// 使用代码编辑器修改此方法的内容。
+ ///
+ private void InitializeComponent()
+ {
+ this.Domain_Txt = new System.Windows.Forms.Label();
+ this.Domain_Text = new System.Windows.Forms.TextBox();
+ this.Select_Txt = new System.Windows.Forms.Label();
+ this.Select_Text = new System.Windows.Forms.RichTextBox();
+ this.Start_Button = new System.Windows.Forms.Button();
+ this.Exit_Button = new System.Windows.Forms.Button();
+ this.Result_Text = new System.Windows.Forms.RichTextBox();
+ this.label1 = new System.Windows.Forms.Label();
+ this.SuspendLayout();
+ //
+ // Domain_Txt
+ //
+ this.Domain_Txt.AutoSize = true;
+ this.Domain_Txt.Location = new System.Drawing.Point(12, 9);
+ this.Domain_Txt.Name = "Domain_Txt";
+ this.Domain_Txt.Size = new System.Drawing.Size(35, 12);
+ this.Domain_Txt.TabIndex = 0;
+ this.Domain_Txt.Text = "域名:";
+ //
+ // Domain_Text
+ //
+ this.Domain_Text.Location = new System.Drawing.Point(53, 6);
+ this.Domain_Text.Name = "Domain_Text";
+ this.Domain_Text.Size = new System.Drawing.Size(499, 21);
+ this.Domain_Text.TabIndex = 1;
+ //
+ // Select_Txt
+ //
+ this.Select_Txt.AutoSize = true;
+ this.Select_Txt.Location = new System.Drawing.Point(12, 41);
+ this.Select_Txt.Name = "Select_Txt";
+ this.Select_Txt.Size = new System.Drawing.Size(35, 12);
+ this.Select_Txt.TabIndex = 2;
+ this.Select_Txt.Text = "查询:";
+ //
+ // Select_Text
+ //
+ this.Select_Text.Location = new System.Drawing.Point(53, 41);
+ this.Select_Text.Name = "Select_Text";
+ this.Select_Text.Size = new System.Drawing.Size(499, 228);
+ this.Select_Text.TabIndex = 3;
+ this.Select_Text.Text = "";
+ //
+ // Start_Button
+ //
+ this.Start_Button.Location = new System.Drawing.Point(12, 386);
+ this.Start_Button.Name = "Start_Button";
+ this.Start_Button.Size = new System.Drawing.Size(75, 23);
+ this.Start_Button.TabIndex = 4;
+ this.Start_Button.Text = "开始";
+ this.Start_Button.UseVisualStyleBackColor = true;
+ this.Start_Button.Click += new System.EventHandler(this.Start_Button_Click);
+ //
+ // Exit_Button
+ //
+ this.Exit_Button.Location = new System.Drawing.Point(477, 386);
+ this.Exit_Button.Name = "Exit_Button";
+ this.Exit_Button.Size = new System.Drawing.Size(75, 23);
+ this.Exit_Button.TabIndex = 5;
+ this.Exit_Button.Text = "退出";
+ this.Exit_Button.UseVisualStyleBackColor = true;
+ this.Exit_Button.Click += new System.EventHandler(this.Exit_Button_Click);
+ //
+ // Result_Text
+ //
+ this.Result_Text.Location = new System.Drawing.Point(53, 275);
+ this.Result_Text.Name = "Result_Text";
+ this.Result_Text.Size = new System.Drawing.Size(499, 105);
+ this.Result_Text.TabIndex = 6;
+ this.Result_Text.Text = "";
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(12, 275);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(35, 12);
+ this.label1.TabIndex = 7;
+ this.label1.Text = "结果:";
+ //
+ // DnsClient
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(564, 421);
+ this.Controls.Add(this.label1);
+ this.Controls.Add(this.Result_Text);
+ this.Controls.Add(this.Exit_Button);
+ this.Controls.Add(this.Start_Button);
+ this.Controls.Add(this.Select_Text);
+ this.Controls.Add(this.Select_Txt);
+ this.Controls.Add(this.Domain_Text);
+ this.Controls.Add(this.Domain_Txt);
+ this.Name = "DnsClient";
+ this.Text = "Form1";
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label Domain_Txt;
+ private System.Windows.Forms.TextBox Domain_Text;
+ private System.Windows.Forms.Label Select_Txt;
+ private System.Windows.Forms.RichTextBox Select_Text;
+ private System.Windows.Forms.Button Start_Button;
+ private System.Windows.Forms.Button Exit_Button;
+ private System.Windows.Forms.RichTextBox Result_Text;
+ private System.Windows.Forms.Label label1;
+ }
+}
+
diff --git a/DnsClientForm.cs b/DnsClientForm.cs
new file mode 100644
index 0000000..42bc2ef
--- /dev/null
+++ b/DnsClientForm.cs
@@ -0,0 +1,420 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Net;
+using System.Net.Http;
+using System.Collections.Concurrent;
+using System.Threading;
+using System.Text.Json;
+using System.Net.Security;
+using System.Net.Sockets;
+using DnsClientX;
+
+namespace DnsClient
+{
+ public partial class DnsClientForm : Form
+ {
+ public DnsClientForm()
+ {
+ InitializeComponent();
+ }
+
+ private (string result, int time) fastestDohResult;
+ private (string result, int time) fastestDotResult;
+
+ public async Task<(List dohResults, List dotResults)> GetNotice(string domain)
+ {
+ fastestDohResult = (null, int.MaxValue);
+ fastestDotResult = (null, int.MaxValue);
+
+ // 创建DoH客户端列表
+ var dohServers = new List
+ {
+ "https://cloudflare-dns.com/dns-query",
+ "https://dns.cloudflare.com/dns-query",
+ "https://1.1.1.1/dns-query",
+ "https://1.0.0.1/dns-query",
+ "https://dns.google/resolve",
+ "https://sm2.doh.pub/dns-query",
+ "https://doh.pub/dns-query",
+ "https://dns.alidns.com/resolve",
+ "https://223.5.5.5/resolve",
+ "https://223.6.6.6/resolve",
+ "https://doh.360.cn/resolve"
+ };
+
+ // 创建DoT客户端列表
+ var dotServers = new List
+ {
+ // 360
+ new NameServer(IPAddress.Parse("101.226.4.6"), 853),
+ // Aliyun
+ new NameServer(IPAddress.Parse("223.5.5.5"), 853),
+ new NameServer(IPAddress.Parse("223.6.6.6"), 853),
+ // Tencent
+ new NameServer(IPAddress.Parse("1.12.12.12"), 853),
+ // Cloudflare DoT
+ new NameServer(IPAddress.Parse("1.1.1.1"), 853),
+ new NameServer(IPAddress.Parse("1.0.0.1"), 853),
+ // Google DoT
+ new NameServer(IPAddress.Parse("8.8.8.8"), 853),
+ new NameServer(IPAddress.Parse("8.8.4.4"), 853),
+ // Quad9 DoT
+ new NameServer(IPAddress.Parse("9.9.9.9"), 853),
+ new NameServer(IPAddress.Parse("149.112.112.112"), 853)
+ };
+
+ var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
+
+ var dohResults = new ConcurrentBag();
+ var dotResults = new ConcurrentBag();
+
+ var dohTasks = dohServers.Select(server =>
+ QueryDohAsync(server, domain, dohResults, cts.Token)).ToList();
+ var dotTasks = dotServers.Select(server =>
+ QueryDotAsync(server, domain, dotResults, cts.Token)).ToList();
+
+ await Task.WhenAll(dohTasks.Concat(dotTasks));
+
+ return (dohResults.ToList(), dotResults.ToList());
+
+ }
+
+ private async Task QueryDohAsync(string server, string domain, ConcurrentBag results, CancellationToken token)
+ {
+ var stopwatch = System.Diagnostics.Stopwatch.StartNew();
+ try
+ {
+ var httpClient = new HttpClient();
+ httpClient.Timeout = TimeSpan.FromSeconds(5);
+ httpClient.DefaultRequestHeaders.Add("Accept", "application/dns-json");
+ // Change type=1 (A record) to type=16 (TXT record)
+ var response = await httpClient.GetAsync($"{server}?name={domain}&type=16", token);
+ response.EnsureSuccessStatusCode();
+ var responseString = await response.Content.ReadAsStringAsync();
+ var json = JsonDocument.Parse(responseString);
+
+ stopwatch.Stop();
+ var elapsedMs = (int)stopwatch.ElapsedMilliseconds;
+
+ if (json.RootElement.TryGetProperty("Answer", out var answers))
+ {
+ foreach (var answer in answers.EnumerateArray())
+ {
+ // For TXT records, the data might be in quotes, so we'll just display it as-is
+ string txtData = answer.GetProperty("data").GetString();
+ string result = $"{server} => {txtData} (耗时: {elapsedMs}ms)";
+ results.Add(result);
+
+ if (elapsedMs < fastestDohResult.time)
+ {
+ fastestDohResult = (server, elapsedMs);
+ }
+ }
+ }
+ else
+ {
+ string result = $"{server} => 无 TXT 记录 (耗时: {elapsedMs}ms)";
+ results.Add(result);
+
+ if (fastestDohResult.result == null || elapsedMs < fastestDohResult.time)
+ {
+ fastestDohResult = (result, elapsedMs);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ stopwatch.Stop();
+ var elapsedMs = (int)stopwatch.ElapsedMilliseconds;
+ string result = $"{server} => 错误: {ex.Message} (耗时: {elapsedMs}ms)";
+ results.Add(result);
+
+ if (fastestDohResult.result == null)
+ {
+ fastestDohResult = (result, elapsedMs);
+ }
+ }
+ }
+
+ private async Task QueryDotAsync(NameServer server, string domain, ConcurrentBag results, CancellationToken token)
+ {
+ var stopwatch = System.Diagnostics.Stopwatch.StartNew();
+ try
+ {
+ using (var cts = CancellationTokenSource.CreateLinkedTokenSource(token))
+ {
+ cts.CancelAfter(TimeSpan.FromSeconds(5));
+
+ using (var tcpClient = new TcpClient())
+ {
+ var connectTask = tcpClient.ConnectAsync(server.Address.ToString(), server.Port);
+ var timeoutTask = Task.Delay(5000, cts.Token);
+
+ if (await Task.WhenAny(connectTask, timeoutTask) == timeoutTask)
+ {
+ throw new TimeoutException("连接超时");
+ }
+
+ using (var sslStream = new SslStream(tcpClient.GetStream(), false,
+ (sender, certificate, chain, sslPolicyErrors) => true))
+ {
+ var authTask = sslStream.AuthenticateAsClientAsync(server.Address.ToString());
+ if (await Task.WhenAny(authTask, timeoutTask) == timeoutTask)
+ {
+ throw new TimeoutException("SSL握手超时");
+ }
+
+ var request = CreateDnsQuery(domain);
+
+ var writeTask = sslStream.WriteAsync(request, 0, request.Length, cts.Token);
+ if (await Task.WhenAny(writeTask, timeoutTask) == timeoutTask)
+ {
+ throw new TimeoutException("写入请求超时");
+ }
+
+ var response = new byte[512];
+
+ var readTask = sslStream.ReadAsync(response, 0, response.Length, cts.Token);
+ if (await Task.WhenAny(readTask, timeoutTask) == timeoutTask)
+ {
+ throw new TimeoutException("读取响应超时");
+ }
+
+ int bytesRead = await readTask;
+ stopwatch.Stop();
+ var elapsedMs = (int)stopwatch.ElapsedMilliseconds;
+
+ var txtRecords = ParseDnsResponse(response, bytesRead);
+ string serverInfo = $"{server.Address}:{server.Port}";
+
+ if (txtRecords.Any())
+ {
+ foreach (var txt in txtRecords)
+ {
+ string result = $"{serverInfo} => {txt} (耗时: {elapsedMs}ms)";
+ results.Add(result);
+
+ if (elapsedMs < fastestDotResult.time)
+ {
+ fastestDotResult = (serverInfo, elapsedMs);
+ }
+ }
+ }
+ else
+ {
+ string result = $"{serverInfo} => 无 TXT 记录 (耗时: {elapsedMs}ms)";
+ results.Add(result);
+ }
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ stopwatch.Stop();
+ var elapsedMs = (int)stopwatch.ElapsedMilliseconds;
+ string serverInfo = $"{server.Address}:{server.Port}";
+ string result = $"{serverInfo} => 错误: {ex.Message} (耗时: {elapsedMs}ms)";
+ results.Add(result);
+ }
+ }
+
+ private byte[] CreateDnsQuery(string domain)
+ {
+ var random = new Random();
+ ushort transactionId = (ushort)random.Next(0, ushort.MaxValue);
+
+ var query = new List();
+
+ // Transaction ID
+ query.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)transactionId)));
+
+ // Flags: standard query (0x0100)
+ query.Add(0x01);
+ query.Add(0x00);
+
+ // Questions: 1
+ query.Add(0x00);
+ query.Add(0x01);
+
+ // Answer RRs: 0
+ query.Add(0x00);
+ query.Add(0x00);
+
+ // Authority RRs: 0
+ query.Add(0x00);
+ query.Add(0x00);
+
+ // Additional RRs: 0
+ query.Add(0x00);
+ query.Add(0x00);
+
+ // Question section
+ var labels = domain.Split('.');
+ foreach (var label in labels)
+ {
+ query.Add((byte)label.Length);
+ query.AddRange(System.Text.Encoding.ASCII.GetBytes(label));
+ }
+ query.Add(0x00); // End of domain name
+
+ // Type TXT (0x0010) instead of A (0x0001)
+ query.Add(0x00);
+ query.Add(0x10);
+
+ // Class IN (0x0001)
+ query.Add(0x00);
+ query.Add(0x01);
+
+ // Prefix length for TLS framing
+ var length = query.Count;
+ var framed = new List
+ {
+ (byte)(length >> 8),
+ (byte)(length & 0xFF)
+ };
+ framed.AddRange(query);
+
+ return framed.ToArray();
+ }
+
+
+ private List ParseDnsResponse(byte[] response, int length)
+ {
+ var txtRecords = new List();
+
+ // Skip TLS length prefix (2 bytes)
+ int offset = 2;
+
+ // Transaction ID (2 bytes) + Flags (2 bytes)
+ offset += 4;
+
+ // Questions
+ int qdCount = (response[offset] << 8) | response[offset + 1];
+ offset += 2;
+
+ // Answer RRs
+ int anCount = (response[offset] << 8) | response[offset + 1];
+ offset += 6; // Skip authority + additional too
+
+ // Skip question section
+ for (int i = 0; i < qdCount; i++)
+ {
+ while (response[offset] != 0)
+ {
+ offset += response[offset] + 1;
+ }
+ offset += 5; // null byte + QTYPE(2) + QCLASS(2)
+ }
+
+ // Parse answer section
+ for (int i = 0; i < anCount; i++)
+ {
+ // Skip name (compressed)
+ offset += 2;
+
+ ushort type = (ushort)((response[offset] << 8) | response[offset + 1]);
+ offset += 8; // TYPE(2) + CLASS(2) + TTL(4)
+
+ ushort dataLength = (ushort)((response[offset] << 8) | response[offset + 1]);
+ offset += 2;
+
+ if (type == 16) // TXT record
+{
+ int end = offset + dataLength;
+ var txtBuilder = new List();
+
+ while (offset < end)
+ {
+ int txtLen = response[offset++];
+ if (offset + txtLen > end) break;
+
+ var txt = System.Text.Encoding.UTF8.GetString(response, offset, txtLen);
+ txtBuilder.Add(txt);
+ offset += txtLen;
+ }
+
+ txtRecords.Add(string.Join("", txtBuilder));
+}
+else
+{
+ offset += dataLength;
+}
+ }
+
+ return txtRecords;
+ }
+
+ private string GetPreferredResult()
+ {
+ // 只返回成功的解析结果
+ string preferredDoh = fastestDohResult.time != int.MaxValue ?
+ fastestDohResult.result : "无可用DoH结果";
+
+ string preferredDot = fastestDotResult.time != int.MaxValue ?
+ fastestDotResult.result : "无可用DoT结果";
+
+ return $"=== 优选结果 ===\n" +
+ $"DoH: {preferredDoh}\n" +
+ $"DoT: {preferredDot}";
+ }
+
+ // 辅助类型定义
+ private enum ResultType { Success, NoRecord, Error }
+
+ private class DnsResult
+ {
+ public ResultType Type { get; set; }
+ public string FullResult { get; set; }
+ public string IP { get; set; }
+ public int Time { get; set; }
+ }
+
+ private async void Start_Button_Click(object sender, EventArgs e)
+ {
+ Select_Text.Clear();
+ Result_Text.Clear();
+ string domain = Domain_Text.Text.Trim();
+
+ if (string.IsNullOrEmpty(domain))
+ {
+ Select_Text.AppendText("请输出正确的域名!\n");
+ return;
+ }
+
+ try
+ {
+ Select_Text.AppendText($"正在查询: {domain}\n");
+ var (dohResults, dotResults) = await GetNotice(domain);
+
+ Select_Text.AppendText("=== DoH 查询结果 ===\n");
+ foreach (var result in dohResults.OrderBy(r => r))
+ {
+ Select_Text.AppendText(result + "\n");
+ }
+
+ Select_Text.AppendText("=== DoT 查询结果 ===\n");
+ foreach (var result in dotResults.OrderBy(r => r))
+ {
+ Select_Text.AppendText(result + "\n");
+ }
+
+ Result_Text.AppendText(GetPreferredResult());
+ }
+ catch (Exception ex)
+ {
+ Select_Text.AppendText($"查询出错: {ex.Message}\n");
+ }
+ }
+
+ private void Exit_Button_Click(object sender, EventArgs e)
+ {
+ this.Close();
+ Application.Exit();
+ }
+ }
+}
diff --git a/DnsClientForm.csproj b/DnsClientForm.csproj
new file mode 100644
index 0000000..29301ff
--- /dev/null
+++ b/DnsClientForm.csproj
@@ -0,0 +1,173 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {8CFA10EB-21BD-4146-BACC-2D143E08D01D}
+ WinExe
+ DnsClient
+ DnsClient
+ v4.7.2
+ 512
+ true
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ packages\DnsClient.1.8.0\lib\net472\DnsClient.dll
+
+
+ packages\DnsClientX.0.3.4\lib\net472\DnsClientX.dll
+
+
+ packages\Microsoft.Bcl.AsyncInterfaces.9.0.3\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll
+
+
+ packages\Microsoft.Win32.Registry.5.0.0\lib\net461\Microsoft.Win32.Registry.dll
+
+
+ packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll
+
+
+
+ packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
+
+
+
+
+ packages\System.IO.4.3.0\lib\net462\System.IO.dll
+ True
+ True
+
+
+ packages\System.IO.Pipelines.9.0.3\lib\net462\System.IO.Pipelines.dll
+
+
+ packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
+
+
+ packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll
+ True
+ True
+
+
+
+ packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
+
+
+ packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll
+ True
+ True
+
+
+ packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
+
+
+ packages\System.Security.AccessControl.5.0.0\lib\net461\System.Security.AccessControl.dll
+
+
+ packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll
+ True
+ True
+
+
+ packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll
+ True
+ True
+
+
+ packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll
+ True
+ True
+
+
+ packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll
+ True
+ True
+
+
+ packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll
+
+
+ packages\System.Text.Encodings.Web.9.0.3\lib\net462\System.Text.Encodings.Web.dll
+
+
+ packages\System.Text.Json.9.0.3\lib\net462\System.Text.Json.dll
+
+
+ packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll
+
+
+ packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+ DnsClientForm.cs
+
+
+
+
+ DnsClientForm.cs
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ True
+ Resources.resx
+
+
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DnsClientForm.resx b/DnsClientForm.resx
new file mode 100644
index 0000000..29dcb1b
--- /dev/null
+++ b/DnsClientForm.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/DnsClientForm.sln b/DnsClientForm.sln
new file mode 100644
index 0000000..130ac35
--- /dev/null
+++ b/DnsClientForm.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.13.35825.156 d17.13
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DnsClientForm", "DnsClientForm.csproj", "{8CFA10EB-21BD-4146-BACC-2D143E08D01D}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8CFA10EB-21BD-4146-BACC-2D143E08D01D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8CFA10EB-21BD-4146-BACC-2D143E08D01D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8CFA10EB-21BD-4146-BACC-2D143E08D01D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8CFA10EB-21BD-4146-BACC-2D143E08D01D}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {A3547717-4913-48FB-A92B-66C04E86FF81}
+ EndGlobalSection
+EndGlobal
diff --git a/DnsClientX.ico b/DnsClientX.ico
new file mode 100644
index 0000000..665c508
Binary files /dev/null and b/DnsClientX.ico differ
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..29f81d8
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..a927c96
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,3 @@
+ARSoft.Tools.Net - C# DNS client/server and SPF Library, Copyright (c) 2010-2017 Alexander Reinert (https://github.com/alexreinert/ARSoft.Tools.Net)
+
+The library uses the Bouncy Castle C# API, Copyright (c) 2000-2016 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org/csharp/)
diff --git a/Program.cs b/Program.cs
new file mode 100644
index 0000000..bd9e449
--- /dev/null
+++ b/Program.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace DnsClient
+{
+ static class Program
+ {
+ ///
+ /// 应用程序的主入口点。
+ ///
+ [STAThread]
+ static void Main()
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ Application.Run(new DnsClientForm());
+ }
+ }
+}
diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..0926d6f
--- /dev/null
+++ b/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("DnsClient")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("DnsClient")]
+[assembly: AssemblyCopyright("Copyright © 2025")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("8cfa10eb-21bd-4146-bacc-2d143e08d01d")]
+
+// 程序集的版本信息由下列四个值组成:
+//
+// 主版本
+// 次版本
+// 生成号
+// 修订号
+//
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..d8e9c7c
--- /dev/null
+++ b/Properties/Resources.Designer.cs
@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+//
+// 此代码由工具生成。
+// 运行时版本: 4.0.30319.42000
+//
+// 对此文件的更改可能导致不正确的行为,如果
+// 重新生成代码,则所做更改将丢失。
+//
+//------------------------------------------------------------------------------
+
+namespace DnsClient.Properties
+{
+
+
+ ///
+ /// 强类型资源类,用于查找本地化字符串等。
+ ///
+ // 此类是由 StronglyTypedResourceBuilder
+ // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
+ // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
+ // (以 /str 作为命令选项),或重新生成 VS 项目。
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources
+ {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources()
+ {
+ }
+
+ ///
+ /// 返回此类使用的缓存 ResourceManager 实例。
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager
+ {
+ get
+ {
+ if ((resourceMan == null))
+ {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DnsClient.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// 重写当前线程的 CurrentUICulture 属性,对
+ /// 使用此强类型资源类的所有资源查找执行重写。
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
+ return resourceCulture;
+ }
+ set
+ {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/Properties/Resources.resx b/Properties/Resources.resx
new file mode 100644
index 0000000..ffecec8
--- /dev/null
+++ b/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..0257ebc
--- /dev/null
+++ b/Properties/Settings.Designer.cs
@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace DnsClient.Properties
+{
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+ {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default
+ {
+ get
+ {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Properties/Settings.settings b/Properties/Settings.settings
new file mode 100644
index 0000000..abf36c5
--- /dev/null
+++ b/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..11cc357
--- /dev/null
+++ b/README.md
@@ -0,0 +1,26 @@
+DoH & DoT
+
+DoH:
+"https://cloudflare-dns.com/dns-query",
+"https://dns.cloudflare.com/dns-query",
+"https://1.1.1.1/dns-query",
+"https://1.0.0.1/dns-query",
+"https://dns.google/resolve",
+"https://sm2.doh.pub/dns-query",
+"https://doh.pub/dns-query",
+"https://dns.alidns.com/resolve",
+"https://223.5.5.5/resolve",
+"https://223.6.6.6/resolve",
+"https://doh.360.cn/resolve"
+
+DoT:
+"101.226.4.6"
+"223.5.5.5"
+"223.6.6.6"
+"1.12.12.12"
+"1.1.1.1"
+"1.0.0.1"
+"8.8.8.8"
+"8.8.4.4"
+"9.9.9.9"
+"149.112.112.112"
\ No newline at end of file
diff --git a/packages.config b/packages.config
new file mode 100644
index 0000000..a55b712
--- /dev/null
+++ b/packages.config
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file