VyOSで主にスマホを対象としたIPv6シングルスタック試験環境を作る設定のメモ書き(DHCPv6-PD編)

# はじめの駄文

- 目的
    - 自宅のネットワークをセグメント分けする
        - 自分用、家族用、仕事用、スマホ試験用みたいな感じ
    - IPv6は一部をIPv6シングルスタック（IPv6SS）とする
        - [IPv6のみのネットワーク](https://developer.apple.com/jp/support/ipv6/)試験環境の常設
        - [都度macでインターネット共有をやる](https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html#//apple_ref/doc/uid/TP40010220-CH213-SW16)のが面倒くさい

## 勝手な定義

- IPv6シングルスタック
    - 文中ではIPv6SSと略記
    - クライアントにはIPv6アドレスのみを配布する
    - クライアントが464XLATに対応し、clatが動作すれば ```192.0.0.0/29``` のアドレスが生成され、IPv4が割り当てられているように見える
    - IPv4へはNAT64/DNS64/464XLATといったIPv4/v6互換技術を用いてアクセスする
    - 一部のISP（MNO）がコレで面倒くさい
- IPv6ネイティブシングルスタック 
    - IPv6SSで464XLATが動作していない状態を指したい
    - クライアントから見ると、本当にIPv6だけしかないように見える状態
    - NAT64/DNS64があれば、IPv4のみのホストへはアクセスできるがIPv4生アドレスで行けるかはOS実装次第
    - たぶん、[biglobeの特定サービス](https://support.biglobe.ne.jp/ipv6/nat64.html)に直結するとコレになるような気がするが試す環境がない
- IPv4/v6デュアルスタック
    - 文中ではv4/v6DSと略記しているかもしれない
    - クライアントにはIPv4アドレスとIPv6アドレスの両方を配布する
    - いまどきのモバイル/ブロードバンド回線で一般的と思われる構成
    - IP4,IPv6へはそれぞれ直接通信する
- IPv4シングルスタック
    - クライアントにIPv4アドレスだけを配布する
    - IPv6へは基本的にはつながらない
    - 一部のISP（たぶんMVNOが多そう）とか、ここ7年ぐらいルーターと設定を変えていない場合はたぶんこれ


## 環境とか

- フレッツDHCPv6-PD（ネクスト+ひかり電話契約）＋transix環境前提
    - クロスはひかり電話なしでもDHCPv6-PD /56と聞くが、併用しているISPがクロス非対応なので切り替えられんし試す環境がない、欲しい
- DNS/DNS64は外部サービスに頼る
    - [Google Public DNS](https://developers.google.com/speed/public-dns/docs/using?hl=ja)と[Google Public DNS64](https://developers.google.com/speed/public-dns/docs/dns64?hl=ja)、あと[AdGuard DNS](https://adguard-dns.io/ja/public-dns.html)のファミリー保護（広告、トラッカー、アダルトコンテンツをブロックし、できる限りセーフサーチとセーフモードを有効）
    - ローカルDNSもあるが、今回は省略

既に/64が飛んでくるRA環境下に作る場合

https://qiita.com/garupon/items/e9e35d75668616861a2f

### HW

- Minisforum GK41
    - 終売モデルだがN100系ほど熱くならないのがいい
    - GbE x2なモデル

### NW

```
Interface    IP Address                                  MAC                VRF        MTU  S/L    Description
-----------  ------------------------------------------  -----------------  -------  -----  -----  -------------
eth1         -                                           xx:xx:xx:xx:xx:e9  default   1500  u/u    
eth2         192.168.11.254/24                           xx:xx:xx:xx:xx:ea  default   1500  u/u    
             24xx:xxxx:xxxx:xx01:xxxx:xxxx:xxxx:xxea/64
eth2.64      192.168.64.254/24                           xx:xx:xx:xx:xx:ea  default   1500  u/u    
             24xx:xxxx:xxxx:xx64:xxxx:xxxx:xxxx:xxea/64
eth2.100     192.168.100.254/24                          xx:xx:xx:xx:xx:ea  default   1500  u/u    
             24xx:xxxx:xxxx:xxaa:xxxx:xxxx:xxxx:xxea/64
lo           127.0.0.1/8                                 00:00:00:00:00:00  default  65536  u/u
             ::1/128
tun0         -                                           n/a                default   1460  u/u
wlan0        -                                           xx:xx:xx:xx:xx:30  default   1500  u/D
```

- WAN
    - eth1
        - フレッツ1G、IIJmio FiberAccess/NF、ONUへ接続
    - tun0
        - mfeed transix(DS-LITE)
- LAN
    - eth2（VLANなし）
        - IPv4/v6デュアルスタック１
    - eth2.64(VLAN64)
        - IPv6シングルスタック
    - eth2.100(VLAN100)
        - IPv4/v6デュアルスタック２
    - wlan0
        - 未使用

本文中にこれ以外のインターフェースが出てきた場合、ただの消し忘れなので気にしないで頂きたい

## SW(VyOS)

### sh ver

```
Version:          VyOS 1.5-rolling-202412160007
Release train:    current
Release flavor:   generic

Built by:         autobuild@vyos.net
Built on:         Mon 16 Dec 2024 00:07 UTC
Build UUID:       b8cd31f7-b8e3-443a-98da-45b4cfa867c2
Build commit ID:  64737049995158

Architecture:     x86_64
Boot via:         installed image
System type:      bare metal
Secure Boot:      disabled

Hardware vendor:  BESSTAR TECH LIMITED
Hardware model:   GK41
Hardware S/N:     Default string
Hardware UUID:    

Copyright:        VyOS maintainers and contributors
```

### sh conf com

以下、VyOSのコンフィグとコメントを記述する。

#### firewall

::: note warn
最小限と思うもののみ
セグメント間など個人的なものは省略している
:::

```
set firewall global-options state-policy established action 'accept'
set firewall global-options state-policy invalid action 'drop'
set firewall global-options state-policy related action 'accept'
set firewall ipv6 forward filter default-action 'drop'
set firewall ipv6 forward filter rule 1 action 'accept'
set firewall ipv6 forward filter rule 1 outbound-interface name 'eth1'
set firewall ipv6 forward filter rule 2 action 'accept'
set firewall ipv6 forward filter rule 2 protocol 'ipv6-icmp'
set firewall ipv6 input filter default-action 'drop'
set firewall ipv6 input filter rule 1 action 'accept'
set firewall ipv6 input filter rule 1 destination port '546'
set firewall ipv6 input filter rule 1 protocol 'udp'
set firewall ipv6 input filter rule 1 source port '547'
set firewall ipv6 input filter rule 2 action 'accept'
set firewall ipv6 input filter rule 2 protocol 'ipv6-icmp'
```

プライベート用、仕事用、家族用の間はよしなにフィルタを掛けておいた方がいいし、同居のご家族に好奇心旺盛でやんちゃなご令息が居る場合はガッチガチにしておいた方がいい。
今回のパターンで言うと、AdGuard DNSでフィルタを掛けているので、それ以外のDNSをDoT/DoH含め使えないようにしてしまえ。そしてMDMで縛り上げよ。

#### interface

:::note warn
一部のNICや特定の仮想環境下ではoffloadを切らないとパフォーマンスが落ちる
というか、offることでパフォーマンスが落ちることは無さそうなのでoffっとく方が無難かもしれない
:::

```
set interfaces ethernet eth1 address 'dhcpv6'
set interfaces ethernet eth1 dhcpv6-options duid '00:03:00:01:xx:xx:xx:xx:xx:e9'
set interfaces ethernet eth1 dhcpv6-options pd 0 interface eth2 sla-id '1'
set interfaces ethernet eth1 dhcpv6-options pd 0 interface eth2.64 sla-id '100'
set interfaces ethernet eth1 dhcpv6-options pd 0 interface eth2.100 sla-id '170'
set interfaces ethernet eth1 dhcpv6-options pd 0 length '56'
set interfaces ethernet eth1 hw-id 'xx:xx:xx:xx:xx:e9'
set interfaces ethernet eth1 ipv6 address autoconf
set interfaces ethernet eth1 ipv6 adjust-mss 'clamp-mss-to-pmtu'
set interfaces ethernet eth1 offload gro
set interfaces ethernet eth1 offload gso
set interfaces ethernet eth1 offload tso
set interfaces ethernet eth2 address '192.168.11.254/24'
set interfaces ethernet eth2 address 'fe80::1/64'
set interfaces ethernet eth2 hw-id 'xx:xx:xx:xx:xx:ea'
set interfaces ethernet eth2 ipv6 address no-default-link-local
set interfaces ethernet eth2 offload gro
set interfaces ethernet eth2 offload gso
set interfaces ethernet eth2 offload tso
set interfaces ethernet eth2 vif 64 address '192.168.64.254/24'
set interfaces ethernet eth2 vif 64 address 'fe80::1/64'
set interfaces ethernet eth2 vif 64 ipv6 address no-default-link-local
set interfaces ethernet eth2 vif 100 address '192.168.100.254/24'
set interfaces ethernet eth2 vif 100 address 'fe80::1/64'
set interfaces ethernet eth2 vif 100 ipv6 address no-default-link-local
set interfaces loopback lo
set interfaces tunnel tun0 encapsulation 'ipip6'
set interfaces tunnel tun0 ip adjust-mss 'clamp-mss-to-pmtu'
set interfaces tunnel tun0 ipv6 address no-default-link-local
set interfaces tunnel tun0 mtu '1460'
set interfaces tunnel tun0 parameters ipv6 encaplimit 'none'
set interfaces tunnel tun0 remote 'xxxx:xxxx::feed:100'
set interfaces tunnel tun0 source-address 'xxxx:xxxx:xxxx:xx01:xxxx:xxxx:xxxx:xxea'
set interfaces wireless wlan0 hw-id 'xx:xx:xx:xx:xx:3d'
set interfaces wireless wlan0 physical-device 'phy0'
```

``` dhcp-option pd ```を設定すればそのインターフェースにIPv6アドレスが設定される。
強制取得する場合は ``` force ipv6-rd interface eth1 ```

``` fe80::1/64 ``` の設定と、 ``` ipv6 address no-default-link-local ``` の設定は、クライアントから見たときにルーター（デフォルトゲートウェイ）が ``` fe80::xxxx:xxxx:xxxx:xxxx ``` と長ったらしくならないよう、見た目のためだけに設定。

##### sla-id

/56で降ってくる場合、設定できる値は0-255（0x00-0xff）

2001:db8:0000:0000::/56 -> 2001:db8:0000:00xx::/64 

sla-idは10進、IPv6は16進数。見た目をすっきりさせるためだけの値にしているだけなので被らなければいい。

100 -> 0x64 -> 2001:db8:0000:0064::/64
170 -> 0xAA -> 2001:db8:0000:00AA::/64

#### duid

[NTT東](https://www.ntt-east.co.jp/gisanshi/)の[IP通信網サービスのインタフェース 第三分冊](chrome-extension://efaidnbmnnnibpcajpcglclefindmkaj/https://flets.com/pdf/ip-int-3.pdf)より
> 端末側のDUID生成方式はRFC3315に規定されるDUID-LL方式に準拠する必要があります。

[RFC3315](https://datatracker.ietf.org/doc/html/rfc3315)は廃止->[RFC8415](https://datatracker.ietf.org/doc/html/rfc8415)


https://zenn.dev/sdb_blog/articles/353e1855111737

> フレッツ網ではDHCPv6でPrefix Delegationのリクエストを受け取る際にはDUIDをDUID-LL形式(00:03:00:01:[MACアドレス])の形にする必要があります。

#### nat64

```
set nat64 source rule 1 source prefix '64:ff9b::/96'
set nat64 source rule 1 translation pool 1 address '192.168.64.0/24'
set nat64 source rule 1 translation pool 1 port '1500-65000'
```

VLAN64以外でもNAT64が効いてしまうのはちょっと悶々とするで、フィルタでごまかす。
```
set firewall ipv6 prerouting raw rule 64 action 'reject'
set firewall ipv6 prerouting raw rule 64 destination address '64:ff9b::/96'
set firewall ipv6 prerouting raw rule 64 inbound-interface name '!eth2.64'
```

#### route

:::note warn
最小限と思うもののみ
ポリシールーディングや特定経路設定などは省略している
:::

```
set protocols static route 0.0.0.0/0 interface tun0
```

#### dhcp-server

- VLANなし
    - Google Public DNS
- VLAN100
    - AdGuard DNS

```
set service dhcp-server shared-network-name LAN authoritative
set service dhcp-server shared-network-name LAN subnet 192.168.11.0/24 lease '3600'
set service dhcp-server shared-network-name LAN subnet 192.168.11.0/24 option default-router '192.168.11.254'
set service dhcp-server shared-network-name LAN subnet 192.168.11.0/24 option name-server '8.8.8.8'
set service dhcp-server shared-network-name LAN subnet 192.168.11.0/24 option name-server '8.8.4.4'
set service dhcp-server shared-network-name LAN subnet 192.168.11.0/24 option time-zone 'Asia/Tokyo'
set service dhcp-server shared-network-name LAN subnet 192.168.11.0/24 range all start '192.168.11.101'
set service dhcp-server shared-network-name LAN subnet 192.168.11.0/24 range all stop '192.168.11.199'
set service dhcp-server shared-network-name LAN subnet 192.168.11.0/24 subnet-id '11'
set service dhcp-server shared-network-name VLAN100 authoritative
set service dhcp-server shared-network-name VLAN100 subnet 192.168.100.0/24 lease '600'
set service dhcp-server shared-network-name VLAN100 subnet 192.168.100.0/24 option default-router '192.168.100.254'
set service dhcp-server shared-network-name VLAN100 subnet 192.168.100.0/24 option name-server '94.140.14.15'
set service dhcp-server shared-network-name VLAN100 subnet 192.168.100.0/24 option name-server '94.140.15.16'
set service dhcp-server shared-network-name VLAN100 subnet 192.168.100.0/24 option time-zone 'Asia/Tokyo'
set service dhcp-server shared-network-name VLAN100 subnet 192.168.100.0/24 range all start '192.168.100.51'
set service dhcp-server shared-network-name VLAN100 subnet 192.168.100.0/24 range all stop '192.168.100.199'
set service dhcp-server shared-network-name VLAN100 subnet 192.168.100.0/24 subnet-id '100'
```

一部スマホでたまにタイムゾーンがUTCのままになるのを回避できるかとtime-zoneを入れてみたが、あまり効果は無い様子

##### IPv6 only preferred

:::note
VLAN64でIPv6シングルスタック非対応のOSを混在させる場合は以下のオプションを含めたDHCPを設定する
:::

```
set service dhcp-server shared-network-name VLAN64 option ipv6-only-preferred
```

#### router-advert

- VLANなし
    - Google Public DNS
- VLAN64
    - Google Public DNS64
- VLAN100
    - AdGuard DNS

```
set service router-advert interface eth2 default-lifetime '600'
set service router-advert interface eth2 name-server '2001:4860:4860::8888'
set service router-advert interface eth2 name-server '2001:4860:4860::8844'
set service router-advert interface eth2 name-server-lifetime '600'
set service router-advert interface eth2 prefix ::/64 preferred-lifetime '3600'
set service router-advert interface eth2 prefix ::/64 valid-lifetime '3600'
set service router-advert interface eth2.64 default-lifetime '600'
set service router-advert interface eth2.64 name-server '2001:4860:4860::64'
set service router-advert interface eth2.64 name-server '2001:4860:4860::6464'
set service router-advert interface eth2.64 name-server-lifetime '600'
set service router-advert interface eth2.64 nat64prefix 64:ff9b::/96
set service router-advert interface eth2.64 prefix ::/64 preferred-lifetime '3600'
set service router-advert interface eth2.64 prefix ::/64 valid-lifetime '3600'
set service router-advert interface eth2.100 default-lifetime '600'
set service router-advert interface eth2.100 name-server '2a10:50c0::bad1:ff'
set service router-advert interface eth2.100 name-server '2a10:50c0::bad2:ff'
set service router-advert interface eth2.100 name-server-lifetime '600'
set service router-advert interface eth2.100 prefix ::/64 preferred-lifetime '3600'
set service router-advert interface eth2.100 prefix ::/64 valid-lifetime '3600'
```

#### other

:::note
``` set console keymap ``` はもう効かないため ``` set system option keyboard-layout 'jp106' ```を使う
:::

:::note warn
WAN環境によってはsystem name-serverをNTTのものに設定した方が都合よい
:::

```
set service ntp server time.google.com
set service ssh disable-password-authentication
set system config-management commit-revisions '100'
set system host-name 'VyOS'
set system login user xxxx authentication encrypted-password '$6$...'
set system login user xxxx authentication public-keys sshkey key 'xxx...'
set system login user xxxx authentication public-keys sshkey type 'ssh-ed25519'
set system name-server '2001:4860:4860::8888'
set system name-server '2001:4860:4860::8844'
set system option keyboard-layout 'jp106'
set system syslog global facility all level 'info'
set system syslog global facility local7 level 'debug'
set system time-zone 'Asia/Tokyo'
set system wireless country-code 'jp'
```

# おわりの駄文

- Wi-Fiでのclat発動条件は割と謎
    - ``` ipv4only.arpa ``` のクエリ結果以外見ている？
    - raのnat64prefixも一つのトリガっぽいが、削っても動きが読めん
     - 464xlatの動作
         - iOS: だいたいOK
         - Android: 条件付きでOK（IPv6 GA必須？）
         - Windows11: NG（今のところ非対応っぽく、期待させるようなコメントだけはある模様）
         - Linux: 条件付きでOK（clatd入れて起動すりゃ動く）
             - https://github.com/toreanderson/clatd
- AndroidにおけるWi-Fi下でのIPv6SS制限についてのソースが見つからん
    - IPv6 ULAは使えずGAでなければならない仕様あり？
    - その場合 ``` 2001:db8:: ``` 以外に使えるものは無いか（これも本来NGなんやろけど）
    - IPv6-RA（/64しかもらえない場合）だと、ここら辺が課題
        - ULAだと優先順位が違うので挙動が変わる
        - VyOSだとRA-proxyができそうでできていない
    - [IPv6 Tunnel Brokerを使ってIPv6ネイティブな環境を構築する](https://qiita.com/kazuhidet/items/b295d4932f478c488646)
        - まだ使える手段なのか試していないが、それ以外にMTUの影響が大きそう
            - IPv6SS下の通信で起こる問題の半分がMTUフラグメント臭い、知らんけど
- IPv4SS ISP下でIPv6SS環境の再現できないか
    - 理屈で言えばIPv6 GAが無くても作れると思うし、macでもできるし、試した感じできなくはないんだけども
    - 前述のIPv6 ULA以外のセグメント候補
    - DNS64の構築も課題、GAは返さず ``` 64:ff9b::/96 ``` のみを返すものが要る
    - 二層にする以外ないか
        - AdGuardの場合、``` aaaa_disabled: false ``` して ``` use_dns64: true ```
        - 理屈でいえば464XLATがあればDNS64が無くてもいけると思うんだけれどもすっきりしない
- AdGuard組み込み
    - だいたい下記サイトのやり方でいける
        - [VyOS 1.4にAdGuardHomeを入れる@/home/tnishinaga/TechMEMO](https://tnishinaga.hatenablog.com/entry/2023/01/06/172651)
    - 内蔵DNSフォワーダのポート変更し、コンテナのポートを公開するやり方が楽
        - dns 53/tcp,53/udp
        - initial 3000/tcp
        - http 80/tcp
        - https/doh 443/tcp
        - dot 853/tcp
        - doq 853/udp
            - ``` set service dns forwarding port 10053 ```
            - ``` set container name AdGuard port dns source 53 ```
            - ``` set container name AdGuard port dns protocol udp ```
    - 上記サイトのやり方では、設定も面倒だしクライアント設定やログが活用できないため
    - 証明書を設定する場合はlet's encryptを使わず自己署名とし、SANにIPを設定する手順にする
        - SANにIPが無いLet's Encryptでは全機能が使えない
        - ZeroSSLは面倒だしローカルIP使えない
    - というか、仮想化してVyOSとかDNSとか詰め込んでしまう方が楽だわコレ
- 464XLATなしでNAT64/DNS64のみに頼るIPv6ネイティブシングルスタックでの動作確認
    - だいたいNG
        - なんでそんな挙動になるのかわからない挙動が多い、特にWindows
- IPv4SSとする場合の設定を追記したいがとりあえず
    - sla-idを入れない
    - dhcpを喋らせる
    - raを喋らせない
- ubiquiti の Cloud Gateway Max 辺りに手ぇ出したいんだけれど、これと同じような設定ができるのだろうか
    - Fiberはよ
    - なお、pfsenseはできそう