お伝えしたいこと
Fedora33以降で、/etc/nsswitch.confのhosts行のデフォルト値が変わりました。
その変更に伴ってLinuxの名前解決の挙動がどのように変わったかを記事前半の#サマリで紹介します。
また記事後半の#Name Service Switch以降では、Name Service Switchの概要と/etc/nsswitch.confファイルの読み方を紹介します。
- お伝えしたいこと
- サマリ
- Name Service Switch
- /etc/nsswitch.confの読み方
- getent
- (参考) その他のDNSクエリコマンド
- (参考) NSSの利用例
- (参考) /etc/nsswitch.confのさらなる最適化
- まとめ
- 次の記事
サマリ
本セクションに各ディストリビューションの/etc/nsswitch.confのhosts行に書かれている内容の意味を記載します。
挙動のみを知りたい場合は、本セクションのみ読めば十分です。
/etc/nsswitch.confの読み方については、本記事の後半で取り扱います。
Fedora33以降
Fedora33以降の/etc/nsswitch.confの内容は、以下のとおりです。
hosts: files myhostname resolve [!UNAVAIL=return] dns
端的に言うと、ほとんどの場合は/etc/hostsかsystemd-resolvedによる名前解決になります。
/etc/resolv.confは、基本的に使われません。
systemd-resolved.serviceが停止している場合のみ、/etc/resolv.confによるDNS名前解決が行われます。
以下に詳細を示します。
まずは1で名前解決を試み、1で名前解決できなければ2、次に3...という流れで進みます。
/etc/hostsの定義を元に名前解決する (files)- 自身のホスト名やFQDNを名前解決する (myhostname)
- systemd-resolvedによるDNS名前解決を行う (resolve)
- systemd-resolvedが問題なく起動していた場合、この先に進まず名前解決の結果を返す (
[!UNAVAIL=return])
- systemd-resolvedが問題なく起動していた場合、この先に進まず名前解決の結果を返す (
/etc/resolv.confによるDNS名前解決を行う (dns)
Fedora33以前、RHEL7、RHEL8
Fedora32以前、RHEL7、RHEL8の/etc/nsswitch.confの内容は、以下のとおりです。
RHEL9 Bataについても同じ内容でした。
hosts: files dns myhostname
ほとんどの場合は/etc/hostsか/etc/resolv.confによる名前解決になります。
Name Service Switch
Name Service Switch (NSS) とは、GNU C Library (glibc) に含まれる名前解決手段のデータベースです1。
例えばFQDNやホスト名をIPアドレスに解決する手段は、以下のとおり複数存在します。
/etc/hostsを参照して名前解決する/etc/resolv.confに記載されたDNSサーバに問い合わせて名前解決する- systemd-resolved DNSクライアントの機能で名前解決する
- (他)
NSSは、上記のような名前解決手段に優先順位付けをします。
そして、優先順位の高い順に名前解決を試みます。
多くの場合は/etc/hostsの優先順位が高く、その次に/etc/resolv.conf、またはsystemd-resolvedが使用されるようNSSに制御されます。
上記はFQDNやホスト名からIPアドレスへ名前解決する場合の例ですが、NSSの用途はもっと多岐に渡ります。
以下にNSSが提供する名前解決の対象 (※) を列挙します2。
(※) 以下に列挙した名前解決の対象は、NSSの用語でdatabaseといいます
- aliases
- ethers
- group
- hosts
- initgroups
- netgroup
- networks
- passwd
- protocols
- publickey
- rpc
- services
- shadow
Linuxでは、多くのアプリケーションが/etc/nsswitch.confを参照し、NSSによって名前解決の手段を決定します。
しかし、全てのプログラムがNSSを使うわけではありません。
「NSSが何に使われ、何に使われていないか」については、#(参考) NSSの利用例でいくつかの例を示します。
次のセクションからは、NSSの設定ファイルである/etc/nsswitch.confの読み方について詳しく説明します。
/etc/nsswitch.confの読み方
基本構造
本セクションの情報は、man nsswitch.confの内容を情報源としています。
/etc/nsswitch.confは、NSSの設定ファイルです。
1列目にdatabase、2列目以降にservice specifications (※) を列挙します。
databaseとservice specificationsの間は:で区切ります。
(※) service specificationsは、単にservicesと呼ばれることもあります
serviceは、1つ以上指定します。
左に書いてあるものほど優先順位が高く、最初に検索されます。
優先順位が高いserviceにおいて名前解決できなかった場合、次に優先順位の高いserviceで名前解決を試みます。
以下に、Fedora35の/etc/nsswitch.confのhosts database行の例を示します。
hosts databaseは、FQDNやホスト名からIPアドレスを求める、またはその逆の名前解決を行う際に参照されるdatabaseです。
hosts: files myhostname resolve [!UNAVAIL=return] dns
上記において、hostsがdatabaseです。
そして、service specificationsは以下の通りです。
上に書いてあるものほど優先順位が高いです。
filesmyhostnameresolve [!UNAVAIL=return]dns
[]で囲まれた文字列は、actionと呼ばれるパラメータです。
service specificationの後に指定することで、デフォルトの動作を一部変えることができます。
詳細は#actionセクションにて説明します。
service specifications
本セクションでは、代表的なservice specificationsの意味を紹介します。
files
filesは、/etc/配下の設定ファイルによる名前解決を行うserviceです。
具体的にどのファイルに記述するかは、databaseによって異なります。
下表に例を示します。
| database名 | 設定ファイル (※) | 内容 |
|---|---|---|
| hosts | /etc/hosts |
IPアドレスとホスト名/FQDNの紐付け |
| passwd | /etc/passwd |
ユーザー名と詳細情報 (※) の紐付け (※) UID, GID, ホームディレクトリパス, ログインシェルなど |
| group | /etc/group |
グループ名とGID/所属ユーザー名の紐付け |
| shadow | /etc/shadow |
ユーザー名とパスワード (ハッシュ値) の紐付け |
| networks | /etc/networks |
ネットワーク名とネットワークアドレスの紐付け |
| services | /etc/services |
サービス名とTCP/UDPポート番号の紐付け |
(※) 各databaseのfiles serviceに紐づく具体的なファイルは、manを追いかけることで推定できます。例えばhosts databaseの場合、man nsswitch.conf → man gethostsbynameと辿ると/etc/hostsという情報に行き着きます
各種ファイルの詳細情報は、ファイル名のmanページで確認できます。
例えば/etc/hostsの情報はman hostsで、/etc/passwdの情報はman 5 passwdで確認できます。
myhostname
myhostnameは、自分自身のホスト名をIPアドレスに名前解決します。
私達がmyhostnameの機能を直接使うことはほとんどありません。
どちらかというと、アプリケーションの内部処理で利用される機能だと思います。
myhostnameの簡単な例を示します。
以下のコマンドにより、myhostname serviceを指定してNSSを検索しています。
実行しているLinuxのホスト名はpcです。
(※) getentはNSSを参照して名前解決を行うコマンドです。詳細は#getentで説明します
getent -s myhostname ahostsv4 pc | grep STREAM # 192.168.1.110 STREAM pc # 192.168.122.1 STREAM # 192.168.100.1 STREAM
ホスト名の他にも、以下のような名前解決が可能です。
| 名前 | IPアドレス |
|---|---|
| ※自身のホスト名 | |
|
|
_gateway |
デフォルトゲートウェイのIPアドレス |
dns
dnsは、/etc/resolv.confの記載内容に基づいてDNSによって名前解決を行うserviceです。
/etc/resolv.confの書き方については詳しく触れません。
詳細はman resolv.confに書いてあります。
nameserverとsearchを指定するのが一般的だと思います。
resolve
resolveは、systemd-resolvedというDNSクライアントによって名前解決を行うserviceです3。
systemd-resolvedは、RHEL7やRHEL8においては現状使われていません。
Fedoraでは、Fedora33以降でdnsを置き換える形で使われ始めました。
systemd-resolvedは、以下の特徴を持ちます。
- モダンなDNS機能に対応する
- D-Bus APIに対応し、NetworkManagerなどと連携して動作できる
- 名前解決結果をキャッシュできる
- hosts databaseのfiles, myhostname, dnsと同等の機能を持つ
- ドメイン名に応じたDNSサーバの使い分けができる (※)
(※) Split DNSと呼ばれる機能。systemd-resolved用語ではPer-link DNSやDNS Routingとも呼ばれる
systemd-resolvedについては、以下の記事で詳細に説明します。
(参考) mdns4_minimal
環境によっては、mdns4_minimal [NOTFOUND=return]がhosts databaseに含まれることもあるので、軽く触れておきます。
mdns4_minimalがhosts databaseに含まれていない場合は、本セクションごとスキップして差し支えありません。
私の環境では、Cinnamon Desktop Environmentに依存関係として含まれていました。
mdns4_minimalは、デフォルトでは/etc/nsswitch.confには書いてありませんし、書いたとしても使えません。
このserviceが表すmDNS機能は、以下のRPMパッケージをインストールすることで使えるようになります。
sudo dnf install nss-mdns
nss-mdnsをインストールすることで、/etc/nsswitch.confにmdns4_minimal [NOTFOUND=return]が追記されます。
また、mDNSの動作に必要なライブラリやプログラムも追加されます。
mdns4_minimalは、ホスト名.localの名前解決を行います。
上記に該当しない名前については、そもそも名前解決のクエリ自体がスキップされます。
そして、NSSの優先順位にしたがい、次のserviceで名前解決を試みるという動きになります。
言い換えると、ホスト名.local以外の名前を使う限り、mdns4_minimalは一切関与しません。
多くの場合、mdns4_minimalを利用したり意識することはないと思います。
nss-mdnsには、他にも以下のservice specificationが含まれます4。
| mDNSのservice | 機能 |
|---|---|
| mdns | IPv4/IPv6の全てのmDNS機能 (.local以外のドメインも名前解決可能) |
| mdns4 | IPv4の全てのmDNS機能 |
| mdns6 | IPv6の全てのmDNS機能 |
| mdns_minimal | IPv4/IPv6について、.local限定のmDNS機能 |
| mdns4_minimal | IPv4について、.local限定のmDNS機能 |
| mdns6_minimal | IPv6について、.local限定のmDNS機能 |
2点ほど余談を挟みます。
1つ目ですが、DNSサーバの検証をする際は.localや.localhost、.localhost.localdomainを使わないように気をつけましょう。
.localはmDNSと競合しますし、後者の2つはmyhostname serviceと競合します。
結果として上記ドメインはDNSサーバに問い合わせられず、意図せぬ結果を招くことがあります。
2つ目は、mDNS (multicast DNS) についてです。5,6
mDNSは、名前解決のクエリにマルチキャストを使います。
IPv4は224.0.0.251、IPv6はff02::fbを宛先にセットしてクエリします。
宛先ポート番号はUDP5353です。
通常のDNSとは異なり、DNSサーバのIPアドレスを指定せず使えるのがmDNSの利点です。
その代わり、基本的には同一ネットワーク内限定のサービスとなります。
(参考) sss
sssは、sssデーモンによる名前解決を行います。
ここでの名前解決はFQDNやホスト名ではなく、ユーザー名やグループの名前解決です。
RHEL8では、passwd databaseやgroup databaseにおいてデフォルトで使用されています。
sssを使う主なメリットは、名前解決結果のキャッシュ機構を持つことで処理が効率化されていることです。
詳細が気になる方は、RHEL8のマニュアルを参照してください。
Fedoraについては、Fedora35以降よりsssdを使わなくなりました (参考: Fedora35の変更点)。
action
actionとは、/etc/nsswitch.confにおいて[]で囲まれた部分のことです。
以下のフォーマットで記述されます。
[STATUS=ACTION]
STATUSもACTIONも複数存在しますが、最低限resolve [!UNAVAIL=return]の意味さえ理解できれば十分です。
STATUSに入る値は、下表のいずれかです。
クエリに成功した場合はreturn、何らかのエラーが発生した場合はcontinueするのがデフォルトの動作です。
| STATUS名 | 意味 |
|---|---|
| SUCCESS |
|
| NOTFOUND |
|
| UNAVAIL |
|
| TRYAGAIN |
ACTIONに入る値は、下表のいずれかです。
| ACTION名 | 意味 |
|---|---|
| return |
|
| continue | 次のNSS serviceによる名前解決を行う |
| merge |
|
actionは、service specificationsの後に記述することで意味を持ちます。
例えば、以下の例ではmdns4_minimalで名前解決を試みたとき、クエリ結果が "not found" だった場合はその場で結果を返します。
mdns4_minimal [NOTFOUND=return]
STATUSの前に! (否定) を記述することで、STATUS部分の意味が逆になります。
例えば以下の場合、resolveが恒久的に利用不能な場合を除けば必ず結果を返すようになります。
具体的には、systemd-resolvedサービスが停止している場合にはcontinueになりますが、そうでなければreturnになります。
resolve [!UNAVAIL=return]
getent
/etc/nsswitch.confに記述したNSSの挙動を確認するには、getentコマンドが便利です。
getentは、databaseを指定して名前解決を実行し、その結果を返すコマンドです。
syntaxは以下の通りです。
getent [-s <service>] <database> <key>
それぞれ以下の意味を持ちます。
| キーワード | 意味 |
|---|---|
-s <service> |
|
<database> |
<key> | |
いくつか例を示します。
hosts databaseの場合は、以下のようなコマンドが便利です。
あまり詳しくは理解していませんが、hostsを指定するとIPv6の結果が返ることが多いです。
IPv4アドレスの結果が欲しい場合は、ahostsv4が便利です。
getent hosts google.com # 2404:6800:4004:812::200e google.com getent ahostsv4 google.com # 142.250.196.142 STREAM google.com # 142.250.196.142 DGRAM # 142.250.196.142 RAW
STREAM、DGRAM、RAWはUnix Socketを表しています。
Unix Socketについてはあまり詳しくありませんが、TCP通信はSTREAM、UDP通信はDGRAM、ICMP通信はRAWを使うようです。7,8,9,10,11
3行とも同じ結果が出てくるので、あまり気にしなくても良いのではと思います。
もう一つ例を示します。
以下の出力では、passwd databaseの内容を表示しています。
LDAPを利用している環境では、LDAP経由で得られるユーザー情報もこのコマンドから確認できるようです。
getent passwd # root:x:0:0:root:/root:/bin/bash # (以下略)
(参考) その他のDNSクエリコマンド
getent以外にもDNSの名前解決をテストするコマンドはいくつかあります。
これらのコマンドは特定のserviceに特化したもので、NSSを参照しません。
dighostresolvectl query
bind-utils RPMパッケージに含まれるdigやhostは、/etc/resolv.confのみを参照します。12,13
systemd-resolvedを操作するresolvectl queryコマンドは、systemd-resolvedを介した名前解決を試みます14。
(参考) NSSの利用例
本セクションでは、NSSが利用される具体的な場面をいくつか紹介します。
一方、NSSを使わないケースについても一部触れます。
hosts databaseの利用例
FQDNやホスト名を指定して通信を行う場合、名前解決を行ってIPアドレスに変換した上で通信します。
Linuxにおいては、このFQDN/ホスト名の名前解決手段を決めるためにNSSのhosts databaseを使用します。
具体的な挙動は、#サマリにて説明したとおりです。
passwd,shadow,group,gshadow databaseの利用例
以下のdatabaseは、ユーザー/グループの認証に使用されます。
- passwd
- shadow
- group
- gshadow
それぞれ/etc/配下の同名のファイルに従ってユーザー名やグループ名と詳細情報を紐付けます。
詳細情報とは、具体的に以下のような内容です。
LDAPなどの認証プロトコルを利用する場合は、上記databaseを書き換えることになります。
services databaseの利用例
RHEL7、RHEL8の/etc/nsswitch.confの一部を以下に抜粋します。
services: files sss
files serviceに対応するファイルは、/etc/servicesです。
このファイルには、TCP/UDPポート番号とサービス名の紐付け情報が書かれています。
一部を抜粋します。
# (一部抜粋) ssh 22/sctp # SSH
ssなどのプログラムは、ポート番号の表示にservices databaseを使用しています。
ssの実行結果を一部抜粋します。
以下の出力ではポート番号の表示にsshと表示されていますが、これは22と同じ意味です。
このsshと名前で表示する処理に、NSSのservices databaseを介して/etc/nsswitch.confが使われています(※)。
(※) /etc/nsswitch.confをservices: sssに書き換えたり、/etc/servicesのssh行を#でコメントアウトするとssの表示結果に影響を与えました。
ss -lt # State Recv-Q Send-Q Local Address:Port Peer Address:Port Process # LISTEN 0 128 0.0.0.0:ssh 0.0.0.0:* # LISTEN 0 128 [::]:ssh [::]:*
networks databaseは、ipコマンドには使われていない
servicesと似たようなdatabaseとして、networksもあります。
/etc/networksは、以下のようにネットワークアドレスと和名を紐付けています。
default 0.0.0.0 loopback 127.0.0.0 link-local 169.254.0.0
ip routeコマンドで表示されるネットワークアドレスにもdefaultキーワードが出てきます。
しかし、ip routeコマンドについては/etc/nsswitch.confも/etc/networksも参照していません(※)。
(※) どちらの設定ファイルをいじっても、ip routeの出力結果に影響を与えませんでした
その他
ここまで見てきたように、NSSを使っているか使っていないかを見分けることは容易ではありません。
hostsやpasswdのような重要なdatabaseについては挙動をしっかり理解しておくべきですが、他のdatabaseについてはあまり気にしないのが良いバランスなのではないかと思います。
他にも色々なdatabaseがありますが、どうしても情報が必要なケースがあれば/etc/nsswitch.confを変更しながら地道に挙動確認しようと思います。
しかし、そのようなケースはほとんどないと思います。
(参考) /etc/nsswitch.confのさらなる最適化
systemd-resolvedは、NSS hosts databaseの以下の機能を内包します。
- files (
/etc/hosts) - dns (DNSサーバによる名前解決。
/etc/resolv.confとの互換性もある) - myhostname (自分のホスト名やデフォルトゲートウェイなどの名前解決)
また上記の仕組みとは異なり、systemd-resolvedは名前解決の結果を一定時間キャッシュするので、処理がより効率化されています。
唯一の弱点は、systemd-resolvedデーモンがクラッシュした場合に名前解決機能を継続できなくなることぐらいです。
こういった事情から、systemd-resolvedの作者は以下のように/etc/nsswitch.confを更新することを推奨しています15。
↓更新前 (Fedora33以降)
hosts: files myhostname resolve [!UNAVAIL=return] dns
↓更新後
hosts: resolve [!UNAVAIL=return] files myhostname dns
「基本的には、処理が効率的なsystemd-resolvedに全て任せる。万が一systemd-resolvedがクラッシュしたときのために、filesやmyhostnameは後ろに残しておく。」
こういった設計思想のようです。
Fedoraのデフォルト値はあくまで「更新前」の状態ですが、名前解決が処理能力のボトルネックになるような状況が万が一発生した場合は「更新後」に変更することを検討しても良いのかもしれませんね。
まとめ
前半では、/etc/nsswitch.confのhosts database行の意味を解釈しました。
後半では、その解釈の根拠として/etc/nsswitch.confのファイルの読み方について、詳細に説明しました。
参考情報として、hosts以外のdatabaseやgetentコマンドについても少し触れました。
次の記事
Fedora33以降で使われ始めたsystemd-resolvedについて紹介します。
RHEL7、RHEL8ではまだ使われていませんが、そのうちスタンダードになるかもしれません。
-
The GNU C Library - System Databases and Name Service Switch↩
-
resolvectl queryがNSSではなくsystemd-resolvedを参照するというドキュメント上のエビデンスはありませんが、手元の検証で確認しました。NSSでmdns4_minimalを有効化した上でgetent hosts remote.localでリモートホストのmDNSによる名前解決を試みたところ、成功しました。一方で、resolvectl query remote.localでは失敗しました。systemd-resolvedのmDNS機能はデフォルトで無効化されていることから、systemd-resolvedでmDNSの名前解決を実行しようとすると失敗するのは想定通りです。もちろん、getent -s resolve hosts remote.localでも名前解決できません。以上の結果から、resolvectl queryはNSSを利用せず、systemd-resolvedの機能のみで名前解決を行うことが確認できました。↩