Alecriar Studioの中の人の技術メモ

横浜の個人事業主が日々の技術的な情報をつづります

家庭内LANに名前解決のみを行うDNSサーバを設置する

DNSの役割

インターネットに接続されている機器はすべてネット上の住所であるIPアドレスを持っています。IPアドレスは「XXX.XXX.XXX.XXX」(Xは数字)の形式で、例えば「123.456.789.0」のように書き、ブラウザでアクセスする場合は「http://123.456.789.0」といった形になります。

リモートホストにアクセスするためにIPアドレスを知ればいいのですが、数字とピリオドのみの形式では人が覚えるにはどうにも使い勝手が悪い。そのため、それぞれの持つIPアドレスを人がわかりやすい、覚えやすい形式に対応させるための仕組みが、DNSとなります。

例えば、さきほどの「123.456.789.0」のIPアドレスに「example.com」という名前を割り振れば、ブラウザでアクセスする際、「http://example.com」と書けばよくなり、はるかに視認性が高くなります。

家庭内LANの構成図

f:id:alecriarstudio:20200123231043p:plain

ここで一例として、以上のような家庭内LANを想定します。HGW兼ルーター以下にスイッチを通してサーバーやPCやプリンター、モバイル機などがぶら下がり、同一のサブネットを構成しています。各ホストには固定のIPアドレスが割り振られているとし、IPアドレスでのアクセスは正常にできるものとします。

ここでホストの一つをDNSサーバとし、各ホストをホスト名とドメイン名で名前を引けるようにしていきます。

BINDとNSD

DNSは様々な機能があります。IPアドレスからホスト名を引く機能を持つDNSサーバは正確にはDNSコンテンツサーバといわれます。その他にもDNSには以下のような機能が存在します。

www.atmarkit.co.jp

これらすべてのDNS機能を持つDNSサーバソフト、いわばフルスペックのソフトがBINDと呼ばれるものです。BINDは古くから開発され、DNSSECなどの新機能も取り入れられ、現在もっとも使用されているDNSサーバです。しかし、その歴史ゆえに極めて複雑な仕様となっており、インストールし設定を行うまでたいへんな苦労を要します。

BINDに対し、比較的シンプルでDNSコンテンツサーバ機能のみに特化したDNSサーバソフトがNSDです。機能がシンプルな分インストールや設定も比較的容易であり、動作も軽快です。

今回のケースではIPアドレスからホスト名が引ければ良いだけなので、その機能に特化したNSDを使用するのが最適と考えました。もしその他のDNS機能を必要とする場合は、NSD+Unboundという組み合わせであればBINDに匹敵するようなDNSを提供することもできます。

Arch LinuxNSD をインストール

以下のコマンドで nsd のパッケージがインストールされます。

$ pikaur -S nsd

※pikaur はAURヘルパーであり、pacmanの互換です。その他のAURヘルパーでも同様

設定ファイル nsd.conf

設定ファイルは /etc/nsd/nsd.conf で行います。変更箇所は以下です。

  • server-count

DNSサーバのCPUコア数に合わせて数値を変更します。

例)server-count: 4

  • ip-address

DNSサーバのIPアドレスを指定。

例)ip-address: 192.168.1.100

  • ip-freebind

サーバ機起動時にnsdサービスが起動しない場合、このパラメータをyesにすることで解決することがある。

例)ip-freebind: yes

  • do-ip4

IPv4を使用する。

例)do-ip4: yes

  • username

NSDサービスを動作させるユーザ名を指定します。先に同名のユーザを作成しておく必要があります。

例)username: nsd

  • zonesdir

ゾーン情報ファイルを格納するディレクトリです。ゾーンファイルの実際の場所に合わせて変更します。

例)zonesdir: "//etc/nsd/zones"

  • hide-version

問い合わせ時にバージョン情報を秘匿します。

例)hide-version: yes

  • ゾーンファイルの設定については外部のファイルに切り出し

ゾーンファイルについての設定ファイルのディレクトリを include で指定します。

例)include: "etc/nsd/nsd.conf.d/*.conf"

nsd.conf の全体の設定例は以下の通りです。

/etc/nsd/nsd.conf

#
# nsd.conf -- the NSD(8) configuration file, nsd.conf(5).
#
# Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
#
# See LICENSE for the license.
#

# This is a comment.
# Sample configuration fileA
# include: "file" # include that file's text over here.  Globbed, "*.conf"

# options for the nsd server
server:
    # Number of NSD servers to fork.  Put the number of CPUs to use here.
    server-count: 4

    # uncomment to specify specific interfaces to bind (default are the
    # wildcard interfaces 0.0.0.0 and ::0).
    # For servers with multiple IP addresses, list them one by one,
    # or the source address of replies could be wrong.
    # Use ip-transparent to be able to list addresses that turn on later.
    # ip-address: 1.2.3.4
    # ip-address: 1.2.3.4@5678
    # ip-address: 12fe::8ef0
    ip-address: 192.168.1.100

    # Allow binding to non local addresses. Default no.
    # ip-transparent: no

    # Allow binding to addresses that are down.  Default no.
    ip-freebind: yes

    # use the reuseport socket option for performance. Default no.
    # reuseport: no

    # enable debug mode, does not fork daemon process into the background.
    # debug-mode: no

    # listen on IPv4 connections
    do-ip4: yes

    # listen on IPv6 connections
    # do-ip6: yes

    # port to answer queries on. default is 53.
    port: 53

    # Verbosity level.
    # verbosity: 0

    # After binding socket, drop user privileges.
    # can be a username, id or id.gid.
    username: nsd

    # Run NSD in a chroot-jail.
    # make sure to have pidfile and database reachable from there.
    # by default, no chroot-jail is used.
    # chroot: "//etc/nsd"

    # The directory for zonefile: files.  The daemon chdirs here.
    zonesdir: "//etc/nsd/zones"
    
    # the list of dynamically added zones.
    # zonelistfile: "//var/db/nsd/zone.list"

    # the database to use
    # if set to "" then no disk-database is used, less memory usage.
    # database: "//var/db/nsd/nsd.db"

    # log messages to file. Default to stderr and syslog (with
    # facility LOG_DAEMON).  stderr disappears when daemon goes to bg.
    # logfile: "//var/log/nsd.log"

    # File to store pid for nsd in.
    # pidfile: "/run/nsd/nsd.pid"

    # The file where secondary zone refresh and expire timeouts are kept.
    # If you delete this file, all secondary zones are forced to be 
    # 'refreshing' (as if nsd got a notify).  Set to "" to disable.
    # xfrdfile: "//var/db/nsd/xfrd.state"

    # The directory where zone transfers are stored, in a subdir of it.
    # xfrdir: "/tmp"

    # don't answer VERSION.BIND and VERSION.SERVER CHAOS class queries
    # hide-version: no
    hide-version: yes

    # version string the server responds with for chaos queries.
    # default is 'NSD x.y.z' with the server's version number.
    # version: "NSD"

    # identify the server (CH TXT ID.SERVER entry).
    # identity: "unidentified server"
    identity: "Home network authoritative DNS"

    # NSID identity (hex string, or "ascii_somestring"). default disabled.
    # nsid: "aabbccdd"

    # Maximum number of concurrent TCP connections per server.
    # tcp-count: 100

    # Maximum number of queries served on a single TCP connection.
    # By default 0, which means no maximum.
    # tcp-query-count: 0

    # Override the default (120 seconds) TCP timeout.
    # tcp-timeout: 120

    # Maximum segment size (MSS) of TCP socket on which the server
    # responds to queries. Default is 0, system default MSS.
    # tcp-mss: 0

    # Maximum segment size (MSS) of TCP socket for outgoing AXFR request.
    # Default is 0, system default MSS.
    # outgoing-tcp-mss: 0

    # Preferred EDNS buffer size for IPv4.
    # ipv4-edns-size: 4096

    # Preferred EDNS buffer size for IPv6.
    # ipv6-edns-size: 4096

    # statistics are produced every number of seconds. Prints to log.
    # Default is 0, meaning no statistics are produced.
    # statistics: 3600

    # Number of seconds between reloads triggered by xfrd.
    # xfrd-reload-timeout: 1
    
    # log timestamp in ascii (y-m-d h:m:s.msec), yes is default.
    # log-time-ascii: yes

    # round robin rotation of records in the answer.
    # round-robin: no

    # minimal-responses only emits extra data for referrals.
    # minimal-responses: no

    # refuse queries of type ANY.  For stopping floods.
    # refuse-any: no

    # check mtime of all zone files on start and sighup
    # zonefiles-check: yes
    
    # write changed zonefiles to disk, every N seconds.
    # default is 0(disabled) or 3600(if database is "").
    # zonefiles-write: 3600

    # RRLconfig
    # Response Rate Limiting, size of the hashtable. Default 1000000.
    # rrl-size: 1000000

    # Response Rate Limiting, maximum QPS allowed (from one query source).
    # If set to 0, ratelimiting is disabled. Also set
    # rrl-whitelist-ratelimit to 0 to disable ratelimit processing.
    # Default is on.
    # rrl-ratelimit: 200

    # Response Rate Limiting, number of packets to discard before
    # sending a SLIP response (a truncated one, allowing an honest
    # resolver to retry with TCP). Default is 2 (one half of the
    # queries will receive a SLIP response, 0 disables SLIP (all
    # packets are discarded), 1 means every request will get a
    # SLIP response.  When the ratelimit is hit the traffic is
    # divided by the rrl-slip value.
    # rrl-slip: 2

    # Response Rate Limiting, IPv4 prefix length. Addresses are
    # grouped by netblock. 
    # rrl-ipv4-prefix-length: 24

    # Response Rate Limiting, IPv6 prefix length. Addresses are
    # grouped by netblock. 
    # rrl-ipv6-prefix-length: 64

    # Response Rate Limiting, maximum QPS allowed (from one query source)
    # for whitelisted types. Default is on.
    # rrl-whitelist-ratelimit: 2000
    # RRLend

# Remote control config section. 
# remote-control:
    # Enable remote control with nsd-control(8) here.
    # set up the keys and certificates with nsd-control-setup.
    # control-enable: no

    # what interfaces are listened to for control, default is on localhost.
    # control-interface: 127.0.0.1
    # control-interface: ::1

    # port number for remote control operations (uses TLS over TCP).
    # control-port: 8952

    # nsd server key file for remote control.
    # server-key-file: "//etc/nsd/nsd_server.key"

    # nsd server certificate file for remote control.
    # server-cert-file: "//etc/nsd/nsd_server.pem"

    # nsd-control key file.
    # control-key-file: "//etc/nsd/nsd_control.key"

    # nsd-control certificate file.
    # control-cert-file: "//etc/nsd/nsd_control.pem"


# Secret keys for TSIGs that secure zone transfers.
# You could include: "secret.keys" and put the 'key:' statements in there,
# and give that file special access control permissions.
#
# key:
    # The key name is sent to the other party, it must be the same
    #name: "keyname"
    # algorithm hmac-md5, or sha1, sha256, sha224, sha384, sha512
    #algorithm: sha256
    # secret material, must be the same as the other party uses.
    # base64 encoded random number.
    # e.g. from dd if=/dev/random of=/dev/stdout count=1 bs=32 | base64
    #secret: "K2tf3TRjvQkVCmJF3/Z9vA=="


# Patterns have zone configuration and they are shared by one or more zones.
# 
# pattern:
    # name by which the pattern is referred to
    #name: "myzones"
    # the zonefile for the zones that use this pattern.
    # if relative then from the zonesdir (inside the chroot).
    # the name is processed: %s - zone name (as appears in zone:name).
    # %1 - first character of zone name, %2 second, %3 third.
    # %z - topleveldomain label of zone, %y, %x next labels in name.
    # if label or character does not exist you get a dot '.'.
    # for example "%s.zone" or "zones/%1/%2/%3/%s" or "secondary/%z/%s"
    #zonefile: "%s.zone"
    
    # If no master and slave access control elements are provided,
    # this zone will not be served to/from other servers.

    # A master zone needs notify: and provide-xfr: lists.  A slave
    # may also allow zone transfer (for debug or other secondaries).
    # notify these slaves when the master zone changes, address TSIG|NOKEY
    # IP can be ipv4 and ipv6, with @port for a nondefault port number.
    #notify: 192.0.2.1 NOKEY
    # allow these IPs and TSIG to transfer zones, addr TSIG|NOKEY|BLOCKED
    # address range 192.0.2.0/24, 1.2.3.4&255.255.0.0, 3.0.2.20-3.0.2.40
    #provide-xfr: 192.0.2.0/24 my_tsig_key_name
    # set the number of retries for notify.
    #notify-retry: 5

    # uncomment to provide AXFR to all the world
    # provide-xfr: 0.0.0.0/0 NOKEY
    # provide-xfr: ::0/0 NOKEY

    # A slave zone needs allow-notify: and request-xfr: lists.
    #allow-notify: 2001:db8::0/64 my_tsig_key_name
    # By default, a slave will request a zone transfer with IXFR/TCP.
    # If you want to make use of IXFR/UDP use: UDP addr tsigkey
    # for a master that only speaks AXFR (like NSD) use AXFR addr tsigkey
    #request-xfr: 192.0.2.2 the_tsig_key_name
    # Attention: You cannot use UDP and AXFR together. AXFR is always over 
    # TCP. If you use UDP, we higly recommend you to deploy TSIG.
    # Allow AXFR fallback if the master does not support IXFR. Default
    # is yes.
    #allow-axfr-fallback: yes
    # set local interface for sending zone transfer requests.
    # default is let the OS choose.
    #outgoing-interface: 10.0.0.10
    # limit the refresh and retry interval in seconds.
    #max-refresh-time: 2419200
    #min-refresh-time: 0
    #max-retry-time: 1209600
    #min-retry-time: 0
    # Slave server tries zone transfer to all masters and picks highest
    # zone version available, for when masters have different versions.
    #multi-master-check: no

    # limit the zone transfer size (in bytes), stops very large transfers
    # 0 is no limits enforced.
    # size-limit-xfr: 0

    # if compiled with --enable-zone-stats, give name of stat block for
    # this zone (or group of zones).  Output from nsd-control stats.
    # zonestats: "%s"

    # if you give another pattern name here, at this point the settings
    # from that pattern are inserted into this one (as if it were a 
    # macro).  The statement can be given in between other statements,
    # because the order of access control elements can make a difference
    # (which master to request from first, which slave to notify first).
    #include-pattern: "common-masters"


# Fixed zone entries.  Here you can config zones that cannot be deleted.
# Zones that are dynamically added and deleted are put in the zonelist file.
#
#zone:
    # name: "example.com"
    # you can give a pattern here, all the settings from that pattern
    # are then inserted at this point
    # include-pattern: "master"
    # You can also specify (additional) options directly for this zone.
    # zonefile: "example.com.zone"
    # request-xfr: 192.0.2.1 example.com.key

    # RRLconfig
    # Response Rate Limiting, whitelist types
    # rrl-whitelist: nxdomain
    # rrl-whitelist: error
    # rrl-whitelist: referral
    # rrl-whitelist: any
    # rrl-whitelist: rrsig
    # rrl-whitelist: wildcard
    # rrl-whitelist: nodata
    # rrl-whitelist: dnskey
    # rrl-whitelist: positive
    # rrl-whitelist: all
    # RRLend

# zone configuration files
include: "etc/nsd/nsd.conf.d/*.conf"

ゾーンファイル

上記設定ファイルで、ゾーン情報については外部の設定ファイルを読み込む形にしています。 外部の設定ファイルを作成し、適時正引き、逆引き用のゾーンファイルを編集します。

$ cd /etc/nsd
$ sudo mkdir nsd.conf.d zones

/etc/nsd/nsd.conf.d/zone-example.com.conf

zone:
    name: "example.com"
    zonefile: "exmaple.com.zone"

/etc/nsd/nsd.conf.d/zone-example.com.rev.conf

zone:
    name: "1.168.192.in-addr.arpa"
    zonefile: "example.com.rev.zone"

正引きゾーンファイル

/etc/nsd/zones/example.com.zone

$TTL 1W
@       IN      SOA     server.example.com. root.example.com.  (
                                      2020010101 ; Serial    # 数字は自由に変えられる
                                      28800      ; Refresh
                                      14400      ; Retry
                                      604800     ; Expire - 1 week
                                      86400 )    ; Minimum
                   IN  NS      server.example.com.
                   IN  A       192.168.1.100

server          IN  A       192.168.1.100
pc1              IN  A       192.168.1.2
pc2              IN  A       192.168.1.3
pc3              IN  A       192.168.1.4
mobile         IN  A       192.168.1.5
printer         IN  A       192.168.1.6

逆引きゾーンファイル

/etc/nsd/zones/example.com.rev.zone

$TTL 1W
@                       IN SOA  server.exmaple.com. root.example.com. (
                                        2020010101 ; Serial    # 数字は自由に変えられる
                                        3H              ; Refresh
                                        15M             ; Retry
                                        1W              ; Expire
                                        1D )            ; Minimum
                           IN NS   server.example.com.

100                     IN PTR  server.example.com.

NSD の起動

設定ファイル、ゾーン情報ファイルを編集後、NSD を起動します。

$ sudo systemctl start nsd

正常に起動していることを確認します。

$ systemctl status nsd

● nsd.service - NSD Name Server Daemon
     Loaded: loaded (/usr/lib/systemd/system/nsd.service; enabled; vendor preset: disabled)
     Active: active (running) since Thu 2020-01-23 18:54:32 JST; 4h 20min ago
   Main PID: 416 (nsd)
      Tasks: 6 (limit: 18787)
     Memory: 214.9M
     CGroup: /system.slice/nsd.service
             ├─416 /usr/bin/nsd -d -c /etc/nsd/nsd.conf
             ├─422 /usr/bin/nsd -d -c /etc/nsd/nsd.conf
             ├─506 /usr/bin/nsd -d -c /etc/nsd/nsd.conf
             ├─508 /usr/bin/nsd -d -c /etc/nsd/nsd.conf
             ├─509 /usr/bin/nsd -d -c /etc/nsd/nsd.conf
             └─510 /usr/bin/nsd -d -c /etc/nsd/nsd.conf

 1月 23 18:54:32 systemd[1]: Started NSD Name Server Daemon.

家庭内ドメインにあるホスト名を家庭内DNSサーバに問い合わせ

NSDDNSコンテンツサーバの機能しか持たないため、自身の保持しているホストテーブルに記載されているホスト名しか解決できません。そのためインターネット上にある各ホストの名前までは解決できず、他のDNSサーバに問い合わせる必要があります。

通常、家庭用ルータやHGWにはDNSサーバが備わっており、自身で解決できないホスト名を上位DNSサーバに問い合わせを行うDNSゾルバの機能を備えています。クライアント側で指定するDNSサーバは家庭用ルータやHGWを設定します。

また、家庭用ルータやHGWには、特定の宛先ドメインのみ特定のDNSサーバに問い合わせを転送する機能を持つものがあります。これは「ローカルドメイン問合せテーブル」や「DNSルーティング設定」といった名称で呼ばれています。こちらの機能を使い、ドメインexample.com」については家庭内DNSサーバへ問い合わせを投げる設定を施します。

以下はHGW「PR-400KI」での設定例です。 f:id:alecriarstudio:20200123233556p:plain

ドメイン名を「example.com」とし、プライマリDNSサーバアドレスを「::FFFF:C0A8:164」と指定します。「::FFFF:C0A8:164」はIPv4アドレス「192.168.1.100」をIPv6形式に変換したものです。

各クライアントからのDNS問い合わせ

Windowsから問い合わせを行い、以下のように応答があれば正常です。

> nslookup pc3.example.com
サーバー:  UnKnown
Address:  XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX   # DNSサーバのIPアドレス

名前:    pc3.example.com
Addresses:  192.168.1.4

以上の名前解決の流れは以下のような形となります。家庭内LANのホストについては家庭内DNSサーバで名前解決しています。

f:id:alecriarstudio:20200124024215p:plain