LAN内にDNSサーバーを立てた時のメモ

## 概要
当記事は、[Dockerを使って最速でDNSを構築してみた](https://nomunomu0504.dev/entry/2022/08/21/230228)を参考にLAN内にDNSサーバーを立てた時に、結構色々と躓いたところがあったので、それらをメモ程度に書いた記事である。

## 環境
+ CoreDNS 1.10.1 (Docker)
+ Ubuntu 22.04 LTS(デスクトップ版, 20.04からのアップグレード)
+ Docker 23.0.5
+ ~~authbind 2.1.3~~

## 動機
ドメイン名をLAN内のIPアドレスに解決するには、`/etc/hosts`を記述するのが定石であるが、これを組み込み機器のような自分で設定をいじれないマシンについて行いたい。

## 手順
### Dockerのインストール
Dockerはcomposeの扱いが変わったので、Ubuntuのリポジトリからではなく、[Dockerのリポジトリ](https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository)から入れたものを以前から使っている。

root権限がなくても使用可能にしてある。docker-ce-rootless-extrasパッケージとかがあるようだが、こういうパッケージが出来る前にdockerグループを作成する方法で実現しているので、ここでは深入りしない。よその記事をあたって欲しい。

### CoreDNSサーバーの作成
といっても、[Dockerを使って最速でDNSを構築してみた](https://nomunomu0504.dev/entry/2022/08/21/230228)をほぼそのまま実施しただけ。

変えた点としては`forward . 8.8.8.8:53`はルーターのアドレスにしたことと、ドメイン名未取得なので、[example.com](https://example.com/)のような、いわゆる予約済みドメイン名のサブドメインを使用したこと。
組み込み機器によっては解決すべきドメイン名が固定というケースが多いかもしれない。

### ~~Privlieged Portの問題~~
組み込み機器では当然DNSのポート番号は53番から変更できない。Ubuntuに限らずLinux系のOSでは、1024番未満のポートを使用するアプリケーションにはroot権限を要求される…のだが、前述したdocker-ce-rootless-extrasの影響なのか何なのか普通にホスト側1024番未満のポートが使用できた。

もちろんファイアウォールの開放は別途行った。

### systemd-resolved.serviceの停止
実際にはDockerを起動するとPrivlieged Portの問題がなくても`port 53 is already used.`と言われてうまく行かない。調べると

```
$ sudo systemctl disable systemd-resolved.service
$ sudo systemctl stop systemd-resolved.service
```

で元からあるサービスを止めないといけないらしい。systemd-resolved自体はDNSクライアントで、止めるとそのホストマシン自体は名前解決が出来なくなる。

正しい解決法かはわからないが、[この辺り](http://nao-yu-ki-pc.blogspot.com/2017/04/systemd-resolveubuntudns.html)を参考に、`/etc/resolv.conf`内の`127.0.0.53`を`127.0.0.1`にして再起動したら何とかなった。

systemd-resolvedをDNSサーバーに出来たらCoreDNSいらないのでは、という考えが今頭をよぎったが試していない。[systemd-resolvedの説明](https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html)を少し見た限りでは"to local applications"と書かれているので、外部のマシンに公開して大丈夫なのか分からないし。

### Docker起動 
上記2つの問題を乗り越えた上で、`compose.yaml`のあるフォルダに移動し、

```
$ docker compose up -d
```

で起動に成功。

### DHCPサーバーへの登録
ルーターのDHCPサーバー機能を使っているので、ルーターの設定をいじった。

DHCP設定で通知するプライマリDNSサーバーのアドレスを新規DNSサーバーにして、元のプライマリDNSサーバー(ルーターのアドレス)をセカンダリDNSサーバーに移して終わり。

後は組み込み機器がDHCPからローカルIPアドレスを取得する時にDNSサーバー情報も一緒に受け取って設定するはず。

組み込み機器を再起動させた後に、ルーターの設定画面でDHCPサーバーのリース期限を表示すると、組み込み機器が情報を更新したか分かるかもしない。

## 動作確認
### PCから
Dockerホスト以外のPCからも`dig`などのコマンドで動作確認出来た。

Ubuntuから`nslookup`で確認すると、DNSキャッシュが効いているのかすぐに反映されなかったが、ネットワーク接続を切断して再接続するとDNSサーバー側での変更が反映された。

### 組み込み機器から
機会があれば別途書くが、組み込み機器側の動作が予想と異なっていたので、残念ながら自分自身の組み込み機器からの動作確認はできていない。
また、自分自身の目的が果たせず運用をやめてしまったので長期間の運用確認などもしていない。

## 考察
あまりないとは思うが、組み込み機器がDHCPからのDNSサーバー指定を使用せずに`8.8.8.8`など固定されたDNSを使用している場合や、そもそも機器内部で名前解決が済んでしまっている場合などは、この方法は使えない。

組み込み機器にローカルIPアドレスへのアクセス制限がかけられているということはあるかもしれない。

## 参考: authbind
Linuxの1024番未満のポート使用制限の回避方法は[マニュアルにもあるように](https://docs.docker.jp/engine/security/rootless.html#rootless-exposing-privileged-ports)`CAP_NET_BIND_SERVICE`を使うのが定番のようだが、さらに調べると[authbindを使う方法](http://var.blog.jp/archives/83447917.html)というものが見つかり、Ubuntuのリポジトリからインストール可能。

```
$ authbind docker compose up -d
```

で起動でき、停止は`docker copose down`でauthbindなしで出来る。実際にはDockerに限って言えばauthbind自体がいらなかったようだ…orz

## 改訂履歴(表現の修正などは除く)
+ 2023/5/6: 元となる記事の作成開始。
+ 2023/5/7: 上記から分離独立。authbind不要と判明して改訂。投稿。
+ 2023/5/14: 環境に補足。