c#编写一个dns服务
一、什么是DNS
域名系统(DNS)是因特网的电话簿。人类通过域名在线访问信息,如baidu.com或bfw.wiki。Web浏览器通过Internet协议(IP)地址进行交互。DNS将域名转换为IP地址,以便浏览器可以加载Internet资源。
连接到Internet的每个设备都有一个唯一的IP地址,其他计算机可以使用该IP地址来查找设备。DNS服务器无需人类记忆IP地址,如192.168.1.1(在IPv4中),或更复杂的新字母数字IP地址,如2400:cb00:2048:1 :: c629:d7a2(在IPv6中)。
也就是说dns服务器充当的是翻译的工作,将人类易理解的域名转换成机器能理解的ip地址,方便进行资源的加载,如下图
二、DNS报文的构成
DNS占用53号端口,同时使用TCP和UDP协议。DNS在区域传输的时候使用TCP协议,其他时候使用UDP协议。DNS区域传输的时候使用TCP协议:
1.辅域名服务器会定时(一般3小时)向主域名服务器进行查询以便了解数据是否有变动。如有变动,会执行一次区域传送,进行数据同步。区域传送使用TCP而不是UDP,因为数据同步传送的数据量比一个请求应答的数据量要多得多。
2.TCP是一种可靠连接,保证了数据的准确性。
域名解析时使用UDP协议:
客户端向DNS服务器查询域名,一般返回的内容都不超过512字节,用UDP传输即可。不用经过三次握手,这样DNS服务器负载更低,响应更快。理论上说,客户端也可以指定向DNS服务器查询时用TCP,但事实上,很多DNS服务器进行配置的时候,仅支持UDP查询包。
三、c#代码实现
今天使用的是ARSoft.Tools.Net这个动态库,他已经实现了dns的报文解析及发送,我们将他引入项目中using System; using System.Collections.Generic; using System.Text; using System.Threading; using ARSoft.Tools.Net.Dns; using System.Net; namespace Bo { class Program { static void Main(string[] args) { using (DnsServer server = new DnsServer(IPAddress.Any, 10, 10, ProcessQuery)) { server.Start(); Console.WriteLine("Press any key to stop server"); Console.ReadLine(); } } public static IPAddress ClientQuery(string domain) { IPAddress Ip = null; DnsMessage dnsMessage = DnsClient.Default.Resolve(domain, RecordType.A); if ((dnsMessage == null) || ((dnsMessage.ReturnCode != ReturnCode.NoError) && (dnsMessage.ReturnCode != ReturnCode.NxDomain))) { Console.WriteLine("DNS request failed"); } else { foreach (DnsRecordBase dnsRecord in dnsMessage.AnswerRecords) { ARecord aRecord = dnsRecord as ARecord; if (aRecord != null) { Ip = aRecord.Address; Console.WriteLine("DNS request successfully : {0}", aRecord.Address.ToString()); } } } return Ip; } static DnsMessageBase ProcessQuery(DnsMessageBase message, IPAddress clientAddress, System.Net.Sockets.ProtocolType protocol) { message.IsQuery = false; DnsMessage query = message as DnsMessage; // 官方的样例文档中没有体现DNS请求发起者的IP,我在这里增加了。 Console.WriteLine("Client Address:{0}", clientAddress.ToString()); Console.WriteLine("query.Questions.Count:{0}", query.Questions.Count); Console.WriteLine("query.Questions.ToString():{0}", query.Questions.ToString()); Console.WriteLine("query.Questions[0].ToString():{0}", query.Questions[0].ToString()); Console.WriteLine("query.Questions[0].GetType():{0}", query.Questions[0].GetType().ToString()); Console.WriteLine("query.Questions[0].Name:{0}", query.Questions[0].Name.ToString()); Console.WriteLine("query.Questions[0].RecordType:{0}", query.Questions[0].RecordType.ToString()); Console.WriteLine("query.Questions[0].RecordClass {0}", query.Questions[0].RecordClass.ToString()); if (query.Questions[0].Name.Contains("www.jd.com")) { Console.WriteLine("Contains jd.com"); query.AnswerRecords.Add(new ARecord("www.jd.com", 3600, IPAddress.Parse("112.82.246.51"))); message.ReturnCode = ReturnCode.NoError; return message; } else { Console.WriteLine("local not ,go to server found"); IPAddress Ip = ClientQuery(query.Questions[0].Name); if (Ip != null) { query.AnswerRecords.Add(new ARecord(query.Questions[0].Name, 3600, Ip)); message.ReturnCode = ReturnCode.NoError; } else { message.ReturnCode = ReturnCode.ServerFailure; } //message.ReturnCode = ReturnCode.ServerFailure; // Console.WriteLine(message.ReturnCode.ToString()); return message; } } } }这里我们增加了一条记录,将jd.coim的域名指向了一台服务器ip,当客户进行请求的时候我们可以直接返回地址,其他的域名请求我们直接去查询上级域名服务器,将返回的结果再返回给客户端,相当于dns劫持的效果
下面我们模拟一下客户端的域名解析请求
using System; using System.Collections.Generic; using System.Text; using ARSoft.Tools.Net.Dns; namespace BoDnsClient { class Program { static void Main(string[] args) { ClientQuery("jd.com"); Console.ReadKey(); } public static void ClientQuery(string domain) { DnsMessage dnsMessage = DnsClient.Default.Resolve(domain, RecordType.A); if ((dnsMessage == null) || ((dnsMessage.ReturnCode != ReturnCode.NoError) && (dnsMessage.ReturnCode != ReturnCode.NxDomain))) { Console.WriteLine("DNS request failed"); } else { foreach (DnsRecordBase dnsRecord in dnsMessage.AnswerRecords) { ARecord aRecord = dnsRecord as ARecord; if (aRecord != null) { Console.WriteLine("DNS request successfully : {0}", aRecord.Address.ToString()); } } } } } }ok,这样就实现了,这个项目的源码大家可以下载,直接运行
网友评论0