我想知道是否有办法强制System.Net.Dns类使用一组自定义DNS服务器来解析主机名,而不是使用与主网络连接相关联的服务器。
我怀疑这只能使用像DnDns(http://dndns.codeplex.com)之类的自定义库,但我希望这可以在.NET中完成。
答案 0 :(得分:11)
使用.Net Framework无法做到这一点。 Dns.Resolve方法依赖于内部Win32 API,后者又通过与网络连接关联的DNS服务器。
为了使其正常工作,您必须更改与网络适配器地址关联的DNS服务器。
答案 1 :(得分:2)
在.net标准中测试:
public static async Task<IPHostEntry> GetHostEntryAsync(string host, string dns = null)
{
if (string.IsNullOrEmpty(host))
{
return null;
}
//Check if any cached result exists
Tuple<string, string> key = new Tuple<string, string>(host, dns);
if (NetHelper._dnsCache.TryGetValue(key, out Tuple<IPHostEntry, DateTime> record) && record.Item2 > DateTime.Now)
{
return record.Item1;
}
//Check dns server's address or port
IPHostEntry result = null;
int dnsPort;
if (dns != null)
{
string[] blocks = dns.Split(':');
if (blocks.Length == 2 && int.TryParse(blocks[1], out dnsPort))//dns is ip v4
{
dns = blocks[0];
}
else if (blocks.Length == 9 && int.TryParse(blocks[8], out dnsPort))//dns is ip v6
{
blocks[0] = blocks[0].TrimStart('[');
blocks[7] = blocks[7].TrimStart(']');
dns = string.Format("{0}:{1}:{2}:{3}:{4}:{5}:{6}:{7}", blocks);
}
else
{
dnsPort = 53;
}
}
else
{
dnsPort = 53;
}
//Check if host is ip address
if (host[0] == '[' && host[host.Length - 1] == ']')//IPV6 address
{
host = host.Substring(1, host.Length - 2);
}
if (IPAddress.TryParse(host, out IPAddress address))
{
result = new IPHostEntry { AddressList = new IPAddress[] { address } };
}
else if (string.IsNullOrEmpty(dns))
{
result = await Dns.GetHostEntryAsync(host);
}
else
{
#region Resolve with customized dns server
IPAddress dnsAddr;
if (!IPAddress.TryParse(dns, out dnsAddr))
{
throw new ArgumentException("The dns host must be ip address.", nameof(dns));
}
using (MemoryStream ms = new MemoryStream())
{
Random rnd = new Random();
//About the dns message:http://www.ietf.org/rfc/rfc1035.txt
//Write message header.
ms.Write(new byte[] {
(byte)rnd.Next(0, 0xFF),(byte)rnd.Next(0, 0xFF),
0x01,
0x00,
0x00,0x01,
0x00,0x00,
0x00,0x00,
0x00,0x00
}, 0, 12);
//Write the host to query.
foreach (string block in host.Split('.'))
{
byte[] data = Encoding.UTF8.GetBytes(block);
ms.WriteByte((byte)data.Length);
ms.Write(data, 0, data.Length);
}
ms.WriteByte(0);//The end of query, muest 0(null string)
//Query type:A
ms.WriteByte(0x00);
ms.WriteByte(0x01);
//Query class:IN
ms.WriteByte(0x00);
ms.WriteByte(0x01);
Socket socket = new Socket(SocketType.Dgram, ProtocolType.Udp);
try
{
//send to dns server
byte[] buffer = ms.ToArray();
while (socket.SendTo(buffer, 0, buffer.Length, SocketFlags.None, new IPEndPoint(dnsAddr, dnsPort)) < buffer.Length) ;
buffer = new byte[0x100];
EndPoint ep = socket.LocalEndPoint;
int num = socket.ReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref ep);
//The response message has the same header and question structure, so we move index to the answer part directly.
int index = (int)ms.Length;
//Parse response records.
void SkipName()
{
while (index < num)
{
int length = buffer[index++];
if (length == 0)
{
break;
}
else if (length > 191)
{
return;
}
index += length;
}
}
List<IPAddress> addresses = new List<IPAddress>();
while (index < num)
{
SkipName();//Seems the name of record is useless in this scense, so we just needs to get the next index after name.
byte type = buffer[index += 2];
index += 7;//Skip class and ttl
int length = buffer[index++] << 8 | buffer[index++];//Get record data's length
if (type == 0x01)//A record
{
if (length == 4)//Parse record data to ip v4, this is what we need.
{
addresses.Add(new IPAddress(new byte[] { buffer[index], buffer[index + 1], buffer[index + 2], buffer[index + 3] }));
}
}
index += length;
}
result = new IPHostEntry { AddressList = addresses.ToArray() };
}
finally
{
socket.Dispose();
}
}
#endregion
}
//Cache and return result
NetHelper._dnsCache[key] = new Tuple<IPHostEntry, DateTime>(result, DateTime.Now.AddMinutes(15));
#pragma warning disable CS4014
Task.Run(async () =>
{
await Task.Delay((int)TimeSpan.FromMinutes(15).TotalMilliseconds);
NetHelper._dnsCache.Remove(key);
});
#pragma warning restore CS4014
return result;
}
答案 2 :(得分:1)
您可以使用“JH Software的.NET Client for .NET”执行此操作 - 而无需更改DNS本地服务器。 请参阅http://www.simpledns.com/dns-client-lib.aspx
上的第二个代码示例答案 3 :(得分:0)
如果您能够在docker容器中运行应用程序,则可以在启动时提供dns服务器IP地址。
docker run --dns=1.2.3.4 repo/myimage command.exe
https://docs.docker.com/v17.09/engine/userguide/networking/configure-dns/