/// <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])); }
/// <summary> /// Initialize a new DNS question. /// </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> /// <param name="qclass">A two octet code that specifies the class of the query.</param> public Question(string qname, QTYPE qtype, QCLASS qclass) { if (String.IsNullOrEmpty(qname)) throw new ArgumentNullException("qname", "Value cannot be null or empty."); this.QNAME = qname; this.QTYPE = qtype; this.QCLASS = qclass; }
/// <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; }
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); } }
private static Question[] ToQuestions(string QNAME, QTYPE[] QTYPEs, QCLASS QCLASS) { int i, c = QTYPEs.Length; Question[] Questions = new Question[c]; for (i = 0; i < c; i++) { Questions[i] = new Question(QNAME, QTYPEs[i], QCLASS); } return(Questions); }
/// <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); } }
/// <summary> /// Execute a DNS query. /// </summary> /// <param name="QNAME">Query Name</param> /// <param name="QTYPEs">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[] QTYPEs, QCLASS QCLASS, IPEndPoint Destination) { return(this.QueryAsync(ToQuestions(QNAME, QTYPEs, QCLASS), Destination)); }
/// <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)); }
/// <summary> /// Execute a DNS query. /// </summary> /// <param name="QNAME">Query Name</param> /// <param name="QTYPEs">Query Types</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[] QTYPEs, QCLASS QCLASS, IPEndPoint Destination, DnsMessageEventHandler Callback, object State) { this.Query(ToQuestions(QNAME, QTYPEs, QCLASS), Destination, Callback, State); }
/// <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); }
/// <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> /// 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--; } } }
/// <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)); }
public Question(string qName, QTYPE qType, QCLASS qClass) { this.QName = qName; this.QType = qType; this.QClass = qClass; }
void Internal.IResponseReader.ReadResponse(Internal.ByteReader reader) { QNAME = reader.ReadDomain(); QTYPE = reader.ReadUIn16Enum <QTYPE>(); QCLASS = reader.ReadUIn16Enum <QCLASS>(); }