NanoPi NEO2をv6プラスのルーターにする 後編

新しく NanoPi NEO3をv6プラスのルーターにする systemd-networkd + nftables を書きました。この記事と合わせてご参照下さい。

NanoPi NEO2をv6プラスのルーターにする
USBネットワークアダプタ(黒)を繋いだNanoPi NEO2(金)。ネットワークケーブルは未接続。これにダイソーのmicroUSBのACアダプタを繋ぐ。ストレージは後述するが200円程度の2GBのmicroSDカードなのでケース含めてNanoPi NEO2はシステム全体で3000円程度。追加で今回は1000円のUSBネットワークアダプタ。でも正直なところUSBネットワークアダプタは無くても良いしUSB2.0の制限で最大速度が遅くなるのでむしろ要らないかな。

題名は「NanoPi NEO2を」と書いているけどNanoPi NEO2でなくてはならない要素は全く無くて機材としてはPCなどを含めほぼ何でも、Linux全般で通用します。

前回はv6プラスのMAP-Eを設定するためのアドレス・ポートのマッピングを計算した。今回はその値を使ってNanoPiNEO2をIPv4ルーターにする。

この記事ではNanoPi NEO2のネットワークポートはeth0でこれをLAN側NICとする。 USBのネットワークアダプタはenxenxXXXXXXXXXXXXで、これをIPv6のWAN側NICとする。IPv4 over IPv6のトンネルを掘るのでそのネットワークインターフェースをip6tnl1とする。

armbian公式サイトのNanoPi NEO2用のダウンロードページではDebian StretchとUbuntu Xenialは2018年1月下旬のものが最新で、それ以降更新されていない。更新されているのはUbuntu bionicだけ。それさえもNightly言いつつ途切れ途切れでリリースされている状況。
個人的にはDebian Stretchが好みなので時々ビルドしてGoogle Driveに上げている。ビルドオプションは弩ノーマルなので野良ビルドでよければ使って下さい。この記事ではビルドしたArmbian_5.55_Nanopineo2_Debian_stretch_next_4.17.11で動作確認している。
イメージを書き込むmicroSDカードは2GB程度あればイメージを書き込んだ状態でルートFSの使用率が70%程度。いろいろ入れてということではなくルーター専用程度なら書き換えもほぼ発生しないので激安の2GBで十分かと。最近は4GBが送料込みで200〜400円程度。2GBはもう売ってるのを見かけない。日本だとAmazonとかならまだあるかも。無駄に高いから買わないけど。

armbianの最近のdebian stretch(他も)はネットワークインターフェースのeth0が標準で無効という嫌な状態になっているので以前のようにmicroSDカードにOSイメージを焼いてネットワークケーブル繋いだらすぐにSSHで通信できるというようには優しくない。microSDカードにarmbianを書き込んだら、NanoPi NEO2に挿す前にPCでそのmicroSDカードのファイルシステムを開いて以下の変更を行う。

/etc/network/interfaces.default (2行追記)
1
2
3
#auto eth0
allow-hotplug eth0
iface eth0 inet dhcp

書き込んだらmicroSDカードを安全な方法でアンマウントしてから、NanoPi NEO2に挿して電源投入。
armbianの初期設定を適切に行う。(この記事では初期設定は省略)

/etc/sysctl.conf (1行変更、1行追記)
1
2
net.ipv4.ip_forward=1                    #IPv4ルーターの指定
net.ipv6.conf.eth0.disable_ipv6=1        #LAN側はIPv6を無効にする

今回はIPv4用のルーターにするのでnet.ipv4.ip_forward=1を指定した。
ただし、フォワーディングさせたいのはトンネルインターフェイスだけなので、他のネットワークインターフェイスでフォワーディングは困るという場合は/etc/sysctl.confでnet.ipv4.forwarding=1を指定するのではなく、トンネルを張った後にsysctl net.ipv4.conf.トンネルIF名.forwarding=1 を実行する。システム起動時にはトンネルインターフェイスが存在しないので/etc/sysctl.confでは指定できない点に注意。

tracerouteとtcpdumpをインストールする。これがあるとネットワークの疎通確認に便利。

# apt-get update                      #パッケージ情報の更新
# apt-get upgrade                     #パッケージを最新のものに更新
# apt-get install traceroute tcpdump

トンネル

DS-LiteとMAP-Eはズボンの表と裏のようなものなので結構似ている。カプセル化はDS-Liteと同じだし。 なので、トンネル堀りは基本的に以前のDS-Liteと同じ。DS-LiteのAFTRをBRのアドレスに読み替えて、CE側のアドレスも前回はIPv6アドレス指定だったのをインターフェース名にした程度。ただし、最近のLinuxの仕様変更なのかしら、そのままだとパケットを送ることはできても一切パケットが返ってこない。エラーになるなら調べやすいのだが、何も返ってこないというのは調べようがなくて凄い悩まされた。

参考記事:
愚行録 the Next Generation

こちらの記事はMAP-EではなくVPS目的のようだけど症状が同じで原因も特定されていた。(EncapsulationLimit=none)
参考記事では.netdevファイルを作成する方法を使ってるので設定の書き方は違うけど ipコマンドのトンネルでも同様の指定ができるのでコマンドで書くことにした。(encaplimit none)

NAT

正直Linuxのiptablesに不慣れなので苦労するかと思ったが、パケットにマークする、返ってきたパケットをマークで見分けるというなかなか素晴らしい方法が使えるということなのそれを採用することに。 で、ポートの範囲ごとにそれぞれTCP,UDP,ICMPのNATを書く。
が、面倒なのでスクリプトにしようと決意。で、ググッてたら1年半も前の2chのスレにそのものズバリがあったのね。

2ch v6プラス スレ
http://maguro.2ch.sc/test/read.cgi/isp/1473155603/
-----------------------------------------------------
358 : 名無しさんに接続中…[sage] 投稿日:2016/12/26(月) 17:08:09.63 ID:3u+uf4Mv.net [1/1回]
OpenWrtの真似してNATテーブル作って
CEからBRにIPIPトンネル張って流したら繋がった
CE同士の直接通信はできないけど
http://pastebin.com/QCSKwq72

WXR-1750DHP使うのやめてLinuxルータに戻そうかな
-----------------------------------------------------
/usr/local/bin/map.sh (新規作成)
 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
#!/bin/sh

BR='BRのIPv6アドレス'
CE='CEのIPv6アドレス'
IP4='IPv4アドレス'
PSID='PSIDを10進数に変換したもの'
WANDEV='enxXXXXXXXXXXXX'
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

route delete default
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

緑字のCE, IP4, PSIDの部分に前回求めた値を書き込む。BRのアドレスはググれば見つけられる筈。WANDEVは今回はNanoPi NEO2のUSBネットワークアダプタのNIC名。(ちなみにLAN側はeth0)
TUNDEVはトンネルを作ると生まれるインターフェース名。
掲示板の人のスクリプトのままだと(最近は?)BRからの戻りパケット全く通らないのでトンネル作成時にencaplimit noneを追加指定している。
触ったのはそれくらい。NATの部分は詳しい人からするともっと上手い方法あるよというのがあるかもだけど、iptablesは不慣れなので掲示板の人のそのままで十分過ぎるほど上手だと思ってる。

スクリプトに実行属性を付ける。
# chmod +x /usr/local/bin/map.sh
システム起動時に自動的にMAP-Eで接続させる。
/etc/rc.local (2行挿入)
1
2
sleep 10
/usr/local/bin/map.sh

exit 0の行の直前あたりに挿入する。上の例ではシステム起動後10秒待ってからMAP-Eで接続させるようにしたが、待ち時間は好みで。

他のPCがIPv4でインターネットに出るためのルートとしてNanoPi NEO2を指定する。DHCPサーバを使っているならDHCPサーバの設定でIPv4のルーターアドレスをNanoPi NEOのLANのIPアドレスに変える。トンネル用のIPv4アドレスではない点に注意。向き先を手動で変更するかPC(等)を再起動する。

speedtest.net
土曜日の21時半というまぁまぁ混む時間帯にSpeedtest.netで計測した結果。 この時間でこれなら深夜や午前中はもっと速度は出る筈。特に上り側。しかし、NanoPi NEO2のUSBが2.0なので300Mbpsが精一杯というところか。
画像の時刻を見て「昼過ぎじゃん」って思う人がいるので念の為。GMTならその時刻に9時間足したのが日本時間ね。

v6プラスの接続図
今回NanoPi NEO2は標準のネットワークポートとUSBネットワークアダプタの2つのポートでルーターにしているが、使用したUSBネットワークアダプタはUSB3.0対応なもののNanoPi NEO2側がUSB2.0なのでどう足掻いてもネットワークの実効速度は300Mbpsいくかいかないか程度。
それならNanoPi NEO2標準のネットワークポートだけ、1ポートでやる方が速いかもと思った。どうせ2ポートでも両端を同じハブに繋ぐんだし。思っただけでまだやってないわけだがヒマがあったら1ポートでも試したい。

2018年9月3日追記:
事前の予想では240ポート(TCPセッション)だと足りなくて使い物にならないんじゃないかと思ってたけど、約1ヶ月使ってみて意外にも不満無く普通に使えてる。家庭用のMAP-E対応ルーターとか買う必要無いと思った。

関連記事:

NanoPi NEO2をv6プラスのルーターにする 前編

MAP-Eのマッピング計算
©いらすとや.

題名は「NanoPi NEO2を」と書いているけどNanoPi NEO2でなくてはならない要素は全く無くて機材としてはPCなどを含めほぼ何でも、Linux全般で通用します。今回の前編はNanoPi NEO2すら登場しないし。

個人用の回線として使っているISPがSo-netで、昨年2月から今年の5月まではPPPoEの遅さをなんとかするためにインターネットマルチフィードのtransixを利用できるようになっていた。(So-netに申し込めばだけど)
そうするとIPv6(IPoE)はSo-netのPPPoEのIPv6を使うよりは速くなるよということだった。So-netは公式には認めなかったようだけどtransixにはDS-LiteによるIPv4 over IPv6が利用可能というオマケ?が付いているので、まぁ当然それも使うよね。するとIPv4もSo-netのPPPoEのipv4よりは遥かに速くて嬉しいという状態になった。DS-LiteのCPE側は非常に単純なカプセル化だけなのでFreeBSDやLinuxなどの標準機能だけで利用できるので、DS-Liteのためにわざわざルーターを買うという馬鹿らしいことをしなくて済むし。

関連記事:
NanoPi NEO2でDS-Liteなルーター ネットワークポート1つ版
FreeBSDルーターでDS-Lite

それがSo-netの突然の掌返しでmfeedのtransixからJPNEのv6プラスに強制的に変更させられたのが今年の5月。夜中に突然切り替えられて後からメールで切り替えましたって連絡なのでどうしようもない。NTTからHGWを渡されている場合は、それにソフトウエアが降ってくればHGWが全部やってくれるルーターになるので別に何かを用意する必要はないんだけど、HGWではなくONUを渡されている場合はその時点でv6プラス対応ルーターを持ってなければ対応のしようがないので飛行機に乗ってていきなり外に放り出された感じ。

v6プラスのIPv4 over IPv6はMAP-E方式だけど、これは公式には情報が殆ど提供されていないので「どう設定してよいかよくわからないもの」。カプセル化の部分はDS-Liteと変わらないんだけど、IPアドレスとポートのマッピングルールの取得方法が謎なのよね。BRのアドレスは公表はされてないし。それと、MAP-EはMAP-Eでもv6プラスのはだいぶ古いdraft-ietf-softwire-map-03相当「らしい」ということなのでRFC7597版とはちょっとルールの計算方法が違うようだし。これはドキュメントを読めばなんとかなる部分だけど。
でも、例によってネット上には情報が流れているようなので「v6プラス対応ルーター?」なんてのを買わずにLinuxあたりでなんとかしたいなというのが始まり。

手動でマッピングを計算してみる

基本的には与えられているIPv6のPrefixを元に計算してCE用のIPv6アドレス, IPv4アドレス、利用可能なポートが決まる。 で、その計算方法の部分は本当はマッピングルールの配信サーバから取得するのが筋なんだと思われるがそこへのアクセス方法が不明。
ただし、ネット上に計算方法があって、それは現在も一応有効。その計算方法に自分のIPv6 Prefixを突っ込めば必要な設定値は出せる。トンネルの対向になるBRのIPアドレスもいまのところはネットの情報が有効。

参考にしたページ

3つ目のリンクは便利だけど、1回だけでも自分で実際に計算するのが良さ気。答え合わせ用として使うのが良いかな。でないとマッピングがどんなのかよくわからないままになる。

アドレスマッピング

「ひかり電話」などを使ってなくてONUを渡されているユーザーのIPv6 Prefixは基本的に64。できたらifconfig -a(Linuxなど) ipconfig /a(Windows)で端末に割り当てられたIPv6アドレスとprefixを確認。

割り当てられているIPv6アドレスが下のような場合
240b:10:aabb:ccdd:8888:8888:8888:8888
ABCDEFGH
Prefixが64ビットなら240b:10:aabb:ccdd。 これはコロン : で区切られた先頭4つ分(A〜D)

CEのIPv4アドレス

IPアドレスのマッピングルール (ネットで調べた分のみ)
IPv6アドレスはprefix/31, IPv4は/15らしいが、解りやすいよう/32, /16で書いている。
IPv6 prefixIPv4 prefix
240b:10::106.72.x.y
240b:11::106.73.x.y
240b:12::14.8.x.y
240b:250::14.10.x.y
240b:251::14.11.x.y
240b:252::14.12.x.y
240b:253::14.13.x.y

IPv6Prefixの先頭32ビット分が合致するのを探す。
240b:10なら106.72.x.yになる。

上のIPv6 PrefixのCの部分(コロン区切りの3つめ)を2文字ずつに分ける。 aabb→ aaとbb
それぞれ16進数を10進数に変換する。
aa→ 170、これがxになる。
bb→187、これがyになる。
よって、IPv4アドレスは106.72.170.187になる。

PSID (Port-Set ID)

IPv6 Prefixの上の例でDの部分(コロン区切りの4つめ)、その上位8ビット分(16進数の2桁分)を取り出す。
ccddならccとなる。

CEのIPv6アドレス

上で求めたCEのIPv4アドレスを16進数に変換、それとPSIDを使う。 上で求めたIPv4アドレス: 106.72.170.187 ピリオド区切りでそれぞれ16進数に変換する
106→6a72→48170→aa187→bb
VWXY

上で求めたPSID: cc これをZとする。

IPv6 prefix/31 (下は/32で表示) アドレスルール(V〜Zは上の値を代入)

240b:10::2409:10:XY:Z00:V:WX:Y00:Z00
240b:11::2409:11:XY:Z00:V:WX:Y00:Z00
240b:12::2409:12:XY:Z00:V:WX:Y00:Z00
240b:250::2409:250:XY:Z00:V:WX:Y00:Z00
240b:251::2409:251:XY:Z00:V:WX:Y00:Z00
240b:252::2409:252:XY:Z00:V:WX:Y00:Z00
240b:253::2409:253:XY:Z00:V:WX:Y00:Z00

V, W, X, Y, Zをそれぞれ代入すると、2409:10:aabb:cc00:6a:48aa:bb00:cc00 になる。

ボートマッピング

上で求めたPSIDの前に1〜f※が、PSIDの後に0〜fが、それぞれ全ての組み合わせで付く (※ > 0なので注意)
PSIDがccの場合は1cc0〜fccf(例) 16連続したポートが15グループになる (16グループじゃない)
15グループをそれぞれ10進数に変換するとポートの範囲となる。

1cc0〜1ccf7360〜7375
2cc0〜2ccf11456〜11471
3cc0〜3ccf15552-〜5567
(中略)
ecc0〜eccf60608〜60623
fcc0〜fccf64704〜64719

今回求めた値を使って次はNanoPi NEO2をMAP-E対応ルーターにする。

関連記事:

Up