IPv6は直接グローバルIPが当たってるから怖いのでIPv6もNATする話

# 前書き
Qiitaをご覧の皆様にとってはごく当然のことでしょうが、IPv6通信はその膨大なアドレス数を活かし、各端末1台1台に直接グローバルIP（グローバルユニキャストアドレス、GUA）を与えます。**（※普通の環境なら）**
つまり、上流のルーターで適切なファイアウォールを設定しパケットをフィルタリングしない限り、各端末はインターネット側からReachableな状態です。
大抵のルーターではインターネット側からLAN側宛のPort 22,25,80,110,135,137:139,443,445,465,587,993,995,3389,5060,5900あたりの通信は塞ぐ設定になっているのではないかと思います。
~~某社のHGWは偶に素通しになってることがある気がしますが~~
しかしこのまま通信すると、通信先には自分の端末の生IPアドレスが記録されることになります。
常識的な設定のネットワークであれば、通常は/64で振り出されたRAを元に、MACアドレスを加えた半固定的なIPと、一時的な乱数生成的な実際の通信用のIPが各端末に設定され（しかも一定時間後に変わる）、後者の方で通信をするので、そんなに（通信相手にMACアドレスを類推され該当MACアドレスを有する機器の脆弱性を突くような攻撃を受けることに）神経質になる必要はないでしょう。
しかし、世の中には私の様な「各端末にGUAを割り当てるとか論外論外！！！！LAN内の端末は全てプライベートIPを使うべし！！！！！！」という**プライベートIP勢過激派が一定数存在します（存在しますよね？？？？）。**
今回はそんな~~ニッチな~~需要向けに、「各端末にグローバルIPを振らないけど、インターネットとも通信出来る環境」を作ってみた話です。

# 前提条件
拙宅は仮想化基盤サーバーに収容した仮想マシンをルーターにしています。

https://qiita.com/daisuke_yanase/items/32b3e86905896b9d1147

インターネット回線は近頃流行りのマンションに備え付けの無料インターネット回線（1Gbps）です。
IPから類推するにJPNE/JPIX系のIPoE接続な環境で、実効スループットは100〜200Mbpsぐらいでしょうか。
各居室にはIPv4プライベートIPが一つとインターネットからUnReachableなIPv6 GUAが/64で降ってきます。
勿論、ルーターとなっている仮想マシンには適切なファイアウォールを設定していて、仮令同じマンションの部屋からの通信であっても応答しません（の、筈）。
従来はこの/64のアドレスブロックから更に適当なPrefixを付けて/112のアドレスブロックを切り出して、NDP Proxyで上流にルートを広告していました。
今回はNDP Proxyを停止（廃止）して、新たにプライベートIP（IPv6ではユニークローカルアドレス、ULAと言います）オンリーな環境とし、尚且つインターネットとはIPv4と同様に上流ルーターだけが持つIPv6 GUAを使って通信出来る状態を作ります。
**要するにIPv6でNAT（IPマスカレード）をします。**

::: note info
ちなみに某社UTMもUTMだけがGUAを持ち、配下にはULAを配布して通信させる様なので、特別トリッキーというわけではない、筈です。
:::

# 実践
先ずはLAN内に広告するULAのアドレスブロックを決めましょう。
ULAのアドレスブロックはfd00::/8ですが、この内上位40bitをPrefix、更にその後ろ16bitをSubnetとして持ちます。

https://yoshi0808.github.io/new-technology/2020/04/18/ipv6/

に寄れば、

:::note warn
厳密にはULA≠プライベートIPアドレスなので、外部のサイトとは重複しないIPアドレスを利用することが求められます。
:::

つまり安易にオレオレPrefixを付けてはいけない、ということです。
自由にして良いのはSubnetの範囲だけ、という風に私は理解しました。

::: note alert
~~つまり今まで上流から勝手にPrefix付けて/112で切り出していたのも厳密にはアカン様な~~
:::

上記条件を満たすためRFC4193が制定されており、上記URLから飛べるULA算出プログラムにルーターのMACアドレスを入力して実行するだけで簡単にULAを求めることが出来ます。
ありがたやありがたや。
というわけで仮想ルーターのMACアドレスを入力して得られたULAを元に、仮想ルーターの設定を変更していきます。
先ず仮想ルーターのNDP Proxyを停止します。
~~~
sudo systemctl stop ndppd
sudo systemctl disable ndppd
~~~

次に /etc/radvd.conf を次のように変更します。
以下、変更箇所または注釈は「 # <- 」の形で図示します。**実際の設定の際には省いてください。**

~~~ /etc/radvd.conf
interface ethX
{
        AdvSendAdvert on;
        MinRtrAdvInterval 30;
        MaxRtrAdvInterval 100;
        AdvDefaultLifetime 120;
        AdvManagedFlag off;
        AdvOtherConfigFlag on;
        prefix fdXX:XXXX:XXXX:XXXX::/64 # <-
        {
                AdvAutonomous on;
                AdvOnLink on;
                AdvRouterAddr on;
        };
        RDNSS fdXX:XXXX:XXXX:XXXX::1 # <-
        {
                AdvRDNSSPreference 8;
                AdvRDNSSOpen off;
                AdvRDNSSLifetime 119;
        };
};
~~~
次に /etc/bind/named.conf.options を次の様に変更します。

~~~ /etc/bind/named.conf.options
options {
        directory "/var/cache/bind";
        recursion yes;
        listen-on port 53 {
                localhost;
                192.168.XXX.0/2X;
        };
        listen-on-v6 port 53 {
                localhost;
                fdXX:XXXX:XXXX:XXXX::1; # <-
        };
        allow-query {
                localhost;
                192.168.XXX.0/2X;
                fdXX:XXXX:XXXX:XXXX::/64; # <-
        };
        forwarders {
                2606:4700:4700::1111;
                2606:4700:4700::1001;
                1.1.1.1;
                1.0.0.1;
        };
        dnssec-validation no;
};
~~~
::: note info
forwarders の部分はお好きなDNSサーバーの値に置き換えてください。
ここではCloudFlareのパブリックDNSを指定していますが、通常はDHCPで上流から広告されるDNSサーバーを指定した方が高速な気がします。
:::
次に /etc/kea/kea-dhcp6.conf を次の様に変更します。

~~~ /etc/kea/kea-dhcp6.conf
{
"Dhcp6": {
        "valid-lifetime": 86400,
        "renew-timer": 3600,
        "rebind-timer": 7200,
        "preferred-lifetime": 54000,
        "decline-probation-period": 3600,
        "interfaces-config": {
                "interfaces": ["ethX”]
        },
        "lease-database": {
                "type": "memfile",
                "persist": true,
                "name": "/var/lib/kea/dhcp6.leases"
        },
        "option-data": [
                {
                "name": "dns-servers",
                "data": "fdXX:XXXX:XXXX:XXXX::1” # <-
                },
                {
                "name": "domain-search",
                "data": “XXXX.XXXX”
                }
        ],
        "subnet6": [
                {
                "subnet": "fdXX:XXXX:XXXX:XXXX::/64", # <-
                "pools": [{
                        "pool": "fdXX:XXXX:XXXX:XXXX::/64" # <-
                }],
                "id": 1,
                "interface": "ethX”
                }
        ]
}
}
~~~

次に、 NetplanのLAN側インターフェイスの値を次の様に変更します。

~~~ /etc/netplan/xxxx.yaml
network:
  ethernets:
    eth0:
      accept-ra: false
      addresses:
      - 192.168.XX.1/24
      - fdXX:XXXX:XXXX:XXXX::1/64 # <-
      dhcp4: false
      dhcp6: false
      optional: true
 version: 2
~~~

次に、 /etc/default/ufw を次の様に変更します。

~~~ /etc/default/ufw.
IPV6=yes
DEFAULT_INPUT_POLICY="DROP"
DEFAULT_OUTPUT_POLICY="ACCEPT"
DEFAULT_FORWARD_POLICY="DROP"
~~~

次に、 /etc/ufw/sysctl.conf に次の行を追加します（既に値が存在する場合は変更してください）。

~~~ /etc/ufw/sysctl.conf
net/ipv6/conf/default/forwarding=1
net/ipv6/conf/all/forwarding=1
net/ipv6/conf/ethX/accept_ra=2 # <- WAN側のインターフェイスを指定してください。
net/ipv6/conf/ethX/accept_ra_pinfo=1 # <- WAN側のインターフェイスを指定してください。
net/ipv6/conf/ethX/autoconf=1 # <- WAN側のインターフェイスを指定してください。
~~~

次に、 /etc/ufw/before6.rules の下の方の「COMMIT」の下に以下の様な行を追加します。

~~~ /etc/ufw/before6.rules
# NAT rules
*nat
:POSTROUTING ACCEPT [0:0]
-F
-A POSTROUTING -s fdXX:XXXX:XXXX:XXXX::/64 -o ethX -j MASQUERADE # <- 「ethX」はWAN側のインターフェイスを指定してください。
COMMIT
~~~
最後に、UFWに内から外（LAN側インターフェイスからWAN側インターフェイス）へのパケット転送を許可するルールを設定します。
~~~
sudo ufw route allow in on ethX out on ethX from ::/0 port 32768:65535 proto udp # <- 「in on ethX」のethXはLAN側、「out on ethX」のethXはWAN側のインターフェイスを設定してください。
sudo ufw route allow in on ethX out on ethX from ::/0 port 32768:65535 proto tcp # <- 「in on ethX」のethXはLAN側、「out on ethX」のethXはWAN側のインターフェイスを設定してください。
~~~
以上が終わったら、sudo netplan try をして設定が正しいかどうか確かめます。

::: note info
問題なければそのままENTERを押せば永続的に適用することが可能になります。
:::

続いて sudo ufw reload を行います。

::: note info
設定が正しければUFW Reloadedの表示が出ると思います。
:::

続いて sudo systemctl daemon-reload を行った後、ルーターを再起動します。
ついでにDHCPでIPv6を取得していた機器も一旦LANから切断するか、IPv6を一旦オフ -> オンにすることをお勧めします（**変更前のIPアドレスを掴み続ける端末があって大変だった……**）。

ルーターの再起動が終わって新しいプリフィックスのIPとDNSとデフォルトゲートウェイが振られたのを確認したら、次の様なサイトにアクセスします。

https://www.kame.net/

https://test-ipv6.com/index.html.ja_JP

::: note info
カメが動いたり、実際の自分の端末IPではなくルーターが上流から取得しているGUAが表示されていれば成功です。
:::

::: note warn
ちなみに最近のブラウザはアクセスしようとしているページがIPv4/IPv6デュアルスタックな場合、どちらからも読み込みを行ってデータのロードが速かった方を優先して表示する、という挙動をする様です。
その為、IPv6対応サイトでもIPv4で接続されたり、IPv6で読み込まれたのにリロードするとIPv4になる、といった様な挙動が発生する様です。
:::

::: note warn
また、WindowsではULAのみが振り出される環境下に於いてインターネット上のIPv6のサービスに到達可能な状態であっても、GUAが振られていない場合は「インターネット接続なし」という表示になる様です（Windows10で確認）。
:::

# 総括

:::note alert
被り難いとは言え、アドレスブロックの移譲を受けていないネットワークに**勝手にオレオレPrefixを設定してはいけない（それはそう）。**
:::

:::note info
GUAをルーターのみが持つネットワーク設計とすることにより、NDP Proxyが不要になり、また外から中のULAを直接知ることが出来ないのでセキュリティが向上した（と思う）。
:::

::: note info
GUAをルーターのみが持つことにより、従前環境では自宅側に居るVMとの通信ルートを起動時にStaticに（/usr/sbin/ip route -A inet6…を叩いて）設定しなくてはならなかったのが不要になった。
:::

::: note info
マンション備え付けの無料インターネットのプリフィックスが変わった場合（半固定的なIPoEなのでまず変わらないと思うが……）にあちこち書き直さなくてはいけなかった状態が、LAN内はULAを使う様にしたことで不要になった。
:::

::: note warn
GUAに代わってULAを使う様になったため、従前ではIPv6で表示できていたサイトがIPv4になったり、あるいはその逆が発生することがある。
:::

::: note warn
どうもULAしか振られていない場合、SpeedTestはIPv4でのみ稼働する節がある。
ちなみにFast.comはIPv6で接続できてIPv6で計測された。
:::

::: note warn
今回の自宅ネットワーク改定により、特に速度が向上するとかいうことはない。
:::