UbuntuでmDNS(マルチキャストDNS)をavahiとsystemdそれぞれ試した

よく、Hyper-Vで雑にVMUbuntuをいれたりミニPCにLinuxいれたりしているが、固定のプライベートIPを振って運用している。しかし、よく使わないものはIPアドレスを忘れるようになった。でもDNSサーバはなんか立てるのも面倒だしIPに変更があったとき追従してくれないのも面倒。ということでmDNSの出番。(設定したホスト名を忘れるという問題は見なかったことにします)

マルチキャストDNS(mDNS)はマルチキャストを利用してDNSサーバ無しに名前解決する。mDNSの要求に対して、ホスト名.local を持つサーバがマルチキャストに応答することで実現するため、同一ネットワークに属するような小規模なネットワーク向きらしい。類似のプロトコルにLLMNRがある。

mDNSを動かすには、リクエストを送る側とリクエストを受けるためにデーモンを動かす必要があり、mDNSリクエストを送るためにリゾルバも対応が必要なので注意。(mDNSにおいては相互に同じ立場なので呼び名がないっぽい?ものの、2つの役割で成り立ってるので、デーモンとリゾルバと呼んで区別している。デーモン=サーバ、リゾルバ=クライアントというようなイメージ。)

細かい話はあるかもしれないけど、とにかく使える状態にするための手順をメモ。

mDNS設定

実現するには、avahiを使うか、systemdを使うかの2つが主らしい。

ファイアウォールがある場合はUDP:5353を開ける必要がある。

Ubuntu + avahi の場合

デーモン

sudo apt install  avahi-daemon
sudo systemctl start avahi-daemon
sudo systemctl enable avahi-daemon

これだけでよい。

ゾル

/etc/nssswitch.conf で設定することになる。avahiをインストールすると依存でlibnss-mdnsもインストールされる。

あとは使うだけ。インストール後に以下のように設定されており、IPv4のみでよければすぐに使える。

hosts:          files mdns4_minimal [NOTFOUND=return] dns

# 参考: インストール前
# hosts:          files dns
  • mdns4_minimal: IPv4 で解決する
  • mdns6_minimal: IPv6 で解決する
  • mdns_minimal: IPv4もしくはIPv6 で解決する

環境によるが、mdns_minimalが良い場合もあるはず。適宜設定すること。

他にもあり、挙動についてはこの辺をよむ。でもほとんど上記のどれかでいいはず。

github.com

Ubuntu + Systemd-resolve/Systemd-networkdの場合

Systemdでも行える。パッケージを増やしたくない場合はこちらがいいかもしれない。

デーモン

/etc/systemd/resolved.conf を修正する。

[Resolve]
MulticastDNS=yes

その後、 反映させるために systemd-resolved.service で再起動

sudo systemctl restart systemd-resolved.service

resolvectl mdns でmDNSの設定状況を確認できる

$ resolvectl mdns 
Global: yes
Link 2 (eth0): no

noがあるネットワークインターフェースはmDNSのリクエストを受けても返さないのでうまくいかない模様。なので、次はその設定をしていく。(リゾルバとしてはこの時点でも使える。)

まず設定対象のファイルを調べる。ネットワークインタフェース名を含むので、設定したいネットワークインタフェースの数だけ設定。

$ ls /run/systemd/network/
10-netplan-eth0.network

この場合、 /etc/systemd/network/${FILENAME}.d/override.conf にファイルを作る。(/etc/systemd/network/${FILENAME} だと再起動時にダメになった)

NETWORK_FILE_NAME="10-netplan-eth0.network"

sudo mkdir "/etc/systemd/network/${NETWORK_FILE_NAME}.d"
cat << __EOF__  | sudo tee "/etc/systemd/network/${NETWORK_FILE_NAME}.d/override.conf"
[Network]
MulticastDNS=yes
__EOF__

その後、 反映させるために systemd-networkd.service を再起動

sudo systemctl restart systemd-networkd.service

resolvectl mdns で設定状況を確認し、yesになっていればOK。

$ resolvectl mdns 
Global: yes
Link 2 (eth0): yes

ゾル

ゾルバだけでいい場合は、/etc/systemd/resolved.confMulticastDNS=resolve とすればよい。

その他

疎通確認方法

Linux: getent

getent hosts ホスト名.local がよいでしょう。GLIBCについてくるっぽいので大抵の環境で使えるはず。

 getent hosts test3.local

出力例

$ getent hosts test3.local
fe80::215:5dff:fe01:a605 test3.local

IPv4もあるはずだけど、IPv6のものしかみえなかった。

当たり前かもしれないけど、nslookupやdigはDNS用っぽいので機能しなかった。(wgetであればgetentと同じような雰囲気)

Windows: PowerShellResolve-DnsName

PowerShellResolve-DnsName ホスト名.local がよいでしょう。

Resolve-DnsName test3.local

出力例

> Resolve-DnsName test3.local

Name                                           Type   TTL   Section    IPAddress
----                                           ----   ---   -------    ---------
test3.local                                    AAAA   120   Answer     fe80::215:5dff:fe01:a605
test3.local                                    A      120   Answer     172.28.21.94

IPv6を無効にすればIPv4で解決するようになる

当たり前だけど、IPv4IPv6のどちらも有効な場合、IPv6を使うっぽいので、この挙動が困る場合はIPv6のサポートを切ればよい

  • デーモン側でIPv6を無効にする場合
    • avahi: /etc/avahi/avahi-daemon.conf[server]セクションでuse-ipv6=noを設定する
    • systemd-networkd ではわからない
  • ゾルバ側でIPv6を無効にする場合
    • avahiならnsswitch.conf では msdn4_minimal を使う
    • systemd-networkd ではわからない
  • 共通
    • sysctl等でIPv6を無効にする(mDNS関係なくIPv6自体が使えなくなる)

以下はtest3.local上でtest2.localを探す際にsysctl net.ipv6.conf.all.disable_ipv6=1としてIPv6を無効にした場合とその前後のgetentの結果。(test2.localはIPv6/IPv4のmDNSをサポートしている)

ryozi@test3:~$ getent hosts test2.local
fe80::215:5dff:fe01:a604 test2.local

ryozi@test3:~$ sudo sysctl net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.all.disable_ipv6 = 1

ryozi@test3:~$ getent hosts test2.local
172.28.18.148   test2.local