用c#编写的简单DNS服务器
转自:http://blog.csdn.net/skytouchzyt/article/details/7342224
目前只处理 A 类型的请求,其他一律转发给公共DNS服务器.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.IO; using Tools; namespace DNSProxy { /// <summary> /// DNS代理服务器 /// </summary> class Proxy { private Socket server; private TaskFactory tf = new TaskFactory(); private ListBox box; private Dictionary<string, byte[]> cache = new Dictionary<string, byte[]>(); public Proxy() { server=new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp); server.Bind(new IPEndPoint(IPAddress.Any,53)); var DNSServer = new IPEndPoint(IPAddress.Parse("202.106.0.20"), 53);//公共DNS服务器IP tf.StartNew(() => { while (true) { try { var client = (EndPoint)new IPEndPoint(IPAddress.Any, 0); var buff = new byte[512]; int read = server.ReceiveFrom(buff, ref client); tf.StartNew( () => { var dns = new DNS(buff, read); //只处理A 类请求 if (dns.QR == 0 && dns.opcode == 0 && dns.Querys.Count == 1 && dns.Querys[0].QueryType == QueryType.A) { var queryName = dns.Querys[0].QueryName;//要查询的域名 if (queryName == "www.csdn.net") //重定向csdn,嘿嘿 { var subname = queryName.Substring(0, queryName.Length - ".donata.cn".Length); var ip = new byte[4]{127,0,0,1}; //返回IP:127.0.0.1 //DisplayString(string.Format("{0}==>{1}", queryName, new IPAddress(ip))); dns.QR = 1; dns.RA = 1; dns.RD = 1; dns.ResouceRecords = new List<ResouceRecord>{ new ResouceRecord{ Datas=ip, TTL=100, QueryClass=1, QueryType=QueryType.A } }; server.SendTo(dns.ToBytes(), client); return; } } tf.StartNew( () => { try { var proxy = new UdpClient(); proxy.Client.ReceiveTimeout = 5000; proxy.Connect(DNSServer); proxy.Send(buff, read); var bytes = proxy.Receive(ref DNSServer); //bytes.ToHexString().Log(); server.SendTo(bytes, client); } catch { } } ); }); } catch { } } } ); } } public enum QueryType { A=1, NS=2, CNAME=5, PTR=12, HINFO=13, MX=15, AXFR=252, ANY=255 } public class Query { public string QueryName { get; set; } public QueryType QueryType { get; set; } public Int16 QueryClass { get; set; } public Query() { } public Query(Func<int,byte[]> read) { var name = new StringBuilder(); var length = read(1)[0]; while (length != 0) { for (var i = 0; i < length; i++) { name.Append((char)read(1)[0]); } length = read(1)[0]; if (length != 0) name.Append("."); } QueryName=name.ToString(); QueryType = (QueryType)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(read(2), 0)); QueryClass = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(read(2), 0)); } public virtual byte[] ToBytes() { var list = new List<byte>(); var a = QueryName.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries); for (var i = 0; i < a.Length; i++) { list.Add((byte)a[i].Length); for (var j = 0; j < a[i].Length; j++) list.Add((byte)a[i][j]); } list.Add(0); list.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((Int16)QueryType))); list.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(QueryClass))); return list.ToArray(); } } public class ResouceRecord:Query { public Int16 Point { get; set; } public Int32 TTL { get; set; } public byte[] Datas { get; set; } public ResouceRecord():base() { var bytes = new byte[] { 0xc0, 0x0c }; Point = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, 0)); } public ResouceRecord(Func<int, byte[]> read):base() { TTL = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(read(4), 0)); var length = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(read(2), 0)); Datas = read(length); } public override byte[] ToBytes() { var list = new List<byte>(); list.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(Point))); list.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((Int16)QueryType))); list.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(QueryClass))); list.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(TTL))); list.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((Int16)Datas.Length))); list.AddRange(Datas); return list.ToArray(); } } public class DNS { public Int16 标志 { get;set; } public int QR { get; set; } //0表示查询报文 1表示响应报文 public int opcode { get;set; } //0表示标准查询,1表示反向查询,2表示服务器状态请求 public int AA { get; set; } //授权回答 public int TC { get; set; } //表示可截断的 public int RD { get; set; } //表示期望递归 public int RA { get; set; } //表示可用递归 public int rcode { get;set; } //0表示没有错误,3表示名字错误 public List<Query> Querys { get;set; } //问题数 public List<ResouceRecord> ResouceRecords { get;set; } //资源记录数 public Int16 授权资源记录数 { get;set; } public Int16 额外资源记录数 { get;set; } public byte[] ToBytes() { var list = new List<byte>(); var bytes=BitConverter.GetBytes(IPAddress.HostToNetworkOrder(标志)); list.AddRange(bytes); var b = new byte(); b = b.SetBits(QR, 0, 1) .SetBits(opcode, 1, 4) .SetBits(AA, 5, 1) .SetBits(TC, 6, 1); b=b.SetBits(RD, 7, 1); list.Add(b); b = new byte(); b = b.SetBits(RA, 0, 1) .SetBits(0, 1, 3) .SetBits(rcode,4,4); list.Add(b); list.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((Int16)Querys.Count))); list.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((Int16)ResouceRecords.Count))); list.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(授权资源记录数))); list.AddRange(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(额外资源记录数))); foreach (var q in Querys) { list.AddRange(q.ToBytes()); } foreach (var r in ResouceRecords) { list.AddRange(r.ToBytes()); } return list.ToArray(); } private int index; private byte[] package; private byte ReadByte() { return package[index++]; } private byte[] ReadBytes(int count = 1) { var bytes = new byte[count]; for (var i = 0; i < count; i++) bytes[i] = ReadByte(); return bytes; } public DNS(byte[] buffer,int length) { package = new byte[length]; for (var i = 0; i < length; i++) package[i] = buffer[i]; 标志 = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(ReadBytes(2), 0)); var b1 = ReadByte(); var b2 = ReadByte(); QR = b1.GetBits(0, 1); opcode = b1.GetBits(1, 4); AA = b1.GetBits(5, 1); TC = b1.GetBits(6, 1); RD = b1.GetBits(7, 1); RA = b2.GetBits(0, 1); rcode = b2.GetBits(4, 4); var queryCount = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(ReadBytes(2), 0)); var rrCount = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(ReadBytes(2), 0)); 授权资源记录数 = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(ReadBytes(2), 0)); 额外资源记录数 = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(ReadBytes(2), 0)); Querys = new List<Query>(); for (var i = 0; i < queryCount; i++) { Querys.Add(new Query(ReadBytes)); } for (var i = 0; i < rrCount; i++) { ResouceRecords.Add(new ResouceRecord(ReadBytes)); } } } public static class Extension { public static int GetBits(this byte b, int start, int length) { var temp=b>>(8-start-length); var mask = 0; for (var i = 0; i < length; i++) { mask = (mask << 1) + 1; } return temp & mask; } public static byte SetBits(this byte b, int data,int start, int length) { var temp = b; var mask = 0xFF; for (var i = 0; i < length; i++) { mask = mask - (0x01 << (7 - (start + i))); } temp = (byte)(temp & mask); mask = ((byte)data).GetBits(8-length, length); mask = mask << (7 - start); return (byte)(temp | mask); } public static string ToBinaryString(this byte b) { var sb = new StringBuilder(); for (var i = 0; i < 8; i++) { if (i % 4 == 0) sb.Append(" "); var bit = b.GetBits(i, 1); sb.Append(bit); } return sb.ToString(); } public static string BinaryString(this int b) { var sb = new StringBuilder(); for (var i = 15; i >= 0; i--) sb.Append((b >> i) & 0x01); return sb.ToString(); } public static string ToHexString(this IEnumerable<byte> bytes) { var sb = new StringBuilder(); foreach (var b in bytes) { sb.Append(string.Format("{0:x2}({1}) ", b,(char)b)); } return sb.ToString(); } /// <summary> /// 日志文件保存到d:\donata\log文件夹,每天保存一个文件 /// </summary> /// <param name="log"></param> public static void Log(this string log) { try { var logfie = "d:\\dns.txt"; if (!File.Exists(logfie)) { File.Create(logfie).Close(); } using (var sw = File.AppendText(logfie)) { sw.WriteLine(log); } } catch { } } } }
运行程序,把网络协议中的DNS改为127.0.0.1,如果ping www.csdn.net,如果给出的地址是127.0.0.1,说明有效果
本文出自 小古Blog,转载时请注明出处及相应链接。
本文永久链接: http://blog.chdz1.com/?post=207