dnsimple / erldns

DNS server, in Erlang.
MIT License
398 stars 98 forks source link

Addressing Mnesia backend failing on erldns_zone_cache functions #103

Closed m0rcq closed 4 years ago

m0rcq commented 4 years ago

Mnesia related changes addressing https://github.com/dnsimple/erldns/issues/102.

Addressing Mnesia backend failing on erldns_zone_cache functions:

* added type bag on table creation (zone_records, zone_records_typed)
* set explicit type set on table creation (zones)
* refactored select/3: using ETS match spec converted to Mnesia's
match_object pattern
* using different pattern in erldns_zone_cache:zone_names_and_versions/0
depending on backend (ETS/Mnesia foldl/3 return values are different)
nisbus commented 4 years ago

Thanks for the fix, I was just testing it:

Config:

[
 {erldns,[
      {servers, [
             [{name, inet_localhost_1}, {address, "127.0.0.1"}, {port, 8053}, {family, inet}, {processes, 2}],
             [{name, inet6_localhost_1}, {address, "::1"}, {port, 8053}, {family, inet6}]
            ]},
      {storage, [
             {type, erldns_storage_mnesia},
             {dir, "."}
            ]
      },
      {dnssec, [
            {enabled, true}
           ]},
      {use_root_hints, false},
      {catch_exceptions, false},
      {zones, "priv/example.zone.json"},
      {pools, [
           {tcp_worker_pool, erldns_worker, [
                             {size, 10},
                             {max_overflow, 20}
                            ]}
          ]}
     ]},
 {mnesia,
  [
   {dir, "."}
  ]}, 
 {lager, [
      {error_logger_redirect, false}
     ]}
].
1> erldns_zone_cache:zone_names_and_versions().
[{<<"example.com">>,[]}]

All of the calls seem to work properly from the shell, however I have issues when trying to query using dig:

 dig @127.0.0.1 -p 8053 example.com    

; <<>> DiG 9.16.1-Ubuntu <<>> @127.0.0.1 -p 8053 example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 48585
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 17c2a8de562683aa (echoed)
;; QUESTION SECTION:
;example.com.           IN  A

;; AUTHORITY SECTION:
example.com.        300 IN  SOA ns1.example.com. admin.example.com. 2013022001 86400 7200 604800 300

;; Query time: 16 msec
;; SERVER: 127.0.0.1#8053(127.0.0.1)
;; WHEN: Fri Jun 12 12:20:52 CEST 2020
;; MSG SIZE  rcvd: 98

I haven't edited the example.zone.json at all

Also if I comment out the mnesia storage from the config then dig is working properly:

; <<>> DiG 9.16.1-Ubuntu <<>> @127.0.0.1 -p 8053 example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23513
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 7e7857c7169b399d (echoed)
;; QUESTION SECTION:
;example.com.           IN  A

;; ANSWER SECTION:
example.com.        3600    IN  A   1.2.3.4

;; Query time: 1 msec
;; SERVER: 127.0.0.1#8053(127.0.0.1)
;; WHEN: Fri Jun 12 12:26:24 CEST 2020
;; MSG SIZE  rcvd: 68
nisbus commented 4 years ago

The issue is get_records_by_name
With Mnesia:

1> erldns_zone_cache:get_records_by_name(<<"example.com">>).
[]

JSON:

1> erldns_zone_cache:get_records_by_name(<<"example.com">>).
[{dns_rr,<<"example.com">>,1,1,3600,
         {dns_rrdata_a,{1,2,3,4}}},
 {dns_rr,<<"example.com">>,1,2,3600,
         {dns_rrdata_ns,<<"ns1.example.com">>}},
 {dns_rr,<<"example.com">>,1,2,3600,
         {dns_rrdata_ns,<<"ns2.example.com">>}},
 {dns_rr,<<"example.com">>,1,6,3600,
         {dns_rrdata_soa,<<"ns1.example.com">>,
                         <<"admin.example.com">>,2013022001,86400,7200,604800,300}},
 {dns_rr,<<"example.com">>,1,15,3600,
         {dns_rrdata_mx,10,<<"mail.example.com">>}},
 {dns_rr,<<"example.com">>,1,16,3600,
         {dns_rrdata_txt,[<<"Hi, this is some text">>]}},
 {dns_rr,<<"example.com">>,1,28,3600,
         {dns_rrdata_aaaa,{8193,1704,0,1,528,19455,65099,19553}}},
 {dns_rr,<<"example.com">>,1,257,3600,
         {dns_rrdata_caa,0,<<"issue">>,<<"example.net">>}}]
nisbus commented 4 years ago

Here is a fix that works at least:

-spec get_records_by_name(dns:dname()) -> [dns:rr()].
get_records_by_name(Name) ->
    case find_zone_in_cache(Name) of
    {ok, Zone} ->
        case erldns_config:storage_type() of
        erldns_storage_json ->
            case erldns_storage:select(zone_records, {erldns:normalize_name(Zone#zone.name), erldns:normalize_name(Name)}) of
            [] -> [];
            [{_, Records}] -> Records
            end;
        erldns_storage_mnesia ->
            lists:filter(fun(#dns_rr{name = RecordName}) ->
                     RecordName =:= erldns:normalize_name(Name)
                    end, get_zone_records(erldns:normalize_name(Zone#zone.name)))
        end;
    _ ->
        []
  end.
m0rcq commented 4 years ago

Here is a fix that works at least:

-spec get_records_by_name(dns:dname()) -> [dns:rr()].
get_records_by_name(Name) ->
    case find_zone_in_cache(Name) of
  {ok, Zone} ->
      case erldns_config:storage_type() of
      erldns_storage_json ->
          case erldns_storage:select(zone_records, {erldns:normalize_name(Zone#zone.name), erldns:normalize_name(Name)}) of
          [] -> [];
          [{_, Records}] -> Records
          end;
      erldns_storage_mnesia ->
          lists:filter(fun(#dns_rr{name = RecordName}) ->
                   RecordName =:= erldns:normalize_name(Name)
                  end, get_zone_records(erldns:normalize_name(Zone#zone.name)))
      end;
  _ ->
      []
  end.

Hello @nisbus, thank you for flagging this up.

You're correct - get_records_by_name/1 with Mnesia backend is failing due to hitting select/2 in erldns_storage_mnesia which in turn just does mnesia:read/2 and will fail on calls with FQDN lookups.

Check: https://github.com/dnsimple/erldns/pull/103/commits/3ccdcffd1825dfaef46163429e6cbb5d5a3a0ee9 - it does address this scenario and allows for proper execution of erldns_zone_cache:zone_records_by_name/1 against Mnesia and ETS' backends.

nisbus commented 4 years ago

looks good to me, everything seems to be working now

m0rcq commented 4 years ago

looks good to me, everything seems to be working now

@nisbus: Great to hear - all changes merged to master now.