如何获得与System.Net.DNS DNS名称的mxlogging?

.NET库中是否有内置的方法可以返回给定域的所有MXlogging? 我看你如何得到CNAMES,但不是MXlogging。

Alexander Reinert的ARSoft.Tools.Net库似乎做得很好。

它可以从NuGet:

 PM> Install-Package ARSoft.Tools.Net 

导入名称空间:

 using ARSoft.Tools.Net.Dns; 

然后进行同步查找就像下面这样简单:

 var resolver = new DnsStubResolver(); var records = resolver.Resolve<MxRecord>("gmail.com", RecordType.Mx); foreach (var record in records) { Console.WriteLine(record.ExchangeDomainName?.ToString()); } 

这给了我们输出:

 gmail-smtp-in.l.google.com. alt1.gmail-smtp-in.l.google.com. alt2.gmail-smtp-in.l.google.com. alt3.gmail-smtp-in.l.google.com. alt4.gmail-smtp-in.l.google.com. 

在底层,看起来像库可以构build发送到parsing器所需的UDP(或TCP)包,就像你可能期望的那样。 该库甚至具有逻辑(用DnsClient.Default调用)来发现要查询的DNS服务器。

完整的文档可以在这里find。

我花了一整天的时间来弄清楚如何发送/接收DNS请求,并提出了这个问题。 它是一个完整的通用处理器 你只需要设置DNS服务器,并通过'D'例如。 my.website.com?d=itmanx.com

 <%@ WebHandler Language="C#" Class="Handler" %> using System; using System.Web; using System.Text; using System.Net; using System.Net.Sockets; using System.Collections.Generic; public class Handler : IHttpHandler { string dns = "dc1"; //change to your dns string qtype = "15"; //A=1 MX=15 string domain = ""; int[] resp; public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; try { if (context.Request["t"] != null) qtype = context.Request["t"]; if (context.Request["d"] != null) domain = context.Request["d"]; if (string.IsNullOrEmpty(domain)) throw new Exception("Add ?d=<domain name> to url or post data"); Do(context); } catch (Exception ex) { string msg = ex.Message; if (msg == "1") msg = "Malformed packet"; else if (msg == "5") msg = "Refused"; else if (msg == "131") msg = "No such name"; context.Response.Write("Error: " + msg); } } public void Do(HttpContext context) { UdpClient udpc = new UdpClient(dns, 53); // SEND REQUEST-------------------- List<byte> list = new List<byte>(); list.AddRange(new byte[] { 88, 89, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 }); string[] tmp = domain.Split('.'); foreach (string s in tmp) { list.Add(Convert.ToByte(s.Length)); char[] chars = s.ToCharArray(); foreach (char c in chars) list.Add(Convert.ToByte(Convert.ToInt32(c))); } list.AddRange(new byte[] { 0, 0, Convert.ToByte(qtype), 0, 1 }); byte[] req = new byte[list.Count]; for (int i = 0; i < list.Count; i++) { req[i] = list[i]; } udpc.Send(req, req.Length); // RECEIVE RESPONSE-------------- IPEndPoint ep = null; byte[] recv = udpc.Receive(ref ep); udpc.Close(); resp = new int[recv.Length]; for (int i = 0; i < resp.Length; i++) resp[i] = Convert.ToInt32(recv[i]); int status = resp[3]; if (status != 128) throw new Exception(string.Format("{0}", status)); int answers = resp[7]; if (answers == 0) throw new Exception("No results"); int pos = domain.Length + 18; if (qtype == "15") // MX record { while (answers > 0) { int preference = resp[pos + 13]; pos += 14; //offset string str = GetMXRecord(pos, out pos); context.Response.Write(string.Format("{0}: {1}\n", preference, str)); answers--; } } else if (qtype == "1") // A record { while (answers > 0) { pos += 11; //offset string str = GetARecord(ref pos); context.Response.Write(string.Format("{0}\n", str)); answers--; } } } //------------------------------------------------------ private string GetARecord(ref int start) { StringBuilder sb = new StringBuilder(); int len = resp[start]; for (int i = start; i < start + len; i++) { if (sb.Length > 0) sb.Append("."); sb.Append(resp[i + 1]); } start += len + 1; return sb.ToString(); } private string GetMXRecord(int start, out int pos) { StringBuilder sb = new StringBuilder(); int len = resp[start]; while (len > 0) { if (len != 192) { if (sb.Length > 0) sb.Append("."); for (int i = start; i < start + len; i++) sb.Append(Convert.ToChar(resp[i + 1])); start += len + 1; len = resp[start]; } if (len == 192) { int newpos = resp[start + 1]; if (sb.Length > 0) sb.Append("."); sb.Append(GetMXRecord(newpos, out newpos)); start++; break; } } pos = start + 1; return sb.ToString(); } //------------------------------------------------------ public bool IsReusable { get { return false; } } } 

刚刚罗嗦我自己的图书馆,因为没有.net核心/ xplat的支持… https://github.com/MichaCo/DnsClient.NET

它工作得非常好,如果你愿意,可以像日志消息一样dig

简单易用

 var lookup = new LookupClient(); var result = await lookup.QueryAsync("google.com", QueryType.ANY); 

并与运行在任何端口,多个服务器等上的自定义服务器一起工作。

另请参阅DnsClient网站了解更多详情

被接受的答案不适用于.NET框架<4.5,所以build议那些不能使用ARSOFT.Tools的人可以使用来自https://dndns.codeplex.com的; DNDN

下面给出的是一个控制台应用程序,它返回给定域的MXlogging,修改它们的示例。

 using System; using System.Net.Sockets; using DnDns.Enums; using DnDns.Query; using DnDns.Records; namespace DnDnsExamples { class Program { static void Main(string[] args) { DnsQueryRequest request3 = new DnsQueryRequest(); DnsQueryResponse response3 = request3.Resolve("gmail.com", NsType.MX, NsClass.INET, ProtocolType.Tcp); OutputResults(response3); Console.ReadLine(); } private static void OutputResults(DnsQueryResponse response) { foreach (IDnsRecord record in response.Answers) { Console.WriteLine(record.Answer); Console.WriteLine(" |--- RDATA Field Length: " + record.DnsHeader.DataLength); Console.WriteLine(" |--- Name: " + record.DnsHeader.Name); Console.WriteLine(" |--- NS Class: " + record.DnsHeader.NsClass); Console.WriteLine(" |--- NS Type: " + record.DnsHeader.NsType); Console.WriteLine(" |--- TTL: " + record.DnsHeader.TimeToLive); Console.WriteLine(); } } } } 

这里是我只用来查找MXlogging的类。

  using System; using System.Text; using System.Net; using System.Net.Sockets; using System.Collections.Specialized; namespace Mx.Dns { public class Query { //Build a DNS query buffer according to RFC 1035 4.1.1 e 4.1.2 private readonly int id; private readonly int flags; private readonly int QDcount; private readonly int ANcount; private readonly int NScount; private readonly int ARcount; private readonly string Qname; private readonly int Qtype; private readonly int Qclass; public byte[] buf; public Query(int ID, string query, int qtype) { //init vectors with given + default values id = ID; flags = 256; QDcount = 1; ANcount = 0; NScount = 0; ARcount = 0; Qname = query; Qtype = qtype; Qclass = 1; //Internet = IN = 1 //build a buffer with formatted query data //header information (16 bit padding buf = new byte[12 + Qname.Length + 2 + 4]; buf[0] = (byte)(id / 256); buf[1] = (byte)(id - (buf[0] * 256)); buf[2] = (byte)(flags / 256); buf[3] = (byte)(flags - (buf[2] * 256)); buf[4] = (byte)(QDcount / 256); buf[5] = (byte)(QDcount - (buf[4] * 256)); buf[6] = (byte)(ANcount / 256); buf[7] = (byte)(ANcount - (buf[6] * 256)); buf[8] = (byte)(NScount / 256); buf[9] = (byte)(NScount - (buf[8] * 256)); buf[10] = (byte)(ARcount / 256); buf[11] = (byte)(ARcount - (buf[10] * 256)); //QNAME (RFC 1035 4.1.2) //no padding string[] s = Qname.Split('.'); int index = 12; foreach (string str in s) { buf[index] = (byte)str.Length; index++; byte[] buf1 = Encoding.ASCII.GetBytes(str); buf1.CopyTo(buf, index); index += buf1.Length; } //add root domain label (chr(0)) buf[index] = 0; //add Qtype and Qclass (16 bit values) index = buf.Length - 4; buf[index] = (byte)(Qtype / 256); buf[index + 1] = (byte)(Qtype - (buf[index] * 256)); buf[index + 2] = (byte)(Qclass / 256); buf[index + 3] = (byte)(Qclass - (buf[index + 2] * 256)); } } public class C_DNSquery { public StringCollection result = new StringCollection(); public int Error = 0; public string ErrorTxt = "undefined text"; public bool Done = false; public UdpClient udpClient; private string DNS; private string Query; private int Qtype; public bool IS_BLACKLIST_QUERY = false; public C_DNSquery(string IPorDNSname, string query, int type) { DNS = IPorDNSname; Query = query; Qtype = type; } public void doTheJob() { //check if provided DNS contains an IP address or a name IPAddress ipDNS; IPHostEntry he; try { //try to parse an IPaddress ipDNS = IPAddress.Parse(DNS); } catch (FormatException ) { // Console.WriteLine(e); //format error, probably is a FQname, try to resolve it try { //try to resolve the hostname he = Dns.GetHostEntry(DNS); } catch { //Error, invalid server name or address Error = 98; ErrorTxt = "Invalid server name:" + DNS; Done = true; return; } //OK, get the first server address ipDNS = he.AddressList[0]; } //Query the DNS server //our current thread ID is used to match the reply with this process Query myQuery = new Query(System.Threading.Thread.CurrentThread.ManagedThreadId, Query, Qtype); //data buffer for query return value Byte[] recBuf; //use UDP protocol to connect udpClient = new UdpClient(); do { try { //connect to given nameserver, port 53 (DNS) udpClient.Connect(DNS, 53); //send query udpClient.Send(myQuery.buf, myQuery.buf.Length); //IPEndPoint object allow us to read datagrams.. //..selecting only packet coming from our nameserver and port IPEndPoint RemoteIpEndPoint = new IPEndPoint(ipDNS, 53); //Blocks until a message returns on this socket from a remote host. recBuf = udpClient.Receive(ref RemoteIpEndPoint); udpClient.Close(); } catch (Exception e) { //connection error, probably a wrong server address udpClient.Close(); Error = 99; ErrorTxt = e.Message + "(server:" + DNS + ")"; Done = true; return; } //repeat until we get the reply with our threadID } while (System.Threading.Thread.CurrentThread.ManagedThreadId != ((recBuf[0] * 256) + recBuf[1])); //Check the DNS reply //check if bit QR (Query response) is set if (recBuf[2] < 128) { //response byte not set (probably a malformed packet) Error = 2; ErrorTxt = "Query response bit not set"; Done = true; return; } //check if RCODE field is 0 if ((recBuf[3] & 15) > 0) { //DNS server error, invalid reply switch (recBuf[3] & 15) { case 1: Error = 31; ErrorTxt = "Format error. The nameserver was unable to interpret the query"; break; case 2: Error = 32; ErrorTxt = "Server failure. The nameserver was unable to process the query."; break; case 3: Error = 33; ErrorTxt = "Name error. Check provided domain name!!"; break; case 4: Error = 34; ErrorTxt = "Not implemented. The name server does not support the requested query"; break; case 5: Error = 35; ErrorTxt = "Refused. The name server refuses to reply for policy reasons"; break; default: Error = 36; ErrorTxt = "Unknown. The name server error code was: " + Convert.ToString((recBuf[3] & 15)); break; } Done = true; return; } //OK, now we should have valid header fields int QDcnt, ANcnt, NScnt, ARcnt; int index; QDcnt = (recBuf[4] * 256) + recBuf[5]; ANcnt = (recBuf[6] * 256) + recBuf[7]; NScnt = (recBuf[8] * 256) + recBuf[9]; ARcnt = (recBuf[10] * 256) + recBuf[11]; index = 12; //sometimes there are no erros but blank reply... ANcnt == 0... if (ANcnt == 0) { // if blackhole list query, means no spammer !!//if ((ANcnt == 0) & (IS_BLACKLIST_QUERY == false)) //error blank reply, return an empty array Error = 4; ErrorTxt = "Empty string array"; Done = true; return; } //Decode received information string s1; // START TEST s1 = Encoding.ASCII.GetString(recBuf, 0, recBuf.Length); // END TEST if (QDcnt > 0) { //we are not really interested to this string, just parse and skip s1 = ""; index = parseString(recBuf, index, out s1); index += 4; //skip root domain, Qtype and QClass values... unuseful in this contest } if (IS_BLACKLIST_QUERY) { // get the answers, normally one ! // int the four last bytes there is the ip address Error = 0; int Last_Position = recBuf.Length - 1; result.Add(recBuf[Last_Position - 3].ToString() + "." + recBuf[Last_Position - 2].ToString() + "." + recBuf[Last_Position - 1].ToString() + "." + recBuf[Last_Position].ToString()); Done = true; return; } int count = 0; //get all answers while (count < ANcnt) { s1 = ""; index = parseString(recBuf, index, out s1); //Qtype int QType = (recBuf[index] * 256) + recBuf[index + 1]; index += 2; s1 += "," + QType.ToString(); //QClass int QClass = (recBuf[index] * 256) + recBuf[index + 1]; index += 2; s1 += "," + QClass.ToString(); //TTL (Time to live) int TTL = (recBuf[index] * 16777216) + (recBuf[index + 1] * 65536) + (recBuf[index + 2] * 256) + recBuf[index + 3]; index += 4; s1 += "," + TTL.ToString(); int blocklen = (recBuf[index] * 256) + recBuf[index + 1]; index += 2; if (QType == 15) { int MXprio = (recBuf[index] * 256) + recBuf[index + 1]; index += 2; s1 += "," + MXprio.ToString(); } string s2; index = parseString(recBuf, index, out s2); s1 += "," + s2; result.Add(s1); count++; } Error = 0; Done = true; } private int parseString(byte[] buf, int i, out string s) { int len; s = ""; bool end = false; while (!end) { if (buf[i] == 192) { //next byte is a pointer to the string, get it.. i++; s += getString(buf, buf[i]); i++; end = true; } else { //next byte is the string length len = buf[i]; i++; //get the string s += Encoding.ASCII.GetString(buf, i, len); i += len; //check for the null terminator if (buf[i] != 0) { //not null, add a point to the name s += "."; } else { //null char..the string is complete, exit end = true; i++; } } } return i; } private string getString(byte[] buf, int i) { string s = ""; int len; bool end = false; while (!end) { len = buf[i]; i++; s += Encoding.ASCII.GetString(buf, i, len); i += len; if (buf[i] == 192) { i++; s += "." + getString(buf, buf[i]); return s; } if (buf[i] != 0) { s += "."; } else { end = true; } } return s; } } } 

这是你如何使用它。

 /// <summary> /// Get the MX from the domain address. /// </summary> public static string getMXrecord(string domain) { domain = domain.Substring(domain.IndexOf('@') + 1); string LocalDNS = GetDnsAdress().ToString(); Console.WriteLine("domain: " + domain); // resolv the authoritative domain (type=2) C_DNSquery DnsQry = new C_DNSquery(LocalDNS, domain, 2); Thread t1 = new Thread(new ThreadStart(DnsQry.doTheJob)); t1.Start(); int timeout = 20; while ((timeout > 0) & (!DnsQry.Done)) { Thread.Sleep(100); timeout--; } if (timeout == 0) { if (DnsQry.udpClient != null) { DnsQry.udpClient.Close(); } t1.Abort(); DnsQry.Error = 100; } string[] ns1; string MyNs = ""; if (DnsQry.Error == 0) { ns1 = DnsQry.result[0].Split(','); MyNs = ns1[4]; t1.Abort(); } else { t1.Abort(); MyNs = LocalDNS; } // Resolve MX (type = 15) DnsQry = new C_DNSquery(MyNs, domain, 15); Thread t2 = new Thread(new ThreadStart(DnsQry.doTheJob)); t2.Start(); timeout = 20; string TTL = ""; string MXName = ""; Int32 preference = 9910000; while ((timeout > 0) & (!DnsQry.Done)) { Thread.Sleep(100); timeout--; } if (timeout == 0) { if (DnsQry.udpClient != null) { DnsQry.udpClient.Close(); } t2.Abort(); DnsQry.Error = 100; } if (DnsQry.Error == 0) { if (DnsQry.result.Count == 1) { string[] ns2 = DnsQry.result[0].Split(','); MXName = ns2[5]; TTL = ns2[3]; preference = Int32.Parse(ns2[4]); Console.WriteLine("domaine: {0} MX: {1} time: {2} pref: {3} ttl: {4}", domain.Substring(domain.IndexOf('@') + 1), MXName, DateTime.Now, preference, TTL); } else { for (int indns = 0; indns <= DnsQry.result.Count - 1; indns++) { string[] ns2 = DnsQry.result[indns].Split(','); if (Int32.Parse(ns2[4]) < preference) { MXName = ns2[5]; TTL = ns2[3]; preference = Int32.Parse(ns2[4]); Console.WriteLine("domain: {0} MX: {1} time: {2} pref: {3} ttl: {4}", domain.Substring(domain.IndexOf('@') + 1), MXName, DateTime.Now, preference, TTL); } } } } return MXName; } 

我的方法是使用nslookup.exe来检索MXlogging。

该解决scheme不像重写整个DNS或使用系统DLL那样花哨 – >但它可以工作,只需less量的行数。

为了使事情正确,这个代码>正常工作<它不是有效而且快速的资源,并且有很大的改进空间(多个主机名,asynchronous,更有用的返回值,添加优先级):

 static List<string> GetMxRecords(string host){ ProcessStartInfo nslookup_config = new ProcessStartInfo("nslookup.exe"); nslookup_config.RedirectStandardInput = true; nslookup_config.RedirectStandardOutput = true; nslookup_config.RedirectStandardError = true; nslookup_config.UseShellExecute = false; var nslookup = Process.Start(nslookup_config); nslookup.StandardInput.WriteLine("set q=mx"); nslookup.StandardInput.WriteLine(host); nslookup.StandardInput.WriteLine("exit"); List<string> lines = new List<string>(); while (!nslookup.StandardOutput.EndOfStream) { string l = nslookup.StandardOutput.ReadLine(); if (l.Contains("internet address =")) { while (l.Contains("\t\t")) { l = l.Replace("\t\t", "\t"); } lines.Add(l.Replace("\tinternet address = ","=")); } } nslookup.Close(); } 

应该是国际性的,因为nslookup不支持任何翻译(我正在德国的机器上工作,我得到英文输出)。

结果是这样的string:

 alt4.gmail-smtp-in.l.google.com=74.125.28.27 alt2.gmail-smtp-in.l.google.com=74.125.200.27 alt1.gmail-smtp-in.l.google.com=209.85.233.26 gmail-smtp-in.l.google.com=66.102.1.27 alt3.gmail-smtp-in.l.google.com=108.177.97.27 

你可以使用这个开源库来做几乎任何你通常需要的查询。

用法:

 DnsClient dnsClient = new DnsClient(); string mxDomain = dnsClient.ResolveMX("example.com"); string mxDomainIP = dnsClient.ResolveMX("example.com", true); string mxDomainIPv6 = dnsClient.ResolveMX("example.com", true, true);