家で使っているルーターはIPv6パススルー機能はついているものの、IPv6 プラスは非対応なので、ソフトウェア的に対応できないかなーと探していたところこんな記事を見つけた。
簡単に言うと、家中のIPv4の通信をUbuntuの上のルーターに集めてIPv6でカプセリングし、予め調べておいたカスタマーエッジに転送するというもの。
手元にあったAndroid端末のNexus 5にUbuntu Touchを焼いてトンネリングを実現してみた。
効果
有線化してNexus 5を介した「IPoE + IPv4 over IPv6(v6プラス)」と「PPPoE」を比較した結果がこちら
Nexus 5を介した通信
もともとの通信
IPv4の上り速度は低下しているが(というかPPPoeの上りが以上に早い)
IPv4の下り速度が、5.87Mbpsから60.7Mbpsにアップしている。
追記:
Apex Legendsなどのオンラインゲームでは何故か半分くらいの確率でパケットロスが起きる。
うまくつながったときは1試合通して大丈夫。うまくつながらなかったときは1試合通してパケロス。困る…
カーネルとシステムの両方をビルドする
UBports公式の記事を参考にビルドを行う。
環境構築 (Docker)
後々詰まることの無いように、Dockerfileも用意しておいた。
Dockerをインストール済みであれば、以下コマンドを打つだけで環境構築ができる。
docker run --name hoge -it kajindowsxp/ubp-build-hammerhead
環境構築 (Ubuntu)
Dockerを使わない場合はこっち。
公式はUbuntu 16.04を推奨しています。
必要パッケージのインストール
sudo dpkg --add-architecture i386 && sudo apt update
sudo apt install schedtool gcc g++ g++-multilib zlib1g-dev:i386 \
zip libxml2-utils bc python-launchpadlib phablet-tools
ディレクトリ作成
mkdir ~/ubp-5.1
cd ~/ubp-5.1
リポジトリをinitする
allthefixingsブランチには、現在サポートされているUbuntu Touchのデバイス固有の情報が追加されている。
repo init -u https://github.com/ubports/android -b ubp-5.1-allthefixings --depth=1
ソースコードを取ってくる
repo sync -j10 -c
config設定
デフォルトのビルド設定では、IPv6トンネル機能が無効化されているので、kernel/lge/hammerhead/arch/arm/configs/cyanogenmod_hammerhead_defconfig
を編集する。
# CONFIG_IPV6_TUNNEL is not set
の下に、CONFIG_IPV6_TUNNEL=y
を追記すればOK
# CONFIG_IPV6_TUNNEL is not set
CONFIG_IPV6_TUNNEL=y
ビルド
ビルド時の環境情報(環境変数など)を読み込む
source build/envsetup.sh
ビルド対象端末の固有情報を読み込む
書式は、cm_[デバイス名]-userdebug
lunch cm_hammerhead-userdebug
ビルド開始
mka
イメージを端末に焼く
生成先のディレクトリに移動するcoutというコマンドを実行する
cout
Dockerを使った場合は、生成物をホストにコピーしておく
root@b3771880db02:/work/ubp-5.1# cout
root@b3771880db02:/work/ubp-5.1/out/target/product/hammerhead# pwd
/work/ubp-5.1/out/target/product/hammerhead
root@b3771880db02:/work/ubp-5.1/out/target/product/hammerhead# exit
exit
aaa@DESKTOP-4BC47UM:~$ docker cp hoge:/work/ubp-5.1/out/target/product/hammerhead ./
aaa@DESKTOP-4BC47UM:~$ cd hammerhead/
aaa@DESKTOP-4BC47UM:~/hammerhead$ ls
android-info.txt data obj recovery system.img
boot.img fake_packages previous_build_config.mk recovery.img ubuntu
cache gen ramdisk-android.img root userdata.img
cache.img installed-files.txt ramdisk-recovery.img symbols
clean_steps.mk kernel ramdisk-ubuntu.img system
Nexus 5をfastbootモードで起動しておき、PCにつなげる。
以下コマンドを実行し、bootとrecoveryを焼く
fastboot flash boot boot.img fastboot flash recovery recovery.img
次に、以下のテキストを[replace-file-system.sh](https://github.com/janimo/phablet-porting-scripts/blob/68734ca07998b8e784397df77d9aca4b968b3815/build/replace-android-system)
として保存する。
#!/bin/bash
# Wait until the adb shell is unavailable, meaning the device is rebooting
wait_for_reboot() {
while test -n "$(adb shell echo '1' 2>/dev/null)"
do
echo -n ".";
sleep 3;
done
echo
}
#Wait until we get a working adb shell, meaning the device is in normal or recovery mode
wait_for_device() {
while test -z "$(adb shell echo '1' 2>/dev/null)"
do
echo -n ".";
sleep 3;
done
echo
}
SYSTEM_IMAGE=$1
if [ ! -f "$SYSTEM_IMAGE" ]; then
echo "Usage: $0 system.img"
exit
fi
echo "Rebooting to recovery"
adb reboot recovery
wait_for_device
echo "Mounting system partition"
adb shell "mkdir /a; if [ -e emmc@android ]; then mount emmc@android /a; else mount /data; mount /data/system.img /a; fi"
if file $SYSTEM_IMAGE | grep -v ": Linux rev 1.0 ext4" >/dev/null; then
echo "Converting from sparse ext4 image to mountable ext4 image"
simg2img $SYSTEM_IMAGE tmp.img >/dev/null
resize2fs -M tmp.img >/dev/null 2>&1
mv tmp.img $SYSTEM_IMAGE
fi
echo Pushing android system image...
adb push $SYSTEM_IMAGE /a/var/lib/lxc/android/system.img >/dev/null 2>&1 &
SIZE=$(stat -t $SYSTEM_IMAGE |awk '{print $2}')
S=0
while test $S -lt $SIZE
do
sleep 1
S=$(adb shell stat -t /a/var/lib/lxc/android/system.img | awk '{print $2}')
printf "%0.2d%%\r" $[100*$S/$SIZE]
done
echo "Done, rebooting to Ubuntu"
adb reboot
# vim: expandtab: ts=4: sw=4
以下コマンドで実行権限を付与し、systemをnexus 5に書き込む
chmod +x ./replace-file-system.sh
./replace-file-system.sh system.img
端末がfastbootのままrecoveryモードにならない場合は、音量ボタンでrecoveryを選択し、電源ボタンを押す。
IPv4 over IPv6を設定する
こちらの記事を参考にnetwork.shを作成する
私の環境ではこんな感じになった。
#!/bin/sh
#set -x
BR='xxxx:xxxx:xxxx:xxxx::xxxx'
CE='xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx'
IP4='xxx.xxx.xxx.xxx'
PSID='xx'
WANDEV='wlan0'
TUNDEV='testtun'
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
network.shを実行する
sudo bash network.sh
ここで端末のブラウザ(Morph Browser)からhttp://kiriwake.jpne.co.jp/v/にアクセスすると
「v6プラスつかっています」と表示される。
他のPCからのアクセスに対応する
nexus 5でやること
まず、書き込みができるようにrwでマウントする
sudo mount -o remount,rw /
次に/etc/sysctl.conf
を開き、net.ipv4.ip_forward=1
のコメントアウト(#)を外す
sudo nano /etc/sysctl.conf
編集前
#net.ipv4.ip_forward=1
編集後
net.ipv4.ip_forward=1
変更が終わったら下記コマンドで反映させる
sudo sysctl -p
また、端末のローカルのIPv4アドレスを調べておく。
私の環境では192.168.11.6であることがわかる
$ ip -4 a show wlan0
22: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 192.168.11.6/24 brd 192.168.11.255 scope global wlan0
他のPCでやること
IPv4のデフォルトルートを削除し、新たにNexus 5を経由して通信するように変更する
アドレスは先程調べたものを指定する
Linuxの場合
ターミナルで以下コマンドを入力する
sudo ip -4 route delete default
sudo ip -4 route add default via 192.168.11.6
Windowsの場合
コマンドプロンプトを管理者権限で開き、以下コマンドを入力する
route DELETE 0.0.0.0
route add 0.0.0.0/0 192.168.11.9
同様にブラウザからhttp://kiriwake.jpne.co.jp/v/にアクセスし、
「v6プラスつかっています」と表示されれば成功
知らなかった用語集
ネットワークを弄くり回すのは初めてだったので知らない単語や仕組みが沢山あった。
自分向けのメモ。
- UT
Ubuntu Touch - ubp
ubports - phablet
phone + tabletでスマートフォンのこと - JPNE
- 一般人はVPSとインターネット回線の契約をするが、IPv6通信ではVPSが更にJPNEという組織に委託している。
- CE(Customer Edge)
自宅にある、IPv6トンネルの始端となる装置 - BR(Border Relay)
JPNEに存在している、IPv6トンネルの終端となる装置。 - PSID(Port-Set Identifiers)
CEごとに割り当てられる識別子。これを使ってどのポート番号を利用できるかが計算される。 - dev (device) (developmentではない)
「外部への通信」や「トンネリング」など機能をもたせることでインターフェースとして利用できる。 - repo
gitを管理するツール。複数のリポジトリを一気にプルしたりコミットしたりできる。