How to get mx records for a dns name with System.Net.DNS?

前端 未结 7 1299
难免孤独
难免孤独 2020-11-29 00:34

Is there any built in method in the .NET library that will return all of the MX records for a given domain? I see how you get CNAMES, but not MX records.

7条回答
  •  情歌与酒
    2020-11-29 01:09

    Here is a Class I use to look up MX records only.

        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)
                    uint TTL = (recBuf[index] * 16777216u) + (recBuf[index + 1] * 65536u) + (recBuf[index + 2] * 256u) + 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;
            }
        }
    }
    

    Here is how you use it.

    /// 
            /// Get the MX from the domain address.
            /// 
            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;
            }
            
    

提交回复
热议问题