anchor.diff:  -export([siplookup/1, enumlookup/1, enumlookup/2, get_ip_port/2]).
   
   -include("inet_dns.hrl").
  -
  -srvlookup(Proto, Name) ->
  +-include_lib("kernel/include/inet.hrl").
  +
  +%% For debugging
  +-compile(export_all).
  +
  +%% These records is entirely internal to this module
  +-record(srventry, {proto, dnsrrdata}).
  +-record(naptrrecord, {order, preference, flags, services, regexp, replacement}).
  +
  +%%--------------------------------------------------------------------
  +%% Function: srvlookup/2
  +%% Description: Resolve a SRV record (indicated by Name) and return a
  +%%              list of srventry records. The DNS RR data in them is
  +%%              of the format {Order, Pref, Port, Host}.
  +%% Returns: SRVList         |
  +%%          {error, Reason}
  +%%--------------------------------------------------------------------
  +srvlookup(Proto, Name) when list(Name) ->
       case inet_res:nslookup(Name, in, srv) of
   	{ok, Rec} ->
   	    ParseSRV = fun(Entry) ->
  -			       {Proto, Entry#dns_rr.data}
  -			  end,
  +			       #srventry{proto=Proto, dnsrrdata=Entry#dns_rr.data}
  +		       end,
   	    lists:map(ParseSRV, Rec#dns_rec.anlist);
   	{error, What} ->
   	    logger:log(debug, "dns resolver: Error ~p when resolving ~p IN SRV", [What, Name]),
   	    {error, What}
       end.
   
  +
  +%%--------------------------------------------------------------------
  +%% Function: siplookup/1
  +%% Description: Look up where to send SIP requests for a domain name.
  +%%              Ultimately return a list of {Proto, Host, Port} and/or
  +%%              {error, E} entrys. Proto is tcp, udp or tls. Never
  +%%              tcp6, udp6 or tls6 since we do not resolve Host into
  +%%              an address.
  +%% Returns: ProtoHostPortList
  +%%--------------------------------------------------------------------
   siplookup([]) ->
       none;
   siplookup(Domain) ->
  -    TCP = srvlookup(tcp, "_sip._tcp." ++ Domain),
  -    UDP = srvlookup(udp, "_sip._udp." ++ Domain),
  -    combine_srvresults(lists:sort(fun sortsrv/2, lists:flatten([TCP, UDP]))).
  -
  +    case siplookup_naptr(Domain) of
  +	nomatch ->
  +	    %% No domain NAPTR records found. Perform RFC2543 backwards compatible
  +	    %% SRV lookup of the domain.
  +	    logger:log(debug, "Resolver: Domain ~p has no NAPTR records, perform RFC2543 backwards " ++
  +		       "compatible lookup for SIP SRV records under that domain name", [Domain]),
  +	    TCP = srvlookup(tcp, "_sip._tcp." ++ Domain),
  +	    UDP = srvlookup(udp, "_sip._udp." ++ Domain),
  +	    combine_srvresults(lists:sort(fun sortsrv/2, lists:flatten([TCP, UDP])));
  +	Res ->
  +	    %% siplookup_naptr does it's own sorting
  +	    combine_srvresults(Res)
  +    end.
  +
  +%%--------------------------------------------------------------------
  +%% Function: siplookup_naptr/1
  +%% Description: Look for NAPTR records for a domain telling us where
  +%%              to look for SRV records for the very same domain.
  +%% Returns: SRVList |
  +%%          nomatch
  +%%--------------------------------------------------------------------
  +siplookup_naptr(Domain) when list(Domain) ->
  +    case naptrlookup(Domain) of
  +	[] ->
  +	    nomatch;
  +	L1 ->
  +	    L2 = lists:append([filter_naptr(L1, "s", "SIP+D2U"), filter_naptr(L1, "s", "SIP+D2T"),
  +			      filter_naptr(L1, "s","SIPS+D2T")]),
  +	    L3 = lists:sort(fun sortenum/2, L2),
  +	    %% Ok, we now have a preference sorted list of NAPTR results. Look for
  +	    %% SRV records matching each of them. Sort SRV records only per NAPTR -
  +	    %% the NAPTR order of preference supersedes the SRV ordering.
  +	    naptr_to_srvlist(Domain, L3)
  +    end.
  +
  +
  +%%--------------------------------------------------------------------
  +%% Function: siplookup_naptr/1
  +%% Description: Take a list of sorted NAPTR records and try to turn
  +%%              them into SRV records.
  +%% Returns: SRVList |
  +%%          nomatch
  +%%--------------------------------------------------------------------
  +naptr_to_srvlist(Domain, In) ->
  +    naptr_to_srvlist2(Domain, In, []).
  +
  +naptr_to_srvlist2(Domain, [], Res) ->
  +    logger:log(debug, "dns resolver: Domain ~s NAPTR lookup result : ~p", [Domain, Res]),
  +    Res;
  +naptr_to_srvlist2(Domain, [H | Rest], Res) when record(H, naptrrecord) ->
  +    Proto = case H#naptrrecord.services of
  +		"SIP+D2U"  ++ _ -> udp;
  +		"SIP+D2T"  ++ _ -> tcp;
  +		"SIPS+D2T" ++ _ -> tls
  +	    end,
  +    %% Regexp should be empty for domain NAPTR - RFC3263 #4.1. The
  +    %% interesting thing is the replacement.
  +    This = srvlookup(Proto, H#naptrrecord.replacement),
  +    Sorted = lists:sort(fun sortsrv/2, This),
  +    naptr_to_srvlist2(Domain, Rest, lists:flatten([Res, Sorted])).
  +
  +
  +%%--------------------------------------------------------------------
  +%% Function: combine_srvresults/1
  +%% Description: Walk through a list of srventry records or {error, R}
  +%%              tuples and turn the srventry records into
  +%%              {Proto, Host, Port} tuples.
  +%% Returns: ProtoHostPortList
  +%%--------------------------------------------------------------------
   combine_srvresults(List) ->
       combine_srvresults(List, [], []).
   
  
positive.code:     Res;
  combine_srvresults([{error, What} | T], Res, Errors) ->
      combine_srvresults(T, Res, lists:append(Errors, [{error, What}]));
  combine_srvresults([{Proto, {_, _, Port, Host}} | T], Res, Errors) ->
      combine_srvresults(T, lists:append(Res, [{Proto, Host, Port}]), Errors).
  
  sortsrv({_, {Order1, Preference1, Port1, Host1}}, {_, {Order2, Preference2, Port2, Host2}}) ->
      if
  	Order1 < Order2 ->
  	    true;
  
negative.code: 	    Rewrite
      end.
  
  
  %%--------------------------------------------------------------------
  %% Function: enumalldomains/2
  %% Description: Perform ENUM NAPTR lookup of Number under a set of
  %%              domains and result a list of naptrrecord records.
  %% Returns: NAPTRList
  %%--------------------------------------------------------------------
  enumalldomains(Number, Domains) ->
      enumalldomains2(Number, Domains, []).
  
  enumalldomains2(Number, [], Res) ->
      Res;
  enumalldomains2(Number, [Domain | Rest], Res) ->
      ENUMdomain = number2enum(lists:reverse(Number), Domain),
      This = naptrlookup(ENUMdomain),
      enumalldomains2(Number, Rest, lists:append(Res, This)).
  
  
  %%--------------------------------------------------------------------
  %% Function: chooseenum/2
  %% Description: Pick out all NAPTR records we recognize as ENUM NAPTR
  %%              records from a list of naptrrecord records.
  %% Returns: ENUMNAPTRList
  %%--------------------------------------------------------------------
  chooseenum([], Type) ->
      [];
  chooseenum([Elem | Rest], Type) when record(Elem, naptrrecord), Elem#naptrrecord.flags == "u", Elem#naptrrecord.replacement == "" ->
      case Elem#naptrrecord.services of
  	Type ->
  	    %% exact match of Type
  	    [Elem | chooseenum(Rest, Type)];
  	OtherType ->
  	    TypeColon = Type ++ ":",
  	    case string:substr(OtherType, 1, length(Type) + 1) of
  		TypeColon ->
  		    %% Type matches, but there is also a subtype (which we ignore)
  		    [Elem | chooseenum(Rest, Type)];
  		_ ->
  		    chooseenum(Rest, Type)
  	    end;
  	_ ->
  	    chooseenum(Rest, Type)
      end;
  chooseenum([H | Rest], Type) when record(H, naptrrecord), H#naptrrecord.flags /= "u" ->
      logger:log(debug, "Resolver: Skipping ENUM NAPTR because flags is not 'u' : ~p", [H]),
      chooseenum(Rest, Type);
  chooseenum([H | Rest], Type) when record(H, naptrrecord), H#naptrrecord.replacement /= "" ->
      logger:log(debug, "Resolver: Skipping ENUM NAPTR because replacement is not empty : ~p", [H]),
      chooseenum(Rest, Type).
  
  
  %%--------------------------------------------------------------------
  %% Function: sortenum/2
  %% Description: lists:sort function for ENUM naptrrecord records.
  %%              Return true if A has lower order, or if the order
  %%              is the same, if A has the lowest preference.
  %% Returns: true  |
  %%          false
  %%--------------------------------------------------------------------
  sortenum(A, B) when record(A, naptrrecord), record(B, naptrrecord), A#naptrrecord.order < B#naptrrecord.order ->
      true;
  sortenum(A, B) when record(A, naptrrecord), record(B, naptrrecord), A#naptrrecord.preference < B#naptrrecord.preference ->
      true;
  sortenum(A, B) when record(A, naptrrecord), record(B, naptrrecord) ->
      false.
  
  
  %%--------------------------------------------------------------------
  %% Function: naptr_regexp/1
  %% Description: Return the regexps from a list of naptrrecords.
  %% Returns: RegexpList
  %%--------------------------------------------------------------------
  naptr_regexp([]) ->
      [];
  naptr_regexp([H | T]) when record(H, naptrrecord) ->
      [H#naptrrecord.regexp | naptr_regexp(T)].
  
  
  %%--------------------------------------------------------------------
  %% Function: enumlookup/1
  %% Description: Do ENUM (RFC2916 and 2916bis) lookup on a E.164 number
  %%              in the default configured list of ENUM domains. Uses
  %%              enumlookup/2 below.
  %% Returns:
  %%--------------------------------------------------------------------
  enumlookup(none) ->
      none;
  enumlookup("+" ++ Number) ->
  