DNS Response Rate Limiting as implemented in NSD.

October 11, 2012 by wouter

(Note 10 Oct 2012: Rate limiting is worked on at this time, and is being tested, it is not available in NSD production code yet).

(Update 10 Dec 2012 : changed title to indicate it is based on Vixie and Schryver’s work)

Rate Limits

Rate limiting is seen as a way to combat reflection attacks, where spoofed UDP packets are bounced off DNS servers to attack a target, and rate limits stop these high volume query streams. BCP38 (source IP checks on originating networks, bcp38) is the real fix, but has not seen sufficient deployment. We would not want to complicate our software needlessly; the rate limiting must not become a target itself. But the knowledge that the DNS server has, makes rate limiting easier to implement. We chose an implementation that should be easy to separate from the DNS server, if desired. Our approach is based on RRL by Vixie and Schryver (RRL) and Tony Finch’s analysis (fanf).

The RRL (response rate limiting) is implemented in the NSD server, for convenience. This makes server operations easier and implementation faster, and it saves time classifying the response. This code is enabled with the –enable-ratelimit option for configure. We plan to implement RRL for NSD4 and NSD3. There is a whitelist option available for allowing higher traffic for some parts.

The approach is meant to be different from others, for code diversity goals, thus we do not use the code from Vixie and Schryver, but we use similar false positive prevention mechanisms. The NSD RRL code uses a fixed-size hashtable, and smoothed averaged qps rates per bucket. If two different source netblocks (/24 ip4, /64 ip6) hash to the same bucket, it is reinitialized, causing a potential false positive to turn into a false negative. Additionally, the SLIP mechanism from Vixie and Schryver is used to give TCP fallback in case of a false positive.


Howto: Add new RRtypes to NSD

September 20, 2012 by matthijs

People like to put stuff in the DNS. While we could put everything in a TXT record, in general it is better to define a new record type (RRtype). The latest addition is the TLSA record, to support the DANE protocol. The RRtype was added to NSD just one day after the RFC was published.

It must be said that NSD does not support all RRtypes. For example, the CDS RRtype, a record that allows a child zone to update its DS RRset at the parent, has been assigned a code point, but its specification has not been finished. Therefore, it hasn’t been implemented in NSD yet. Fortunately, NSD is written in such a way that it is very easy to add new RRtypes. Let us look at the changes we made to NSD in order to support the TLSA record.

First of all, the zone compiler needs to understand the new record. This requires editing the Yacc file zparser.y. We need to add a token for the TLSA record.

%token T_TLSA

The format of the TLSA record is defined to have four RDATA elements, three unsigned 8-bit integers and a hexadecimal and one raw data field that represents the certification association data element, presented as a hexadecimal string. The NSD zone compiler has functions defined that can convert these representation formats to their respective wire format. That makes the grammar rule fairly straightforward:

rdata_tlsa: STR sp STR sp STR sp str_sp_seq trail
        zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str));
        zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str));
        zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str));
        zadd_rdata_wireformat(zparser_conv_hex(parser->region, $7.str, $7.len));

Now we need to add the TSLA grammar rule to the list of supported records. And for every RRtype, the zone compiler also needs to be able to parse the unkown record presentation format. This list is defined by the grammar rule type_and_rdata:

     |	T_TLSA sp rdata_tlsa
     |	T_TLSA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }

We also need to add the TLSA record to the DNS definitions. IANA has allocated the number 52 to represent the TLSA RRtype. This goes in dns.h:

#define TYPE_TLSA 52

In the file dns.c, an array of RRtype descriptors is declared. A descriptor consists of the RRtype code point (52, or TYPE_TLSA), the RRtype name (“TLSA”), the parser token (T_TLSA), the minimum and maximum number of RDATA elements (both 4) and the wire and representation format. The TLSA descriptor becomes:

    { TYPE_TLSA, "TLSA", T_TLSA, 4, 4,

Luckily, we don’t need to define new RDATA elements. The octet (RDATA_WF_BYTE) represented as an unsigned 8-bit integer (RDATA_ZF_BYTE) are well known formats and already exist a long time in NSD, as is the binary element (RDATA_WF_BINARY) represented as a hexadecimal string (RDATA_ZF_HEX). If you do need to introduce new RDATA elements, Yuri’s HOWTO-HACK-NEW-RRTYPE can be of great value in order to guide you through that effort.

So that’s it! This should provide you with enough information to hack your own RRtypes into NSD. You only have to edit three files in order to support a new RRtype (that does not require special processing). Nevertheless, it would be better to enable new RRtype support without having to touch the code. That’s why we hope in the future we can implement the DNS extension language into NSD.

NSD4 Features

September 14, 2012 by wouter

NSD 4 is under development. The plan is to improve NSD 3 with a number of new features. The main goals are:

  • More dynamic configuration support
  • High number of zones supported
  • It stays the lean and mean, typical secondary authoritative DNS server that you know it for.

To do this, the implementation includes the following features (available today, from development snapshots):

  • patterns – config file structures that macro-ize the configuration of different zones, so you do not have to repeat configuration for many zones.
  • nsd-control – basically a copy of our BSD-licensed unbound product’s unbound-control, it connects over SSL to the daemon and you can then tell it new configuration without a restart.  Add and remove zones, and other commands.
  • changes to the database, both in memory and on disk to accommodate the goals. This includes incremental NSEC3 precompilation which speeds up the change of very large zones.
  • nsdc and zonec gone. the cronjob is gone – scratch files are kept in /tmp and deleted when no longer needed.

The patterns are a collection of zone options with a name. When you add new zones you can specify the options for the zone with the name of the pattern to apply. It is possible to use included-patterns to create shorthands for options shared by (many) other patterns. In this way you can easily specify the patterns for a large number of zones, and change options for all of them at once.

The zone compiler is part of NSD now, and is forked to read a zone file when needed. The modification times of the file system are used to read changed zone files (on the SIGHUP signal and the reload command). The database on disk is edited in-place, so that no restart is needed.

Further features are worked on to finish the implementation of NSD4.


Wed Sep 25 2013

© Stichting NLnet Labs

Science Park 400, 1098 XH Amsterdam, The Netherlands

labs@nlnetlabs.nl, subsidised by NLnet and SIDN.