dns-proxy, test-dns — Domain Name System (DNS) proxy
dns-proxy  [-hv] [-d ]  dbglev-f  cfgfile
test-dns  [-hv] [-d ]  dbglev-f   [cfgfile-t ]test_expr
The dns-proxy provides proxying service for the Domain Name System (RFC 1034+1035 and some of their extensions).
The proxy handles incoming requests in four basic modes:
Request is not processed at all. Administrator can choose from several ways of request denial.
Request is responded without querying any other server. The faked response is set by administrator.
Request is resent to one from group of servers defined by the administrator. This mode is typical for
forwarding queries from host not fully connected to the internet
forwarding queries to server hidden in private network
forwarding zone transfers across the firewall.
This is fully functional mode when the proxy tries to recursively resolve the request form the scratch. It starts from the root servers and accepts only authoritative answers until it gets the final authoritative answer.
The proxy is not designed as a server, neither for external queries to our domain, nor as a local caching name server. Typical scenario is that all clients ask another server in the internal network and this server queries the proxy (if needed) and caches the answers. That's why the proxy does not cache answers, there is only a small cache of name servers for internal purpose only.
The proxy behaves like a server for the client and vice versa, with full syntax and semantics verification (see below, protection against cache-poisoning). When querying other servers, dns-proxy uses random source port and ID (protection against reply-spoofing).
The proxy completely reconstructs answers
    from servers and limits the size of reply sent to client
    (configurable by ptr-reply-size and
    adr-reply-size items).
    This feature protects clients against to attack based on buggy resolver
    routines.
The proxy usually runs as two processes: the single child process manages all the sessions and the parent process manages the child and restarts it after a failure. You can learn more in udpserver(7) manual page, although the dns-proxy does not use the udpserver library, in fact. However, it uses the same operation logic.
Format of the proxy configuration file is described in dns-proxy.cfg(5). For the dns-proxy, any host in configuration file must be specified by its address, not by its name.
Program test-dns tests syntax and partially semantics
    of configuration; for test expression syntax, see test-expr(5).
The proxy reads its configuration file and starts listening
        on specified IP sockets (address/port couples), as specified in
        the listen-on configuration section (see listen-on(5)).
        Proxy listens for both UDP and TCP protocols.
If support of transparent connections (see transparency(7)) is requested by item transparent in
        section listen-on, the corresponding NAT redirections
        are established during proxy startup and removed upon exit.
        However, transparent connections are in fact not supported by this
        proxy, decisions about servers are made according to
        the proxy configuration, not by original destination.
In the case of UDP requests redirected to the proxy by more general NAT rules, the real destination is neither being detected nor used in ACL selection.
In the resolve mode, the proxy checks each address being stored into cache whether it matches to one of addresses, the proxy listens on. If it does, the record is not stored, so that this does not lead to infinite loop. For this reason, listening addresses (for port 53) must be specified explicitly, expression [0.0.0.0]:53 is not allowed.
Current version of the dns-proxy implements following subset of protocol:
OPCODEs
    QUERY  RFC 1035
    NOTIFY RFC 1996
Requests with unimplemented OPCODEs are replied with
        the NotImp response code.
        Requests with unknown OPCODEs are replied with
        the FormErr response code.
CLASSes
    IN     RFC 1035
    *      RFC 1035
Requests with query resource record (RR) of unimplemented CLASS
        are replied with the NotImp response code,
        unknown classes cause the FormErr response code.
        The '*' requests are converted to IN, resolved
        and then sent to the client with authority flag set to 0.
TYPEs
    A          RFC 1035
    AAAA       RFC 3596
    AFSDB      RFC 1183
    AXFR       RFC 1035
    CNAME      RFC 1035
    DNSKEY     RFC 4034
    DS         RFC 4034
    HINFO      RFC 1035
    IXFR       RFC 1995
    MX         RFC 1035
    NS         RFC 1035
    NSEC       RFC 4034
    NSEC3      RFC 5155
    NSEC3PARAM RFC 5155
    OPT        RFC 6891
    PTR        RFC 1035
    RRSIG      RFC 4034
    SOA        RFC 1035
    SPF        RFC 4408
    SRV        RFC 2782
    SSHFP      RFC 4255
    TXT        RFC 1035
    *          RFC 1035
Requests with query RR of unimplemented TYPE are by default
        replied with the NotImp response code.
        This behavior can be changed in the configuration (ACL settings).
        Requests to unknown TYPE are replied with the
        FormErr response code.
Every request is stored into a table item containing
        all necessary information.
        Size of this table must be specified in configuration
        (requests-table-size item) and it is
        recommended to reserve a little more items then estimated number
        of parallel requests.
        Some requests processed in resolve mode can generate so called
        internal requests (see below)
        that occupy table items, too.
Besides number of requests, number of simultaneously opened
        sockets is monitored.
        The maximum of sockets must be specified in the configuration
        (sockets-table-size item).
There are two kinds of internal requests:
If the proxy is to ask some server, address of which
                is not in the cache,
                it generates an internal requests with A
                and AAAA query for the name of the server.
                This request is handled in the same way as the original query
                with the exception that the result is stored in the cache.
                
                Choosing just IPv4 or IPv6 protocol when querying servers
                can be done by the server-proto item.
                The default is using both of them, or using just the IPv4
                when no system interface has an IPv6 address defined.
                
If the answer got from a server contains
                CNAME RR and no (trusted) RR for
                the canonical name, proxy generates an internal request
                with the same query RR type and query name
                equal to the canonical name received.
                This request is handled in the same way as the original query
                with the exception that the result is added to the previously
                received RRs.
                If the internal request fails to complete the resolution,
                the original request is replied by
                the ServFail response code.
                
Both types of internal requests suspend processing of the original request (originator) until the internal request is completed. If another request is to generate a new internal request of the same subject as another running one, no new internal request is created and the originator is suspended waiting for the first internal request, too. After (successful or unsuccessful) completion of internal request, all originators are waked up.
Similar principle is used also for client requests. If a request with the same parameters (query name, query type, EDNS UDP payload etc.) is already being processed, new request is also suspended, waiting for the result of the previous request.
Both types of internal requests can also generate new internal requests. For instance, in following definition:
    domain1 IN NS ns.domain2
    domain2 IN NS ns.domain3
        a request to the domain1
        will generate request
        to the ns.domain2 name
        and solution of this will result to a new CACHE
        request to ns.domain3.
        Proxy detects an infinite loop, if occurs. Proxy also limits number of
        internal requests generated by one internal request in the row (item
        internal-request-depth) to prevent DoS attack
        by means of non-infinite but very long loop of references.
Both types of internal requests respect the resolving policy
        according to the query name and type given by the configuration.
        For every new request, the request-acl list (see below)
        is searched through and the new ACL defines operation to be used.
If no free request table item is available,
incoming UDP requests are replied with
                the ServFail response code
incoming TCP requests are rejected by closing the connection
internal requests of any type fail and these failures are propagated to all originators.
The proxy uses two layers of ACL (see access-control(7)) named
        session-acl and request-acl.
When a request arrives, configuration is consulted,
        proper session-acl is selected and according to it,
        request is served or not.
Subsequently, protocol-specific parameters of query is checked
        against set of request-acl entry conditions
        and proper mode of operation is selected.
Additionally to the general Kernun ACL concept,
        request-acl brings new entry condition items:
query-nameThis item contains a set of regular expressions
                and/or strings describing names, querying for which
                is to be dealt by this request-acl.
                When using the regexp form, you have to respect the dot
                placed to the end of every name before request processing.
                The queried name matches a member of the set if
matches the regexp (regexp case) or
is part of the domain (string case).
Examples:
Regular expression
                        /^[^.]*\.tns\.cz\.$/ matches 
                        queries to all hosts in the domain
                        tns.cz.
                        
String kernun.com matches e.g.
                        queries to www.cz.kernun.com,
                        or kernun.com,
                        but not kernun.com.cz.
request-typeThis item can define subset of DNS operation codes
                and RR types that is to be dealt by this
                request-acl.
By these two items, a detail selection of
        request-acl can be done to set special handling
        for different tasks like regular queries, zone transfers,
        server notifications etc.
If no matching ACL is found, request is replied by
        the Refused response code.
        If ACL is found, query type and class are checked.
        Requests with classes other than IN
        and * (ANY class) are rejected with response
        code NotImp.
As we stated above, there are several possible proxy operations.
        The proxy decides among them by matching query RR type against a set of 
        special request-acl
        items query/notify.
        The first matching item is used and the operation is executed.
        If no proper item is found, request is rejected with 
        the Refused response code.
In case of resolve and forward
        operations, request is resent (with a new, random ID) to a new server.
        The set of possible responders is defined in a global section of
        ns-list type.
        Each received reply RR is then checked against a set of special ACL
        items called reply in the same manner as queried
        RR is checked.
        The reply items can tune handling of particular RR
        (permit, remove),
        so as even predefine reaction to the whole request
        (abort, deny).
        If no proper reply item is found,
        request is rejected with the Refused response code.
        If permit action is required for non-implemented RR,
        record is removed.
After filtering the response from server, other proper RRs 
        (given by special fake items) can be added
        to the answer. 
        The same set of items is used for reply construction in case of
        fake operation.
        Fake RRs are placed into the answer in the order of appearance in
        the configuration.
After completing all answer RRs, reply is completely reconstructed
        and sent to the client.
        The resolved requests will have the authority (AA) flag cleared while
        for the forwarded requests, the admin can choose whether to preserve
        or clear the flag (see the request-acl.query.clear-aa
        definition in dns-proxy(5)).
If the response has
        the NXDomain response code,
        or the NoError response code
        with no answer (AN) records,
        and if this status was caused by the proxy
        (e.g. due to denying query or filtering response),
        the proxy will add, by default, a SOA record
        with proper TTL for successful negative caching in clients.
        This behavior can be configured by the neg-resp-ttl
        item of the particular request-acl.
If the authoritative answer in resolve operation
        is not available, request is replied with
        the ServFail response code.
        There are some situations where this approach is not applicable.
        For instance,
        queries to mail-abuse.org
        domain end by non-authoritative answer.
        We recommend using a special request-acl for this case,
        forwarding requests of this type directly to proper name servers.
Besides Security Policy application, the proxy checks both queries and replies to correctness in sense of relevant RFCs.
Names can be at most 254 bytes long,
            every label can be at most 63 bytes long.
            Labels can contain only alphanumerical characters
            and a hyphen ('-').
            We allow also underscore ('_')
            and slash ('/') because they are
            commonly used.
Request ID of the answer is checked to be equal to the ID of query. Query (QD) section of the answer is checked to be equal to the query. Every answer (AN) RR must be relevant to the query or to the previous RR. Every authority (NS) RR must be relevant to the query or to the canonical name of some AN RR. Every additional (AR) RR must be relevant to some AN or NS RR.
Every server is introduced into the cache as an authoritative name server for some domain. So, all answer RRs received from this server are trusted only if they belong to this domain or some subdomain. This criteria may cause an infinite loop when two or more domains refer each other without having any regular glue record (i.e. nameserver in own domain or a subdomain). If you need to accept such a domain, you must make an ACL for this domain forwarding requests directly to proper nameservers.
Name server cache is used for increased efficiency,
        namely for repeated queries to the same domain
        (TLDs, resending query via TCP, resolution of CNAMEs etc.).
        “Root servers” for different network zones are defined
        in ns-list configuration sections,
        each zone has a separated cache “zone” named 
        by the name of ns-list section.
        All other name servers and their addresses are
        introduced to the cache as a result of authoritative answers.
        “Authoritative” server (in sense of dns-proxy)
        is either a root server
        or a server delegated by some “authoritative” server
        for a parent domain
        (already being in the cache).
        All new RRs are used with respect of their time to live (TTL) value.
        When the minimal of TTLs of name servers
        (both their NS and address records)
        for a domain expires, the domain item
        is unusable and it is removed from the cache at nearest cleanup.
        Similarly, when the minimal of TTLs of addresses for a host expires,
        the host item is unusable and it is removed from the cache
        at nearest cleanup.
Some properties of the cache are configurable in a special
        cache section:
cleanup-periodsets the period (in seconds) of cache cleaning up. After the period, all items that were not used within the period and all expired items are removed.
max-domainssets the maximum number
                    of domains
                    (not individual NS RRs) stored in the cache.
                    This value should be at least as large as
                    requests-table-size.
max-hostssets the maximum number
                    of hosts
                    (not individual address RRs) stored in the cache.
                    This value should be at least approximately
                    five times larger than
                    requests-table-size.
If any maximum is reached, a non-periodical cleanup is started. This cleanup removes all items currently not used.
When a domain name is to be resolved, the longest match search in the cache is done. After it, the new best server for the domain found is chosen. Server comparison criteria:
Resolved, but never contacted servers.
Unresolved servers, never tried to be resolved.
Responding servers (sorted by response time rounded to entire seconds).
Non-resolved or non-responding servers (sorted by time of the last attempt).
This algorithm guarantees a primitive "load balancing" and error recovery of multiple servers.
When querying for an EDNS request, the EDNS servers have priority. If a server responds FormErr to an EDNS query, the non-EDNS query is repeated immediately.
First of all, the selected server is queried with a very short (1 sec.) timeout. When this timeout fires, the query is simply repeated to avoid errors caused by loosing UDP packets.
Then the queried server has a longer timeout for the response.
        Each server has its own timeout stored in the cache.
        Starting value of this timeout is set by query-timeout
        configuration directive.
        Each time the server does not respond within the timeout, the timeout
        doubles, up to server-dead value.
        When the timeout reaches this value, server is marked as
        “dead” and a new attempt to contact it cannot be done until
        server-retry seconds period.
        If the server responds within the timeout, his timeout
        for the next attempt
        is set to his response time plus query-timeout.
The number of attempts per one query is hardcoded to eight
        (regardless of which servers were queried).
        However, typically this number is not reached before firing
        the request-timeout (see below).
The same mechanism is used for selection among forwarders. That's why forwarders lists are also stored in the cache (every list in its separated zone).
The timeout for the whole request processing (including resolving
        of generated internal requests etc.) is also set in the configuration
        (request-timeout) and if reached, request is replied
        with the ServFail response code.
Zone transfers need some more special handling.
        First of all, the requests are typically addressed by originators
        directly to a conrete server.
        That's why either the transparent mode (if public addresses are used),
        or non-transparent mode to a dedicated address/port on firewall
        (in the case of server on a private address) should be used.
        Also, besides QUERY operation,
        the NOTIFY operation should be permitted.
Moreover, the own transfers (responses to
        the AXFR/IXFR queries)
        should be sent by servers either separated
        (i.e. more DNS messages with one RR in each one)
        or aggregated (i.e. all RRs in one DNS message).
        The proxy can force one of these methods, or keep the incoming format
        according to the xfr-format configuration directive.
        
Configuration example:
  ns-list MASTER {
    server ns.x.y.z [10.1.1.1];
  }
  ns-list SLAVE {
    server sns.x.y.z [20.2.2.2];
  }
  ...
  dns-proxy ZONE-TRANSFERS {
    ...
    request-acl TO-MASTER {
      to non-transparent [20.2.2.1]; # special external fw adr
      query { axfr, ixfr } forward MASTER;
      ...
    }
    request-acl TO-SLAVE {
      to transparent [20.2.2.2];
      notify forward SLAVE;
      ...
    }
The proxy uses common Kernun mechanism for listening on its sockets, optionally changing root directory and running with alternative user privileges. For more detailed information, see application(5) and listen-on(5).
The proxy uses common Kernun mechanism for network
        input/output operations. Configuration allows for specifying
        several parameters like buffer sizes and timeouts, both for
        client and server connections. They can be included in
        client-conn and server-conn
        configuration sections, respectively.
        For more detailed information, see netio(7).
The proxy uses common Kernun mechanism for logging. For more detailed information, see logging(7). For every request, one REQUEST (DNSP-860-I) message is logged (besides one or two ACL messages - DNSP-810-I and DNSP-820-I). Every log message has process ID suffix equal to the index of request being currently processed.
The proxy, in fact, does not use common Kernun mechanism
        for name resolving (see resolving(7) manual page),
        because it does not use DNS names at all. In spite of that, the item
        use-resolver remains
        in the dns-proxy configuration
        for compatibility with other proxies
        (and thus e.g. ability to use common cml(8) variables).
The dns-proxy handles following signals:
SIGUSR1Log level increasing.
SIGUSR2Log level decreasing.
SIGINFOOperation status logging; parent process logs info about all children, child process dumps cache content and requests table content.
SIGHUP,
                    SIGINT,
                    SIGQUIT,
                    SIGTERMImmediate termination; proxy immediately closes all connections and terminates.
The program options are as follows:
-hPrint usage information and exit.
-vDisplay version information and exit.
-d dbglevSet debuging level to a specific number. Permitted values are 3 through to 9, 3 being the least and 9 the most verbose. See logging(7) for details. This setting is relevant only till configuration reading is finished.
-f cfgfileRead cfgfile
                for configuration information.
-t test-exprTest configuration according to given expression.
                Format of the test-expr
                is described in test-expr(5).
Currently, the dns-proxy doesn't implement following features:
more queries (QD RRs) in one request
wildcard ('*') queries.
dns-proxy.cfg(5), listen-on(5), application(5), test-expr(5), DNSP-810(6), DNSP-820(6), DNSP-860(6), access-control(7), configuration(7), logging(7), netio(7), resolving(7), transparency(7), udpserver(7)
named(8)