はじめに
Note
どちらかというと東日本の方向け。
現在我が家では、次のようなネットワーク構成になっています。
いい加減XG-100NEのレンタル代がもったいないので、今回はOpenwrtにIPv6を完全移譲・NVR500でDHCPv4を受け取って電話処理のみをさせる構成に変えていこうと思います。
Openwrtでbr-wanブリッジを作り、内部的にONUからOpenwrtとNVRがぶら下がっている形にします。
普通のL2スイッチで繋げてもたぶん行けると思いますが、10Gスイッチが必要になると考えたらブリッジのほうが楽です。
前提
次の構成で検証しています。
- 回線: enひかりクロス・v6プラス固定IP1・ひかり電話
- 契約地域: 東日本
- Openwrt 25.12.1
検証
まずはいくつか回線検証を行います。
- ONUから正常にDHCP-v6 PDで/56のプレフィックスが降ってくるかどうか
- ONUから正常にひかり電話用のDHCPv4が降ってくるかどうか
今回はLiveUSBから起動したUbuntu 24.04を使用します。
以下のスクリプトを使うと便利かもしれません。
折り畳んでいます
sudo apt update
sudo apt install -y isc-dhcp-client tcpdump tshark
#!/bin/bash
# v6_v4_probe.sh
# ONU 直結時の DHCPv6-PD と DHCPv4 を同時調査する
#
# Usage: sudo ./v6_v4_probe.sh <NIC>
# Example: sudo ./v6_v4_probe.sh eth0
set -u
# ============================================================
# 引数 / 事前チェック
# ============================================================
if [ $# -ne 1 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
cat <<EOF
Usage: sudo $0 <NIC>
NIC 名は \`ip -br link\` で確認できます。
例:
sudo $0 enx04ab18fe556e
sudo $0 enp3s0
NetworkManager / systemd-networkd / dhcpcd を自動停止し、
DHCPv6-PD と DHCPv4 を順次取得して結果をまとめます。
ログは /tmp/v6v4-probe-<timestamp>/ に保存されます。
EOF
exit 1
fi
IFACE="$1"
if [ "$EUID" -ne 0 ]; then
echo "[ERROR] root 権限が必要です: sudo $0 $IFACE" >&2
exit 1
fi
if ! ip link show "$IFACE" &>/dev/null; then
echo "[ERROR] インターフェース $IFACE が見つかりません" >&2
echo "" >&2
echo "利用可能な NIC:" >&2
ip -br link >&2
exit 1
fi
for cmd in dhclient tcpdump ip; do
if ! command -v "$cmd" &>/dev/null; then
echo "[ERROR] $cmd が見つかりません" >&2
echo " sudo apt install -y isc-dhcp-client tcpdump" >&2
echo " (option 125 自動抽出に tshark もあると便利)" >&2
exit 1
fi
done
# tshark は任意(あれば SIP 抽出が自動化される)
if ! command -v tshark &>/dev/null; then
echo "[INFO] tshark 未インストール。SIP 情報は pcap を Wireshark で見てください"
echo " (自動抽出したい場合: sudo apt install -y tshark)"
fi
# ============================================================
# ログディレクトリ
# ============================================================
TS=$(date +%Y%m%d-%H%M%S)
LOGDIR="/tmp/v6v4-probe-${TS}"
mkdir -p "$LOGDIR"
# ============================================================
# クリーンアップ(EXIT/INT/TERM 時)
# ============================================================
PIDS=()
STOPPED_SVCS=()
cleanup() {
echo ""
echo "[INFO] 後片付け中..."
# バックグラウンドプロセス停止
for pid in "${PIDS[@]}"; do
kill "$pid" 2>/dev/null || true
done
# dhclient 停止
pkill -f "dhclient.*${IFACE}" 2>/dev/null || true
sleep 1
echo ""
echo "[INFO] ログ保存先: $LOGDIR"
if [ ${#STOPPED_SVCS[@]} -gt 0 ]; then
echo ""
echo "[INFO] 停止したサービス(必要なら手動で復帰):"
for svc in "${STOPPED_SVCS[@]}"; do
echo " sudo systemctl start $svc"
done
fi
}
trap cleanup EXIT INT TERM
# ============================================================
# 干渉サービス停止
# ============================================================
echo "[INFO] 干渉する可能性のあるサービスを停止..."
for svc in NetworkManager systemd-networkd wpa_supplicant dhcpcd; do
if systemctl is-active --quiet "$svc" 2>/dev/null; then
echo " - $svc を停止"
systemctl stop "$svc"
STOPPED_SVCS+=("$svc")
fi
done
# 既存 dhclient プロセス停止
pkill -f "dhclient.*${IFACE}" 2>/dev/null || true
sleep 1
# ============================================================
# インターフェース UP
# ============================================================
echo "[INFO] $IFACE を up..."
ip link set "$IFACE" up
sleep 2
if ip link show "$IFACE" | grep -q "NO-CARRIER"; then
echo "[WARN] $IFACE がリンクダウンしています。ケーブル接続を確認してください"
echo " 5秒待って再確認します..."
sleep 5
if ip link show "$IFACE" | grep -q "NO-CARRIER"; then
echo "[ERROR] リンクアップしません。中断します"
exit 1
fi
fi
echo "[INFO] リンクアップ確認 OK"
# ============================================================
# tcpdump 起動(3 種類並列)
# ============================================================
echo "[INFO] パケットキャプチャ開始..."
# DHCPv4 pcap
tcpdump -i "$IFACE" -nev -s 0 -w "$LOGDIR/dhcpv4.pcap" \
'port 67 or port 68' >/dev/null 2>"$LOGDIR/tcpdump-v4.err" &
PIDS+=($!)
# DHCPv6 pcap
tcpdump -i "$IFACE" -nev -s 0 -w "$LOGDIR/dhcpv6.pcap" \
'ip6 and (port 546 or port 547)' >/dev/null 2>"$LOGDIR/tcpdump-v6.err" &
PIDS+=($!)
# 全関連トラフィックのテキストログ
tcpdump -i "$IFACE" -nev -s 0 \
'(port 67 or port 68) or (ip6 and (port 546 or port 547)) or icmp6' \
>"$LOGDIR/all-traffic.log" 2>&1 &
PIDS+=($!)
sleep 2
# ============================================================
# DHCPv6-PD 取得
# ============================================================
echo ""
echo "============================================================"
echo " DHCPv6-PD (IPv6 Prefix Delegation)"
echo "============================================================"
timeout 30 dhclient -6 -P -v "$IFACE" 2>&1 | tee "$LOGDIR/dhclient-v6.log" || true
echo ""
sleep 3
# ============================================================
# DHCPv4 取得
# ============================================================
echo "============================================================"
echo " DHCPv4"
echo "============================================================"
dhclient -r "$IFACE" 2>/dev/null || true
sleep 1
timeout 30 dhclient -v "$IFACE" 2>&1 | tee "$LOGDIR/dhclient-v4.log" || true
echo ""
# RA を追加で待つ
echo "[INFO] 追加の RA を 5 秒待機..."
sleep 5
# ============================================================
# 最終状態スナップショット
# ============================================================
{
echo "===== ip -6 addr show dev $IFACE ====="
ip -6 addr show dev "$IFACE"
echo ""
echo "===== ip -4 addr show dev $IFACE ====="
ip -4 addr show dev "$IFACE"
echo ""
echo "===== ip -6 route ====="
ip -6 route
echo ""
echo "===== ip -4 route ====="
ip -4 route
} > "$LOGDIR/final-state.txt"
# tcpdump 停止
for pid in "${PIDS[@]}"; do
kill "$pid" 2>/dev/null || true
done
wait 2>/dev/null || true
PIDS=()
# ============================================================
# サマリ表示
# ============================================================
echo ""
echo "============================================================"
echo " 結果サマリ"
echo "============================================================"
# --- IPv6 ---
echo ""
echo "IPv6"
echo "----"
PD_LINE=$(grep -E "IAPREFIX|IA_PD-prefix" "$LOGDIR/dhclient-v6.log" 2>/dev/null | head -1)
if [ -n "$PD_LINE" ]; then
PD=$(echo "$PD_LINE" | grep -oE '[0-9a-f:]+/[0-9]+')
echo " 受領 PD : $PD"
PD_SIZE=$(echo "$PD" | grep -oE '/[0-9]+')
echo " サイズ : $PD_SIZE"
else
echo " 受領 PD : (取得失敗)"
fi
V6_ADDRS=$(ip -6 addr show dev "$IFACE" | awk '/inet6/ && !/fe80/ {print $2}')
if [ -n "$V6_ADDRS" ]; then
echo " IF アドレス :"
echo "$V6_ADDRS" | sed 's/^/ /'
fi
# --- IPv4 ---
echo ""
echo "IPv4"
echo "----"
V4_ADDR=$(ip -4 addr show dev "$IFACE" | awk '/inet / {print $2}' | head -1)
if [ -n "$V4_ADDR" ]; then
echo " IF アドレス : $V4_ADDR"
V4_MASK=$(echo "$V4_ADDR" | grep -oE '/[0-9]+')
if [ "$V4_MASK" = "/30" ]; then
echo " /30 リース : YES(ひかり電話セグメントの可能性大)"
else
echo " /30 リース : NO($V4_MASK)"
fi
else
echo " IF アドレス : (取得失敗)"
fi
# --- DHCP オプション ---
echo ""
echo "DHCPv4 SIP情報"
echo "----"
SIP_HIT=0
if command -v tshark &>/dev/null && [ -s "$LOGDIR/dhcpv4.pcap" ]; then
OPT125=$(tshark -r "$LOGDIR/dhcpv4.pcap" -V 2>/dev/null | \
awk '/Option: \(125\)/,/Option: \([0-9]+\)/' | head -40)
if [ -n "$OPT125" ]; then
echo "$OPT125" | sed 's/^/ /'
SIP_HIT=1
fi
# ntt-east / ntt-west / sip 文字列が pcap 内に存在するか
if tshark -r "$LOGDIR/dhcpv4.pcap" -V 2>/dev/null | grep -qiE "ntt-east|ntt-west|\.sip\."; then
echo ""
echo " SIP ドメイン文字列を検出"
SIP_HIT=1
fi
fi
if [ "$SIP_HIT" -eq 0 ]; then
echo " (tshark での自動抽出失敗 or オプション無し)"
echo " → Wireshark で $LOGDIR/dhcpv4.pcap を開いて手動確認"
echo " フィルタ: bootp.option.type == 125"
fi
# ============================================================
# 保存ファイル一覧
# ============================================================
echo ""
echo "============================================================"
echo " 保存ファイル"
echo "============================================================"
echo " $LOGDIR/"
echo " ├ dhclient-v6.log : DHCPv6-PD 詳細ログ"
echo " ├ dhclient-v4.log : DHCPv4 詳細ログ"
echo " ├ dhcpv6.pcap : DHCPv6 パケットキャプチャ"
echo " ├ dhcpv4.pcap : DHCPv4 パケットキャプチャ"
echo " ├ all-traffic.log : 全 DHCP + ICMPv6 テキストログ"
echo " └ final-state.txt : 最終的な ip addr / route スナップショット"
echo ""
echo "詳細解析:"
echo " wireshark $LOGDIR/dhcpv4.pcap"
echo " wireshark $LOGDIR/dhcpv6.pcap"
echo ""
出力ファイル
dhclient-v6.log
dhclient -6 -P -vの出力が入ります。
- 受領したPD プレフィックスとサイズ(IAPREFIX 行)
- リース時間(preferred-lifetime / valid-lifetime)
- 上流 DUID
- ステートマシンの遷移(Solicit → Advertise → Request → Reply)
dhclient-v4.log
dhclient -vの出力が入ります。
- 受領したIP/マスク(bound to ... 行)
- リース時間
- ACKパケットの要約
キャプチャファイル
この2つはClaudeとかに食わせて分析させると楽だと思います。
dhcpv6.pcap
DHCPv6の生パケットが入ります。
dhcpv4.pcap
DHCPv4の生パケットが入ります。
all-traffic.log
tcpdump -nevの出力が入ります。
- DHCPv6/v4 のやり取り(テキストサマリ)
- Router Advertisement(RA)の中身 ← pcapには記録しないのでRA見るならここ
- Prefix Information、MTU
- 上流ルータのlink-local
final-state.txt
ip addrとip routeの出力が入ります。
- IFに最終的に乗ったv6/v4アドレス
- v6/v4のルーティングテーブル
判定
Warning
- DHCPv6-PDのプレフィックスが/56である
- DHCP-v4で/30のリースが降ってくる
- デフォルトゲートウェイが取れている
option 121でSIP網118.177.0.0/16へのスタティックルートが含まれている(東日本の場合)
構築
NVR500
まずはNRV500のコンフィグを流し込みます。
作業用PCから192.168.100.1(デフォルトの場合)で接続します。
コンフィグは以下の通りです。インターフェースは適宜変えてください。
# WAN設定
ip lan2 address dhcp
ngn type lan2 ntt
dhcp client release linkdown on
# ひかり電話関連(東日本契約)
analog arrive number display 1 on
analog sip call display name 1 【電話番号】
analog sip arrive myaddress 1 1 sip:【電話番号】@ntt-east.ne.jp
analog arrive number display 2 on
analog supplementary-service pseudo call-waiting
analog extension emergency-call-dial type normal-number
analog extension dial prefix sip prefix="9#"
analog extension dial prefix routing route-table=1 ngn lan2
analog extension dial prefix port=1 routing route-table=1 ngn lan2
analog extension dial prefix port=2 routing route-table=1 ngn lan2
analog call route-table 1 1
analog call route 1 * * ngn lan2 * line
# SIP 有効化
sip use on
sip codec permit lan2 g711u
# 保存
save
流し込みが終わったら、show configでipv6から始まる行がないことを確認します。
あった場合はno ipv6 ...で消しましょう。これをやらないと家のインターネットが爆発します。
コマンドを受け付けなかった場合はファームを最新にしてみてください。
Openwrt
次はOpenwrtのコンフィグを流し込みます。バッチでコピペできるようにしときました。
まず、br-wanを作成します。インターフェースは適宜。
なお、現状のコンフィグはこの記事が前提になっているので適宜変えて下さい。
光クロス + 固定IP + ひかり電話の構成ならそんなに大きく変わらないと思います。
/etc/config/network
uci batch <<'EOF'
# br-wan
add network device
set network.@device[-1].name='br-wan'
set network.@device[-1].type='bridge'
add_list network.@device[-1].ports='eth2'
add_list network.@device[-1].ports='eth1'
# 所属変更
set network.wan6.device='br-wan'
set network.wan6_static.device='br-wan'
# PD サイズを明示
set network.wan6.reqprefix='56'
EOF
/etc/config/dhcp
uci batch <<'EOF'
# wan6のDHCPをリレーから受信のみに
set dhcp.wan6.ra='disabled'
set dhcp.wan6.dhcpv6='disabled'
set dhcp.wan6.ndp='disabled'
# lanのDHCPをリレーからサーバーモードに
set dhcp.lan.ra='server'
set dhcp.lan.ndp='disabled'
EOF
適用
Caution
service network reloadはしないでください。
uci changes
uci commit
物理切り替え
必ずLAN経由以外でのログイン手段を準備しておきましょう。
次のような形で繋ぎ替えます。
ここでservice network restartします。
繋がらないからって焦らないでください。
IF設定変更
ここからLuciで作業します。物理コンソールの人はAIにコマンド生成してもらってください。
デフォルトDUID削除
インターフェース->グローバルネットワークオプションのデフォルトDUIDを空にします。

wan4 IPIPトンネルインターフェース
詳細設定タブ
たぶんwan4とか命名しててプロトコル: IPv4 over IPv6 (RFC2473-IPIPv6)のやつです。
IPv6割り当て長:64IPv6割り当てヒント:0IPv6 prefix filter:wan6(プロトコル: DHCPv6クライアントのやつ)IPv6サフィックス:契約書類のインターフェイスID

DHCPサーバータブ
画像の通り

wan DHCPv6クライアント
詳細設定タブ
IPv6割り当て長:無効

DHCPサーバータブ
Designated master: チェックRA-Service:無効DHCP-v6 サービス:無効NDP プロキシ:無効

br-lan LANインターフェース
詳細設定タブ
IPv6割り当て長:64IPv6割り当てヒント:1

DHCPサーバータブ
-
IPv6設定->RA-Service:サーバーモード -
IPv6設定->DHCP-v6 サービス:サーバーモード -
IPv6設定->NDPプロキシ:無効

-
IPv6 RA設定->RAフラグ:managed config・other configに設定

動作確認
インターネット
ip -6 addr show dev br-wan: 変更前と同じv6アドレスが降ってきているかip -6 route | head -5: デフォルトルートがbr-wan経由になっていて、next-hopが検証で確認した上流の link-localを指しているかping6 -c 3 2001:4860:4860::8888: グローバルv6で外に出られるかip addr show dev ipip6-wan: IPIP6トンネルがUPしていて、固定IPが乗っているかping -c 3 8.8.8.8: トンネル経由で v4 が外に通るかcurl -4 ifconfig.io: 出口v4が固定IPになっているかcurl -6 ifconfig.io: 出口v6がPDで降ってきた/56配下のアドレスになっているか
ひかり電話
- NVR500で
show status lan2: IPが検証でリースされた/30系のものになっているか show ip route:118.177.0.0/16からのスタティックルートがあるかshow status sip:SIP REGISTERが成功しているか- 発信ができるか
- 受信ができるか
ここまで終われば、1週間くらい安定するか確認してからXG-100NEを返却しましょう。
トラブルシューティング
下の情報を集めてから適当にClaudeにぶちこめばなんとかしてくれます。
IPv6が降ってこない
logread | grep -i dhcpでodhcp6cの動作確認tcpdump -i br-wan -nev port 546 or port 547でDHCPv6のやり取りを見る
IPIPトンネルが上がらない
ip -6 addr show dev br-wanでソースのv6アドレスが正しく付与されているか。プレフィックスがズレていないか。- 契約書類にあったインターフェイスIDを含むアドレスがbr-wanに乗っているか
ひかり電話がREGISTERされない
show status lan2でNVR500がWAN側でIPv4を受け取れているか- 検証で取得したレンジのIPアドレスリースが取れているか
show ip routeで118.177.0.0/16へのスタティックルートが入っているかngn type lan2 nttが入っているかipv6系の設定が残っていないか- ONUとNVR500の間にL3機器が挟まっていないか
- SIPドメインが、東日本なら
ntt-east.ne.jp・西日本ならntt-west.ne.jpになっているか - ファームは最新か
