メルカリの業者さん垢から中古を買った

L12 は NEC 製のルータで比較的お求めやすい値段で中古が売りに出されている. 熱暴走のトラブルが嫌がられて安く手に入るようだ. 民主的平和論に則り, ネットワーク製品は実質的に民主主義である国のメーカーのものを使うようにしてる.

内部を清掃する

分解レポートを写真付きで見せてくれてるブログがあったので手順をなぞって分解した. 基盤の裏表にヒートシンクが付いているのだけど, チップとヒートシンクの間に挟まれている熱伝導接着剤に製造時に剥がすべき保護フィルムが残置されている. クリーニングしておいた. これで熱暴走が予防できたらうれしい.

MTU の調整をする

設定できる MTU は 1400〜1440 なので調整幅が少ない. 設定をいろいろ試したいときは不便.

ウェブ画面以外から MTU を設定してみる

MTU の制限は画面で保存ボタンを押したときにチェックをしているだけという記事を読んだので, ウェブ画面以外から設定する方法を考える. ssh も積んでいるようだが, 設定を on にする方法はわからなかった.

  1. Web ブラウザでルーターのクイック設定 Web を開いてパスワードを入力してログインする. トップページ-> 詳細設定-> その他の設定 を開く.
  2. ブラウザのデベロッパーツール-> アプリケーションタブ-> Cookie で確認すると認証情報が保存されている. sysauth=3fe56f2e0086af243bed7f956152f4de
  3. ブラウザのデベロッパーツール-> 要素 で token を検索すると token に値がセットされているのがわかる. <input type="hidden" name="token" id="token" value="937a36e9ebd2b69e09b9e7a73dbeb4f0">
  4. 設定ボタンを押したときと同じデータ(payload)を sysauth と token と合わせてサーバーに送信(POST)してみる. 設定ボタンを押したときにどんなデータが送られているかはデベロッパーツールのネットワークで見つかる. 実際の payload はこんな感じ "Security_Protection_Function_check=on&Security_Protection_Function=1&TCP_Timer_seconds=1200&UDP_Timer_seconds=100&UPnP_Function=0&DMZ_Host_Function=0&IP_Address_of_DMZ_Host=&Firmware_Update_Notification_Feature_check=on&Firmware_Update_Notification_Feature=1&Lamp_Lighting_Mode=0&Lamp_Off_Transition_Time=1&MTU_bytes=1440&PING_Response_Function_check=on&PING_Response_Function=1&Quality_Report_Function=0&button_id=Apply_9&token=937a36e9ebd2b69e09b9e7a73dbeb4f0"
  • bash にまとめるとこんな感じ
#!/bin/bash

# ルーターの IP とパスワードを指定するよ
IP="192.168.2.1"
PASSWORD="PASSWORD"

# 設定したいMTUを指定するよ
MTU_BYTES="1500" # MTU(Bytes)

# その他の設定を全部指定するよ
SECURITY_PROTECTION_FUNCTION="1" # セキュリティ保護機能 on:1 off:0
TCP_TIMER_SECONDS="1200" # NAPT設定 TCPタイマ(秒)
UDP_TIMER_SECONDS="100" # NAPT設定 UDPタイマ(秒)
UPNP_FUNCTION="0" # UPnP機能 on:1 off:0
DMZ_HOST_FUNCTION="0" # DMZホスト機能 on:1 off:0
IP_ADDRESS_OF_DMZ_HOST="" # DMZホストのIPアドレス
FIRMWARE_UPDATE_NOTIFICATION_FEATURE="1" # ファームウェア更新通知機能 on:1 off:0
LAMP_LIGHTING_MODE="0" # ランプ消灯モード 消灯:1 点灯:0
LAMP_OFF_TRANSITION_TIME="1" # ランプ消灯移行時間(分)
PING_RESPONSE_FUNCTION="1" # PING応答機能 on:1 off:0
QUALITY_REPORT_FUNCTION="0" # 品質情報収集機能 on:1 off:0

# mac の場合は互換性維持のために homebrew の ggrep, gsed を使いたい. Linux ではそのまま grep, sed を使う.
GREP_CMD=$(command -v ggrep || command -v grep)
SED_CMD=$(command -v gsed || command -v sed)

# ログインして sysauth をゲットするよ
SYSAUTH=$(curl -s -D - -d "luci_username=root" -d "Password=${PASSWORD}" http://${IP}/cgi-bin/luci/ \
  | "${GREP_CMD}" -i 'Set-Cookie: sysauth=' \
  | "${SED_CMD}" -n 's/^Set-Cookie: sysauth=\([^;]*\);.*/\1/p')

# 設定に必要な token を取得するよ
TOKEN=$(curl -s "http://${IP}/cgi-bin/luci/Advanced_Settings/Other_Settings" -b "sysauth=${SYSAUTH}" | "${GREP_CMD}" -oP 'id="token" value="\K[^"]+')

if [ -z "${TOKEN}" ]; then
  echo "--------------"
  echo "tokenが取得できなかった! Speed Wi-Fi HOME 5G L12 のIPアドレスと PASSWORD の値を確認してね."
  echo "--------------"

else
    POST_DATA="Security_Protection_Function_check=on&\
Security_Protection_Function=${SECURITY_PROTECTION_FUNCTION}&\
TCP_Timer_seconds=${TCP_TIMER_SECONDS}&\
UDP_Timer_seconds=${UDP_TIMER_SECONDS}&\
UPnP_Function=${UPNP_FUNCTION}&\
DMZ_Host_Function=${DMZ_HOST_FUNCTION}&\
IP_Address_of_DMZ_Host=${IP_ADDRESS_OF_DMZ_HOST}&\
Firmware_Update_Notification_Feature_check=on&\
Firmware_Update_Notification_Feature=${FIRMWARE_UPDATE_NOTIFICATION_FEATURE}&\
Lamp_Lighting_Mode=${LAMP_LIGHTING_MODE}&\
Lamp_Off_Transition_Time=${LAMP_OFF_TRANSITION_TIME}&\
MTU_bytes=${MTU_BYTES}&\
PING_Response_Function_check=on&\
PING_Response_Function=${PING_RESPONSE_FUNCTION}&\
Quality_Report_Function=${QUALITY_REPORT_FUNCTION}&\
button_id=Apply_9&\
token=${TOKEN}"

    # 実際に POSTしてみるよ.
    curl -X POST "http://${IP}/cgi-bin/luci/Advanced_Settings/Other_Settings/Apply_1" \
        -H "Content-Type: application/x-www-form-urlencoded" \
        -b "sysauth=${SYSAUTH}" \
        --data "${POST_DATA}" \
        -v
fi
  • レスポンスは 302
*   Trying 192.168.2.1:80...
* Connected to 192.168.2.1 (192.168.2.1) port 80
> POST /cgi-bin/luci/Advanced_Settings/Other_Settings/Apply_1 HTTP/1.1
> Host: 192.168.2.1
> User-Agent: curl/8.7.1
> Accept: */*
> Cookie: sysauth=3fe56f2e0086af243bed7f956152f47e
> Content-Type: application/x-www-form-urlencoded
> Content-Length: 461
>
* upload completely sent off: 461 bytes
< HTTP/1.1 302 Found
< Connection: Keep-Alive
< Transfer-Encoding: chunked
< Keep-Alive: timeout=20
< Location: /cgi-bin/luci/Advanced_Settings/Other_Settings
<
* Connection #0 to host 192.168.2.1 left intact

最適な MTU を設定する

MTU の最適な値は ping で調べられる. まずルーターの MTU を最大の 1500 にして 1472 のサイズの ping をしてみる. パケットの分割(fragment)が起きていたら MTU の値が大きすぎるので, ルーターの MTU はそのままに, ping のサイズだけ 1472 から下げていって実験を進める. fragment が起きなくなる最大の MTU をルーターに設定する. ping は OS によって引数がバラバラ. macOS だとこんな感じ.

MTU=1500
# MTU からヘッダー部分の28を引いた値で PING する
ping -D -s $(($MTU - 28)) 8.8.8.8
  • 出力に fragment に関する情報がないか確認する
# 556 bytes from openwrt.lan (192.168.2.1): frag needed and DF set (MTU 1440)
# Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
#  4  5  00 bc05 8f4c   0 0000  40  01 d326 192.168.2.22  8.8.8.8
  • macOS なので homebrew の nmap に含まれている nping を使ってみる. SENT に対して RCVD が返ってくれば 分割されずに送信できている. ICMP の優先順位は低いため応答が返ってこない場合もある. そのため 3 回試行することにした.
MAX_MTU=1500
MIN_MTU=1028

for i in $(seq "$MAX_MTU" -1 "$MIN_MTU"); do
  SIZE=$(($i - 28))
  echo "Testing size: ${SIZE}  (MTU: ${i})"
	# --icmp:ICMP Echo Request
	# --df:Don’t Fragment フラグをセット
	# --data-length 1472:ペイロードサイズ
	# -c 3:3パケット(回)送信
  sudo nping --icmp --df -c 3 --data-length "${SIZE}" 8.8.8.8 | grep -E 'SENT|RCVD'
  sleep 0.5
done

いろいろやってみた感想

今回は楽天モバイルの SIM で試した. ここまでやっておいてなんだけど, あんまり速度がでないものだからがっかりした. ルーターのせいなのか, 電波環境のせいなのか, 楽天モバイルのせいなのかは切り分けしないとだけど, めんどくさいなー.