예제 #1
0
        //static byte[] queryID = new byte[2];

        /// <summary>
        ///  Uses host OS's APIs to resolve a hostname (Dns.GetHostAddress()) or an IP address(Dns.GetHostEntry()).
        /// </summary>
        public static (string hostname, IPAddress[] ips, QTYPE qTYPE) OSResolver(string name)
        {
            string hostname;

            IPAddress[] ips;
            QTYPE       qTYPE = 0;

            // if name is an IPAddress, do a PTR query
            if (IPAddress.TryParse(name, out IPAddress ip))
            {
                IPHostEntry entry = Dns.GetHostEntry(ip);
                hostname = entry.HostName;
                ips      = new IPAddress[] { ip };
                qTYPE    = QTYPE.PTR;
            }
            else // if name is a hostname
            {
                hostname = name;
                ips      = Dns.GetHostAddresses(name);
                foreach (IPAddress address in ips)
                {
                    if (address.AddressFamily == AddressFamily.InterNetwork)
                    {
                        qTYPE |= QTYPE.A;
                    }
                    else
                    {
                        qTYPE |= QTYPE.AAAA;
                    }
                }
            }

            return(hostname, ips, qTYPE);
        }
예제 #2
0
파일: Resolver.cs 프로젝트: queueit/Dns
        /// <summary>
        /// Query and get a resource record on specified DNS Server.
        /// </summary>
        /// <param name="host">The name of host to query.</param>
        /// <param name="qType">The QTYPE to use</param>
        /// <param name="qClass">The QCLASS to use</param>
        /// <returns>Return an asynchronsous operation.</returns>
        public Task <IResponse> QueryAsync(string host, QTYPE qType, QCLASS qClass)
        {
            var question = new Question(host, qType, qClass);
            var request  = new Request()
            {
                Retries    = this.Retries,
                DnsServers = this._dnsServers,
                Timeout    = this.Timeout
            };
            var id = (ushort)Interlocked.Increment(ref _uid);

            request.Header.ID = id;
            request.Header.RD = this.Recursion;
            request.AddQuestion(question);
            DnsChannel channel = null;

            if (_transportType == TransportType.Tcp)
            {
                channel = new TcpChannel(request);
            }
            else
            {
                channel = new UdpChannel(request);
            }
            return(channel.GetResponseAsync(_dnsServers[0]));
        }
예제 #3
0
        /// <summary>
        ///  DNS over HTTPS using JSON format.
        ///  Returns HTTPS response body and parsed Json class.
        ///  Throws HttpRequestException.
        /// </summary>
        public static (string responseBody, DoHResponse doHResponse) DoHJson
        (
            string name,
            string dns  = "https://cloudflare-dns.com/dns-query",
            QTYPE qTYPE = QTYPE.A,
            bool dnssec = true
        )
        {
            // make query URI
            StringBuilder queryURI = new StringBuilder(dns, 256);

            queryURI.Append($"?name={name}&type={qTYPE}");
            if (dnssec)
            {
                queryURI.Append($"&do=true");
            }
            // init HttpClient and send query
            HttpClient client = new HttpClient();

            client.Timeout = TimeSpan.FromSeconds(10);
            client.DefaultRequestHeaders.Add("Accept", "application/dns-json");
            client.DefaultRequestVersion = HttpVersion.Version20;

            string      responseBody = client.GetStringAsync(queryURI.ToString()).Result;
            DoHResponse doHResponse  = JsonSerializer.Deserialize <DoHResponse>(responseBody);

            return(responseBody, doHResponse);
        }
 /// <summary>
 /// Default constructor.
 /// </summary>
 public Dns_Answer(string name,QTYPE qType,int rdClass,int ttl,int rdLength,object answerObj)
 {
     m_NAME      = name;
     m_QTYPE     = qType;
     m_CLASS     = rdClass;
     m_TTL       = ttl;
     m_RDLENGTH  = rdLength;
     m_AnswerObj = answerObj;
 }
예제 #5
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 public Dns_Answer(string name, QTYPE qType, int rdClass, int ttl, int rdLength, object answerObj)
 {
     m_NAME      = name;
     m_QTYPE     = qType;
     m_CLASS     = rdClass;
     m_TTL       = ttl;
     m_RDLENGTH  = rdLength;
     m_AnswerObj = answerObj;
 }
예제 #6
0
        /// <summary>
        /// Initialize a new DNS question using QCLASS IN.
        /// </summary>
        /// <param name="qname">A domain name represented as a sequence of labels.</param>
        /// <param name="qtype">A two octet code which specifies the type of the query.</param>
        public Question(string qname, QTYPE qtype)
        {
            if (String.IsNullOrEmpty(qname))
            throw new ArgumentNullException("qname", "Value cannot be null or empty.");

              this.QNAME = qname;
              this.QTYPE = qtype;
              this.QCLASS = DNS.QCLASS.IN;
        }
예제 #7
0
 public QuestionRecord(string n, QTYPE t, RCLASS c)
 {
     if (n.Length > 256)
     {
         throw new MalformedRecord();
     }
     this.name   = n;
     this._type  = t;
     this._class = c;
 }
예제 #8
0
파일: Question.cs 프로젝트: Moerty/dnstools
        /// <summary>
        /// Initialize a new DNS question using QCLASS IN.
        /// </summary>
        /// <param name="qname">A domain name represented as a sequence of labels.</param>
        /// <param name="qtype">A two octet code which specifies the type of the query.</param>
        public Question(string qname, QTYPE qtype)
        {
            if (String.IsNullOrEmpty(qname))
            {
                throw new ArgumentNullException("qname", "Value cannot be null or empty.");
            }

            this.QNAME  = qname;
            this.QTYPE  = qtype;
            this.QCLASS = DNS.QCLASS.IN;
        }
예제 #9
0
        public override int GetHashCode()
        {
            return(0);

            unchecked
            {
                var hashCode = (QNAME != null ? QNAME.GetHashCode() : 0);
                hashCode = (hashCode * 397) ^ QTYPE.GetHashCode();
                hashCode = (hashCode * 397) ^ QCLASS.GetHashCode();
                return(hashCode);
            }
        }
        /// <summary>
        /// Filters out specified type of records from answer.
        /// </summary>
        /// <param name="answers"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        private List<DNS_rr_base> FilterRecordsX(List<DNS_rr_base> answers, QTYPE type)
        {
            List<DNS_rr_base> retVal = new List<DNS_rr_base>();
            foreach (DNS_rr_base record in answers)
            {
                if (record.RecordType == type)
                {
                    retVal.Add(record);
                }
            }

            return retVal;
        }
예제 #11
0
        /// <summary>
        /// Sends query to server.
        /// </summary>
        /// <param name="timeout">Query timeout in milli seconds.</param>
        /// <param name="qname">Query text.</param>
        /// <param name="qtype">Query type.</param>
        /// <param name="qclass">Query class.</param>
        /// <returns>Returns DNS server response.</returns>
        private DnsServerResponse QueryServer(int timeout, string qname, QTYPE qtype, int qclass)
        {
            if (m_DnsServers == null || m_DnsServers.Length == 0)
            {
                throw new Exception("Dns server isn't specified !");
            }

            // See if query is in cache
            if (m_UseDnsCache)
            {
                DnsServerResponse resopnse = DnsCache.GetFromCache(qname, (int)qtype);
                if (resopnse != null)
                {
                    return(resopnse);
                }
            }

            int queryID = Dns_Client.ID;

            byte[] query = CreateQuery(queryID, qname, qtype, qclass);

            // Create transcation and start processing it.
            using (DnsTransaction transaction = new DnsTransaction(this, queryID, qname, (int)qtype, timeout, query)){
                ManualResetEvent wait = new ManualResetEvent(false);

                transaction.Timeout += delegate(object s, EventArgs e){
                    wait.Set();
                };
                transaction.Completed += delegate(object s, EventArgs e){
                    wait.Set();
                };
                m_pTransactions.Add(transaction.ID, transaction);

                // Start transaction processing and wait transaction to complete.
                transaction.Start();
                wait.WaitOne();

                // DNS server response received.
                if (transaction.Response != null)
                {
                    return(transaction.Response);
                }
                // No server response - timeout.
                else
                {
                    throw new Exception("Timeout - no response from DNS server.");
                }
            }
        }
예제 #12
0
        /// <summary>
        /// Queries server with specified query.
        /// </summary>
        /// <param name="queryText">Query text. It depends on queryType.</param>
        /// <param name="queryType">Query type.</param>
        /// <returns></returns>
        public DnsServerResponse Query(string queryText, QTYPE queryType)
        {
            if (queryType == QTYPE.PTR)
            {
                string ip = queryText;

                // See if IP is ok.
                IPAddress ipA = IPAddress.Parse(ip);
                queryText = "";

                // IPv6
                if (ipA.AddressFamily == AddressFamily.InterNetworkV6)
                {
                    // 4321:0:1:2:3:4:567:89ab
                    // would be
                    // b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.IP6.ARPA

                    char[] ipChars = ip.Replace(":", "").ToCharArray();
                    for (int i = ipChars.Length - 1; i > -1; i--)
                    {
                        queryText += ipChars[i] + ".";
                    }
                    queryText += "IP6.ARPA";
                }
                // IPv4
                else
                {
                    // 213.35.221.186
                    // would be
                    // 186.221.35.213.in-addr.arpa

                    string[] ipParts = ip.Split('.');
                    //--- Reverse IP ----------
                    for (int i = 3; i > -1; i--)
                    {
                        queryText += ipParts[i] + ".";
                    }
                    queryText += "in-addr.arpa";
                }
            }

            return(QueryServer(2000, queryText, queryType, 1));
        }
예제 #13
0
        /// <summary>
        /// Represents a DNS message
        /// </summary>
        /// <param name="Data">Binary representation of a DNS message.</param>
        public DnsMessage(byte[] Data)
        {
            this.binary = Data;

            using (MemoryStream ms = new MemoryStream(Data))
            {
                this.id = DnsClient.ReadUInt16(ms);

                byte b = (byte)ms.ReadByte();
                this.response            = (b & 0x80) != 0;
                this.opCode              = (OpCode)((b >> 3) & 15);
                this.authoritativeAnswer = (b & 4) != 0;
                this.truncation          = (b & 2) != 0;
                this.recursionDesired    = (b & 1) != 0;

                b = (byte)ms.ReadByte();
                this.recursionAvailable = (b & 128) != 0;
                this.rCode = (RCode)(b & 31);

                ushort QDCOUNT = DnsClient.ReadUInt16(ms);
                ushort ANCOUNT = DnsClient.ReadUInt16(ms);
                ushort NSCOUNT = DnsClient.ReadUInt16(ms);
                ushort ARCOUNT = DnsClient.ReadUInt16(ms);

                this.questions = new Question[QDCOUNT];
                ushort i;

                for (i = 0; i < QDCOUNT; i++)
                {
                    string QNAME  = DnsClient.ReadName(ms);
                    QTYPE  QTYPE  = (QTYPE)DnsClient.ReadUInt16(ms);
                    QCLASS QCLASS = (QCLASS)DnsClient.ReadUInt16(ms);

                    this.questions[i] = new Question(QNAME, QTYPE, QCLASS);
                }

                this.answer     = DnsClient.ReadResourceRecords(ms, ANCOUNT);
                this.authority  = DnsClient.ReadResourceRecords(ms, NSCOUNT);
                this.additional = DnsClient.ReadResourceRecords(ms, ARCOUNT);
            }
        }
예제 #14
0
        public Response LookUp(IPAddress address, QTYPE qtype, out Request request)
        {
            if (object.ReferenceEquals(null, Client))
            {
                throw new InvalidOperationException(
                          "A client must be associated with the resolver (use the Connect method).");
            }

            Response response;

            //if (LookUpProcessing != null)
            //  LookUpProcessing(this, new NameServerEventArgs(server, qtype, _Domain));

            //IPAddress address = server.GetFirstAddress(_Options.IPVersion);

            ushort id = (ushort)new Random(DateTime.Now.Millisecond).Next(0, ushort.MaxValue);

            request = new Request(id, false, OPCODE.QUERY, new Question(_Domain.ToString(), qtype));

            try
            {
                _Client.Connect(address);
                response = _Client.Process(request);
                if (response.Header.ID != id) // paranoid
                {
                    throw new ResolverException(
                              "Did not get my request ID back. Either the name server or the client software is buggy.");
                }
            }
            finally
            {
                _Client.Close();
            }

            return(response);
        }
예제 #15
0
		/// <summary>
		/// Default constructor.
		/// </summary>
		/// <param name="recordType">Record type (A,MX, ...).</param>
		/// <param name="ttl">TTL (time to live) value in seconds.</param>
		public DnsRecordBase(QTYPE recordType,int ttl)
		{
			m_Type = recordType;
			m_TTL  = ttl;
		}
예제 #16
0
        /// <summary>
        /// Sends query to server.
        /// </summary>
        /// <param name="timeout">Query timeout in milli seconds.</param>
        /// <param name="qname">Query text.</param>
        /// <param name="qtype">Query type.</param>
        /// <param name="qclass">Query class.</param>
        /// <returns></returns>
        private DnsServerResponse QueryServer(int timeout, string qname, QTYPE qtype, int qclass)
        {
            if (m_DnsServers == null || m_DnsServers.Length == 0)
            {
                throw new Exception("Dns server isn't specified !");
            }

            // See if query is in cache
            if (m_UseDnsCache)
            {
                DnsServerResponse resopnse = DnsCache.GetFromCache(qname, (int)qtype);
                if (resopnse != null)
                {
                    return(resopnse);
                }
            }

            int queryID = ID;

            byte[] query = CreateQuery(queryID, qname, qtype, qclass);

            // Create sending UDP socket.
            Socket udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            udpClient.SendTimeout = 500;

            // Send parallel query to all dns servers and get first answer.
            DateTime startTime = DateTime.Now;
            List <DnsServerResponse> responses = new List <DnsServerResponse>();

            while (startTime.AddMilliseconds(timeout) > DateTime.Now)
            {
                foreach (IPAddress dnsServer in m_DnsServers)
                {
                    try
                    {
                        udpClient.SendTo(query, new IPEndPoint(dnsServer, 53));
                    }
                    catch {}
                }

                // Wait 10 ms response to arrive, if no response, retransmit query.
                if (udpClient.Poll(10, SelectMode.SelectRead))
                {
                    try
                    {
                        byte[] retVal        = new byte[1024];
                        int    countRecieved = udpClient.Receive(retVal);

                        // If reply is ok, return it
                        DnsServerResponse serverResponse = ParseQuery(retVal, queryID);

                        // Cache query
                        if (m_UseDnsCache && serverResponse.ResponseCode == RCODE.NO_ERROR)
                        {
                            DnsCache.AddToCache(qname, (int)qtype, serverResponse);
                        }
                        responses.Add(serverResponse);
                    }
                    catch {}
                }
            }

            udpClient.Close();

            // If we reach so far, we probably won't get connection to dsn server
            return(responses.Count > 0?responses[0]:new DnsServerResponse(false,
                                                                          RCODE.SERVER_FAILURE,
                                                                          new List <DNS_rr_base>(),
                                                                          new List <DNS_rr_base>(),
                                                                          new List <DNS_rr_base>()));
        }
예제 #17
0
        /// <summary>
        /// Filters out specified type of records from answer.
        /// </summary>
        /// <param name="answers"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        private List<DNS_rr_base> FilterRecordsX(List<DNS_rr_base> answers, QTYPE type)
        {
            List<DNS_rr_base> retVal = new List<DNS_rr_base>();
            foreach (DNS_rr_base record in answers)
            {
                if (record.RecordType == type)
                {
                    retVal.Add(record);
                }
            }

            return retVal;
        }
예제 #18
0
        /// <summary>
        /// Sends query to server.
        /// </summary>
        /// <param name="timeout">Query timeout in milli seconds.</param>
        /// <param name="qname">Query text.</param>
        /// <param name="qtype">Query type.</param>
        /// <param name="qclass">Query class.</param>
        /// <returns></returns>
        private DnsServerResponse QueryServer(int timeout,string qname,QTYPE qtype,int qclass)
        {
            if(m_DnsServers == null || m_DnsServers.Length == 0){
                throw new Exception("Dns server isn't specified !");
            }

            // See if query is in cache
            if(m_UseDnsCache){
                DnsServerResponse resopnse = DnsCache.GetFromCache(qname,(int)qtype);
                if(resopnse != null){
                    return resopnse;
                }
            }

            int queryID = Dns_Client.ID;
            byte[] query = CreateQuery(queryID,qname,qtype,qclass);

            // Create sending UDP socket.
            Socket udpClient = new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
            udpClient.SendTimeout = 500;

            // Send parallel query to all dns servers and get first answer.
            DateTime startTime = DateTime.Now;
            while(startTime.AddMilliseconds(timeout) > DateTime.Now){
                foreach(IPAddress dnsServer in m_DnsServers){
                    try{
                        udpClient.SendTo(query,new IPEndPoint(dnsServer,53));
                    }
                    catch{
                    }
                }

                // Wait 10 ms response to arrive, if no response, retransmit query.
                if(udpClient.Poll(10,SelectMode.SelectRead)){
                    try{
                        byte[] retVal = new byte[1024];
                        int countRecieved = udpClient.Receive(retVal);

                        // If reply is ok, return it
                        DnsServerResponse serverResponse = ParseQuery(retVal,queryID);

                        // Cache query
                        if(m_UseDnsCache && serverResponse.ResponseCode == RCODE.NO_ERROR){
                            DnsCache.AddToCache(qname,(int)qtype,serverResponse);
                        }

                        return serverResponse;
                    }
                    catch{
                    }
                }
            }

            udpClient.Close();

            // If we reach so far, we probably won't get connection to dsn server
            return new DnsServerResponse(false,RCODE.SERVER_FAILURE,new List<DNS_rr_base>(),new List<DNS_rr_base>(),new List<DNS_rr_base>());
        }
예제 #19
0
        /// <summary>
        /// Queries server with specified query.
        /// </summary>
        /// <param name="queryText">Query text. It depends on queryType.</param>
        /// <param name="queryType">Query type.</param>
        /// <returns></returns>
        public DnsServerResponse Query(string queryText,QTYPE queryType)
        {
            if(queryType == QTYPE.PTR){
                string ip = queryText;

                // See if IP is ok.
                IPAddress ipA = IPAddress.Parse(ip);
                queryText = "";

                // IPv6
                if(ipA.AddressFamily == AddressFamily.InterNetworkV6){
                    // 4321:0:1:2:3:4:567:89ab
                    // would be
                    // b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.IP6.ARPA

                    char[] ipChars = ip.Replace(":","").ToCharArray();
                    for(int i=ipChars.Length - 1;i>-1;i--){
                        queryText += ipChars[i] + ".";
                    }
                    queryText += "IP6.ARPA";
                }
                // IPv4
                else{
                    // 213.35.221.186
                    // would be
                    // 186.221.35.213.in-addr.arpa

                    string[] ipParts = ip.Split('.');
                    //--- Reverse IP ----------
                    for(int i=3;i>-1;i--){
                        queryText += ipParts[i] + ".";
                    }
                    queryText += "in-addr.arpa";
                }
            }

            return QueryServer(2000,queryText,queryType,1);
        }
예제 #20
0
파일: Resolver.cs 프로젝트: queueit/Dns
 /// <summary>
 /// Query and get a resource record on specified DNS Server.
 /// </summary>
 /// <param name="host">The name of host to query.</param>
 /// <param name="qType">The QTYPE to use</param>
 /// <returns>Return an asynchronsous operation</returns>
 public Task <IResponse> QueryAsync(string host, QTYPE qType)
 {
     return(this.QueryAsync(host, qType, QCLASS.IN));
 }
예제 #21
0
 /// <summary>
 /// Execute a DNS query.
 /// </summary>
 /// <param name="QNAME">Query Name</param>
 /// <param name="QTYPE">Query Type</param>
 /// <param name="QCLASS">Query Class</param>
 /// <param name="Destination">Destination. If null, default destination is assumed.</param>
 public Task <DnsMessage> QueryAsync(string QNAME, QTYPE QTYPE, QCLASS QCLASS, IPEndPoint Destination)
 {
     return(this.QueryAsync(new Question[] { new Question(QNAME, QTYPE, QCLASS) }, Destination));
 }
예제 #22
0
        /// <summary>
        ///  Parses the response message.
        /// </summary>
        private static void ParseResponse(ReadOnlySpan <byte> response, int queryLength, QTYPE qTYPE, QueryTransport queryTransport)
        {
            int offset         = 0,
                tcpMsgLength   = 0,
                questionOffset = 0;

            // Tcp & DoT pre-processing
            if (queryTransport == QueryTransport.Tcp || queryTransport == QueryTransport.DoT)
            {
                // save TcpMsgLength and remove it
                byte[] bytesTcpMsgLength = new byte[4];
                Array.Copy(response.Slice(start: 0, length: 2).ToArray(), 0, bytesTcpMsgLength, 2, 2);
                tcpMsgLength = BinaryPrimitives.ReadInt32BigEndian(bytesTcpMsgLength);
                offset       = 2;
            }

            // read header
            var bytesID          = response.Slice(start: offset, length: 2);
            var bytesHeaderStuff = response.Slice(start: offset + 2, length: 2);

            var bytesQDCOUNT = response.Slice(start: offset + 4, length: 2);
            var bytesANCOUNT = response.Slice(start: offset + 6, length: 2);
            var bytesNSCOUNT = response.Slice(start: offset + 8, length: 2);
            var bytesARCOUNT = response.Slice(start: offset + 10, length: 2);

            // parse header
            int QR     = (bytesHeaderStuff[0] & 0b1000_0000) >> 7;
            int OPCODE = (bytesHeaderStuff[0] & 0b0111_1000) >> 3;
            int AA     = (bytesHeaderStuff[0] & 0b0000_0100) >> 2;
            int TC     = (bytesHeaderStuff[0] & 0b0000_0010) >> 1;
            int RD     = bytesHeaderStuff[0] & 0b0000_0001;
            int RA     = (bytesHeaderStuff[1] & 0b1000_0000) >> 7;
            int Z      = (bytesHeaderStuff[1] & 0b0111_0000) >> 4;
            int RCODE  = bytesHeaderStuff[1] & 0b0000_1111;

            UInt16 QDCOUNT = BinaryPrimitives.ReadUInt16BigEndian(bytesQDCOUNT);
            UInt16 ANCOUNT = BinaryPrimitives.ReadUInt16BigEndian(bytesANCOUNT);
            UInt16 NSCOUNT = BinaryPrimitives.ReadUInt16BigEndian(bytesNSCOUNT);
            UInt16 ARCOUNT = BinaryPrimitives.ReadUInt16BigEndian(bytesARCOUNT);

            // checks

            /*if (bytesID[0] != 0x20
            || bytesID[1] != 0x40
            || QR != 1
            || OPCODE != 0
            || TC != 0
            || RCODE != 0
            || QDCOUNT != 1)
            || {
            ||  Console.WriteLine($"Warning: header checks failed.");
            || }*/

            // read question
            // length of QNAME is unknown
            // look for 0x00
            questionOffset = offset + 12;
            // offset is relative to response
            offset = questionOffset + MemoryExtensions.IndexOf(response.Slice(questionOffset), (byte)0x00);
            if (offset == -1)
            {
                Console.WriteLine("Error parsing response: invalid QNAME.");
                return;
            }
            var bytesQNAME  = response.Slice(start: questionOffset, length: offset - questionOffset + 1);
            var bytesQTYPE  = response.Slice(start: offset + 1, length: 2);
            var bytesQCLASS = response.Slice(start: offset + 3, length: 2);
            // parse question
            string QNAME  = NAMEToHostname(bytesQNAME, response, queryTransport);
            UInt16 QTYPE  = BinaryPrimitives.ReadUInt16BigEndian(bytesQTYPE);
            UInt16 QCLASS = BinaryPrimitives.ReadUInt16BigEndian(bytesQCLASS);

            // print info
            Console.WriteLine($@"Received bytes: {response.Length}

####### HEADER #######
ID: {BinaryPrimitives.ReadUInt16BigEndian(bytesID)}
QR: {QR}
OPCODE: {OPCODE}
AA: {AA}
TC: {TC}
RD: {RD}
RA: {RA}
Z: {Z}
RCODE: {RCODE}
QDCOUNT: {QDCOUNT}
ANCOUNT: {ANCOUNT}
NSCOUNT: {NSCOUNT}
ARCOUNT: {ARCOUNT}

####### QUESTION #######
QNAME: {QNAME}
QTYPE: {QTYPE}
QCLASS: {QCLASS}");

            offset += 5;
            // Parse all RRs
            for (int i = 0; i < ANCOUNT; i++)
            {
                Console.WriteLine($"\n####### ANSWER #{i} #######");
                ParseRR(response, ref offset, queryTransport);
            }
            for (int i = 0; i < NSCOUNT; i++)
            {
                Console.WriteLine($"\n####### AUTHORITY #{i} #######");
                ParseRR(response, ref offset, queryTransport);
            }
            for (int i = 0; i < ARCOUNT; i++)
            {
                Console.WriteLine($"\n####### ADDITIONAL #{i} #######");
                ParseRR(response, ref offset, queryTransport);
            }
        }
예제 #23
0
 /// <summary>
 /// Execute a DNS query.
 /// </summary>
 /// <param name="QNAME">Query Name</param>
 /// <param name="QTYPE">Query Type</param>
 /// <param name="QCLASS">Query Class</param>
 /// <param name="Destination">Destination. If null, default destination is assumed.</param>
 /// <param name="Callback">Method to call when response is returned.</param>
 /// <param name="State">State object to pass on to callback method.</param>
 public void Query(string QNAME, QTYPE QTYPE, QCLASS QCLASS, IPEndPoint Destination, DnsMessageEventHandler Callback, object State)
 {
     this.Query(new Question[] { new Question(QNAME, QTYPE, QCLASS) }, Destination, Callback, State);
 }
예제 #24
0
        /// <summary>
        /// Sends query to server.
        /// </summary>
        /// <param name="qname">Query text.</param>
        /// <param name="qtype">Query type.</param>
        /// <param name="qclass">Query class.</param>
        /// <returns></returns>
        private DnsServerResponse QueryServer(string qname, QTYPE qtype, int qclass)
        {
            if (m_DnsServers == null || m_DnsServers.Length == 0)
            {
                throw new Exception("Dns server isn't specified !!!");
            }

            // See if query is in cache
            if (m_UseDnsCache)
            {
                DnsServerResponse resopnse = DnsCache.GetFromCache(qname, (int)qtype);
                if (resopnse != null)
                {
                    return(resopnse);
                }
            }

            int queryID = Dns_Client.ID;

            byte[] query = CreateQuery(queryID, qname, qtype, qclass);

            int helper = 0;

            for (int i = 0; i < (m_DnsServers.Length * 2); i++)
            {
                if (helper >= m_DnsServers.Length)
                {
                    helper = 0;
                }

                try{
                    Socket udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                    udpClient.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 10000);
                    udpClient.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 10000);
                    udpClient.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, 1);

                    udpClient.Connect(new IPEndPoint(IPAddress.Parse(m_DnsServers[helper]), 53));

                    //send query
                    udpClient.Send(query);

                    byte[] retVal        = new byte[512];
                    int    countRecieved = udpClient.Receive(retVal);

                    udpClient.Close();

                    // If reply is ok, return it
                    DnsServerResponse serverResponse = ParseQuery(retVal, queryID);

                    // Cache query
                    if (m_UseDnsCache && serverResponse.ResponseCode == RCODE.NO_ERROR)
                    {
                        DnsCache.AddToCache(qname, (int)qtype, serverResponse);
                    }

                    return(serverResponse);
                }
                catch {
                }

                helper++;
            }

            // If we reach so far, we probably won't get connection to dsn server
            return(new DnsServerResponse(false, RCODE.SERVER_FAILURE, null, null, null));
        }
        /// <summary>
        /// Sends query to server.
        /// </summary>
        /// <param name="qname">Query text.</param>
        /// <param name="qtype">Query type.</param>
        /// <param name="qclass">Query class.</param>
        /// <returns></returns>
        private DnsServerResponse QueryServer(string qname,QTYPE qtype,int qclass)
        {
            if(m_DnsServers == null || m_DnsServers.Length == 0){
                throw new Exception("Dns server isn't specified !!!");
            }

            // See if query is in cache
            if(m_UseDnsCache){
                DnsServerResponse resopnse = DnsCache.GetFromCache(qname,(int)qtype);
                if(resopnse != null){
                    return resopnse;
                }
            }

            int queryID = Dns_Client.ID;
            byte[] query = CreateQuery(queryID,qname,qtype,qclass);

            int helper = 0;
            for(int i=0;i<(m_DnsServers.Length * 2);i++){
                if(helper >= m_DnsServers.Length){
                    helper = 0;
                }

                try{
                    Socket udpClient = new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
                    udpClient.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.ReceiveTimeout,5000);
                    udpClient.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.SendTimeout,5000);

                    udpClient.Connect(new IPEndPoint(IPAddress.Parse(m_DnsServers[helper]),53));

                    //send query
                    udpClient.Send(query);

                    byte[] retVal = new byte[512];
                    int countRecieved = udpClient.Receive(retVal);

                    udpClient.Close();

                    // If reply is ok, return it
                    DnsServerResponse serverResponse = ParseQuery(retVal,queryID);

                    // Cache query
                    if(m_UseDnsCache && serverResponse.ResponseCode == RCODE.NO_ERROR){
                        DnsCache.AddToCache(qname,(int)qtype,serverResponse);
                    }

                    return serverResponse;
                }
                catch{
                }

                helper++;
            }

            // If we reach so far, we probably won't get connection to dsn server
            return new DnsServerResponse(false,RCODE.SERVER_FAILURE,new List<DnsRecordBase>(),new List<DnsRecordBase>(),new List<DnsRecordBase>());
        }
예제 #26
0
 /// <summary>
 /// Contains information about a DNS Question
 /// </summary>
 /// <param name="QNAME">Qujery Name</param>
 /// <param name="QTYPE">Query Type</param>
 /// <param name="QCLASS">Query Class</param>
 public Question(string QNAME, QTYPE QTYPE, QCLASS QCLASS)
 {
     this.qNAME  = QNAME;
     this.qTYPE  = QTYPE;
     this.qCLASS = QCLASS;
 }
 /// <summary>
 /// 
 /// </summary>
 /// <param name="qname"></param>
 /// <param name="qtype"></param>
 /// <param name="qclass"></param>
 public Dns_Query(string qname,QTYPE qtype,int qclass)
 {
     m_QNAME  = qname;
     m_QTYPE  = qtype;
     m_QCALSS = qclass;
 }
예제 #28
0
        /// <summary>
        /// Creates new query.
        /// </summary>
        /// <param name="ID"></param>
        /// <param name="qname"></param>
        /// <param name="qtype"></param>
        /// <param name="qclass"></param>
        /// <returns></returns>
        private byte[] CreateQuery(int ID,string qname,QTYPE qtype,int qclass)
        {
            byte[] query = new byte[521];

            //---- Create header --------------------------------------------//
            // Header is first 12 bytes of query

            /* 4.1.1. Header section format
                                          1  1  1  1  1  1
            0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |                      ID                       |
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |                    QDCOUNT                    |
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |                    ANCOUNT                    |
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |                    NSCOUNT                    |
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |                    ARCOUNT                    |
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            */

            //--------- Header part -----------------------------------//
            query[0]  = (byte) (ID >> 8); query[1]  = (byte) ID;
            query[2]  = (byte) 0;         query[3]  = (byte) 0;
            query[4]  = (byte) 0;         query[5]  = (byte) 1;
            query[6]  = (byte) 0;         query[7]  = (byte) 0;
            query[8]  = (byte) 0;         query[9]  = (byte) 0;
            query[10] = (byte) 0;         query[11] = (byte) 0;
            //---------------------------------------------------------//

            //---- End of header --------------------------------------------//

            //----Create query ------------------------------------//

            /* 	Rfc 1035 4.1.2. Question section format
                                              1  1  1  1  1  1
            0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |                                               |
            /                     QNAME                     /
            /                                               /
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |                     QTYPE                     |
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |                     QCLASS                    |
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

            QNAME
                a domain name represented as a sequence of labels, where
                each label consists of a length octet followed by that
                number of octets.  The domain name terminates with the
                zero length octet for the null label of the root.  Note
                that this field may be an odd number of octets; no
                padding is used.
            */
            string[] labels = qname.Split(new char[] {'.'});
            int position = 12;

            // Copy all domain parts(labels) to query
            // eg. lumisoft.ee = 2 labels, lumisoft and ee.
            // format = label.length + label(bytes)
            foreach(string label in labels){
                // add label lenght to query
                query[position++] = (byte)(label.Length);

                // convert label string to byte array
                byte[] b = Encoding.ASCII.GetBytes(label.ToCharArray());
                b.CopyTo(query,position);

                // Move position by label length
                position += b.Length;
            }

            // Terminate domain (see note above)
            query[position++] = (byte) 0;

            // Set QTYPE
            query[position++] = (byte) 0;
            query[position++] = (byte)qtype;

            // Set QCLASS
            query[position++] = (byte) 0;
            query[position++] = (byte)qclass;
            //-------------------------------------------------------//

            return query;
        }
예제 #29
0
 public QuestionRecord(byte[] bytes, ref ushort i)
 {
     this.name   = readLabel(bytes, ref i);
     this._type  = (QTYPE)GetLEUInt16(bytes, ref i);
     this._class = (RCLASS)GetLEUInt16(bytes, ref i);
 }
예제 #30
0
 /// <summary>
 /// Resolves a DNS name.
 /// </summary>
 /// <param name="Name">Domain Name to resolve</param>
 /// <param name="TYPE">Resource Record Type of interest.</param>
 /// <param name="CLASS">Resource Record Class of interest.</param>
 /// <returns>Answer to the query</returns>
 /// <exception cref="IOException">If the domain name could not be resolved for the TYPE and CLASS provided.</exception>
 public static Task <ResourceRecord[]> Resolve(string Name, QTYPE TYPE, QCLASS CLASS)
 {
     return(Resolve(Name, TYPE, null, CLASS));
 }
예제 #31
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 /// <param name="recordType">Record type (A,MX, ...).</param>
 /// <param name="ttl">TTL (time to live) value in seconds.</param>
 public DNS_rr_base(QTYPE recordType, int ttl)
 {
     m_Type = recordType;
     m_TTL = ttl;
 }
예제 #32
0
 /// <summary>
 /// Queries server with specified query.
 /// </summary>
 /// <param name="queryText">Query text. It depends on queryType.</param>
 /// <param name="queryType">Query type.</param>
 /// <returns>Returns DSN server response.</returns>
 public DnsServerResponse Query(string queryText, QTYPE queryType)
 {
     return(Query(queryText, queryType, 2000));
 }
예제 #33
0
 void Internal.IResponseReader.ReadResponse(Internal.ByteReader reader)
 {
     QNAME = reader.ReadDomain();
       QTYPE = reader.ReadUIn16Enum<QTYPE>();
       QCLASS = reader.ReadUIn16Enum<QCLASS>();
 }
예제 #34
0
        /// <summary>
        ///  Makes a query datagram containing a header and a question.
        ///  Returns a byte array.
        /// </summary>
        private static byte[] MakeQueryDatagram(byte[] QNAME, QTYPE qTYPE, QueryTransport queryTransport)
        {
            byte[]      query;
            byte[]      header     = new byte[12];
            Span <byte> headerSpan = new Span <byte>(header);

            byte[] question = new byte[QNAME.Length + 4];

            // BEGIN Header
            // ID
            // generate random ID
            rnd.NextBytes(headerSpan.Slice(start: 0, length: 2));
            //   0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
            // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            // |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
            header[2] = 0x01; // RD == 1
            header[3] = 0x00;
            // QDCOUNT
            // No support for multiple questions in one query
            // as it's not supported by any DNS server implementation
            header[4] = 0x00;
            header[5] = 0x01;
            // ANCOUNT
            header[6] = 0x00;
            header[7] = 0x00;
            // NSCOUNT
            header[8] = 0x00;
            header[9] = 0x00;
            // ARCOUNT
            header[10] = 0x00;
            header[11] = 0x00;
            // END Header

            // BEGIN Question
            Array.Copy(QNAME, question, QNAME.Length);
            // QTYPE
            byte[] qTYPE4Bytes = new byte[4];
            BinaryPrimitives.WriteInt32BigEndian(qTYPE4Bytes, (int)qTYPE);
            question[QNAME.Length]     = qTYPE4Bytes[2];
            question[QNAME.Length + 1] = qTYPE4Bytes[3];
            // QCLASS: IN
            question[QNAME.Length + 2] = 0x00;
            question[QNAME.Length + 3] = 0x01;
            // END Question

            // make query message based on queryTransport
            if (queryTransport == QueryTransport.Udp || queryTransport == QueryTransport.DoH) // Udp || DoH
            {
                query = new byte[header.Length + question.Length];
                Array.Copy(header, query, header.Length);
                Array.Copy(question, 0, query, header.Length, question.Length);
            }
            else // Tcp || DoT
            {
                query = new byte[2 + header.Length + question.Length];
                // Tcp Message Length
                byte[] tcpMsgLengthBytes = new byte[4];
                BinaryPrimitives.WriteInt32BigEndian(tcpMsgLengthBytes, header.Length + question.Length);
                Array.Copy(tcpMsgLengthBytes, 2, query, 0, 2);
                Array.Copy(header, 0, query, 2, 12);                 // header.Length == 12
                Array.Copy(question, 0, query, 14, question.Length); // 2 + 12 == 14
            }

            return(query);
        }
예제 #35
0
        /// <summary>
        /// Creates new query.
        /// </summary>
        /// <param name="ID">Query ID.</param>
        /// <param name="qname">Query text.</param>
        /// <param name="qtype">Query type.</param>
        /// <param name="qclass">Query class.</param>
        /// <returns></returns>
        private byte[] CreateQuery(int ID,string qname,QTYPE qtype,int qclass)
        {
            byte[] query = new byte[512];

            //---- Create header --------------------------------------------//
            // Header is first 12 bytes of query

            /* 4.1.1. Header section format
                                          1  1  1  1  1  1
            0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |                      ID                       |
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |                    QDCOUNT                    |
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |                    ANCOUNT                    |
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |                    NSCOUNT                    |
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |                    ARCOUNT                    |
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

            QR  A one bit field that specifies whether this message is a
                query (0), or a response (1).

            OPCODE          A four bit field that specifies kind of query in this
                message.  This value is set by the originator of a query
                and copied into the response.  The values are:

                0               a standard query (QUERY)

                1               an inverse query (IQUERY)

                2               a server status request (STATUS)

            */

            //--------- Header part -----------------------------------//
            query[0]  = (byte) (ID >> 8); query[1]  = (byte) (ID & 0xFF);
            query[2]  = (byte) 1;         query[3]  = (byte) 0;
            query[4]  = (byte) 0;         query[5]  = (byte) 1;
            query[6]  = (byte) 0;         query[7]  = (byte) 0;
            query[8]  = (byte) 0;         query[9]  = (byte) 0;
            query[10] = (byte) 0;         query[11] = (byte) 0;
            //---------------------------------------------------------//

            //---- End of header --------------------------------------------//

            //----Create query ------------------------------------//

            /* 	Rfc 1035 4.1.2. Question section format
                                              1  1  1  1  1  1
            0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |                                               |
            /                     QNAME                     /
            /                                               /
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |                     QTYPE                     |
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
            |                     QCLASS                    |
            +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

            QNAME
                a domain name represented as a sequence of labels, where
                each label consists of a length octet followed by that
                number of octets.  The domain name terminates with the
                zero length octet for the null label of the root.  Note
                that this field may be an odd number of octets; no
                padding is used.
            */
            string[] labels = qname.Split(new char[] {'.'});
            int position = 12;

            // Copy all domain parts(labels) to query
            // eg. lumisoft.ee = 2 labels, lumisoft and ee.
            // format = label.length + label(bytes)
            foreach(string label in labels){
                // add label lenght to query
                query[position++] = (byte)(label.Length);

                // convert label string to byte array
                byte[] b = Encoding.ASCII.GetBytes(label);
                b.CopyTo(query,position);

                // Move position by label length
                position += b.Length;
            }

            // Terminate domain (see note above)
            query[position++] = (byte) 0;

            // Set QTYPE
            query[position++] = (byte) 0;
            query[position++] = (byte)qtype;

            // Set QCLASS
            query[position++] = (byte) 0;
            query[position++] = (byte)qclass;
            //-------------------------------------------------------//

            return query;
        }
예제 #36
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="qname"></param>
 /// <param name="qtype"></param>
 /// <param name="qclass"></param>
 public Dns_Query(string qname, QTYPE qtype, int qclass)
 {
     m_QNAME  = qname;
     m_QTYPE  = qtype;
     m_QCALSS = qclass;
 }
예제 #37
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 /// <param name="recordType">Record type (A,MX, ...).</param>
 /// <param name="ttl">TTL (time to live) value in seconds.</param>
 public DNS_rr_base(QTYPE recordType, int ttl)
 {
     m_Type = recordType;
     m_TTL  = ttl;
 }
예제 #38
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 /// <param name="recordType">Record type (A,MX, ...).</param>
 /// <param name="ttl">TTL (time to live) value in seconds.</param>
 public DnsRecordBase(QTYPE recordType, int ttl)
 {
     m_Type = recordType;
     m_TTL  = ttl;
 }
예제 #39
0
        /// <summary>
        /// Resolves a DNS name.
        /// </summary>
        /// <param name="Name">Domain Name to resolve</param>
        /// <param name="TYPE">Resource Record Type of interest.</param>
        /// <param name="ExceptionType">If no answer of type <paramref name="TYPE"/> is found, records of this type can also be accepted.</param>
        /// <param name="CLASS">Resource Record Class of interest.</param>
        /// <returns>Answer to the query</returns>
        /// <exception cref="IOException">If the domain name could not be resolved for the TYPE and CLASS provided.</exception>
        public static async Task <ResourceRecord[]> Resolve(string Name, QTYPE TYPE,
                                                            TYPE?ExceptionType, QCLASS CLASS)
        {
            LinkedList <KeyValuePair <string, IPEndPoint> > Backup = null;
            TYPE?      ExpectedType;
            IPEndPoint Destination = null;
            string     LastName    = null;
            int        Timeout     = 2000;      // Local timeout

            if (Enum.TryParse <TYPE>(TYPE.ToString(), out TYPE T))
            {
                ExpectedType = T;
            }
            else
            {
                ExpectedType = null;
            }

            lock (synchObject)
            {
                if (nestingDepth == 0 && networkChanged)
                {
                    networkChanged = false;
                    client?.Dispose();
                    client = null;
                }

                if (client is null)
                {
                    client = new DnsUdpClient();
                }

                nestingDepth++;
            }

            try
            {
                while (true)
                {
                    DnsResponse Response = null;
                    DnsMessage  Message;

                    if (LastName is null || LastName != Name)
                    {
                        LastName = Name;

                        try
                        {
                            Response = await Database.FindFirstDeleteRest <DnsResponse>(new FilterAnd(
                                                                                            new FilterFieldEqualTo("Name", Name),
                                                                                            new FilterFieldEqualTo("Type", TYPE),
                                                                                            new FilterFieldEqualTo("Class", CLASS)));

                            if (!(Response is null) && Response.Expires <= DateTime.Now)
                            {
                                await Database.Delete(Response);

                                Response = null;
                            }
                        }
                        catch (Exception)
                        {
                            // Some inconsistency in database. Clear collection to get fresh set of DNS entries.
                            await Database.Clear("DnsCache");

                            Response = null;
                        }
                    }

                    if (Response is null)
                    {
                        try
                        {
                            Message = await client.SendRequestAsync(OpCode.Query, true, new Question[]
                            {
                                new Question(Name, TYPE, CLASS)
                            }, Destination, Timeout);

                            switch (Message.RCode)
                            {
                            case RCode.NXDomain:
                                throw new ArgumentException("Domain name does not exist.", nameof(Name));
                            }
                        }
                        catch (TimeoutException)
                        {
                            Message = null;
                        }

                        if (Message is null || Message.RCode != RCode.NoError)
                        {
                            Destination = await NextDestination(Backup);

                            if (Destination is null)
                            {
                                throw new IOException("Unable to resolve DNS query.");
                            }

                            continue;                               // Check an alternative
                        }

                        uint Ttl = 60 * 60 * 24 * 30;                               // Maximum TTL = 30 days

                        Response = new DnsResponse()
                        {
                            Name       = Name,
                            Type       = TYPE,
                            Class      = CLASS,
                            Answer     = CheckTtl(ref Ttl, Message.Answer),
                            Authority  = CheckTtl(ref Ttl, Message.Authority),
                            Additional = CheckTtl(ref Ttl, Message.Additional)
                        };

                        Response.Expires = DateTime.Now.AddSeconds(Ttl);

                        await Database.Insert(Response);
                    }

                    string CName = null;

                    if (!(Response.Answer is null))
                    {
                        if (!ExpectedType.HasValue)
                        {
                            return(Response.Answer);
                        }

                        foreach (ResourceRecord RR in Response.Answer)
                        {
                            if (RR.Type == ExpectedType.Value)
                            {
                                return(Response.Answer);
                            }

                            if (CName is null && RR.Type == Enumerations.TYPE.CNAME && RR is CNAME CNAME)
                            {
                                CName = CNAME.Name2;
                            }
                        }

                        if (ExceptionType.HasValue)
                        {
                            foreach (ResourceRecord RR in Response.Answer)
                            {
                                if (RR.Type == ExceptionType.Value)
                                {
                                    return(Response.Answer);
                                }
                            }
                        }

                        if (!(CName is null))
                        {
                            Name   = CName;
                            Backup = null;
                            continue;
                        }
                    }

                    if (!(Response.Authority is null))
                    {
                        foreach (ResourceRecord RR in Response.Authority)
                        {
                            if (RR is NS NS)
                            {
                                string    Authority        = NS.Name2;
                                IPAddress AuthorityAddress = null;

                                if (!(Response.Additional is null))
                                {
                                    foreach (ResourceRecord RR2 in Response.Additional)
                                    {
                                        if (RR2 is A A)
                                        {
                                            AuthorityAddress = A.Address;
                                            break;
                                        }
                                        else if (RR2 is AAAA AAAA)
                                        {
                                            AuthorityAddress = AAAA.Address;
                                            break;
                                        }
                                    }
                                }

                                if (Backup is null)
                                {
                                    Backup = new LinkedList <KeyValuePair <string, IPEndPoint> >();
                                }

                                if (AuthorityAddress is null)
                                {
                                    Backup.AddLast(new KeyValuePair <string, IPEndPoint>(Authority, null));
                                }
                                else
                                {
                                    Backup.AddLast(new KeyValuePair <string, IPEndPoint>(null, new IPEndPoint(AuthorityAddress, DefaultDnsPort)));
                                }
                            }
                        }
                    }

                    Destination = await NextDestination(Backup);

                    if (Destination is null)
                    {
                        throw new IOException("Unable to resolve DNS query.");
                    }

                    Timeout = 5000;
                }
            }
            finally
            {
                lock (synchObject)
                {
                    nestingDepth--;
                }
            }
        }
예제 #40
0
        public Response LookUp(IPAddress address, QTYPE qtype, out Request request)
        {
            if (object.ReferenceEquals(null, Client))
            throw new InvalidOperationException(
              "A client must be associated with the resolver (use the Connect method).");

              Response response;

              //if (LookUpProcessing != null)
              //  LookUpProcessing(this, new NameServerEventArgs(server, qtype, _Domain));

              //IPAddress address = server.GetFirstAddress(_Options.IPVersion);

              ushort id = (ushort)new Random(DateTime.Now.Millisecond).Next(0, ushort.MaxValue);
              request = new Request(id, false, OPCODE.QUERY, new Question(_Domain.ToString(), qtype));

              try
              {
            _Client.Connect(address);
            response = _Client.Process(request);
            if (response.Header.ID != id) // paranoid
              throw new ResolverException(
            "Did not get my request ID back. Either the name server or the client software is buggy.");
              }
              finally
              {
            _Client.Close();
              }

              return response;
        }
예제 #41
0
        /// <summary>
        /// Creates new query.
        /// </summary>
        /// <param name="ID">Query ID.</param>
        /// <param name="qname">Query text.</param>
        /// <param name="qtype">Query type.</param>
        /// <param name="qclass">Query class.</param>
        /// <returns></returns>
        private byte[] CreateQuery(int ID, string qname, QTYPE qtype, int qclass)
        {
            byte[] query = new byte[512];

            //---- Create header --------------------------------------------//
            // Header is first 12 bytes of query

            /* 4.1.1. Header section format
             *                                                                    1  1  1  1  1  1
             *          0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |                      ID                       |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |                    QDCOUNT                    |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |                    ANCOUNT                    |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |                    NSCOUNT                    |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |                    ARCOUNT                    |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |
             |          QR  A one bit field that specifies whether this message is a
             |  query (0), or a response (1).
             |
             |          OPCODE          A four bit field that specifies kind of query in this
             |  message.  This value is set by the originator of a query
             |  and copied into the response.  The values are:
             |
             |  0               a standard query (QUERY)
             |
             |  1               an inverse query (IQUERY)
             |
             |  2               a server status request (STATUS)
             |
             */

            //--------- Header part -----------------------------------//
            query[0]  = (byte)(ID >> 8);
            query[1]  = (byte)(ID & 0xFF);
            query[2]  = 1;
            query[3]  = 0;
            query[4]  = 0;
            query[5]  = 1;
            query[6]  = 0;
            query[7]  = 0;
            query[8]  = 0;
            query[9]  = 0;
            query[10] = 0;
            query[11] = 0;
            //---------------------------------------------------------//

            //---- End of header --------------------------------------------//

            //----Create query ------------------------------------//

            /*  Rfc 1035 4.1.2. Question section format
             *                                                                            1  1  1  1  1  1
             *          0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |                                               |
             |          /                     QNAME                     /
             |          /                                               /
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |                     QTYPE                     |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |                     QCLASS                    |
             +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
             |
             |          QNAME
             |                  a domain name represented as a sequence of labels, where
             |                  each label consists of a length octet followed by that
             |                  number of octets.  The domain name terminates with the
             |                  zero length octet for the null label of the root.  Note
             |                  that this field may be an odd number of octets; no
             |                  padding is used.
             */
            string[] labels   = qname.Split(new[] { '.' });
            int      position = 12;

            // Copy all domain parts(labels) to query
            // eg. lumisoft.ee = 2 labels, lumisoft and ee.
            // format = label.length + label(bytes)
            foreach (string label in labels)
            {
                // add label lenght to query
                query[position++] = (byte)(label.Length);

                // convert label string to byte array
                byte[] b = Encoding.ASCII.GetBytes(label);
                b.CopyTo(query, position);

                // Move position by label length
                position += b.Length;
            }

            // Terminate domain (see note above)
            query[position++] = 0;

            // Set QTYPE
            query[position++] = 0;
            query[position++] = (byte)qtype;

            // Set QCLASS
            query[position++] = 0;
            query[position++] = (byte)qclass;
            //-------------------------------------------------------//
            string queryStr = Encoding.ASCII.GetString(query);

            return(query);
        }
예제 #42
0
 public ResourceRecord(string n, QTYPE t, RCLASS c, uint _ttl, byte[] _data)
 {
     this.question = new QuestionRecord(n, t, c);
     this.ttl      = _ttl;
     this.data     = _data;
 }
예제 #43
0
        /// <summary>
        /// Sends query to server.
        /// </summary>
        /// <param name="qname">Query text.</param>
        /// <param name="qtype">Query type.</param>
        /// <param name="qclass">Query class.</param>
        /// <returns></returns>
        private ArrayList QueryServer(string qname,QTYPE qtype,int qclass)
        {
            // See if query is in cache
            if(m_UseDnsCache){
                ArrayList entries = DnsCache.GetFromCache(qname,(int)qtype);
                if(entries != null){
                    return entries;
                }
            }

            int queryID = DnsEx.ID;
            byte[] query = CreateQuery(queryID,qname,qtype,qclass);

            int helper = 0;
            for(int i=0;i<10;i++){
                if(helper > m_DnsServers.Length){
                    helper = 0;
                }

                try{
                    IPEndPoint ipRemoteEndPoint = new IPEndPoint(IPAddress.Parse(m_DnsServers[helper]),53);
                    Socket udpClient = new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);

                    IPEndPoint ipLocalEndPoint = new IPEndPoint(IPAddress.Any,0);
                    EndPoint localEndPoint = (EndPoint)ipLocalEndPoint;
                    udpClient.Bind(localEndPoint);

                    udpClient.Connect(ipRemoteEndPoint);

                    //send query
                    udpClient.Send(query);

                    // Wait until we have a reply
                    byte[] retVal = null;
                    if(udpClient.Poll(5*1000000,SelectMode.SelectRead)){
                        retVal = new byte[512];
                        udpClient.Receive(retVal);
                    }

                    udpClient.Close();

                    // If reply is ok, return it
                    ArrayList answers = ParseAnswers(retVal,queryID);
                    if(answers != null){
                        // Cache query
                        if(m_UseDnsCache && answers.Count > 0){
                            DnsCache.AddToCache(qname,(int)qtype,answers);
                        }

                        return answers;
                    }
                }
                catch{
                }

                helper++;
            }

            return null;
        }
예제 #44
0
        /// <summary>
        ///  The resolver public interface.
        /// </summary>
        public static void CubeResolver
        (
            string name,
            IPAddress dns,
            QTYPE qTYPE = QTYPE.A,
            QueryTransport queryTransport = QueryTransport.Udp,
            string DoHURI = "https://cloudflare-dns.com/dns-query"
        )
        {
            byte[] QNAME;
            // if name is an IPAddress, do a PTR query
            if (IPAddress.TryParse(name, out IPAddress ip))
            {
                qTYPE = QTYPE.PTR;
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    QNAME = IPv4ToQNAME(ip);
                }
                else
                {
                    QNAME = IPv6ToQNAME(ip);
                }
            }
            else // if name is a hostname
            {
                QNAME = HostnameToQNAME(name);
            }

            byte[] query = MakeQueryDatagram(QNAME, qTYPE, queryTransport);
            if (queryTransport == QueryTransport.Udp)
            {
                if (TryUdpQuery(query, dns, out Span <byte> response))
                {
                    ParseResponse(response, query.Length, qTYPE, queryTransport);
                }
                else // Udp failed, fallback to Tcp
                {
                    // change queryTransport and remake query message
                    Console.WriteLine($"UDP query failed. Fallback to TCP.");
                    queryTransport = QueryTransport.Tcp;
                    query          = MakeQueryDatagram(QNAME, qTYPE, queryTransport);
                }
            }
            if (queryTransport == QueryTransport.Tcp)
            {
                if (TryTcpQuery(query, dns, out Span <byte> response))
                {
                    ParseResponse(response, query.Length, qTYPE, queryTransport);
                }
                else // Tcp failed, fallback to DoT
                {
                    // change queryTransport and remake query message
                    Console.WriteLine($"TCP query failed. Fallback to DNS over TLS.");
                    queryTransport = QueryTransport.DoT;
                    query          = MakeQueryDatagram(QNAME, qTYPE, queryTransport);
                }
            }
            if (queryTransport == QueryTransport.DoT)
            {
                if (TryDoTQuery(query, dns, out Span <byte> response))
                {
                    ParseResponse(response, query.Length, qTYPE, queryTransport);
                }
                else // DoT failed
                {
                    Console.WriteLine($"DNS over TLS query failed.");
                }
            }
            if (queryTransport == QueryTransport.DoH)
            {
                if (TryDoHQuery(query, out Span <byte> response, DoHURI))
                {
                    ParseResponse(response, query.Length, qTYPE, queryTransport);
                }
                else // DoH failed
                {
                    Console.WriteLine($"DNS over HTTPS query failed.");
                }
            }
        }