小古Blog
用c#编写的简单DNS服务器
2013-10-5 小古


转自: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,说明有效果
发表评论:
昵称

邮件地址 (选填)

个人主页 (选填)

内容