随分前のことなのですが、フレッツ光クロスとNuro光の2回線を引いていた頃があり、クロス(ぷらら、OCNバーチャルコネクト)の方が1Gを安定して超えていたので、Nuroの方を解約することにした時のことです。回線切り替えテストのためNuroの回線を一旦停止し、ブリッジモードのwifiをフレッツ光クロス経由に切り替えところ、ゲームコンソール(具体的にはNintendo Switch)の NAT判定がNATタイプ Dになり、家人から「オンラインモードでお友達を招待できない」とのクレームがでました。
調べたところ、NAT Type Dは対照型NAT(Symmetric NAT)の状態だそうで、単にスクリプトを見直すだけでは当時はNAT越えできませんでした。
そこで、いろいろと試した結果、FULLCONENATのカーネルモジュールがあるのでそれを使えるようにし、スクリプトを書き換えたところNAT判定をタイプAまで持って行けたので当時のことをまとめてみました。
まず、今回の環境(2021-12-08時点)についてですが、ルータはx64機で10G x2 nic + 1G x 1 onboardで、debian versionは11.2、uname -a はLinux gw23 5.10.0-10-amd64 #1 SMP Debian 5.10.84-1 x86_64 GNU/Linuxです。
2023/04/14追記:Debian 12対応方法を追記しました。
2023/04/16追記:モジュール追加無しの場合を新規投稿しました。
まず、FULLCONENATカーネルモジュールとiptablesをコンパイル・パッケージ化します。詳細は割愛しますが、Debianでカーネルモジュールとパッケージがビルドできる状態にしておいてください。 ビルド手順はおよそ以下の通りです。(途中で再起動させるので注意してください。)
追記:2023/03/17:iptablesの設定でTypeAをTypeBにするにはおおよそ以下のようなrules.v4(内側"enp1s0f1,172.16.1.0/24"からのパケットを通すが、外からの新規接続は落とすルール。要 iptables-persistent)で変更できます。
調べたところ、NAT Type Dは対照型NAT(Symmetric NAT)の状態だそうで、単にスクリプトを見直すだけでは当時はNAT越えできませんでした。
そこで、いろいろと試した結果、FULLCONENATのカーネルモジュールがあるのでそれを使えるようにし、スクリプトを書き換えたところNAT判定をタイプAまで持って行けたので当時のことをまとめてみました。
まず、今回の環境(2021-12-08時点)についてですが、ルータはx64機で10G x2 nic + 1G x 1 onboardで、debian versionは11.2、uname -a はLinux gw23 5.10.0-10-amd64 #1 SMP Debian 5.10.84-1 x86_64 GNU/Linuxです。
2023/04/14追記:Debian 12対応方法を追記しました。
2023/04/16追記:モジュール追加無しの場合を新規投稿しました。
まず、FULLCONENATカーネルモジュールとiptablesをコンパイル・パッケージ化します。詳細は割愛しますが、Debianでカーネルモジュールとパッケージがビルドできる状態にしておいてください。 ビルド手順はおよそ以下の通りです。(途中で再起動させるので注意してください。)
apt-get install linux-headers-amd64 apt-get install build-essential debhelper git libxtables-dev cd /usr/src ## 2023/04/14 追記:以下 Debian 11の場合(Debian 12は不可) git clone https://github.com/Chion82/netfilter-full-cone-nat.git ## 2023/04/14 追記:以下 Debian 12の場合(Debian 11でも可) git clone https://github.com/llccd/netfilter-full-cone-nat cd netfilter-full-cone-nat ## 2023/04/14追記: 以下 Debian 11の場合(例) make -C ../linux-headers-5.10.0-10-amd64 M=`pwd` modules ## 2023/04/14追記:以下 Debian 12(test version)の場合 make # 確認 modprobe nf_nat insmod xt_FULLCONENAT.ko cp -a xt_FULLCONENAT.ko /lib/modules/`uname -r`/kernel/net/netfilter/ echo 'kernel/net/netfilter/xt_FULLCONENAT.ko:' >> /lib/modules/`uname -r`/modules.dep depmod echo ' nf_nat xt_FULLCONENAT ' >> /etc/modules-load.d/modules.conf cd /usr/src mkdir iptables chown yourid -R iptables su yourid cd iptables apt-get source iptables ## 2023/04/16 追記: Debian 11の場合 cd iptables/iptables-1.8.7 ## 2023/04/16 追記: Debian 12(test version)の場合 cd iptables/iptables-1.8.9 cp /usr/src/netfilter-full-cone-nat/libipt_FULLCONENAT.c extensions # iptables パッケージのビルドに必要なパッケージのインストール sudo apt-get build-dep iptables # iptables パッケージのビルド dpkg-buildpackage -nc -b # ビルド後 cd .. ## 2023/04/16 追記: Debian 11の場合 sudo dpkg -i iptables_1.8.7-1_amd64.deb libip4tc2_1.8.7-1_amd64.deb libip6tc2_1.8.7-1_amd64.deb libiptc0_1.8.7-1_amd64.deb libxtables12_1.8.7-1_amd64.deb ## 2023/04/16 追記: Debian 12(test version)の場合 sudo dpkg -i iptables_1.8.9-2_amd64.deb libip4tc2_1.8.9-2_amd64.deb libip6tc2_1.8.9-2_amd64.deb libiptc0_1.8.9-2_amd64.deb libxtables12_1.8.9-2_amd64.deb # 2023/03/15追記 apt-mark hold iptables libip4tc2 libip6tc2 libiptc0 libxtables12 reboot基本的にここまで来ると、FULLCONENATモジュールは起動時に読み込まれるようになっていますので、以下のスクリプトを起動時に何らかの方法で実行させてください(/etc/rc.local等)。なお、map-e rouer(debian, iptables)の設定全般についてはこちらを御覧下さい。なおパラメータは例の計算機で算出しています。
#!/bin/bash # 2023/03/18:修正 PLEN=56 PFX=2400:4050:5c71:af00:: GWS=1 BR=2001:380:a120::9 CE=2400:4050:5c71:af00:99:f171:c600:2f00 IP4=153.241.113.198 PSID=47 WANDEV=enp1s0f0 LANDEV=enp1s0f1 TUNDEV='tun0' ## TYPE: [ OCN | V6P ] TYPE='OCN' # ここでOCNまたはV6Pを選択 if [ "$TYPE" = "OCN" ]; then \ lp=64 nxps=1024 pslen=16 elif [ "$TYPE" = "V6P" ]; then \ lp=16 nxps=4096 pslen=16 else echo Unknown TYPE: $TYPE exit 1 fi # 2023/03/23: CEをWANDEVに,$PFX$GWS/$PLENをLANDEVに割り当てるようにしました。 ip -6 addr add $CE dev $WANDEV ip -6 addr add $PFX$GWS/$PLEN dev $LANDEV # 2023/03/23: TUNDEVを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 addr add $IP4/32 dev $TUNDEV ip route delete default ip route add default dev $TUNDEV # nexhopはradbdumpで確認できます。 ip -6 route add default proto static metric 20 \ nexthop via fe80::aaaa:bbbb:cccc:dddd dev $WANDEV weight 10 iptables -t nat -F iptables -t mangle -F # 2023/03/27:以下二行をこちらへ移動させました。 rule=1 skip=0 # 2023/03/27: 加筆修正しました。 iptables -t mangle -o $TUNDEV -I FORWARD 1 -p tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1400:65495 -j TCPMSS --clamp-mss-to-pmtu # 2023/03/27: 以下一行を追加しました(※1) iptables -t mangle -o $TUNDEV -A POSTROUTING -j HMARK --hmark-tuple sport --hmark-mod $(($lp -1)) --hmark-offset 0 --hmark-rnd 0 iptables -t nat -A PREROUTING -i $TUNDEV -j FULLCONENAT while [ $rule -le $(( $lp -1 )) ] ; do mark=$rule pn=`expr $rule - 1` portl=`expr \( $rule + $skip \) \* $nxps + $PSID \* $pslen` portr=`expr $portl + $(( $pslen - 1))` # 2023/03/27: ※1追加に伴い以下三行をコメント化にて無効にしました。 ### iptables -t nat -A PREROUTING -m statistic --mode nth --every $(( $lp -1)) --packet $pn -j MARK --set-mark $mark ### iptables -t nat -A OUTPUT -m statistic --mode nth --every $(( $lp -1)) --packet $pn -j MARK --set-mark $mark ### iptables -t mangle -A POSTROUTING -o $TUNDEV -m statistic --mode nth --every $lp --packet $pn -j MARK --set-mark $mark iptables -t nat -A POSTROUTING -o $TUNDEV -m mark --mark $mark -j FULLCONENAT -p icmp --to-ports ${portl}-$portr --random-fully iptables -t nat -A POSTROUTING -o $TUNDEV -m mark --mark $mark -j FULLCONENAT -p tcp --to-ports ${portl}-$portr --random-fully iptables -t nat -A POSTROUTING -o $TUNDEV -m mark --mark $mark -j FULLCONENAT -p udp --to-ports ${portl}-$portr --random-fully iptables -t nat -A POSTROUTING -o $TUNDEV -m mark --mark $mark -j FULLCONENAT -p sctp --to-ports ${portl}-$portr --random-fully iptables -t nat -A POSTROUTING -o $TUNDEV -m mark --mark $mark -j FULLCONENAT -p dccp --to-ports ${portl}-$portr --random-fully rule=`expr $rule + 1` done# 2023/03/18追記:/etc/network/interfaces/enp1s0f0 の例 (WAN側 IF名,環境に合わせてください)は以下のようにします。
# 2023/03/20訂正:参考 # 1. 今回の環境は/56 prefixのdhcp pdなのでinet6 auto(slaac)をdhcpに訂正 # 2. すでにdhcpをiface行にて記述しているため、dhcp 行を削除 auto enp1s0f0 iface enp1s0f0 inet6 dhcp request_prefix 1# 2023/03/18追記:/etc/network/interfaces/enp1s0f1 の例 (LAN側 IF名,環境に合わせてください。またアドレスは任意で設定してください。)は以下のようにします。
auto enp1s0f1 iface enp1s0f1 inet static address 172.16.1.1 netmask 255.255.255.0 iface enp1s0f1 inet6 static address 2400:4050:5c71:af10::1/64
追記:2023/03/17:iptablesの設定でTypeAをTypeBにするにはおおよそ以下のようなrules.v4(内側"enp1s0f1,172.16.1.0/24"からのパケットを通すが、外からの新規接続は落とすルール。要 iptables-persistent)で変更できます。
#/etc/iptables/rules.v4 *filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] -A INPUT -i lo -j ACCEPT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -i enp1s0f1 -p icmp -j ACCEPT -A FORWARD -i enp1s0f1 -p icmp -j ACCEPT -A INPUT -s 172.16.1.0/24 -j ACCEPT -A FORWARD -s 172.16.1.0/24 -j ACCEPT COMMIT追記2:2023/04/16: Debian 12(test version)にアップグレード後、dhclientが起動されない為、接続確立後しばらくしてからWAN側のIPv6接続が切断され結果としてIPv4接続も切れるのですが、/etc/rc.localに以下を先頭に記述することで対処しました。
dhclient -6 -v -pf /run/dhclient6.enp1s0f0.pid -lf /var/lib/dhcp/dhclient6.enp1s0f0.leases -I -P -N -df /var/lib/dhcp/dhclient.enp1s0f0.leases enp1s0f0今回は以上です。それでは。
コメント
コメントを投稿