//protected virtual void OnResolutionCompleted(DnsClient.DNS.QTYPE question, DnsClient.Response response) //{ // IEnumerable<DnsClient.DNS.RR> requested = response.AnswerRecords.OfQuestion(question); // if (requested.Any()) // { // // The requested record type was found. // LogMessageCreate(Logging.LogMessageText.RESPONSE.ResolutionSucceded(Resolver.Domain, Question, requested)); // } // else // { // // The requested record type was NOT found. // if (question == DnsClient.DNS.QTYPE.ANY) // { // // The question is ANY, so the result is acceptable. // LogMessageCreate(Logging.LogMessageText.RESPONSE.AnyResolutionSucceded(response.AnswerRecords)); // } // else // { // // maybe CNAME // } // } //} #endregion #region private private Results.ResolutionResult Request(NameServerCollection authorities, out bool isCompleted) { // perform name server request DnsClient.Request request; IPAddress address = authorities.Selected.GetFirstAddress(Resolver.Options.IPVersion); DnsClient.Response response = Resolver.LookUp(address, Question, out request); Results.ResolutionResult result = new Results.ResolutionResult(this.NestingLevel, request, response, authorities); // "Request took {0}ms." LogMessageCreate(Logging.LogMessageText.RESPONSE.INFO.RequestDuration(result.Duration.TotalMilliseconds)); if (response.Header.AA) { // authoritative response isCompleted = true; } else { // [RFC 1035] // Name Error - Meaningful only for responses from an authoritative name server, // this code signifies that the domain name referenced in the query does not exist. // stop if the response was any other than NoError or NameError isCompleted = !( response.Header.RCODE == DnsClient.DNS.RCODE.NoError || response.Header.RCODE == DnsClient.DNS.RCODE.NameError); } return(result); }
//// private sub-iterator //private ResolutionIterator(ResolutionIterator iterator, DnsDomain domain, DnsClient.DNS.QTYPE question) // : base(new Resolver(iterator.Resolver, domain), question, iterator.AddressCache) //{ // IsSubIterator = true; //} #endregion #region override public override void Reset() { base.Reset(); LastAddressResult = null; AddressIterator = null; CNameIterator = null; //TCRepeating = false; RootCacheState = true; }
public override void Reset() { base.Reset(); LastAddressResult = null; AddressIterator = null; CNameIterator = null; //TCRepeating = false; RootCacheState = true; }
private NameServerCollection GetResultAuthorities(Results.ResolutionResult result) { // get authority records from existing result NameServerCollection authorities = NameServerCollection.Create( result.Response.AuthorityRecords, result.Response.AdditionalRecords); // save top level name server cache if (!RootCacheState) { RootServers.Cache.Set(authorities.ZoneName, authorities); RootCacheState = true; } return(authorities); }
public IEnumerable <DnsClient.DNS.Records.Address> GetAddresses(Results.ResolutionResult result) { IEnumerable <DnsClient.DNS.RR> rrset = null; switch (result.QueryState) { case QueryState.AuthoritativeAnswer: rrset = result.Response.AnswerRecords; break; case QueryState.NonAuthoritativeAnswer: rrset = result.Response.AdditionalRecords; break; } if (!object.ReferenceEquals(null, rrset)) { return(rrset.Select <DnsClient.DNS.Records.Address>().Where( a => this.Resolver.Domain.Equals(a.Base.NAME))); } return(null); }
protected override Results.ResolutionResult GetNextResult(out bool isCompleted, NameServer selected) { Results.ResolutionResult result = base.GetNextResult(out isCompleted, selected); if (isCompleted) { IEnumerable <DnsClient.DNS.RR> rrset = null; switch (result.QueryState) { case QueryState.AuthoritativeAnswer: rrset = result.Response.AnswerRecords; break; case QueryState.NonAuthoritativeAnswer: rrset = result.Response.AdditionalRecords; break; } if (!object.ReferenceEquals(null, rrset)) { this.Addresses = rrset.Select <DnsClient.DNS.Records.Address>().Where( a => this.Resolver.Domain.Equals(a.Base.NAME)); } } return(result); }
protected override Results.ResolutionResult GetNextResult(out bool isCompleted, NameServer selected) { // Iteration may be delegated to CNameIterator if the requested name // has been identified as alias. if (!object.ReferenceEquals(null, CNameIterator)) { CNameIterator.EnsureConnection(Resolver.Client); return(CNameIterator.GetNextResult(out isCompleted, selected)); } // A subsequent iteration may be running if a name server address needs to be resolved. if (!object.ReferenceEquals(null, AddressIterator)) { AddressIterator.EnsureConnection(Resolver.Client); bool isAddressIteratorCompleted; Results.ResolutionResult addressResult = AddressIterator.GetNextResult(out isAddressIteratorCompleted, selected); if (isAddressIteratorCompleted) { // remember the last result from the subsequent iteration ResolvedAddresses = AddressIterator.GetAddresses(addressResult).ToArray(); if (!ResolvedAddresses.Any()) { // Failed to resolve isCompleted = true; } LastAddressResult = addressResult; AddressIterator.Dispose(); AddressIterator = null; } isCompleted = false; return(addressResult); } // Apply address result from previous step. if (!object.ReferenceEquals(null, LastAddressResult)) { // An address iteration has been completed in the previous step. try { // Apply the resulting address records to the selected authority. IEnumerable <DnsClient.DNS.Records.Address> addresses; if (LastAddressResult.Response.Header.AA) { // fetch addresses from authoritative respone addresses = LastAddressResult.Response.AnswerRecords.OfType < DnsClient.DNS.Records.Address>().Where(a => StoredAuthorities.Selected.Name.Equals(a.Base.NAME)); } else { // fetch address from additional records addresses = LastAddressResult.Response.AdditionalRecords.OfType < DnsClient.DNS.Records.Address>().Where(a => StoredAuthorities.Selected.Name.Equals(a.Base.NAME)); } if (addresses.Any()) { StoredAuthorities.Selected.ApplyAddresses(addresses); OnNameServerResolved(StoredAuthorities.Selected); } } finally { LastAddressResult = null; } } else { // The standard case // Ensure StoredAuthorities with a resolved selected name server. if (object.ReferenceEquals(null, StoredAuthorities)) // initial state { StoredAuthorities = GetStartAuthorities(); OnResolutionStart(StoredAuthorities); } else { OnResolutionContinue(StoredAuthorities); } // apply cached address records to the set of authorities StoredAuthorities.ApplyCache(AddressCache); // Select randomly any name server unless one was explicitly chosen. if (!object.ReferenceEquals(null, selected)) { StoredAuthorities.SelectOne(selected); } else { selected = StoredAuthorities.SelectAny(); } OnAuthoritySelected(StoredAuthorities); if (!selected.IsResolved) { // start a subsequent iteration to resolve the selected name server OnNameServerResolution(selected); AddressIterator = CreateAddressIterator(selected.Name); return(GetNextResult(out isCompleted, null)); } } // Perform the actual name server request. Results.ResolutionResult result = Request(StoredAuthorities, out isCompleted); try // Internal.QueryException { Internal.QueryProcessor query = new Internal.QueryProcessor(Resolver.Domain, Question, result.Response); Internal.QueryResult qr = query.Process(); result.QueryState = qr.State; switch (qr.State) { case QueryState.NextAuthorities: //StoredAuthorities = GetResultAuthorities(result); isCompleted = false; OnNextAuthorities(StoredAuthorities.Selected, qr.NextAuthorities); StoredAuthorities = qr.NextAuthorities; result.NextAuthorities = StoredAuthorities; // "Received {1} '{0}' authorities from '{2}'." //LogMessageCreate(Logging.LogMessageText.RESPONSE.INFO.NextAuthoritiesReceived( StoredAuthorities.Selected, result.NextAuthorities)); break; case QueryState.FollowCName: // CNAME found. isCompleted = true; OnCNameFound(qr.CanonicalName); // Follow, if it's configured. if (Resolver.Options.FollowCanonical) { // Start a new iteration with the canonical name and the same question. // Name servers may or may not be given. CNameIterator = CreateCNameIterator(qr.CanonicalName, qr.NextAuthorities); isCompleted = false; } break; case QueryState.NonAuthoritativeAnswer: isCompleted = true; OnResolutionSucceeded(result.Response, qr.Answers); break; case QueryState.AuthoritativeAnswer: // At least one record of the requested type was found. isCompleted = true; OnResolutionSucceeded(result.Response, qr.Answers); break; case QueryState.NxDomain: isCompleted = true; LogMessageCreate(Logging.LogMessageText.RESPONSE.ERROR.NameNotExisting(qr.CanonicalName ?? Resolver.Domain)); break; case QueryState.NoData: case QueryState.EmptyResponse: isCompleted = true; LogMessageCreate(Logging.LogMessageText.RESPONSE.ERROR.NegativeResponse(qr.State)); break; case QueryState.UnexpectedRCode: isCompleted = true; OnRCodeNonZero(result.Response); break; } } catch (Internal.QueryException ex) { isCompleted = true; result.QueryState = ex.State; LogMessageCreate(Logging.LogMessageText.RESPONSE.ERROR.ResponseInvalid(ex.State)); } return(result); // ===================================================================== #region hidden //// Dealing with non-Zero RCODE. //if (isCompleted && result.Response.Header.RCODE != DnsClient.DNS.RCODE.NoError) //{ // OnRCodeNonZero(result.Response); // return result; //} //// cache response address records //AddressCache.Set(result.Response.AnswerRecords.OfType<DnsClient.DNS.Records.Address>()); //if (!Resolver.Options.StrictAuhtoritative) // optionally cache also additional address records //{ // AddressCache.Set(result.Response.AdditionalRecords.Select<DnsClient.DNS.Records.Address>()); //} //if (result.Response.Header.TC) //{ // // If the result was truncated, the request can be repeated once. // if (Resolver.Options.RepeatTruncated && !TCRepeating) // { // TCRepeating = true; // isCompleted = false; // OnRepeatTruncated(); // return result; // } //} //TCRepeating = false; //if (isCompleted) //{ // // There was an authoritative response. // DnsClient.DNS.Records.SOA soa = result.Response.AnswerRecords.OfType<DnsClient.DNS.Records.SOA>().FirstOrDefault(); // // answer records matching the question // IEnumerable<DnsClient.DNS.RR> requested = result.Response.AnswerRecords; // if (Question != DnsClient.DNS.QTYPE.ANY) // { // // A particular record type has been queried (not ANY). // requested = requested.OfQuestion(Question); // } // if (requested.Any()) // { // // At least one record of the requested type was found. // OnResolutionSucceeded(result.Response, requested); // } // // check for CNAME // // // // [RFC 1034], 5.2.2. Aliases // // // // In most cases a resolver simply restarts the query at the new name when // // it encounters a CNAME. However, when performing the general function, // // the resolver should not pursue aliases when the CNAME RR matches the // // query type. This allows queries which ask whether an alias is present. // // For example, if the query type is CNAME, the user is interested in the // // CNAME RR itself, and not the RRs at the name it points to. // DnsClient.DNS.Records.CNAME cname; // if (!object.ReferenceEquals(null, ( // cname = result.Response.AnswerRecords.FirstOrDefault<DnsClient.DNS.Records.CNAME>()))) // { // // CNAME found. // //OnCNameFound(cname); // if (Question != DnsClient.DNS.QTYPE.CNAME) // { // // A CNAME can lead to the zone itself. // if (!object.ReferenceEquals(null, soa) && // DnsDomain.Equals(soa.Base.NAME, cname.CANONICAL)) // { // // TODO // } // } // // Follow, if it's configured and the question was not CNAME. // if (!Question.Equals(DnsClient.DNS.QTYPE.CNAME) && // Resolver.Options.FollowCanonical) // { // // Start a new iteration with the canonical name and the same question. // CNameIterator = CreateCNameIterator((DnsDomain)cname.CANONICAL); // isCompleted = false; // } // } // else // { // // no matching CNAME found // if (!requested.Any()) // { // // Neither an appropriate CNAME nor the requested RR type was found. // OnMissingRecords(result.Response); // } // } // if (NestingLevel == 0) // { // // "Resolution finished." // LogMessageCreate(Logging.LogMessageText.RESPONSE.INFO.ResolutionFinished(IterationCount)); // } //} //else //{ // // The iteration is not yet completed: get authorities for the next step. // StoredAuthorities = GetResultAuthorities(result); // result.NextAuthorities = StoredAuthorities; // if (StoredAuthorities.IsEmpty) // throw new ResolverException( // "No authority name servers were found although the respone is non-authoritative."); // // "Received {1} '{0}' authorities from '{2}'." // LogMessageCreate(Logging.LogMessageText.RESPONSE.INFO.NextAuthoritiesReceived(result.Authorities.Selected, result.NextAuthorities)); //} //return result; #endregion }
private Results.ResolutionResult Request(NameServerCollection authorities, out bool isCompleted) { // perform name server request DnsClient.Request request; IPAddress address = authorities.Selected.GetFirstAddress(Resolver.Options.IPVersion); DnsClient.Response response = Resolver.LookUp(address, Question, out request); Results.ResolutionResult result = new Results.ResolutionResult(this.NestingLevel, request, response, authorities); // "Request took {0}ms." LogMessageCreate(Logging.LogMessageText.RESPONSE.INFO.RequestDuration(result.Duration.TotalMilliseconds)); if (response.Header.AA) { // authoritative response isCompleted = true; } else { // [RFC 1035] // Name Error - Meaningful only for responses from an authoritative name server, // this code signifies that the domain name referenced in the query does not exist. // stop if the response was any other than NoError or NameError isCompleted = !( response.Header.RCODE == DnsClient.DNS.RCODE.NoError || response.Header.RCODE == DnsClient.DNS.RCODE.NameError); } return result; }
protected override Results.ResolutionResult GetNextResult(out bool isCompleted, NameServer selected) { // Iteration may be delegated to CNameIterator if the requested name // has been identified as alias. if (!object.ReferenceEquals(null, CNameIterator)) { CNameIterator.EnsureConnection(Resolver.Client); return CNameIterator.GetNextResult(out isCompleted, selected); } // A subsequent iteration may be running if a name server address needs to be resolved. if (!object.ReferenceEquals(null, AddressIterator)) { AddressIterator.EnsureConnection(Resolver.Client); bool isAddressIteratorCompleted; Results.ResolutionResult addressResult = AddressIterator.GetNextResult(out isAddressIteratorCompleted, selected); if (isAddressIteratorCompleted) { // remember the last result from the subsequent iteration ResolvedAddresses = AddressIterator.GetAddresses(addressResult).ToArray(); if (!ResolvedAddresses.Any()) { // Failed to resolve isCompleted = true; } LastAddressResult = addressResult; AddressIterator.Dispose(); AddressIterator = null; } isCompleted = false; return addressResult; } // Apply address result from previous step. if (!object.ReferenceEquals(null, LastAddressResult)) { // An address iteration has been completed in the previous step. try { // Apply the resulting address records to the selected authority. IEnumerable<DnsClient.DNS.Records.Address> addresses; if (LastAddressResult.Response.Header.AA) { // fetch addresses from authoritative respone addresses = LastAddressResult.Response.AnswerRecords.OfType< DnsClient.DNS.Records.Address>().Where(a => StoredAuthorities.Selected.Name.Equals(a.Base.NAME)); } else { // fetch address from additional records addresses = LastAddressResult.Response.AdditionalRecords.OfType< DnsClient.DNS.Records.Address>().Where(a => StoredAuthorities.Selected.Name.Equals(a.Base.NAME)); } if (addresses.Any()) { StoredAuthorities.Selected.ApplyAddresses(addresses); OnNameServerResolved(StoredAuthorities.Selected); } } finally { LastAddressResult = null; } } else { // The standard case // Ensure StoredAuthorities with a resolved selected name server. if (object.ReferenceEquals(null, StoredAuthorities)) // initial state { StoredAuthorities = GetStartAuthorities(); OnResolutionStart(StoredAuthorities); } else { OnResolutionContinue(StoredAuthorities); } // apply cached address records to the set of authorities StoredAuthorities.ApplyCache(AddressCache); // Select randomly any name server unless one was explicitly chosen. if (!object.ReferenceEquals(null, selected)) { StoredAuthorities.SelectOne(selected); } else { selected = StoredAuthorities.SelectAny(); } OnAuthoritySelected(StoredAuthorities); if (!selected.IsResolved) { // start a subsequent iteration to resolve the selected name server OnNameServerResolution(selected); AddressIterator = CreateAddressIterator(selected.Name); return GetNextResult(out isCompleted, null); } } // Perform the actual name server request. Results.ResolutionResult result = Request(StoredAuthorities, out isCompleted); try // Internal.QueryException { Internal.QueryProcessor query = new Internal.QueryProcessor(Resolver.Domain, Question, result.Response); Internal.QueryResult qr = query.Process(); result.QueryState = qr.State; switch (qr.State) { case QueryState.NextAuthorities: //StoredAuthorities = GetResultAuthorities(result); isCompleted = false; OnNextAuthorities(StoredAuthorities.Selected, qr.NextAuthorities); StoredAuthorities = qr.NextAuthorities; result.NextAuthorities = StoredAuthorities; // "Received {1} '{0}' authorities from '{2}'." //LogMessageCreate(Logging.LogMessageText.RESPONSE.INFO.NextAuthoritiesReceived( StoredAuthorities.Selected, result.NextAuthorities)); break; case QueryState.FollowCName: // CNAME found. isCompleted = true; OnCNameFound(qr.CanonicalName); // Follow, if it's configured. if (Resolver.Options.FollowCanonical) { // Start a new iteration with the canonical name and the same question. // Name servers may or may not be given. CNameIterator = CreateCNameIterator(qr.CanonicalName, qr.NextAuthorities); isCompleted = false; } break; case QueryState.NonAuthoritativeAnswer: isCompleted = true; OnResolutionSucceeded(result.Response, qr.Answers); break; case QueryState.AuthoritativeAnswer: // At least one record of the requested type was found. isCompleted = true; OnResolutionSucceeded(result.Response, qr.Answers); break; case QueryState.NxDomain: isCompleted = true; LogMessageCreate(Logging.LogMessageText.RESPONSE.ERROR.NameNotExisting(qr.CanonicalName ?? Resolver.Domain)); break; case QueryState.NoData: case QueryState.EmptyResponse: isCompleted = true; LogMessageCreate(Logging.LogMessageText.RESPONSE.ERROR.NegativeResponse(qr.State)); break; case QueryState.UnexpectedRCode: isCompleted = true; OnRCodeNonZero(result.Response); break; } } catch (Internal.QueryException ex) { isCompleted = true; result.QueryState = ex.State; LogMessageCreate(Logging.LogMessageText.RESPONSE.ERROR.ResponseInvalid(ex.State)); } return result; // ===================================================================== #region hidden //// Dealing with non-Zero RCODE. //if (isCompleted && result.Response.Header.RCODE != DnsClient.DNS.RCODE.NoError) //{ // OnRCodeNonZero(result.Response); // return result; //} //// cache response address records //AddressCache.Set(result.Response.AnswerRecords.OfType<DnsClient.DNS.Records.Address>()); //if (!Resolver.Options.StrictAuhtoritative) // optionally cache also additional address records //{ // AddressCache.Set(result.Response.AdditionalRecords.Select<DnsClient.DNS.Records.Address>()); //} //if (result.Response.Header.TC) //{ // // If the result was truncated, the request can be repeated once. // if (Resolver.Options.RepeatTruncated && !TCRepeating) // { // TCRepeating = true; // isCompleted = false; // OnRepeatTruncated(); // return result; // } //} //TCRepeating = false; //if (isCompleted) //{ // // There was an authoritative response. // DnsClient.DNS.Records.SOA soa = result.Response.AnswerRecords.OfType<DnsClient.DNS.Records.SOA>().FirstOrDefault(); // // answer records matching the question // IEnumerable<DnsClient.DNS.RR> requested = result.Response.AnswerRecords; // if (Question != DnsClient.DNS.QTYPE.ANY) // { // // A particular record type has been queried (not ANY). // requested = requested.OfQuestion(Question); // } // if (requested.Any()) // { // // At least one record of the requested type was found. // OnResolutionSucceeded(result.Response, requested); // } // // check for CNAME // // // // [RFC 1034], 5.2.2. Aliases // // // // In most cases a resolver simply restarts the query at the new name when // // it encounters a CNAME. However, when performing the general function, // // the resolver should not pursue aliases when the CNAME RR matches the // // query type. This allows queries which ask whether an alias is present. // // For example, if the query type is CNAME, the user is interested in the // // CNAME RR itself, and not the RRs at the name it points to. // DnsClient.DNS.Records.CNAME cname; // if (!object.ReferenceEquals(null, ( // cname = result.Response.AnswerRecords.FirstOrDefault<DnsClient.DNS.Records.CNAME>()))) // { // // CNAME found. // //OnCNameFound(cname); // if (Question != DnsClient.DNS.QTYPE.CNAME) // { // // A CNAME can lead to the zone itself. // if (!object.ReferenceEquals(null, soa) && // DnsDomain.Equals(soa.Base.NAME, cname.CANONICAL)) // { // // TODO // } // } // // Follow, if it's configured and the question was not CNAME. // if (!Question.Equals(DnsClient.DNS.QTYPE.CNAME) && // Resolver.Options.FollowCanonical) // { // // Start a new iteration with the canonical name and the same question. // CNameIterator = CreateCNameIterator((DnsDomain)cname.CANONICAL); // isCompleted = false; // } // } // else // { // // no matching CNAME found // if (!requested.Any()) // { // // Neither an appropriate CNAME nor the requested RR type was found. // OnMissingRecords(result.Response); // } // } // if (NestingLevel == 0) // { // // "Resolution finished." // LogMessageCreate(Logging.LogMessageText.RESPONSE.INFO.ResolutionFinished(IterationCount)); // } //} //else //{ // // The iteration is not yet completed: get authorities for the next step. // StoredAuthorities = GetResultAuthorities(result); // result.NextAuthorities = StoredAuthorities; // if (StoredAuthorities.IsEmpty) // throw new ResolverException( // "No authority name servers were found although the respone is non-authoritative."); // // "Received {1} '{0}' authorities from '{2}'." // LogMessageCreate(Logging.LogMessageText.RESPONSE.INFO.NextAuthoritiesReceived(result.Authorities.Selected, result.NextAuthorities)); //} //return result; #endregion }