Ubuntu / Debian でIPv4 over IPv6 (OCNバーチャルコネクト, v6プラス), systemdによる設定, ルーター化, VPNおよび自宅サーバー可能な固定グローバルIPv4アドレス

コメント(2024/07/27): ３年弱何も記述を更新していないが、以前から [ニチバンベンチ](https://blog.misosi.ru/2019/12/14/openwrt-v6plus-stuck/#fn1) には問題なく成功している。数行したのリンク先の systemd, nftablesだけでルーターを構成する設定でひかり電話契約ありフレッツジョイント無しのNTTレンタルルーター (RX-600KI) と併用して、IPv4パケットをすべてIPOEで高速に流すことができている。レンタルルーターのPPPOEの接続は解除している。

更新(2021/10/10): 引っ越しするとIPv6のグローバルアドレスが変わるため、各種設定を作り直す必要あり。県によってIPv6の速さはだいぶ異なる

更新 (2021/08/05): `systemd` と `nftables` だけを用いて設定を整理し新たに [Linux・systemd・nftables でv6プラス・OCNバーチャルコネクト用ルーターを作る(~~2021~~2024年版)](https://qiita.com/kakinaguru_zo/items/37777d80ea18c8134108) という記事にした。systemdとnftablesでルーター化すればいいならリンク先の設定をコピペすれば多分十分

更新 (2021/08/04): systemd に[DHCPサーバー](https://qiita.com/kakinaguru_zo/items/f3dbf5c44bf28fc27f9c) と [DNSキャッシュサーバー](https://qiita.com/kakinaguru_zo/items/6a0bd4f43bf0ee4ea85f) をやらせることに成功したのでdnsmasqを使うのを止めた

更新 (2021/07/31): `ip6tnl0` という謎インターフェースが作られて気になっていたのは、カーネル起動オプションに `fb_tunnels=none` をつけて、 `sysctl` の項目に `net.core.fb_tunnels_only_for_init_net = 2` （どっちか片方の項目で十分そう）すると作られなくなります。

更新: Raspberry Pi 4B 8GB に純正 Debian 11 Bullseye を載せて下記の手順にしたがって IPv4 over IPv6 化して700 Mbps出せたので、機材としてはラズパイで十分です。以下の設定をしたあとは [systemd を用いたアクセス制御・ファイアーウォール](https://qiita.com/kakinaguru_zo/items/4bca6bab91d9fa61a62d) などの方法でインターネットに剥き出しにされている機器を防御するほうが無難です。

[IP v4をPPPoE (要するに昔ながらの有線インターネット接続) で繋ぐと遅いよ](https://wifinomori.com/ipv4-ipv6-config/) という話があり、それに比べてIPv6 パケットを IPoE でインターネットに流すと速い（ただしIPv6 でも PPPoEで繋ぐと速くない）という話があり、IPv4を速くするためにIPv4 を IPv6 (IPoE方式）で流す [IPv4 over IPv6](https://dream.jp/ftth/tips_f/hikari17.html) でIPv4のパケットも速くなるという話があります。IPv4 over IPv6 は基本的にIPv4パケットをIPv6パケットでくるんで送っているだけなので、Linuxをちょちょっと設定すると新たに機器を買わないでもできます（設定したパソコン以外のIPv4も高速化するにはおまけ２を参照）。そのやり方は基本的に

* [CentOS7でOCNバーチャルコネクト](https://quintrokk.subness.net/?p=2003)
* [NanoPi NEO2をv6プラスのルーターにする 後編](https://gato.intaa.net/archives/13186)

に書いてある通りだが、Ubuntu / Debian の「標準」（優先度Priorityがstandard）のパッケージの範囲内でできる手順を書いておく。以下はIPv6が OCNバーチャルコネクト で提供されることを仮定しているが、[OCN v6 アルファ](https://www.ntt.com/personal/services/internet/hikari/ocnv6.html) でもたぶん大丈夫で、より広範に[MAP-E方式](http://www.kahemicafe.com/ipv4-over-ipv6-point-to-notice)のIPv4 over IPv6 に対応している業者なら大丈夫だと思われる。記事著者はドコモ光の上でプロバイダーにドコモnetを用いて下記の動作確認をした。ドコモnetを使うとOCNバーチャルコネクトによるIPv6 (IPoE)が提供されることもある（そうではないこともある）。自分のドコモnetのIPv6接続方式の確認は https://v6test.docomonet.jp/ で行える。以下の動作確認は Ubuntu 20.04 LTS (Focal) で行った。おまけのルーター化の部分はDebian Bulllseye (version 11)

更新：[nftables](https://ja.wikipedia.org/wiki/Nftables) で同じことをやる方法を末尾に追記した。固定されたグローバルIPv4アドレスを使えるようになることを追記した。インターフェース初期化にシェルスクリプトを用いずにsystemdとnftableだけで行う方法を追記した。他の機器からのIPv4パケットも拾ってIPv4 over IPv6でインターネットに送り出す設定を追記した。NAPTテーブルの枯渇について追記した。nftablesの設定が1008個のポートを使い切れていないバグを直した。nftablesの設定でMSSを調節しきれていないのを直した

# 業者の確認
https://v6test.ocn.ne.jp/ で自分のIpv6サービスがOCNバーチャルコネクトかどうか確認する。

![スクリーンショット 2020-05-23 15-24-34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259309/e7cc4e85-aeb7-d666-63e2-b9021ca469ac.png)

IPv6が無い場合はそもそもIPv4 over IPv6が出来ない。IPv4のほうが既にIPv4 over IPv6になっている場合はそれ以上やることは無いからここで読み終わりましょう。この状態で https://minsoku.net/speeds/contents/new で接続速度確認する（パソコンとNTTレンタルルーターを有線で直結）と

![スクリーンショット 2020-05-23 15-26-40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259309/061353d9-674a-19d1-3a6f-c4df8deffadc.png)

くらいの速さがでる（まあまあ速い）。

# 下記手順が対応している業者
http://ipv4.web.fc2.com/map-e.html で必要な接続情報（特に`option peeraddr`）が正しく計算されれば、下記の手順でIPv4 over IPv6 できるようになる。ウェブ検索した範囲では次の業者でも大丈夫そう

* ＠nifty [V6プラスでできないことを明確にして回避できることを考える](https://bike8615.blogspot.com/2017/11/v6_20.html)
* enひかり(V6プラスオプション) [OpenWrtでv6プラス(MAP-E)接続する手順](https://blog.mamemaki.com/entry/2019/12/15/171104)
* Biglobe [biglobeのIPv4 over IPv6でハマった話 (RTX830) ](https://blog.hiros.info/2018/06/biglobeipv4-over-ipv6-rtx830.html)
* [v6プラス](https://ja.wikipedia.org/wiki/V6%E3%83%97%E3%83%A9%E3%82%B9)を用いた業者全般が大丈夫なはず

http://ipv4.web.fc2.com/map-e.html はジャバスクリプトだが、そのスクリプトが次の手順で見つかるIPv6アドレスを認識できればよい。ウェブページを覗いてエディターで見た限りではIPv6アドレスの最初が

* 2400:40?? 〜 2400:41??
* 2404:7???
* 240b:0???

で始まっていればいける可能性が高い。そうでないと警告が出るが[それでもうまく行くケース](https://quintrokk.subness.net/?p=2003#i-6)もある。v6プラス系は使えるポートの個数が240個でOCNバーチャルコネクトや普通のv6アルファは1024個使えるという割と大きな違いがある。BiglobeのMAP-Eで使えるポートの数はホームページを読んでもよくわからない…

# インターフェース名とIPv6アドレスのネットワーク部の確認
`ip address` コマンドを実行すると

```shell-session
$ ip address
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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: enp0s31f6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether a8:13:74:97:2f:94 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.36/24 brd 192.168.1.255 scope global dynamic noprefixroute enp0s31f6
       valid_lft 14398sec preferred_lft 14398sec
    inet6 2400:4050:1234:5600:8025:855b:4ea1:601c/64 scope global temporary tentative dynamic 
       valid_lft 14400sec preferred_lft 12600sec
    inet6 2400:4050:1234:5600:6fda:cfff:f671:1719/64 scope global tentative dynamic mngtmpaddr noprefixroute 
       valid_lft 14400sec preferred_lft 12600sec
    inet6 fe80::46:9078:e1b3:83ba/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
```

のような結果がでる。ここで `inet6` で「2400」から始まるアドレスが割り当てられたインターフェースとそのアドレスのネットワーク部を探す。この例では

* インターフェースは `enp0s31f6`
* IPv6アドレスのネットワーク部は `2400:4050:1234:5600` である

# 謎のサイト http://ipv4.web.fc2.com/map-e.html でIPv6でくるんだIPv4パケットの送り先などを調べる

以下のような感じ。OCNの1008個のポート割当を使い切るようにスクリプトを改良する方法は [OpenWrtでOCNバーチャルコネクト(MAP-E)に接続する](https://blog.hinaloe.net/2020/03/14/openwrt-mape-ocn/) にある。そのままで1008個の割り当てポートを使い切るスクリプトは [CentOS7でOCNバーチャルコネクト](https://quintrokk.subness.net/?p=2003) のCentOS７用スクリプトの節にある。

![スクリーンショット 2020-05-23 17-10-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259309/e76c05f1-1897-e41e-03f9-515cf9c1d033.png)

```shell
#!/bin/sh
#set -x
# このスクリプトはポートを240個しか使ってくれないため、常用するならおまけ１の方法を使うか自分でスクリプトを
# 改造して1008個のポート（OCN系の場合）を使い切るようにしたほうがよい。そうしないとポート不足で
# 通信不能になる頻度が増える。またUDP Lite, SCTP, DCCPなどのIPv4パケットもMAP-Eで通るが
# それらに以下のスクリプトは対応していない
BR='スクショのoption peeraddrのアドレスをそのまま書く'
CE='スクショのCEを書く'
IP4='スクショのIPv4アドレスを書く'
PSID='スクショのPSIDを書く'
WANDEV='上記のip addressコマンドで特定したインターフェース'
TUNDEV='ip6tnl1' # 新たに作り出すインターフェース名をは好きなように決める

ip -6 addr add $CE dev $WANDEV
ip -6 tunnel add $TUNDEV mode ip4ip6 remote $BR local $CE dev $WANDEV encaplimit none
ip link set dev $TUNDEV mtu 1460
ip link set dev $TUNDEV up

ip -4 route delete default
ip -4 route add default dev $TUNDEV

iptables -t nat -F

rule=1
while [ $rule -le 15  ] ; do
  mark=`expr $rule + 16`
  pn=`expr $rule - 1`
  portl=`expr $rule \* 4096 + $PSID \* 16`
  portr=`expr $portl + 15`
  iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet $pn -j MARK --set-mark $mark
  iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet $pn -j MARK --set-mark $mark

  iptables -t nat -A POSTROUTING -p icmp -o $TUNDEV -m mark --mark $mark -j SNAT --to $IP4:$portl-$portr
  iptables -t nat -A POSTROUTING -p tcp -o $TUNDEV -m mark --mark $mark -j SNAT --to $IP4:$portl-$portr
  iptables -t nat -A POSTROUTING -p udp -o $TUNDEV -m mark --mark $mark -j SNAT --to $IP4:$portl-$portr
  rule=`expr $rule + 1`
done

iptables -t mangle -o $TUNDEV --insert FORWARD 1 -p tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1400:65495 -j TCPMSS --clamp-mss-to-pmtu
```

上記は [NanoPi NEO2をv6プラスのルーターにする 後編](https://gato.intaa.net/archives/13186) のパクリですがUbuntu / Debian の標準パッケージに含まれるコマンドで書き直している。
このシェルスクリプトをインターフェースにIPv6アドレスが割り振られたあとに実行する（自動実行する方法は記事末尾の「おまけ１」を参照）と…

# 固定グローバルIPv4アドレスの付与・VPN・自宅サーバー
上記の作業をした後に `ip -4 address add $IP4 dev $TUNDEV` すると全世界から見えてアクセスし放題のアドレスとして `$IP4` が使えるようになります。自宅サーバーを建てたりすることに使えますが、気をつけないとセキュリティ的にアブナイです。なお、**MAP-Eの固定グローバルIPv4アドレスではサーバー建てられないとか書いてある記事とか掲示板があるけど、それは大間違い**で記事著者はsshサーバーを建てて外部から使えるようにしている。IPv4固定アドレスでサーバーなど公開している話は

* [IPv6プラス環境におけるIPv4ポート公開設定](https://qiita.com/nbhr/items/2850ccaa3456a8553bbf) や
* [V6プラスでできないことを明確にして回避できることを考える](https://bike8615.blogspot.com/2017/11/v6_20.html)

に書いてあります

[https://qiita.com/nbhr/items/2850ccaa3456a8553bbf](https://qiita.com/nbhr/items/2850ccaa3456a8553bbf) も参考になります。5chとかのいい加減な情報に騙されてはいけない

VPNや自宅サーバーに用いるポート番号にNAPTを割り当てられると問題が起きそうだが、下記おまけ１にあるシェルスクリプトでは使えるポートの一部をNAPTに使わせない設定がシェル変数`KOSUU`の調節でより簡単にできる。

# CPU 動作周波数の固定
CPUが遅くなって処理能力が落ちても仕方がないため、 [linux-cpupower](https://packages.debian.org/stable/linux-cpupower) パッケージをインストールし、以下のようなsystemdサービスファイルを作成して `systemctl enable` して、起動時に周波数を最高値に固定する。以下の例はラズパイ用で、x86なら `/usr/sbin/x86_energy_perf_policy` の設定もしたほうがよさそう。

```config:/etc/systemd/systemd/mycpupower.service
[Unit]
After=modprobe@raspberrypi_cpufreq.service
Requires=modprobe@raspberrypi_cpufreq.service

[Service]
Type=oneshot
ExecStart=/usr/bin/cpupower frequency-set -g performance -d 1.5GHz

[Install]
WantedBy=multi-user.target
```

# IPv4 over IPv6 の効果
https://v6test.ocn.ne.jp/ で接続を確認すると

![スクリーンショット 2020-05-23 16-24-59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259309/444dbe08-e94f-2663-ba14-56bbbebd2e76.png)

https://minsoku.net/speeds/contents/new で接続速度確認すると

![スクリーンショット 2020-05-23 15-48-31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259309/20654458-f656-d16e-0b0d-ee23834ee99f.png)


# おまけ１: systemd と nftables  (/usr/sbin/nftコマンド) に上記のインターフェース初期化を起動時にやらせる方法
この後の話はDebian Linux Bullseye (11) を10年前のしょぼいノートパソコンに入れて行った。それでも800 Mbpsでパケットを処理できて十分な速度を得られた。ちなみに、 [NanoPi NEO3をv6プラスのルーターにする systemd-networkd + nftables](https://gato.intaa.net/archives/25972) に同じ主旨のことが書いてあるけど、やり方の詳細は結構違う。

同じことを[nftable](https://ja.wikipedia.org/wiki/Nftables) にやらせる手順は以下のようになります。思ったよりもすっきり書けない…😨以下のスクリプトはドコモnet（OCNバーチャルコネクト）のように使えるポート数が1008あることを仮定しているため、v6プラスのように240個しかポート使えないMAP-Eでは最初にあるシェル変数の`ZOUKA`と`KOSUU`を調節して下さい。nftables 使ってso-netの MAP-E している記事が https://git.sr.ht/~sirn/grid.in.th/tree/71b5acd05a3e511dfcee1fd39a0d193da53724a3/content/2019/11/apu2-alpine-v6plus.markdown にあるけど、こちらはポート数240決め打ちです。

```shell
#!/bin/sh
#set -x

BR='スクショのoption peeraddrのアドレスをそのまま書く'
CE='スクショのCEを書く'
IP4='スクショのIPv4アドレスを書く'
PSID='スクショのPSIDを書く'
TUNDEV='ip6tnl1' # 名前は好きなように

ZOUKA=1024 # v6プラスなら4096
KOSUU=63 # v6 プラスなら15、本来の値より減らせば使えるポート中でポート番号の大きいほうがNAPTで
# 割り当てられなくなるから、そこに例えばVPNや自宅サーバー用ポートを割り当てることができる

tmp_nft_filename=/tmp/map_e.nft
cat >$tmp_nft_filename <<EOF
#!/usr/sbin/nft -f

flush ruleset

table ip map_e_filter {
	chain POSTROUTING {
		type filter hook postrouting priority filter;
		iifname $TUNDEV tcp flags & syn == syn tcp option maxseg size set rt mtu log prefix "TCPMSS shortened (input) " level debug flags all counter
		oifname $TUNDEV tcp flags & syn == syn tcp option maxseg size set rt mtu log prefix "TCPMSS shortened (output) " level debug flags all counter
	}
}

table ip map_e_nat {
	map myvmap {
		type mark : verdict
EOF

rule=1
mark=$rule # `expr $rule - 1`
echo -n "		elements = { $mark : goto map_e_chain$mark" >>$tmp_nft_filename
rule=`expr $rule + 1`

while [ $rule -le `expr $KOSUU + 1`  ] ; do
  mark=$rule # `expr $rule - 1`
  echo -n ", $mark : goto map_e_chain$mark"
  rule=`expr $rule + 1`
done >>$tmp_nft_filename
echo " }"  >>$tmp_nft_filename
echo "	}" >>$tmp_nft_filename
echo ""  >>$tmp_nft_filename

cat >>$tmp_nft_filename <<EOF
	chain POSTROUTING {
		type nat hook postrouting priority filter;
		oifname $TUNDEV mark set 1 counter packets 0
EOF
for p in tcp udp icmp udplite sctp dccp; do
  echo "		oifname $TUNDEV meta l4proto $p mark set numgen inc mod $KOSUU offset 2 counter packets 0" >>$tmp_nft_filename
done
cat >>$tmp_nft_filename <<EOF
		oifname $TUNDEV meta mark vmap @myvmap
	}
	chain map_e_chain1 { log prefix "Unknown protocol to ip6tnl " level info flags all;  }

EOF

rule=1
while [ $rule -le $KOSUU  ] ; do
  mark=`expr $rule + 1`
  portl=`expr $rule \* $ZOUKA + $PSID \* 16`
  portr=`expr $portl + 15`
  echo  -n "	chain map_e_chain$mark { "
  for p in tcp udp icmp udplite sctp dccp; do
     echo -n "meta l4proto $p counter packets 0 snat to $IP4:$portl-$portr persistent; "
  done
  echo " }"
  rule=`expr $rule + 1`
done  >>$tmp_nft_filename

echo '}' >>$tmp_nft_filename

```

上記のシェルスクリプトを実行すると `/tmp/map_e.nft` ができるので、それを眺めて信じる気分になったら `/etc/nftables.conf` に上書きでする。そして `systemctl enable nftables.service` で起動時に `/etc/nftables.conf` が読み込まれるようにする。

以下の3つのファイルを作る。 $BRなどは上記のシェルスクリプトに記入したアドレスなどに置き換えて下さい。そして `systemctl enable systemd-networkd.service` する。NetworkManagerやnetplan.ioやifupが動いていると干渉して設定を上書きされがちなので、再起動前に`apt-get purge network-manager netplan.io ifupdown` しておいたほうが無難です。そして再起動する。

```config:/etc/systemd/network/WANDEV.network
[Match]
Name=$WANDEV

[Link]
RequiredForOnline=yes

[Network]
DHCP=yes # 他でDHCPサーバーが稼働していてアドレスなどを配布してくれると仮定
#IPForward=ipv4
IPv6AcceptRA=yes
Tunnel=$TUNDEV

[Address]
Address=$CE/64 # /64を付ける
#DupulicateAddressDetection=no
```

```config:/etc/systemd/network/TUNDEV.netdev
[NetDev]
Name=$TUNDEV
Kind=ip6tnl

[Tunnel]
Mode=ipip6
Local=$CE
Remote=$BR
DiscoverPathMTU=yes
EncapsulationLimit=none
#Independent=yes
```

```config:/etc/systemd/TUNDEV.network
[Match]
Name=$TUNDEV

[Link]
RequiredForOnline=yes

[Network]
BindCarrier=$WANDEV
DefaultRouteOnDevice=yes
DHCP=no
IPv6AcceptRA=no
LinkLocalAddressing=no

# 次の2行を有効にすればMAP-Eで貰える固定グローバルIPv4アドレス宛の
# パケットを受け取れるようになるが、結構危険
#[Address]
#Address=$IP4/32 # /32を付け加える
```

# おまけ２: 他の宅内機器からのIPv4パケットをIPv4 over IPv6で高速に送る (ルーター化)
上記の設定だと設定を行ったLinuxだけがIPv4 over v6の恩恵を受けられるが、他の機器からのIPv4パケットもv6パケットに変換してあげれば家庭内の全機器のIPv4通信が速くなる。以下でやる作業は基本的に [NanoPi NEO2をv6プラスのルーターにする 後編](https://gato.intaa.net/archives/13186) と同じでEthernetが一つだけある機器を想定しているが、systemdで設定するところが違う。IPv6パケットの扱いや外部への送り方は変えない。基本的にはIPv4パケットだけフォワーディングする設定とIPv4アドレスを固定する設定を行えばよい。例えば

```config:/etc/systemd/network/WANDEV.network

[Match]
Name=en*

[Link]
RequiredForOnline=yes

[Network]
DNS=192.168.1.1 # NTTの光電話用レンタルルーター上のDNS
IPv6AcceptRA=yes
Tunnel=$TUNDEV

DHCP=ipv6 # IPv4の設定にDHCPを用いない
DHCPServer=no # systemdにDHCPサーバーさせようとしたら動作しなかった😭
IPForward=ipv4

[Address]
Address=192.168.1.2/24  # 自分（IPv4 over v6変換用ルーター）のアドレス
# IPv6アドレスなどの設定はRAならびにDHCPでNTTレンタルルーターから貰う

[Address]
Address=$CE/64
#DupulicateAddressDetection=no

# 以下はsystemd にDHCPサーバーさせようとしてうまく動かなかった設定の残骸
[DHCPServer]
PoolOffset=70
PoolSize=40
EmitDNS=yes
DNS=192.168.1.1
#EmitNTP=yes
#NTP=ntp.nict.jp
EmitRouter=yes
```

他の機器のIPv4パケットをすべて上記の192.168.1.2に送らせる必要があり、
それをするにはDHCPサーバーを立ち上げ192.168.1.2をゲートウェイにするのが簡単でしょう。そうするための手順は例えば [DHCPサーバーの設定](https://www.server-world.info/query?os=Debian_10&p=dhcp&f=1) がわかりやすいと思う。

**追記:** [systemd 247 を用いたらsystemdにDHCPサーバーをやらせることに成功した](https://qiita.com/kakinaguru_zo/items/f3dbf5c44bf28fc27f9c)

ギガビットイーサネットポート一つがついた１０年前のパナソニックノートPC (メモリ4 GB, Intel(R) Core(TM)2 Duo CPU P8800 @ 2.66GHz) を光電話用のNTTレンタルルーター(RX-600KI)のLANポートに直結して、別のPCから無線でスピードテストすると以下のような感じになり、スピード的には十分に思われる。オンボロPCの再活用としては悪くないと思われる。

![スクリーンショット 2020-05-26 15-56-33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259309/6e51583d-8be1-3fee-758e-96fc2d88405e.png)

ルーター化すると常時電源ONになるので、勝手にスリープしないように

```config:/etc/systemd/sleep.conf
[Sleep]
AllowSuspend=no
AllowHibernation=no
AllowSuspendThenHibernate=no
AllowHybridSleep=no
```

とするのがよい。

# おまけ３: NAPTするためのポートの枯渇を調べる
MAP-E するために使えるポートがOCNバーチャルコネクトみたいに1008個あると個人宅ではわりと安心だが、v6プラスだと心もとなくて [YAMAHA RTX1200でMAP-Eした（けどやめた）](https://emeth.jp/diary/?p=356) という記事も出ている。現在実行しているポートとIPアドレス変換処理の数は `conntrack -L` で表示できる。それが多くなければ問題なさそう。特にUDPだとポートの枯渇が激しいので、IPv4でUDPを使うDNSをなるべくIPv6で問い合わせるのが良さそうな気がする。うちでは、dnsmasqでDNS proxyを建てて、IPv4パケットによるDNS問い合わせをGoogle DNSへのIPv6パケットによる問い合わせに変換している。`conntrack -L`で見ると家族二人が使ってるだけでNAPTされるTCP接続が140くらいに達することもあるので、v6プラスの240ポートは結構厳しいかも知れない…GoogleのQUICプロトコル(UDP 443) も結構NAPTテーブルを占有している。[「ヤマハのルーター使ってポートが枯渇して困る」](https://zigsow.jp/item/349845/review/357890) という記事もあります。

ヤマハルーターのウェブページでもUDPで通信するとキツイと書いてある↓

* [OCNバーチャルコネクトサービス対応機能](http://www.rtpro.yamaha.co.jp/RT/docs/ocn_map_e/index.html)
* [「v6プラス」対応機能 ](http://www.rtpro.yamaha.co.jp/RT/docs/v6plus/)

この話題は [CentOS7でOCNバーチャルコネクト](https://quintrokk.subness.net/?p=2003) の「性能」の節にも書いてあります。スピールこうのホームページ https://www.nichiban.co.jp/general/health/foot/corn/speelko_ex/ はつかえるポートを簡単に使い潰せるページとして知られていて、ブラウザで数回シフトリロードすると conntrack -L で数えられるコネクション数がv6プラスの上限値の240を簡単に超えます

# おまけ４: dnsmasqの設定例
**追記:** [systemd 247を使ったらDNSキャッシュサーバーをsystemdにやらせることに成功したのでdnsmasqを使うのを止めた](https://qiita.com/kakinaguru_zo/items/6a0bd4f43bf0ee4ea85f)

上記のNAPTテーブル枯渇を軽減する一般的な方法はproxyサーバーを建てることである。特にIPv4 UDPの大半を占めるDNSによるホスト名解決をIPv6通信に変換するためのdnsmasq設定例を以下に示す

```config:/etc/resolv.conf`
nameserver 127.0.0.1
nameserver 2001:4860:4860::8888 # Google DNS
nameserver 2001:4860:4860::8844 # Google DNS
options inet6 edns0
```

上記のように`resolv.conf` を設定するとdnsmasqからのDNS問い合わせはグーグルDNSにすべて流れるようになる。うちでのdnsmasq の設定ファイルは

```config:/etc/dnsmasq.conf
domain-needed # ドメイン名が無い host0 のようなホスト名解決をグーグルDNSに送らない
dnssec # Google DNSはDNSSEC対応済み
listen-address=127.0.0.1, 192.168.1.2 # LAN内部からの問い合わせだけに応答する
dhcp-range=192.168.1.70,192.168.1.110,12h  # DHCPで他の機器に与えるIPv4アドレスの範囲
# 以下はDNSの問い合わせ先としてdnsmasq稼働ホストのIPv6アドレスとグーグルDNSのIPv6アドレスをDHCPで与える
dhcp-option=option6:dns-server,[::],[2001:4860:4860::8888],[2001:4860:4860::8844]
dhcp-authoritative
cache-size=1000 # 千件DNS問い合わせ結果をdnsmasqは覚えておく
```

dnsmasqはDNS proxyとDHCPサーバーを兼ねるが、上記の設定例ではIPv6アドレスを他の機器に設定することはしない。IPv6関連の設定はもともど可動していたルーターをそのまま使うことを前提としている。
`systemd-resolved` はもう不要であるし`dnsmasq` と同時には使えないから`systemctl disable --now systemd-resolved` しておく

# UPnP, NAT-PMP (Port Mapping Protocol), PCP (Port Control Protocol)によるポート開放
[UPnP](https://ja.wikipedia.org/wiki/Universal_Plug_and_Play) と [NAT PMP](https://ja.wikipedia.org/wiki/NAT_traversal#NAT%E3%81%AE%E5%8B%95%E4%BD%9C%E3%81%AB%E5%9F%BA%E3%81%A5%E3%81%8FNAT_traversal%E3%81%AE%E6%8A%80%E8%A1%93), [PCP](https://en.wikipedia.org/wiki/Port_Control_Protocol) はLAN内側のクライアントが勝手にルーターのNAPT設定を変えてポートを開放できるプロトコルである。これを実現するLinux上のいま標準的なものは [miniupnpd](http://miniupnp.free.fr/) である。これを使えるようになったので、簡単にやったことを紹介する。

## systemd のイーサネット設定の変更
```config
[Link]
RequiredForOnline=yes
Multicast=yes
AllMulticast=yes
```

上記のようにマルチキャスト設定を追加しておく

## [miniupnpd](http://miniupnp.free.fr/) の最新版を入手
[トンネルされたWANインターフェースのIPアドレスをminiupnpdがちゃんと理解できないバグ](https://github.com/miniupnp/miniupnp/issues/460) が最近まで修正されていなかったので `git clone` してソースを持ってくる。以下の手順でコンパイルする

1. `git clone https://github.com/miniupnp/miniupnp.git`
2. `cd miniupnp/miniupnpd`
3. `apt-get install libnftnl-dev libmnl-dev gcc make build-essential`
4. `./configure --disable-fork --igd2 --vendorcfg --pcp-peer --portinuse --disable-pppconn --firewall=nftables`
5. `make`
6. `mkdir /etc/miniupnpd`
7. `cp netfilter_nft/scripts/* /etc/miniupnpd`
8. `cp miniupnpd /usr/sbin`

以下の２つのファイルを作る：

```config:/etc/miniupnpd/miniupnpd.conf
listening_ip=LAN側のネットワークインターフェース名 enp0s25 等
ext_ifname=トンネルのインターフェース名 ip6tnl1 等
ext_ip=トンネルに付けられたIPv4アドレス
#secure_mode=yes
secure_mode=no
allow 65216-65231 192.168.1.0/24 0-65535 # nftables.conf 作成スクリプトの$KOSUUを減らして
# 一部の範囲のポート番号をNAPTに使わないようにして、代わりにminiupnpdに使わせる
deny 0-65535 0.0.0.0/0 0-65535
enable_natpmp=yes
force_igd_desc_v1=no
enable_upnp=yes
bitrate_up=5000000000
bitrate_down=5000000000
```

```config:/etc/systemd/system/miniupnpd.service
[Unit]
Description=UPnP Internet Gateway Device Daemon
Documentation=man:miniupnpd(8)
After=network-online.target minissdpd.service
Requires=network-online.target

[Service]
TasksMax=2
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BROADCAST CAP_NET_RAW CAP_SYSLOG
MountAPIVFS=yes
NoNewPrivileges=yes
PrivateMounts=yes
PrivateDevices=yes
PrivateTmp=yes
MemoryDenyWriteExecute=yes
ProtectSystem=full
ProtectHome=yes
ProtectHostname=yes
ProtectClock=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
LockPersonality=yes
RestrictRealtime=yes
RestrictNamespaces=yes
RestrictSUIDSGID=yes

Type=exec
ExecStartPre=/etc/miniupnpd/nft_init.sh -i ip6tnl1 # ここはトンネルの名前にして下さい
ExecStart=/usr/sbin/miniupnpd -f /etc/miniupnpd/miniupnpd.conf
ExecStopPost=/etc/miniupnpd/nft_removeall.sh -i ip6tnl1 # ここもトンネルの名前にして下さい

[Install]
WantedBy=multi-user.target
```

上記の作業をしたあとに `systemctl enable --now miniupnpd.service` すると`miniupnpd`が起動されると共に次回ブート時以降も自動起動されるようになる。

上記の設定で基本的にminiupnpdが動作するはずなので、`apt-get install miniupnpc` したあとに `upnpc -s`, `upnpc -n`, `upnpc -d`, `upnpc -L` などで動作確認する。NAT-PMPに対応したクライアントは`apt-get install natpmpc` でインストールできる。PCP (Port Control Protocol) のクライアントはDebian/Ubuntuには無さそうだが、 https://github.com/libpcp/pcp から入手できる。