Total Pageviews

Monday, 1 July 2019

dns解析服务器程序-erldns

Erlang-based DNS Server(起着跟bind一样的作用)

Serve DNS authoritative responses...with Erlang.

Building

To build clean:
./build.sh
If you've already built once and just want to recompile the erl-dns source:
./rebar compile

Zones

Zones are loaded from JSON.
Example JSON files are in the priv/ directory.
You can also write new systems to load zones by writing the zones directly to the zone cache using erldns_zone_cache:put_zone/1.

Configuration

An example configuration file can be found in erldns.config.example.
Copy it to erldns.config and modify as needed.

Running

Launch directly:
erl -config erldns.config -pa ebin -pa deps/**/ebin -s erldns
Or use Foreman:
foreman start

Querying

Here are some queries to try:
dig -p8053 @127.0.0.1 example.com a
dig -p8053 @127.0.0.1 example.com cname
dig -p8053 @127.0.0.1 example.com ns
dig -p8053 @127.0.0.1 example.com mx
dig -p8053 @127.0.0.1 example.com spf
dig -p8053 @127.0.0.1 example.com txt
dig -p8053 @127.0.0.1 example.com sshfp
dig -p8053 @127.0.0.1 example.com soa
dig -p8053 @127.0.0.1 example.com naptr

dig -p8053 @127.0.0.1 -x 127.0.0.1 ptr

Performance

In our environment (DNSimple) we are seeing 30 to 65 µs handoff times to retreive a packet from the UDP port and give it to a worker for processing. Your performance may vary, but given those measurements erl-dns is capable of handling between 15k and 30k questions per second. Please note: You may need to configure the number of workers available to handle traffic at higher volumes.

Design

The erldns_resolver module will attempt to find zone data in the zone cache. If you're embedding erl-dns in your application the easiest thing to do is to load the zone cache once the zone cache gen_server starts push an updated zone into the cache each time data changes.
To insert a zone, use erldns_zone_cache:put_zone({Name, Records}) where Name is a binary term such as <<"example.com">> and Records is a list of dns_rr records (whose definitions can be found in deps/dns/include/dns_records.hrl). The name of each record must be the fully qualified domain name (including the zone part).
Here's an example:
erldns_zone_cache:put_zone({
  <<"example.com">>, [
    #dns_rr{
      name = <<"example.com">>,
      type = ?DNS_TYPE_A,
      ttl = 3600,
      data = #dns_rrdata_a{ip = {1,2,3,4}}
    },
    #dns_rr{
      name = <<"www.example.com">>,
      type = ?DNS_TYPE_CNAME,
      ttl = 3600,
      data = #dns_rrdata_cname{dname = <<"example.com">>}
    }
  ]}).

Metrics

Folsom is used to gather runtime metrics and statistics.
There is an HTTP API for querying metric data available at https://github.com/dnsimple/erldns-metrics

Admin

There is a administrative API for querying the current zone cache and for basic control. You can find it in https://github.com/dnsimple/erldns-admin

from https://github.com/dnsimple/erldns
----

Erlang/OTP based DNS server

erlang-dns

Erlang/OTP DNS server
erlang-dns is an authorative non recursive DNS server I am writing for my site http://www.domain-name-registration.co.za.
The idea is to have a simple DNS server that can be configured with arbitrary Zones via simple Erlang modules. It's up to you whether the Zone is defined in some file or a DB for example. As long as the module returns a zone as a list of resource records erlang-dns can serve it up.
In addition, erlang-dns supports custom extensions to enhance or entirely change the server's behaviour.

Releases

  • 2014-01-11 v0.1-alpha - First version that conforms to RFC1034 examples

Example

-module(my_zone_provider).

-export([get_zone/1]).

-include_lib("kernel/src/inet_dns.hrl").

get_zone(_Args) ->
    %% Fetch the Zone from a file, the DB, ...
    %% Here we just hardcode it
    {ok, [                                     
        #dns_rr{domain="bot.co.za", type=soa, data={   
            "ns1.bot.co.za",                         
            "hc.vst.io",              
            870611,          %serial
            1800,            %refresh every 30 min 
            300,             %retry every 5 min
            604800,          %expire after a week
            86400            %minimum of a day
            }
        },
        #dns_rr{domain="bot.co.za", type=ns, data="ns1.bot.co.za"},
        #dns_rr{domain="bot.co.za", type=ns, data="ns2.bot.co.za"},
        #dns_rr{domain="www.bot.co.za", type=cname, data="bot.co.za"},
        #dns_rr{domain="bot.co.za", type=a, data={127,0,0,1}}
    ]}.
Then, bring up the server with erl -pa ./ebin -s edns and register your zone provider.
edns:register_zone_provider("bot.co.za", {my_zone_provider, get_zone, []}).
If you change and recompile my_zone_provider you can flush the zone with
edns:flush("bot.co.za").
without restarting the server.
Also, please have a look at the-end-to end test scenario for an example of how to setup the included src/simple_backend.erl zone provider module.
The simple_backend consists essentially of only the following two lines:
get_zone(Zone) ->
    {ok, Zone}.
Instead of writing the my_zone_provider above, you could have achieved the same result with:
Eshell V5.10.2  (abort with ^G)
1> ends:register_zone_provider("bot.co.za", {simple_backend, get_zone, [
        #dns_rr{domain="bot.co.za", type=soa, data={   
            "ns1.bot.co.za",                         
            "hc.vst.io",              
            870611,          %serial
            1800,            %refresh every 30 min 
            300,             %retry every 5 min
            604800,          %expire after a week
            86400            %minimum of a day
            }
        },
        #dns_rr{domain="bot.co.za", type=ns, data="ns1.bot.co.za"},
        #dns_rr{domain="bot.co.za", type=ns, data="ns2.bot.co.za"},
        #dns_rr{domain="www.bot.co.za", type=cname, data="bot.co.za"},
        #dns_rr{domain="bot.co.za", type=a, data={127,0,0,1}}
    ]}).

Extensions

Extensions live in the priv/extensions folder. Have a look at the simple_stats extension that counts the number of DNS requests.
Extensions can consist of custom resolvers and OTP servers/supervisors.

Custom Resolvers

By default, queries are processed by ed_query_resolver, however you can implement a custom resolver to augment or swap out ed_query_resolver entirely.
edns.app.src specifies what resolver(s) to use:
{env, [
     {port, 1051},
     {resolvers, [ed_query_resolver, simple_stats_resolver]}
   ]}
ed_udp_handler_server foldls over all resolvers to arrive at a DNS query response.
The simple_stats_resolver is a passthrough resolver that does not modify the repsonse. All it does is to notify simple_stats_server that another query has arrived.
Another example usecase of a custom resolver is one that looks up the synopsis of a Wikipedia article and returns it in a TXT record.

Custom OTP servers/supervisors

Modules in the extensions/... directory that implement either the gen_server or supervisor behaviour are automatically started and supervised by ed_extension_sup. This is useful if your custom resolvers need to maintain state.

Tests

To run the end to end test execute make e2e.

System Architecture

No comments:

Post a Comment