anchor.diff:  %% An SOA was found, thus we are authoritative and have the zone.
   %% Step 3: Match records
   resolve(Message, Qname, Qtype, Zone, {ClientIP, ServerIP}, CnameChain) ->
  -  Records = erldns_zone_cache:retrieve_updated_records(ServerIP, Qname),
  -  resolve(Message, Qname, Qtype, Records, ClientIP, CnameChain, Zone).
  +  Records = erldns_zone_cache:retrieve_records(ServerIP, Qname),
  +  resolve(Message, Qname, Qtype, Records, {ClientIP, ServerIP}, CnameChain, Zone).
   
   %% There were no exact matches on name, so move to the best-match resolution.
  -resolve(Message, Qname, Qtype, _MatchedRecords = [], ClientIP, CnameChain, Zone) ->
  +resolve(Message, Qname, Qtype, _MatchedRecords = [], {ClientIP, ServerIP}, CnameChain, Zone) ->
     %erldns_log:debug("No exact matches, using best-match resolution"),
  -  best_match_resolution(Message, Qname, Qtype, ClientIP, CnameChain, best_match(Qname, Zone), Zone);
  +  best_match_resolution(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, best_match(Qname, Zone), Zone);
   
   %% There was at least one exact match on name.
  -resolve(Message, Qname, Qtype, MatchedRecords, ClientIP, CnameChain, Zone) ->
  +resolve(Message, Qname, Qtype, MatchedRecords, {ClientIP, ServerIP}, CnameChain, Zone) ->
     %erldns_log:debug("Exect match on name ~p (records: ~p)", [Qname, MatchedRecords]),
  -  exact_match_resolution(Message, Qname, Qtype, ClientIP, CnameChain, MatchedRecords, Zone).
  +  exact_match_resolution(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, MatchedRecords, Zone).
   
   
   
   %% Determine if there is a CNAME anywhere in the records with the given Qname.
  -exact_match_resolution(Message, Qname, Qtype, ClientIP, CnameChain, MatchedRecords, Zone) ->
  +exact_match_resolution(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, MatchedRecords, Zone) ->
     CnameRecords = lists:filter(erldns_records:match_type(?DNS_TYPE_CNAME), MatchedRecords), % Query record set for CNAME type
  -  exact_match_resolution(Message, Qname, Qtype, ClientIP, CnameChain, MatchedRecords, Zone, CnameRecords).
  +  exact_match_resolution(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, MatchedRecords, Zone, CnameRecords).
   
   %% No CNAME records found in the records with the Qname
  -exact_match_resolution(Message, Qname, Qtype, ClientIP, CnameChain, MatchedRecords, Zone, _CnameRecords = []) ->
  -  resolve_exact_match(Message, Qname, Qtype, ClientIP, CnameChain, MatchedRecords, Zone);
  +exact_match_resolution(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, MatchedRecords, Zone, _CnameRecords = []) ->
  +  resolve_exact_match(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, MatchedRecords, Zone);
   
   %% CNAME records found in the records for the Qname
  -exact_match_resolution(Message, _Qname, Qtype, ClientIP, CnameChain, MatchedRecords, Zone, CnameRecords) ->
  -  resolve_exact_match_with_cname(Message, Qtype, ClientIP, CnameChain, MatchedRecords, Zone, CnameRecords).
  +exact_match_resolution(Message, _Qname, Qtype, {ClientIP, ServerIP}, CnameChain, MatchedRecords, Zone, CnameRecords) ->
  +  resolve_exact_match_with_cname(Message, Qtype, {ClientIP, ServerIP}, CnameChain, MatchedRecords, Zone, CnameRecords).
   
   
   
   
   %% There were no CNAMEs found in the exact name matches, so now we grab the authority
   %% records and find any type matches on QTYPE and continue on.
  -resolve_exact_match(Message, Qname, Qtype, ClientIP, CnameChain, MatchedRecords, Zone) ->
  +resolve_exact_match(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, MatchedRecords, Zone) ->
     AuthorityRecords = lists:filter(erldns_records:match_type(?DNS_TYPE_SOA), MatchedRecords), % Query matched records for SOA type
     TypeMatches = case Qtype of
                     ?DNS_TYPE_ANY ->
  
positive.code:       %erldns_log:debug("No type matches found, using custom handlers"),
        NewRecords = lists:map(erldns_records:replace_name(Qname), lists:flatten(lists:map(custom_lookup(Qname, Qtype, MatchedRecords), erldns_handler:get_handlers()))),
        %erldns_log:debug("Records from custom handlers: ~p", [NewRecords]),
        resolve_best_match_with_wildcard(Message, Qname, Qtype, ClientIP, CnameChain, MatchedRecords, Zone, [], NewRecords);
      _ ->
        resolve_best_match_with_wildcard(Message, Qname, Qtype, ClientIP, CnameChain, MatchedRecords, Zone, [], TypeMatches)
    end;
  
  % It is a wildcard CNAME
  resolve_best_match_with_wildcard(Message, Qname, Qtype, ClientIP, CnameChain, BestMatchRecords, Zone, CnameRecords) ->
    resolve_best_match_with_wildcard_cname(Message, Qname, Qtype, ClientIP, CnameChain, BestMatchRecords, Zone, CnameRecords).
  
  % It is not a CNAME and there were no exact type matches
  resolve_best_match_with_wildcard(Message, _Qname, _Qtype, _ClientIP, _CnameChain, _BestMatchRecords, Zone, [], []) ->
    Message#dns_message{aa = true, authority=Zone#zone.authority};
  
  % It is not a CNAME and there were exact type matches
  resolve_best_match_with_wildcard(Message, _Qname, _Qtype, _ClientIP, _CnameChain, _BestMatchRecords, _Zone, [], TypeMatches) ->
    Message#dns_message{aa = true, answers = Message#dns_message.answers ++ TypeMatches}.
  
  
  
  
  % It is a CNAME and the Qtype was CNAME
  resolve_best_match_with_wildcard_cname(Message, _Qname, ?DNS_TYPE_CNAME, _ClientIP, _CnameChain, _BestMatchRecords, _Zone, CnameRecords) ->
    Message#dns_message{aa = true, answers = Message#dns_message.answers ++ CnameRecords};
  
  % It is a CNAME and the Qtype was not CNAME
  resolve_best_match_with_wildcard_cname(Message, Qname, Qtype, ClientIP, CnameChain, BestMatchRecords, Zone, CnameRecords) ->
    CnameRecord = lists:last(CnameRecords), % There should only be one CNAME. Multiple CNAMEs kill unicorns.
    resolve_best_match_with_wildcard_cname(Message, Qname, Qtype, ClientIP, CnameChain, BestMatchRecords, Zone, CnameRecords, lists:member(CnameRecord, CnameChain)).
  
  % Indicates CNAME loop
  resolve_best_match_with_wildcard_cname(Message, _Qname, _Qtype, _ClientIP, _CnameChain, _BestMatchRecords, _Zone, _CnameRecords, true) ->
    %erldns_log:debug("CNAME loop detected (best match)"),
    Message#dns_message{aa = true, rc = ?DNS_RCODE_SERVFAIL};
  
  % We should follow the CNAME
  resolve_best_match_with_wildcard_cname(Message, _Qname, Qtype, ClientIP, CnameChain, _BestMatchRecords, Zone, CnameRecords, false) ->
    %erldns_log:debug("Follow CNAME (best match)"),
    CnameRecord = lists:last(CnameRecords),
    Name = CnameRecord#dns_rr.data#dns_rrdata_cname.dname,
    restart_query(Message#dns_message{aa = true, answers = Message#dns_message.answers ++ CnameRecords}, Name, Qtype, ClientIP, CnameChain ++ CnameRecords, Zone, erldns_zone_cache:in_zone(Name)).
  
  
  
  
  % There are referral records
  resolve_best_match_referral(Message, Qname, Qtype, ClientIP, CnameChain, BestMatchRecords, Zone, ReferralRecords) ->
    resolve_best_match_referral(Message, Qname, Qtype, ClientIP, CnameChain, BestMatchRecords, Zone, ReferralRecords, lists:filter(erldns_records:match_type(?DNS_TYPE_SOA), BestMatchRecords)). % Lookup SOA in best match records
  
  % Indicate that we are not authoritative for the name as there were no
  % SOA records in the best-match results. The name has thus been delegated
  % to another authority.
  resolve_best_match_referral(Message, _Qname, _Qtype, _ClientIP, _CnameChain, _BestMatchRecords, _Zone, ReferralRecords, []) ->
    Message#dns_message{aa = false, authority = Message#dns_message.authority ++ ReferralRecords};
  
  % We are authoritative for the name since there was an SOA record in
  % the best match results.
  resolve_best_match_referral(Message, _Qname, _Qtype, _ClientIP, [], _BestMatchRecords, _Zone, _ReferralRecords, Authority) ->
    Message#dns_message{aa = true, rc = ?DNS_RCODE_NXDOMAIN, authority = Authority};
  
  % We are authoritative and the Qtype is ANY so we just return the 
  % original message.
  resolve_best_match_referral(Message, _Qname, ?DNS_TYPE_ANY, _ClientIP, _CnameChain, _BestMatchRecords, _Zone, _ReferralRecords, _Authority) ->
    Message;
  resolve_best_match_referral(Message, _Qname, _Qtype, _ClientIP, _CnameChain, _BestMatchRecords, _Zone, _ReferralRecords, Authority) ->
    Message#dns_message{authority = Authority}.
  
  
  
negative.code: 
  % There is a CNAME record and the request was for a CNAME record so append the CNAME records to
  % the answers section..
  resolve_exact_match_with_cname(Message, ?DNS_TYPE_CNAME, {_ClientIP, _ServerIP}, _CnameChain, _MatchedRecords, _Zone, CnameRecords) ->
    Message#dns_message{aa = true, answers = Message#dns_message.answers ++ CnameRecords};
  % There is a CNAME record, however the Qtype is not CNAME, check for a CNAME loop before continuing.
  resolve_exact_match_with_cname(Message, Qtype, {ClientIP, ServerIP}, CnameChain, MatchedRecords, Zone, CnameRecords) ->
    resolve_exact_match_with_cname(Message, Qtype, {ClientIP, ServerIP}, CnameChain, MatchedRecords, Zone, CnameRecords, lists:member(lists:last(CnameRecords), CnameChain)).
  
  %% Indicates a CNAME loop. The response code is a SERVFAIL in this case.
  resolve_exact_match_with_cname(Message, _Qtype, {_ClientIP, _ServerIP}, _CnameChain, _MatchedRecords, _Zone, _CnameRecords, true) ->
    %erldns_log:debug("CNAME loop detected (exact match)"),
    Message#dns_message{aa = true, rc = ?DNS_RCODE_SERVFAIL};
  % No CNAME loop, restart the query with the CNAME content.
  resolve_exact_match_with_cname(Message, Qtype, {ClientIP, ServerIP}, CnameChain, _MatchedRecords, Zone, CnameRecords, false) ->
    CnameRecord = lists:last(CnameRecords),
    Name = CnameRecord#dns_rr.data#dns_rrdata_cname.dname,
    %erldns_log:debug("Restarting query with CNAME name ~p (exact match)", [Name]),
    restart_query(Message#dns_message{aa = true, answers = Message#dns_message.answers ++ CnameRecords}, Name, Qtype, {ClientIP, ServerIP}, CnameChain ++ CnameRecords, Zone, erldns_zone_cache:in_zone(Name)).
  
  
  
  % The CNAME is in the zone so we do not need to look it up again.
  restart_query(Message, Name, Qtype, {ClientIP, ServerIP}, CnameChain, Zone, true) ->
    resolve(Message, Name, Qtype, Zone, {ClientIP, ServerIP}, CnameChain);
  % The CNAME is not in the zone, so we need to find the zone using the
  % CNAME content.
  restart_query(Message, Name, Qtype, {ClientIP, ServerIP}, CnameChain, _Zone, false) ->
    resolve(Message, Name, Qtype, erldns_zone_cache:find_zone(Name), {ClientIP, ServerIP}, CnameChain).
  
  % Delegated, but in the same zone.
  restart_delegated_query(Message, Name, Qtype, {ClientIP, ServerIP}, CnameChain, Zone, true) ->
    resolve(Message, Name, Qtype, Zone, {ClientIP, ServerIP}, CnameChain);
  % Delegated to a different zone.
  restart_delegated_query(Message, Name, Qtype, {ClientIP, ServerIP}, CnameChain, Zone, false) ->
    resolve(Message, Name, Qtype, erldns_zone_cache:find_zone(Name, Zone#zone.authority), {ClientIP, ServerIP}, CnameChain). % Zone lookup
  
  
  
  % There was no exact match for the Qname, so we use the best matches that were
  % returned by the best_match() function.
  best_match_resolution(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, BestMatchRecords, Zone) ->
    %erldns_log:debug("No exact match found, using ~p", [BestMatchRecords]),
    ReferralRecords = lists:filter(erldns_records:match_type(?DNS_TYPE_NS), BestMatchRecords), % NS lookup
    best_match_resolution(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, BestMatchRecords, Zone, ReferralRecords).
  
  % There were no NS records in the best matches.
  best_match_resolution(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, BestMatchRecords, Zone, []) ->
    resolve_best_match(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, BestMatchRecords, Zone);
  % There were NS records in the best matches, so this is a referral.
  best_match_resolution(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, BestMatchRecords, Zone, ReferralRecords) ->
    resolve_best_match_referral(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, BestMatchRecords, Zone, ReferralRecords).
  
  
  % There is no referral, so check to see if there is a wildcard.
  resolve_best_match(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, BestMatchRecords, Zone) ->
    %erldns_log:debug("No referrals found"),
    resolve_best_match(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, BestMatchRecords, Zone, lists:any(erldns_records:match_wildcard(), BestMatchRecords)).
  
  %% It's a wildcard match
  resolve_best_match(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, BestMatchRecords, Zone, true) ->
    %erldns_log:debug("Matched records are wildcard."),
    CnameRecords = lists:filter(erldns_records:match_type(?DNS_TYPE_CNAME), lists:map(erldns_records:replace_name(Qname), BestMatchRecords)),
    resolve_best_match_with_wildcard(Message, Qname, Qtype, {ClientIP, ServerIP}, CnameChain, BestMatchRecords, Zone, CnameRecords);
  %% It is not a wildcard.
  resolve_best_match(Message, Qname, _Qtype, {_ClientIP, _ServerIP}, _CnameChain, _BestMatchRecords, Zone, false) ->
    %erldns_log:debug("Matched records are not wildcard."),
    [Question|_] = Message#dns_message.questions,
    case Qname =:= Question#dns_query.name of
  