NanoPI上でdeadwoodを動かす

# 摘要
介绍用于嵌入式使用的MaraDNS-deadwood。

- 用C，C ++编写
- 尺寸小于800 KiB
- 很轻
- 设置简单

它具有的特点
# はじめに
インターネットで外部ホストと通信するとき普通は「名前」からIP Addressを参照するDNS (Domain Name System)を使います。
RouterやServerのBINDに接続するパターンが多いでしょう。DHCP Serverから提供される情報に、DNS ServerのAdderssが含まれるので、これを使うのが一般的です。

# IoTの事情

一般のClient Machineの話をしましたが、IoT機器の場合、

- DHCP Serverがない
- DNS Serverがない
- DNS Serverを使用する権限がない
- 自分自身がサーバーである

と言った事情でDNS Serverを参照できない場合があります。

# 自前で名前を解決する

こうした場合サーバーを自前で立ち上げるのですが、おなじみのBIND9は

- 多くのマシンからリクエストを受けるのを前提としている
- でかい
- 重い
- コーディングが汚い
- バグが多い

すみません。終わりの2つは愚痴です。

# コンパクトで軽いDNS Server

そこで、組み込み用に書かれたMaraDNS-deadwoodをご紹介します。

- C, C++でコーデングされている
- 800KiBに満たない大きさ
- 大変に軽い
- セッティングが簡単

という特長を持っています。

では早速Installしてみましょう。
NanoPI Noe2 Armbian (Debian)を前提にしてます。

```
apt update
apt upgrade
apt install maradns-deadwood
```

```
mkdir -p /etc/maradns/deadwood
mkdir /etc/deadwood
```

vi /etc/maradns/deadwood/dwood3rcで

```
# This is an example deadwood rc file
# Note that comments are started by the hash symbol

bind_address="192.168.254.40, 127.0.0.1"

# The following line is disabled by being commented out
# bind_address="::1" # We have optional IPv6 support

chroot_dir = "/etc/deadwood" # Directory we run program from (not used in Win32)

# The following upstream DNS servers are Google's newly-announced (as of
# December, 2009) public DNS servers.  For more information, see
# the page at http://code.google.com/speed/public-dns/
#
# These IPs can be changed to the IPs of any recursive DNS servers that
# can be reached from the computer running Deadwood.
#
# These are commented out; if upstream_servers is not set, Deadwood will
# act as a recursive DNS server
#
# Please note that each upstream_servers entry takes up space in Deadwood's
# cache and that maximum_cache_elements will need to be increased to store
# a large number of these entries.
#upstream_servers = {}
#upstream_servers["."]="8.8.8.8, 8.8.4.4" # Servers we connect to

# It is also possible to use other root servers or to blacklist
# a phising website.  However, to do this, root_servers needs to be
# defined.  For example, to blacklist the domain "phish.example.com":
# ICANN DNS root servers (Deadwood default if both root_servers and
# upstream_servers are not defined)
root_servers = {}
root_servers["."]="198.41.0.4, 199.9.14.201, 192.33.4.12, 199.7.91.13,"
root_servers["."]+="192.203.230.10, 192.5.5.241, 192.112.36.4, "
root_servers["."]+="198.97.190.53, 192.36.148.17, 192.58.128.30, "
root_servers["."]+="193.0.14.129, 199.7.83.42, 202.12.27.33"
#root_servers["phish.example.com."]="10.254.254.254"
# Please note that each root_servers entry takes up space in Deadwood's
# cache and that maximum_cache_elements will need to be increased to store
# a large number of these entries.
# Who is allowed to use the cache
recursive_acl = "192.168.0.0/16, 127.0.0.1/8"

maxprocs = 2048 # Maximum number of pending requests
handle_overload = 1 # Send SERVER FAIL when overloaded

maradns_uid = 99 # UID Deadwood runs as
maradns_gid = 99 # GID Deadwood runs as

maximum_cache_elements = 60000

# If you want to read and write the cache from disk, make sure chroot_dir
# above is readable and writable by the maradns_uid/gid above, and
# uncomment the following line
cache_file = "dw_cache"

# The following line tells deadwood to fetch an expired record if it's
# impossible to connect to any nameservers
resurrections = 1
filter_rfc1918=1
```

次の起動ファイルを作ります。
vi /etc/init.d/deadwood

```
cat /etc/init.d/deadwood
#! /bin/sh
### BEGIN INIT INFO
# Provides:          deadwood
# Required-Start:    $remote_fs $network $syslog
# Required-Stop:     $remote_fs $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start and stop deadwood
# Description:       deadwood is a Domain Name Server (DNS)
#       which translates IP addresses to and from internet names
### END INIT INFO

# Do NOT "set -e"

# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="domain name server"
NAME=deadwood
DAEMON=/usr/sbin/$NAME
DUENDE=/usr/sbin/duende
SCRIPTNAME=/etc/init.d/$NAME
WORKING_DIR=/run/$NAME
OUR_UID=`id --user maradns`
OUR_GID=`id --group maradns`

# It is possible to have more than one maradns server
# running on the same machine so long as they bind to different IP
# addresses. You specify multiple config files in the
# SERVERS variable in /etc/default/maradns.
# This goes back to #176066.

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions

#
# Function that starts the daemon/service
#
do_start()
{

        # Return
        #   0 if daemon has been started
        #   1 if daemon was already running
        #   2 if daemon could not be started

        # Now start the actual maradns process
        PIDFILE="$WORKING_DIR/$SERVERNAME.pid"
        start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null || return 1
        start-stop-daemon --start --quiet --background --pidfile $PIDFILE --startas $DUENDE -- --pid $PIDFILE --uid $OUR_UID --gid $OUR_GID --ident $SERVERNAME -- $DAEMON -f $rcfile
        sleep 3
        if ! pidofproc -p $PIDFILE $DAEMON > /dev/null
        then
            rm -rf $PIDFILE
            return 2
        fi
}

#
# Function that stops the daemon/service
#
do_stop()
{
        # Return
        #   0 if daemon has been stopped
        #   1 if daemon was already stopped
        #   2 if daemon could not be stopped
        #   other if a failure occurred
        PIDFILE="$WORKING_DIR/$SERVERNAME.pid"
        start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name duende
        RETVAL="$?"
        [ "$RETVAL" = 2 ] && return 2
        # Many daemons don't delete their pidfiles when they exit.
        rm -f $PIDFILE
        return "$RETVAL"
}

#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
        #
        # If the daemon can reload its configuration without
        # restarting (for example, when it is sent a SIGHUP),
        # then implement that here.
        #
        PIDFILE="$WORKING_DIR/$SERVERNAME.pid"
        start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name duende
        return 0
}

if [ -z "$SERVERS" ]
then
    log_action_msg "No maradns servers configured"
    exit 0
fi

case "$1" in
  start)
        [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC..."

        # dir can go away on reboots
        mkdir -p $WORKING_DIR
        chmod 775 $WORKING_DIR
        chown maradns:root $WORKING_DIR >/dev/null 2>&1 || true

        for rcfile in $SERVERS
        do
            SERVERNAME=`echo $rcfile | sed 's/\//_/g;s/^_*//;' | awk -F. '{print $NF}'`
            do_start
            case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_progress_msg "$SERVERNAME" ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1
                exit 1
                ;;
            esac
        done
        [ "$VERBOSE" != no ] && log_end_msg 0
        ;;
  stop)
        [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC"
        for rcfile in $SERVERS
        do
            SERVERNAME=`echo $rcfile | sed 's/\//_/g;s/^_*//;' | awk -F. '{print $NF}'`
            do_stop
            case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_progress_msg "$SERVERNAME" ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1
                exit 1
                ;;
            esac
        done
        [ "$VERBOSE" != no ] && log_end_msg 0
        ;;
  status)
        for rcfile in $SERVERS
        do
            SERVERNAME=`echo $rcfile | sed 's/\//_/g;s/^_*//;' | awk -F. '{print $NF}'`
            status_of_proc -p "$WORKING_DIR/$SERVERNAME.pid" $DAEMON $SERVERNAME || exit $?
        done
        exit 0
        ;;
  reload|force-reload)
        for rcfile in $SERVERS
        do
            SERVERNAME=`echo $rcfile | sed 's/\//_/g;s/^_*//;' | awk -F. '{print $NF}'`
            log_daemon_msg "Reloading $DESC" "$NAME"
            do_reload
            case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_progress_msg "$SERVERNAME" ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1
                exit 1
                ;;
            esac
        done
        log_end_msg 0
        ;;
  restart)
        $0 stop
        [ "$?" = "0" ] || exit "$?"
        sleep 3
        $0 start
        ;;
  *)
        echo "Usage: $SCRIPTNAME {start|stop|status|restart|reload|force-reload}" >&2
        exit 3
        ;;
esac
```
BIND9を使っていたなら、止めます。
deadwoodを起動して設定変更を有効にします。

```
systemctl stop bind9
chmod +x /etc/init.d/deadwood
/lib/systemd/systemd-sysv-install enable deadwood
mkdir /var/deadwood
cp /dev/null /var/deadwood/dw_chache
chown -R maradns.maradns /var/deadwood

systemctl restart deadwood
```
deadwoodを使う設定か確かめ、なってなければ直します。
vi /etc/network/interfaces

```
iface eth0 inet static
        address 192.168.254.31
        gateway 192.168.254.31
        dns-servers 127.0.0.1
```
試験します。

```
apt install dnsutils
dig www.microsoft.com
```
BIND9を消してdeadwoodを自動起動にします。

```
apt remove bind9
update-rc.d deadwood enable
```


# 結論

MaraDNS-deadwoodは組み込みに適した小型軽量のDNS Serverです。