用c#编写的简单DNS服务器

作者: 小古 分类: C# NET技术 发布时间: 2013-10-5 ė14835 次浏览 60 条评论

转自: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

|

发表评论:

电子邮件地址不会被公开。 必填项已用*标注

Ɣ回顶部
sitemap