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