0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

sysctl とカーネル起動オプションによる IPv6 無効化方法の違い

Last updated at Posted at 2021-09-25

はじめに

Linux 上で IPv6 を無効化する方法として、よく以下の2つが紹介されています。

  1. sysctl による net.ipv6.conf.*.disable_ipv6 = 1の設定
  2. カーネル起動オプションに ipv6.disable=1 を設定

昔は 1. の紹介をよく見ていたので私もこちらをよく設定していたのですが、最近になって 1. と 2. の挙動の違いについて知ることになったので共有したいと思います。

ちなみに、

  • Network Managerで ipv6.method は ignore に設定されている前提です。
  • Network Managerで ipv4.dns は 192.168.1.1 に設定されており、ローカルで dnsmasq などは動かしていないです。
  • 今回の挙動は環境依存の部分が大きいかもしれないので、どの環境でも再現するとは限らないです。

sysctl による設定時の挙動

まずは、以下のように sysctl を設定します。sysctl -p でロードすればカーネル再起動は不要ですが、一応再起動はしておきます。

/etc/sysctl.d/99-ipv6disable.conf
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1

再起動後、ip addr の結果から inet6 の記述が消えていることを確認します。

[root@centos01 ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:a3:7d:51 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.201/24 brd 192.168.1.255 scope global noprefixroute enp0s3
       valid_lft forever preferred_lft forever

この状態で、curl によるファイルダウンロードを行います。その際にシステムコールをトレースするために strace コマンドを挟みます。

[root@centos01 ~]# strace -o strace.dat curl http://ftp.jaist.ac.jp > /dev/null
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  4514  100  4514    0     0  16521      0 --:--:-- --:--:-- --:--:-- 16534
[root@centos01 ~]#

strace によるシステムコールトレースの結果を以下に抜粋します。socket の第1引数が AF_INET6 になっており、UDP ソケットのドメインに IPv6 インターネット・プロトコルが指定されていることが分かります。ソケットのディスクリプターも正常に返ってきているようです。

strace.dat(抜粋)
open("/root/.curlrc", O_RDONLY)         = -1 ENOENT (そのようなファイルやディレクトリはありません)
ioctl(1, TCGETS, 0x7ffcef491ea0)        = -1 ENOTTY (デバイスに対する不適切なioctlです)
brk(NULL)                               = 0x167a000
brk(0x169c000)                          = 0x169c000
socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = 3
close(3)                                = 0
mmap(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7fa54cc200
00
mprotect(0x7fa54cc20000, 4096, PROT_NONE) = 0

とはいえ、tcpdump で UDP の通信を確認すると別に IPv6 で通信しているわけではなさそうです。というか、AAAA レコード(IPv6 アドレス)を問い合わせているんですね。

12:25:30.426393 IP 192.168.1.201.41974 > 192.168.1.1.domain: 55084+ A? ftp.jaist.ac.jp. (33)
12:25:30.426404 IP 192.168.1.201.41974 > 192.168.1.1.domain: 55609+ AAAA? ftp.jaist.ac.jp. (33)
12:25:30.427310 IP 192.168.1.1.domain > 192.168.1.201.41974: 55084 1/0/0 A 150.65.7.130 (49)
12:25:30.427366 IP 192.168.1.1.domain > 192.168.1.201.41974: 55609 1/0/0 AAAA 2001:df0:2ed:feed::feed (61)

カーネル起動オプションによる設定時の挙動

次にカーネル起動オプションで IPv6 無効化を設定します。今回は sysctl による設定を外さずに設定します。

まず、GRUB の設定ファイルを修正します。GRUB_CMDLINE_LINUXipv6.disable=1というオプションを追加します。

GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="ipv6.disable=1 crashkernel=auto rhgb quiet"
GRUB_DISABLE_RECOVERY="true"

その後、grub.cfg を再生成し、カーネルを再起動します。

[root@centos01 ~]# grub2-mkconfig -o /boot/grub2/grub.cfg

この状態で、sysctl の時と同様に curl コマンドを実行し、そのシステムコールを strace で追います。すると、socket システムコールの呼び出しは EAFNOSUPPORT でエラーになりました。

brk(NULL)                               = 0xba9000
brk(0xbcb000)                           = 0xbcb000
socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP) = -1 EAFNOSUPPORT (アドレスファミリはプロトコルによってサポ
ートされていません)
mmap(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7ff4e189d0
00
mprotect(0x7ff4e189d000, 4096, PROT_NONE) = 0

ちなみに、その時の tcpdump による通信は以下になります。sysctl 設定時と異なり、AAAA レコードは問い合わせていないですね。

12:57:14.070559 IP 192.168.1.201.43179 > 192.168.1.1.domain: 30876+ A? ftp.jaist.ac.jp. (33)
12:57:14.071303 IP 192.168.1.1.domain > 192.168.1.201.43179: 30876 1/0/0 A 150.65.7.130 (49)

おわりに

今回、この違いに気付いたのは、sysctl の設定のみの際に名前解決が5秒程度待たされるという事象(poll システムコールで待たされる)を調査したのがきっかけでした。この問題は環境によって発生有無が異なっていてまだ原因がよく分かっていないのですが、カーネル起動オプションを設定すると回避できることは分かっています。

調査してみたのはよいものの、

  • sysctl の設定時にも問題なく名前解決できるのはなぜか?
    • AF_INET6 指定で作成したソケットディスクリプターに対して IPv4 アドレス構造体を渡してデータ送信しても OK なのか?
  • カーネル起動オプションの設定時はエラーが発生しているのに名前解決できているのはなぜか?
    • strace の結果からは、エラーになっている箇所以外で SOCK_DGRAM パラメータを渡してソケット作成しているところが見当たらない。

など、結局分からないことは多くあり、また wget だと挙動が違ったりもします。

ひとまず、カーネル起動オプションによる設定(実際には両方)を採用したいと思いますが、IPv6 含めてネットワークの知識が足りてないなぁ。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?