This article reports the current status of the dnsext
packages in Haskell. If you don't know what dnsext
is, please read "Developing network related libraries in Haskell in 2022FY" first. The purpose of this project is provide DNS full resolver (cache server).
bowline
Our DNS full resolver is now called bowline
named after the king of knots. (I used to climb rocks with double eight knot but I like bowline.) Most importantly, our DNSSEC verifier has been integrated into bowline
by Kei Hibino.
New features
To make bowline
practical, the following features have been added:
- Configuration:
bowline.conf
is in the key-value format. Especially,local-zone:
,local-data:
,root-hints:
andtrust-anchor-file:
can be specified. - Logging: the standard way of logging for DNS servers is DNSTAP whose format is protocol buffer and transport is fast stream. Instead of using other libraries, we implement them in
dnsext-utils
. - Statistic monitoring: Prometheus is supported.
- Web API: the recent trend for server management is containers. When servers run in containers, the traditional signal scheme is not feasible. So,
bowline
provides web API for reading statistic, reloading, etc.
DNS transport
To protect privacy, the transport between DNS full resolvers and stub resolvers should be encrypted. The send-receive API of tls
and quic
is suitable to implement DoT (DNS over TLS) and DoQ (DNS over QUIC). However, the worker model of http2
and http3
is inefficient for DoH (DNS over HTTP). To emulate the send-receive API, runIO
is implemented and provided from Internal
module of http2
. Unfortunately, I have no idea on how to implement runIO
for http3
at this moment.
While verifying safety of http2
and quic
, I noticed that not all cases of flow control are covered. The following should be implemented for stream numbers in a connection, amount of sending/receiving data in a connection and amount of sending/receiving data in a stream:
- Telling the limit of receiving data to the peer in proper timing
- Closing the connection if the receiving data reaches the limit
- Sending data with the respect of the limit of sending data
To extract common patterns of flow-control, the network-control
package is created. With network-control
, http2
and quic
have covered the all cases.
Refactoring and testing
The code for iterative queries was huge and monolithic. So, it was divided into multiple modules with the help of calligraphy which can visualize call-graph of functions.
dnsperf
is used to measure server performance and to run stress testing. We noticed that stacks of Haskell lightweight threads consume huge memory. Their initial size of 1 KiB. When the limit are reached, they glow 33 KiB since the next chunk size is default to 32 KiB. In my opinion, this value is too big because threads might use only 2 KiB, for instance. So, we specify -kc2k
(2 KiB) as an RTS option so that the size of stack glows 1KiB, 3 KiB, 5 KiB, 7 KiB and so on.
dug
dug
is a command line interface for DNS queries. Of course, it can resolve records for a target domain using UDP as a stub resolver:
% dug www.iij.ad.jp aaaa ;; 2001:a7ff:5f01:1::a#53/UDP, Tx:42bytes, Rx:196bytes, 34usec ... ;; ANSWER SECTION: www.iij.ad.jp. 300(5 mins) IN AAAA 2001:240:bb81::10:180
The characteristics of dug
are as follows:
- Queries can be sent with DoT, DoQ and DoH if the
-d
option is specified. - Such a transport is automatically selected by parsing SVCB RRs if the
-d auto
is specified. - It can execute the iterative query algorithm used in
bowline
if the-i
option is specified.
The followings are the new feature added in 2023FY:
tcp
is added in addition toauto
,doq
,dot
etc for the-d
option.- The result of DNSSEC is displayed with colors if the
--demo
option is specified. - The query result is displayed in the JSON format if the
--json
option is specified.