はじめに
CentOS7 を IPv4(PPPoE) のブロードバンドルーターとして稼働させていますが、今回は IPv6(IPoE) も使えるようにしたいと思います。タイトルは CentOS7 ですが、修正を重ねて CentOS8.2 向けの記事になってきてる気がします
firewalld のバージョンによって挙動がコロコロ変わるので、バージョン次第ではこの記事通りの設定ではうまくいかないかもしれません
Linux の知識もネットワークの知識もセキュリティの知識もない素人なのでつっこみどころがあるのはご容赦ください。この記事を書く3日前に NDP とか IPv6 リンクローカルアドレスとかを初めて聞いたくらいのレベルです
IPv4はそのままPPPoEで、IPv6のみIPoEを使うようにします。市販の家庭用のブロードバンドルーターだとPPPoEとIPoEの共存は2台のルーターが必要になることもあるようですが、今回は1台で両方使えるようにします
流行?のIPv4 over IPv6はこの記事では扱いません。
次の記事でやってます → CentOS7でOCNバーチャルコネクト
環境
- 回線:フレッツ光ネクスト
- プロバイダ:OCN
- ひかり電話なし、HGWなし
- 最終確認:CentOS 8.2(firewalld のバックエンドは iptables)
大体こんな環境です。タイトルは CentOS7 ですが、最後に確認したのは 8.2 です。ご了承ください
ひかり電話契約がない場合は、独立したLAN用プレフィックスが委譲されないため、同一 /64 をNDP Proxyで使用する構成とします
雑な図ですが、上図から下図に変更します。IPv4(PPPoE) 環境は全く変更せず、IPv6(IPoE) を追加します。IPv6 対応サイトにアクセスするときに IPv6(IPoE) でアクセスするようにします。また、自分で建てているサーバーに IPv6(IPoE) でアクセスできるようにします
市販の家庭用 IPv6 のルーターは、IPv6 ブリッジ(パススルー)のものと ND プロキシのものがあるようですが、今回は ND プロキシを使用します。IPv6 環境下でも IPv4 のように WAN 側と LAN 側でわけ、セキュリティを確保します
基本的には IPv6 対応サイトへのアクセスと IPv6 からのアクセスが PPPoE から IPoE に変わるだけで、それ以外については変わらないようにします
手順
以下、WAN 側のインターフェイスを enp2s0 、LAN 側のインターフェイスを br0 としてすすめていきます
また、すでにプロバイダ等との契約が済んでいて、WAN 側 (enp2s0) に IPv6 のグローバル IP が降ってきているものとします
sysctlの設定
まずは IPv6 パケット転送を有効にしてルーターとして動作できるようにします
|
1 |
# vi /etc/sysctl.conf |
|
1 |
net.ipv6.conf.all.forwarding=1 |
|
1 |
# sysctl -p |
1行追加し、反映させます
radvdの設定
|
1 |
# dnf install radvd |
LAN 内の PC が IPv6 アドレスを自動で設定できるようにするために radvd をインストールします
|
1 |
# ip a |
WAN 側 NIC の IPv6 のグローバルアドレスを確認します
|
1 2 3 4 5 6 |
2: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1454 qdisc mq state UP group default qlen 1000 link/ether --:--:--:--:--:-- brd ff:ff:ff:ff:ff:ff inet6 2400:xxxx:xxxx:xxxx:82ee:73ff:feab:4f68/64 scope global noprefixroute dynamic valid_lft 2591901sec preferred_lft 604701sec inet6 fe80::...../64 scope link noprefixroute valid_lft forever preferred_lft forever |
inet6 の fe80 から始まらない方がグローバルアドレスです
|
1 |
# vi /etc/radvd.conf |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
interface br0 { AdvSendAdvert on; AdvLinkMTU 1500; MaxRtrAdvInterval 1800; MinRtrAdvInterval 600; AdvDefaultLifetime 7200; prefix 2400:xxxx:xxxx:xxxx::/64 { AdvOnLink on; AdvAutonomous on; AdvValidLifetime 604800; AdvPreferredLifetime 259200; }; }; |
interface には LAN 側のインターフェイスを指定します。prefix にはさきほど調べたグローバルアドレスのプレフィックスを入れます。(16桁目まで)
AdvLinkMTU を設定すると LAN 内の NIC の IPv6 の MTU が自動で設定されます。統一したい場合は WAN 側の MTU と同じ値をいれてしまいましょう
radvd.conf のマニュアル – https://linux.die.net/man/5/radvd.conf
|
1 |
# systemctl start radvd |
これで LAN 内のPCに IPv6 アドレスが自動で設定されるようになります。30秒ほど待って設定されているか確認します
|
1 |
# ip a |
|
1 2 3 4 5 6 |
5: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether --:--:--:--:--:-- brd ff:ff:ff:ff:ff:ff inet 192.168.1.1/24 brd 192.168.1.255 scope global noprefixroute br0 valid_lft forever preferred_lft forever inet6 2400:xxxx:xxxx:xxxx:78e8:420d:fa0:7fa8/64 scope global noprefixroute dynamic valid_lft 86202sec preferred_lft 14202sec |
LAN 側のインターフェイスにも 2400:xxxx:xxxx:xxxx からはじまるグローバル IP が設定されたら成功です。xxxx 以降の部分はMACアドレスなどから自動で決まるようです
これでLANの端末にはすべて 2400:xxxx:xxxx:xxxx から始まるグローバル IP アドレスが自動で振られるようになります
ルーティングの確認
ルーティングに問題があると通信ができないので確認します
|
1 |
# ip -6 r |
|
1 2 |
2400:xxxx:xxxx:xxxx::/64 dev enp2s0 proto ra metric 100 pref medium 2400:xxxx:xxxx:xxxx::/64 dev br0 proto ra metric 425 pref medium |
私の例。 2400:xxxx:xxxx:xxxx~のIPアドレスはグローバルアドレスですが、ルーターから見た場合は LAN のPCのアドレスということになります。つまり 2400:xxxx:xxxx:xxxx~ とは LAN 側のインターフェイス (br0) で通信しないといけません。
ということはメトリック値は LAN 側のインターフェイスの方が低くなければいけません。この私の例の場合、 WAN 側 (enp2s0) が LAN 側 (br0) より優先されてしまうので、LAN 側への通信も WAN 側 (enp2s0) で行おうとしてしまい、通信に失敗してしまいます
|
1 2 3 |
# nmcli connection modify enp2s0 ipv6.route-metric 500 # nmcli connection down enp2s0 # nmcli connection up enp2s0 |
もし WAN 側のメトリック値が LAN 側のメトリック値より低かった場合は、LAN 側よりも高くします
|
1 |
# ip -6 r |
|
1 2 |
2400:xxxx:xxxx:xxxx::/64 dev br0 proto ra metric 425 pref medium 2400:xxxx:xxxx:xxxx::/64 dev enp2s0 proto ra metric 500 pref medium |
確認。これで LAN 側の端末へパケットが流れるようになります
|
1 2 3 4 5 6 7 8 9 10 11 12 |
C:\WINDOWS\system32>ping -6 2400:xxxx:xxxx:xxxx:78e8:420d:fa0:7fa8 2400:xxxx:xxxx:xxxx:78e8:420d:fa0:7fa8 に ping を送信しています 32 バイトのデータ: 2400:xxxx:xxxx:xxxx:78e8:420d:fa0:7fa8 からの応答: 時間 <1ms 2400:xxxx:xxxx:xxxx:78e8:420d:fa0:7fa8 からの応答: 時間 <1ms 2400:xxxx:xxxx:xxxx:78e8:420d:fa0:7fa8 からの応答: 時間 <1ms 2400:xxxx:xxxx:xxxx:78e8:420d:fa0:7fa8 からの応答: 時間 <1ms 2400:xxxx:xxxx:xxxx:78e8:420d:fa0:7fa8 の ping 統計: パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、 ラウンド トリップの概算時間 (ミリ秒): 最小 = 0ms、最大 = 0ms、平均 = 0ms |
LAN にある他の端末から Ping が通るか確認します。Windows から Ping を試した例です。ルーティングが正しければ、あとは Ping 拒否の設定をしていなければ通るはずです
LAN の PC とルーターが通信できないと、LAN の PC がインターネットにつながりません
ndppdの設定
NDプロキシの設定を自動でやってくれるndppdのインストールをします
インストール
パッケージをインストール
いつの間にか EPEL リポジトリに追加されていました。EPEL リポジトリを有効にしてインストールします
|
1 |
# dnf install ndppd |
以下のソースからインストールの部分は不要になりましたが、一応残しておきます
ソースからインストールする場合
|
1 2 3 4 |
# git clone https://github.com/DanielAdolfsson/ndppd # cd ndppd # make # make install |
ndppdを入手し、make&インストールします
|
1 2 |
# cp ndppd.service /etc/systemd/system/ # vim /etc/systemd/system/ndppd.service |
デーモン用ファイルをコピーして編集します
|
1 2 3 4 |
[Service] ExecStart=/usr/local/sbin/ndppd -d -p /var/run/ndppd.pid Type=forking PIDFile=/var/run/ndppd.pid |
ndppd のパスを合わせます。PID ファイルの場所も適宜変更します
|
1 |
# systemctl daemon-reload |
リロードします
設定
|
1 |
# vim /etc/ndppd.conf |
|
18 19 20 21 22 23 24 25 26 27 28 29 |
route-ttl 30000 address-ttl 30000 proxy enp2s0 { router no autowire yes promiscuous no rule 2400:xxxx:xxxx:xxxx::/64 { iface br0 autovia yes } } |
proxyにはWAN側デバイスを、ruleには radvd.conf でも使ったプレフィックスを使います。ifaceはなんとなくautoからLAN側のインターフェイスの明記に変えました
ndppd/ndppd.conf-dist at master · DanielAdolfsson/ndppd · GitHub
設定ファイルの説明はこちらを参照してください
|
1 |
# systemctl start ndppd |
起動します
firewalldの設定
WAN 側の IF を external ゾーン(マスカレードを有効にしているゾーン)につっこみます。firewalld の設定でつっこむか、networek manager の方で設定するかどちらかで
|
1 2 |
# firewall-cmd --permanent --zone=external --change-interface=enp2s0 # firewall-cmd --reload |
firewalldの場合
CentOS 8.1(firewalld-0.7.1) 以前の場合、ゾーンのマスカレードの設定を有効にすると、IPv4 だけでなく IPv6 のフォワードと NAT の設定もする(してしまう)ので、特に設定しなくても通信できてしまいます
CentOS 8.2(firewalld-0.7.2) 以降の場合は本来不要な IPv6 の NAT をしなくなりました。フォワードの設定は自分で書く必要がある場合があります。
firewalldのバージョン、設定次第(バックエンドを iptables にしている場合等)では以下が必要な場合があります。IPv6での接続確認ができない場合は以下を実行してみてください。
|
1 2 |
# firewall-cmd --permanent --direct --add-rule ipv6 filter FORWARD 0 -i br0 -o enp2s0 -j ACCEPT # firewall-cmd --reload |
-i の方は LAN 側、-o の方は WAN 側デバイスを指定します
DNSの設定
使っている DNS サーバーがAレコード(IPv4 アドレス)と AAAA レコード(IPv6 アドレス)の両方を返すものであれば変更する必要はありません。A レコードしか返さないものであれば変更する必要があります
例えば Google Public DNS (8.8.8.8) を使っている場合であれば変更する必要はありません
|
1 |
# dig AAAA google.com |
|
1 2 |
;; ANSWER SECTION: google.com. 299 IN AAAA 2404:6800:4004:81a::200e |
dig コマンドで AAAA レコードを調べることができます。このように AAAA レコードが返ってこなければ DNS サーバーの設定を変更する必要があります
DNS サーバーを立てている場合は DNS サーバーの設定を、立てていない場合は /etc/resolv.conf 等 PC の DNS の設定を変える必要があります
DNS サーバーへのアクセスもI Pv6(IPoE) にしたい場合は使用する DNS サーバーをIPv6 のアドレスに変更しましょう
例えば Google Public DNS であれば
2001:4860:4860::8888 / 2001:4860:4860::8844
です。これらもAレコードと AAAA レコードの両方が返ってくるので、IPv4 にも IPv6 にも使えます
接続確認
IPv6 動作確認サイトにアクセスします

|
1 2 |
# systemctl enable radvd # systemctl enable ndppd |
問題なさそうであれば、radvd と ndppd を自動起動するようにします
ファイアウォールの設定
IPv6 で LAN 内のサーバーを外部に公開したい場合、したくない場合の手順を確認します。IPv4 のときと同じような感覚で運用できるような気がします
| 端末 | IF | zone | IPv4アドレス | IPv6アドレス |
| ルーター | enp2s0 | external | 2400:xxxx:xxxx:xxxx:82ee:73ff:feab:4f68 | |
| br0 | internal | 192.168.1.1 | 2400:xxxx:xxxx:xxxx:78e8:420d:fa0:7fa8 | |
| サーバー | eno1 | internal | 192.168.1.10 | 2400:xxxx:xxxx:xxxx:ec4:7aff:fee0:440b |
たとえば LAN にサーバーがあったとします。サーバーで Web サーバー(ポート番8080)をたて、外部に公開する例を考えてみます。サーバーの 8080 番ポートはすでにあいてるものとします
ポートフォワード
IPv4 の場合であれば、ポートフォワードの設定をして外部に公開しますが、IPv6 でも同じような手順で公開できます
|
1 2 3 |
# firewall-cmd --zone=external --add-forward-port=port=8080:proto=tcp:toaddr=192.168.1.10 --permanent # firewall-cmd --zone=external --add-forward-port=port=8080:proto=tcp:toaddr=2400:xxxx:xxxx:xxxx:ec4:7aff:fee0:440b --permanent # firewall-cmd --reload |
上が IPv4 のポート転送の設定、下が IPv6 のポート転送の設定です。IPv4 を IPv6 のアドレスに変えるだけで手順は同じです。これで
http://IPv4 のグローバルアドレス:8080
http://[2400:xxxx:xxxx:xxxx:82ee:73ff:feab:4f68]:8080
でアクセスできます
この場合ではサーバー側のグローバル IP を使って
http://[2400:xxxx:xxxx:xxxx:ec4:7aff:fee0:440b]:8080
とアクセスしようとしてもアクセスできません。IPv4のときのようなNATの内側と同じ感覚での運用になると思います
firewalld の説明だとゾーンでのポート転送は IPv4 限定と表記されているのですが使えてしまいます(バージョン次第?)
また、ND プロキシがなくてもアクセスできてしまうので、ndppd を起動してなくてもアクセスできてしまいます
通過許可
サーバーのグローバル IP を使って、ポートフォワードを使わすにサーバーにアクセスできるようにすることも可能です
|
1 |
# firewall-cmd --direct --add-rule ipv6 filter FORWARD 0 -i enp2s0 -o br0 -p tcp -d 2400:xxxx:xxxx:xxxx:ec4:7aff:fee0:440b --dport 8080 -j ACCEPT |
LAN側のサーバーの8080ポートへのアクセスを通過許可する設定例です
これで、サーバーのグローバル IP を使って
http://[2400:xxxx:xxxx:xxxx:ec4:7aff:fee0:440b]:8080
でアクセスできるようになります。ndppd を切るとアクセスできなくなります
ドメインを持っている場合は、IPv6 のグローバルアドレスを追加すれば IPv4 と IPv6 の両方に対応したWebサーバーになります
もちろんIPv4 (または IPv6 )でのみ外部公開する、ということもできます
設定したらテストサイトを使って確認します
IPv6 ポートテストサイト
http://www.ipv6scanner.com/cgi-bin/main.py
https://ipv6.chappell-family.com/ipv6tcptest/
おまけ
ndppd の SELinux の設定。ドメインを独自に作成します。
|
1 |
# vim ndppd.te |
ChatGPT に頼っていますが、できるだけ最小構成になるように試行錯誤はしてます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
policy_module(ndppd, 1.0) ######################################## # # Types # type ndppd_t; type ndppd_exec_t; init_daemon_domain(ndppd_t, ndppd_exec_t) role system_r types ndppd_t; # # Configuration # type ndppd_conf_t; files_config_file(ndppd_conf_t) # # PID/runtime files under /run # type ndppd_var_run_t; files_pid_file(ndppd_var_run_t) ######################################## # # Required base policy types # gen_require(` type proc_net_t; ') ######################################## # # Configuration # allow ndppd_t ndppd_conf_t:file { open read }; ######################################## # # Runtime / PID # manage_files_pattern( ndppd_t, ndppd_var_run_t, ndppd_var_run_t ) ######################################## # # Logging # logging_send_syslog_msg(ndppd_t) ######################################## # # Network capabilities # allow ndppd_t self:capability { net_admin net_raw }; ######################################## # # ICMPv6 / NDP raw socket # allow ndppd_t self:rawip_socket { create ioctl setopt read write }; ######################################## # # Packet socket # allow ndppd_t self:packet_socket { create ioctl bind setopt read }; ######################################## # # Network state # allow ndppd_t proc_net_t:file { open read }; # # SO_ATTACH_FILTER succeeds without CAP_SYS_ADMIN. # Suppress the harmless capability denial. # dontaudit ndppd_t self:capability sys_admin; |
sys_admin に関しては警告が出たのですが動作には問題ないため、隠すことにしました。
|
1 2 3 4 5 6 7 8 |
# make -f /usr/share/selinux/devel/Makefile ndppd.pp # semodule -i ndppd.pp # semanage fcontext -a -t ndppd_exec_t '/usr/sbin/ndppd' # semanage fcontext -a -t ndppd_conf_t '/etc/ndppd\.conf' # semanage fcontext -a -t ndppd_var_run_t '/var/run/ndppd(/.*)?' # restorecon -v /usr/sbin/ndppd /etc/ndppd.conf # restorecon -RFv /var/run/ndppd |
ver 0.25 にて動作確認。1.0 では確認していません。
参考サイト
https://yudai.arielworks.com/memo/2012/05/08/000441




コメント