resolv

Table of Contents

/etc/resolv.conf

Q: Ubuntu 24.04 LTS /etc/resolv.conf について質問します。 OpenBSDでは、このファイルを編集する事により、DNSへの問い合わせ優先をIPv4に するかIPv6にするかリアルタイムに変更できました。

Ubuntuで確認すると、冒頭に編集するなって書いてありました。

どのファイルを変更して、どんなコマンドで有効にすれば良いのでしょうか? 思想の違いもあると思いますので、それも含めて解説してください。

A: いい質問です。Ubuntu 24.04 LTS の /etc/resolv.conf 周りは、OpenBSD と思想がかなり違いますので整理して説明します。


## 1. OpenBSD の場合

  • /etc/resolv.conf を直接編集するのが基本。
  • ここに書いた内容が libc (resolver) が参照する設定そのものになる。
  • 例えば
nameserver 8.8.8.8
family inet

のように書くと、即座に優先するプロトコル(IPv4/IPv6)や問い合わせ先が変わる。

  • 「ユーザーが直接書き換えるのが当たり前」という設計。

## 2. Ubuntu (systemd-resolved) の場合

Ubuntu 24.04 LTS ではデフォルトで systemd-resolved が DNS 解決を管理しています。

  • /etc/resolv.conf は単なる「stub(中継)」用で、systemd が自動生成したものを指しています。
# This is /run/systemd/resolve/stub-resolv.conf managed by systemd-resolved(8).
  • 実体は /run/systemd/resolve/ 以下にあり、systemd が再起動やネットワーク更新のたびに書き換えます。
  • ユーザーが直接編集してもすぐに上書きされるので「編集するな」と警告してあるわけです。

## 3. Ubuntu での設定方法

### (A) DNS サーバや問い合わせ設定を変更したい場合

  1. 永続的に指定するなら:
    • systemd-resolved の設定ファイル
/etc/systemd/resolved.conf

例:

[Resolve]
DNS=8.8.8.8 2001:4860:4860::8888
FallbackDNS=1.1.1.1
  • 変更を反映するコマンド:
sudo systemctl restart systemd-resolved
  1. 一時的に変更するなら:
    • =resolvectl=(systemd-resolved の操作コマンド)を使います。
resolvectl dns eth0 8.8.8.8
resolvectl dns-priority eth0 100

### (B) IPv4 / IPv6 の優先度を変えたい場合

DNS サーバ自体の設定とは別に、「問い合わせ時にIPv4を優先するかIPv6を優先するか」は /glibc の getaddrinfo() の挙動/で決まります。

これは /etc/gai.conf に書きます。 例えば、IPv4 を優先したい場合はコメントを外して以下を有効化:

precedence ::ffff:0:0/96  100

これにより IPv6 アドレスより IPv4 アドレスを優先して返すようになります。 このファイルは systemd とは独立しており、OpenBSD の resolv.conf に書いていたような「IPv4 優先/IPv6 優先」を制御する場所に相当します。


## 4. 思想の違い

  • OpenBSD
    • シンプルさ重視。
    • 1つのファイル /etc/resolv.conf に全てを書き、編集即反映。
    • 管理は楽だが、大規模環境では自動管理との相性が悪いこともある。
  • Ubuntu (systemd-resolved)
    • モジュール化・自動化重視。
    • DNS サーバ設定は systemd が一元管理。
    • アプリの挙動(IPv4/IPv6優先度)は glibc 側の gai.conf で制御。
    • 人間が直接 /etc/resolv.conf をいじるのではなく、「レイヤーごとに役割を分離」する設計。

✅ まとめると:

  • /etc/resolv.conf は直接編集しない(systemd が上書きする)。
  • DNS サーバを指定するなら /etc/systemd/resolved.conf または =resolvectl=。
  • IPv4/IPv6 の優先度を変えるなら =/etc/gai.conf=。

Q: AlmaLinux9.6 とかでも、同様なファイル編集で目的を達しられるのでしょうか? systemdとglibcはどのLinuxでも同一なはずだから、一緒かな?

A: はい、良い視点です。整理するとこうなります 👇


## 1. AlmaLinux 9.6 の DNS 解決基盤

  • AlmaLinux 9(=RHEL9系)は systemd-resolved をデフォルトでは使っていません。
  • 代わりに NetworkManager/etc/resolv.conf を管理しているのが一般的です。
    • 例えば /etc/resolv.conf の冒頭にこんな記述が入ります:
# Generated by NetworkManager
  • なので、直接 /etc/resolv.conf を編集しても上書きされてしまう点は Ubuntu と同様です。

## 2. DNS サーバを設定する場合 (AlmaLinux 9 系)

  • 永続的に変更したいときは NetworkManager の設定を使います。
    • 例:特定のインターフェイス ens33 に Google DNS を設定する場合
nmcli connection modify ens33 ipv4.dns "8.8.8.8 1.1.1.1"
nmcli connection modify ens33 ipv4.ignore-auto-dns yes
nmcli connection up ens33
  • IPv6 DNS も同様に
nmcli connection modify ens33 ipv6.dns "2001:4860:4860::8888"
nmcli connection modify ens33 ipv6.ignore-auto-dns yes
nmcli connection up ens33
  • /etc/NetworkManager/NetworkManager.conf[main] dns=systemd-resolved を書けば Ubuntu 同様に /systemd-resolved を使う構成/に切り替えることもできます。

## 3. IPv4/IPv6 の優先度

ここは Ubuntu とまったく同じです。

  • /glibc の getaddrinfo() の挙動で決まる/ので、制御するのは =/etc/gai.conf=。
  • 例えば IPv4 を優先したい場合:
precedence ::ffff:0:0/96  100

を有効化する。

  • この部分は Ubuntu でも AlmaLinux でも Debian でも Arch でも同一です。

## 4. まとめ

  • Ubuntu (24.04 LTS): systemd-resolved が管理。
  • AlmaLinux (9.6): NetworkManager が管理(ただし systemd-resolved に切り替え可能)。
  • IPv4/IPv6 の優先制御: どのディストリでも glibc の /etc/gai.conf 編集で共通。

Linuxシステム管理標準教科書 こんな案内が来てたぞ。ディストリ毎に微妙に 違うから、適した資料に当たってくれ、だな。オイラーは当分OpenBSDで行くぞ。

readonly

とあるシェルスクリプトを見ていたら、readonlyなんてのが利用されてた。一度 変数に代入したら、以後は再代入できないってのは、容易に想像がつく。 じゃ、違反したらどうなるの? 多分manに説明が有るだろうけど、こういうのは 自分で実験するに限るな。

#! /bin/sh
rv="hello"
rv="world"
echo $?
echo $rv

まずは、こんなコード。

/tmp/ck.sh
0
world

再代入は成功で、確かに書き変わっている。そんじゃ、2行を readonly rv="hello"に変更。

/tmp/ck.sh
/tmp/ck.sh[3]: rv: is read only
ad$ echo $?
1

3行目を実行しようとして落ちた。そしてエラーだよってステータスだった。

ruby

readonlyな変数って、haskellではデフォだよな。完全に関数型な言語だからね。 じゃ、rubyはどうよ。こちらは完全にオブジェクト指向な言語。readonlyに相当 する機能って提供されてたかな? えぇーと、かすかな記憶を掘り起こしてみると 大文字で始まる変数は書き換え不可だったような。確かめてみるか。

あれ、OpenBSD 7.6 には入れていなかった。昔は、No Ruby, No Life. だったんだ けどな。2007年のruby会議のグッツのトート・バッグにでかでかと表示してあって、 毎週使ってるよ。図書館との通い袋としてね。丈夫に作ってあるんで、10冊ぐらい 本を入れてもビクともしない。

折角なのでrubyを入れておこうか。来月には 7.6のサポートも切れてpkgの配信が 停止されるからね。そう、バージョンの保証期間は1年って掟になってる。 その点、マイクロソフトなんかは結構長期に渡ってサポートしてくれてるな。 巷では、ブースカ言われているけど。もうすぐ、Good by Windows 10 ですよ。

ad$ pkg_info -Q ruby

色々なバージョンが列挙されたぞ。勿論gemで提供されてると思われるライブラリィー も含めてね。とりあえず、基礎になるruby-3.3.5 を入れた。それだけではri用の原稿 が入ってこないので、追加で ruby33-ri_docs も入れた。

こんな作業をやってて、shellとの重大な差異に今更気がついてしまったぞ。 そう、言語の機能を増強するライブラリィーが提供されてるか否かって事。

C,python,go,rust, … 言語系は、膨大なライブラリィーによって支えられている。 それが悩みの種でもある。曰く、どんなライブラリィーを使ったら良いの? とか、ライブラリィーに毒(ウィルス)が混っていたぞ等々。

ShopifyがRuby Centralを操りBundlerとRubyGemsの乗っ取りを強制したという調査結果が公表される

最近、こんな事件も発生したようですよ。世の中、不確実ですな。

言語系でコードを書くって、ライブラリィから必要な関数を探し出し、使い方を 調べてってのの繰り返しなんだな。今更ながら、ご苦労なこったい。その点、shellは そういう考慮は必要ないな。shellを極めてみるのも一興かと。

inside ksh

んな訳なんで、お近づきの印として、中がどうなってるか潜ってみたい。上でやった readonlyのエラー検出ね。それにはgdbできるkshが必要だな。ソースツリー内で コンパイルしちゃうと、そこが汚れるので、/tmpにコピー。

cc -g -O0 -DEMACS -DVI -I. -I/tmp/ksh -I/tmp/ksh/../../lib/libc/gen -Wall -Wpointer-arith -Wuninitialized -Wstrict-prototypes -Wmissing-prototypes -Wunused -Wsign-compare -Wshadow  -MD -MP  -c misc.c
misc.c:16:10: fatal error: 'charclass.h' file not found
#include "charclass.h"
         ^~~~~~~~~~~~~
1 error generated.

ツリーから外れた所でコンパイルした影響が出てる。-Iを見るとlib/libc/genが関係 してるな。まあ、そんな事を横目で見ながら、必要なヘッダーを補充してあげる。

ad$ locate charclass.h
/usr/libdata/perl5/amd64-openbsd/CORE/regcharclass.h
/usr/src/gnu/usr.bin/perl/regcharclass.h
/usr/src/lib/libc/gen/charclass.h
/usr/src/usr.bin/rsync/charclass.h
ad$ cp /usr/src/lib/libc/gen/charclass.h .

次は、どの辺でエラーを出しているか確認。

ad$ fgrep 'is read only' *.c
c_sh.c:                 bi_errorf("%s is read only", *wp);
c_sh.c:                         bi_errorf("%s is read only", vp->name);
var.c:          warningf(true, "%s: is read only", vq->name);
var.c:          errorf("%s: is read only", tvar);
var.c:          errorf("%s: is read only", var);

bi_errorf と errorf 関数のどちらなんだろう? 順番に確認してみる。

ad$ gdb -q ksh
Reading symbols from ksh...
(gdb) b bi_errorf
Breakpoint 1 at 0x2d250: file io.c, line 63.
(gdb) r ck.sh
Starting program: /tmp/ksh/ksh ck.sh
ck.sh[3]: rv: is read only
[Inferior 1 (process 7436) exited with code 01]
(gdb) b errorf
Breakpoint 2 at 0xecc145f7ea0: file io.c, line 28.
(gdb) r ck.sh
Starting program: /tmp/ksh/ksh ck.sh

Breakpoint 2, errorf (
    fmt=0x130e923676170e17 <error: Cannot access memory at address 0x130e923676170e17>) at io.c:28
28      {
(gdb) bt
#0  errorf (
    fmt=0x130e923676170e17 <error: Cannot access memory at address 0x130e923676170e17>) at io.c:28
#1  0x0000049cf7fce036 in typeset (var=0x49faa0125b0 "rv=world", set=0, clr=0,
    field=0, base=0) at var.c:658
#2  0x0000049cf7fa8f49 in comexec (t=0x49faa02be20, tp=0x0, ap=0x49faa02e670,
    flags=0, xerrok=0x7007c59c01f0) at exec.c:524
#3  0x0000049cf7fa735c in execute (t=0x49faa02be20, flags=0,
    xerrok=0x7007c59c01f0) at exec.c:132
#4  0x0000049cf7fbc82f in shell (s=0x49faa024c10, toplevel=1) at main.c:650
#5  0x0000049cf7fbbf08 in main (argc=2, argv=0x7007c59c0598) at main.c:452

frame 1 の typeset関数の引数にオイラーが指定したコード片が出てきてるな。 typesetと言う番人が書き換えの可否を判定してそうだ。

基本に立ち返ってkshのマニュアルを調べた方がよさそう。

slaacctl

slaacdってダエモン君が居る。Stateless Address Autoconfiguration (SLAAC) って IPv6で用意されたdhcpにちょっと足りない機能だ。そいつをダエモン君にすると、 最後にdを付けるのが慣習。ダエモン君はコンソールとのやりとり手段を放棄してる。 そこで、通信用のソケットを用意し、それを通じて交信する様になってる。その 専用アプリだよってのが一目で分るように、最後にctlを付けるも慣習になってる。

で、そのアプリで何が出来るかmanして実験。

ad$ slaacctl show interface
em0:
         index:   1 running: yes temporary: yes
        lladdr: 52:54:00:12:34:56
         inet6: fe80::5054:ff:fe12:3456%em0
        Router Advertisement from fe80::2%em0
                received: 2025-09-23 06:52:59; 113s ago
                Cur Hop Limit:  64, M: 0, O: 0, Router Lifetime:  1800s
                Default Router Preference: Medium
                Reachable Time:         0ms, Retrans Timer:         0ms
                prefix: fec0::/64
                        On-link: 1, Autonomous address-configuration: 1
                        vltime:      86400, pltime:      14400
        Address proposals
                id:    3, state: PROPOSAL_CONFIGURED, temporary: y
                vltime:      86400, pltime:      14400, timeout:      14275s
                updated: 2025-09-23 06:52:59; 113s ago
                fec0::ab51:2d08:b44:7e35, fec0::/64
                id:    2, state: PROPOSAL_CONFIGURED, temporary: n
                vltime:      86400, pltime:      14400, timeout:      14275s
                updated: 2025-09-23 06:52:59; 113s ago
                fec0::e855:a9df:d987:4714, fec0::/64
        Default router proposals
                id:    1, state: PROPOSAL_CONFIGURED
                router: fe80::2%em0
                router lifetime:       1800
                Preference: Medium
                updated: 2025-09-23 06:52:59; 113s ago, timeout:       1675s

この他にも

send solicitation interface
        Send a router solicitation on interface interface.

こんな機能が提供されてる。ルーター広告してねってやつ。ifconfig down/up em0 とかやって、広告要請を前回やったけど、こちらの方が断然スマートだな。

httpd

IPv6のhttpdを起動させてみたいぞ。どうやるんだっけ? 昔やったんで、残骸を 確認してみる。

ob$ cat /etc/httpd.conf
server "example.com" {
    listen on * port 80
}

example.comってのは、単なる目印か。DNSサーバーを立てると連携してくれたり、 しないかな。まあ、オイラーのライトなテストでは関係無いと思われる。

ob$ ls htdocs/sakura/
hes2009/     hes2013/     hes2017/     hes2021/     index.html
hes2010/     hes2014/     hes2018/     hes2022/     
hes2011/     hes2015/     hes2019/     hes2023/     
hes2012/     hes2016/     hes2020/     hes2024/

コンテンツは、こんな風に用意するんだった。

ob$ doas /usr/sbin/httpd
ob$ w3m http://ob/sakura

起動と確認。

そんじゃ、仮想マシンで実験。index.htmlの記述方法を失念してたので、 デフォのhtdocs/bgplg/index.htmlをhtdocs/ipv6へcpして、apache風なコンテンツにしてみた。

ad$ w3m http://10.0.2.15/ipv6
It's worked on OpenBSD httpd
ad$ w3m http://fec0::a3da:7b7d:9be4:6c70/ipv6
w3m: Can't load http://fec0::a3da:7b7d:9be4:6c70/ipv6.

IPv4は良いけどIPv6(temporary)では拒否されるなあ。emacs/ewwでもIPv6では アクセス出来なかった。こういう場合は、ping6しょ。

ad$ ping6 -c 2 fec0::a3da:7b7d:9be4:6c70
PING fec0::a3da:7b7d:9be4:6c70 (fec0::a3da:7b7d:9be4:6c70): 56 data bytes
64 bytes from fec0::a3da:7b7d:9be4:6c70: icmp_seq=0 hlim=64 time=0.111 ms
64 bytes from fec0::a3da:7b7d:9be4:6c70: icmp_seq=1 hlim=64 time=0.229 ms

導通確認問題無し。

ひょっとしてブラウザーがDNSを引いていないか?

ad$ doas tcpdump -i em0 port 53
doas (sakae@ad.my.domain) password:
tcpdump: listening on em0, link-type EN10MB
05:59:12.853537 10.0.2.15.4407 > 10.0.2.3.domain: 12176+ A? fec0.my.domain.(32)
05:59:12.880392 10.0.2.15.39877 > 10.0.2.3.domain: 32394+ AAAA? fec0.my.domain.(32)

IPv4を指定した時は、resolvしないけど、IPv6の時はしっかりとお世話になってるなあ。 これは、おかしな挙動だ。生IPを指定してるんだから、DNSを引く必要なんて、さらさら 無いはず。これがブラウザーの仕様ってか?

しょうがないので、自家製のDNSを用意する。

ad$ cat /etc/hosts
127.0.0.1       localhost
::1             localhost
fec0::a3da:7b7d:9be4:6c70 ad
ad$ w3m http://ad/ipv6
It's worked on OpenBSD httpd

やっと成功した。勿論、resolv.confのlookupにはfile(= /etc/hostsの事)を 加えておく事。

ad$ cat /etc/resolv.conf
nameserver 10.0.2.3 # resolvd: em0
lookup bind file
family net6 inet4

ついでなんでhttpdのアクセスログも確認しておく。

ad$ lv access.log
example.com 10.0.2.15 - - [25/Sep/2025:05:46:38 +0900] "GET /ipv6/ HTTP/1.0" 200 142
example.com fec0::a3da:7b7d:9be4:6c70 - - [25/Sep/2025:05:56:15 +0900] "GET /ipv6 HTTP/1.1" 400 0
example.com fec0::a3da:7b7d:9be4:6c70 - - [25/Sep/2025:06:29:57 +0900] "GET /ipv6 HTTP/1.0" 301 0
example.com fec0::a3da:7b7d:9be4:6c70 - - [25/Sep/2025:06:29:57 +0900] "GET /ipv6/ HTTP/1.0" 200 142

httpdのステータス、400とか301って何だっけ? 401はewwでアクセスした時の痕跡です。

HTTPの301は「Moved Permanently」(恒久的な移動)を意味し、URLが永続的に変更されたことを示すステータスコードです。一方、400は「Bad Request」で、クライアントからのリクエストに何らかの不備があるため、サーバーが処理できなかったことを示します。これらは根本的に異なる状況を示すステータスコードです。

ああ、今思いついたんだけど、/etc/hostsってハッシュ表だね。ドメイン名から、意味不明 なIPAddressを一意に拾い出してくれるから。そりゃ違うんじゃねぇ。上の例だと 同名なlocalhostが2個登録されてたぞ。いや、それでいいんです。表を引く時、 IPv4(6)を区別してますから。要するにv4用とv6用が合体してんだな。

【インターリンク ドメイン島巡り 第53回「.ax」】 及び関連記事。

こんなドメイン巡りってか、特化型の地球の歩き方ってシリーズが面白い。これも ドメインの最後にソルトとして、.ax やら .to などを付与してハッシュの衝突を 回避してんだなあ。

acces by IPv6

Q: ブラウザーの仕様について尋ねます。

ad$ w3m http://10.0.2.15/ipv6
It's worked on OpenBSD httpd IPv6
ad$ w3m http://fec0::e855:a9df:d987:4714/ipv6
w3m: Can't load http://fec0::e855:a9df:d987:4714/ipv6.

の様に、IPv4の生アドレスの場合はアクセスが可能。しかし、IPv6の場合は アクセスが出来ませんでした。 使うブラウザーをenmacs/ewwに変更すると、IPv6の生アドレスの場合、httpd statusは400を返してきて、アクセスできませんでした。

上記の生IPv6アドレスを/etc/hostsに登録し、resolvさせると、アクセスが できました。

この結果からブラウザはIPv4の生アドレスのみ正常に扱ってくれると判定 しました。 こういう事実は、仕様になっているのでしょうか?

A: 良い観察ですね。ご質問の件、整理するとこういうことになります:


### 1. IPv4リテラルとIPv6リテラルのURL表記の違い

  • IPv4: http://10.0.2.15/ipv6 のように、そのまま数字で書けます。
  • IPv6: RFC 3986 (URI の仕様) に従うと、IPv6リテラルは角括弧 [] で囲う必要があります。 例:
http://[fec0::e855:a9df:d987:4714]/ipv6

この括弧がないと、ブラウザは「:」をポート番号の区切りと誤解するため、URL として不正扱いになります。


### 2. w3m や eww の挙動

  • w3m http://fec0::e855:a9df:d987:4714/ipv6 → 括弧なしなので /パースエラー/。
  • eww の場合 → URL としては通るけど、サーバー側に送る Host: ヘッダが不正(角括弧なし)になり、=httpd= 側で /400 Bad Request/。
  • /etc/hosts に名前を登録して名前解決させた場合 → Host: に正しいホスト名が入り、問題なくアクセスできる。

### 3. 仕様かどうか?

はい、これは /仕様です/。

  • RFC 3986 に明確に「IPv6 アドレスは http://[IPv6]/... のように \[] で囲む」と書かれています。
  • 実際のブラウザ (Firefox, Chrome, curl, wget など) もすべてこのルールを実装しています。
  • IPv4 は括弧不要ですが、IPv6 は必須です。

結論 ブラウザやHTTPクライアントが「IPv6生アドレスをそのまま扱えない」のはバグではなく、/標準仕様 (RFC 3986) に従った正しい挙動/です。 アクセスしたい場合は必ず

http://[fec0::e855:a9df:d987:4714]/ipv6

のように [] を付けてください。


また一つ、利口になったな。こういうの、実際に体験しないと分らないぞ。

README

炎はつなぐ なんて本を読んだ。

今や風前の灯である和ロウソクを巡る職人さん達を余す所なく捉えている力作。 風前の灯なんて言うと失礼だぞ。それを必要とする人が居るからこそ成り立って いる。でも、現実は、きびしい。

たとえば、ロウソクの芯は和紙を丸め、そこにイグサ似の草を巻き付け 、それが緩まないように、真綿で固定するそうだ。その草を生産する農家が もうからない、高齢化とかで、文字通り、風前の灯。 真綿って、蚕の繭をほぐして作るそう。昔の日本は絹の輸出で外貨をかせいでいた。 それが、化学繊維に押されて激減してる。

取材の過程で、こういう現実が見えてくる。でも、めげずにこういうサプライ・チェーン を丁寧に追って行く。職種については32種。和紙って、どうやって作られるの? 製造元へ取材。金沢で金箔が作られているけど、その製造になくてはならない和紙が ある。早速、金箔製造所に取材。そこから、金箔は仏像に貼付するよ。今度は、その 現場を訪問。漆が使われている事を知る。漆って、どう作られるの? 漆の製造 者を直撃。特殊な鑿が使われている。今度は、鍛冶屋さんを訪問。 よくもまあ、こんな深堀をするものだ。

この方の気質とオイラーは似ているな。今やってるIP番号検索なんかもそうだ。 興味の趣くまま、アチコトに顔を出す。知ったつもりより、現地訪問だな。 これで、よく繋がりが見えてくると思うんだ。


This year's Index

Home