Cover Image for Openwrt + NVR500でフレッツ光クロスとひかり電話を使う

Openwrt + NVR500でフレッツ光クロスとひかり電話を使う

2026/05/30
...

はじめに

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
probe.sh
#!/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を作成します。インターフェースは適宜。

なお、現状のコンフィグはこの記事が前提になっているので適宜変えて下さい。

openwrtでenひかりクロス+v6プラス+固定IP+ひかり電話環境用ルーターを作った - Qiita
はじめに ひかり電話を契約しているので、ONU直結ではないです。 XG-100NE(HGW)の配下トンネル手順になります。 最近になってProxmoxのVMや家の中のネットワークデバイスが増え、XG-100NEの動作が不安定になってきました。 また、ポート開放時に...
openwrtでenひかりクロス+v6プラス+固定IP+ひかり電話環境用ルーターを作った - Qiita favicon https://qiita.com/katori_m/items/92fd87ea8206d4ec6bb7
openwrtでenひかりクロス+v6プラス+固定IP+ひかり電話環境用ルーターを作った - Qiita

光クロス + 固定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を空にします。
    image.png

wan4 IPIPトンネルインターフェース

詳細設定タブ

たぶんwan4とか命名しててプロトコル: IPv4 over IPv6 (RFC2473-IPIPv6)のやつです。

  • IPv6割り当て長: 64
  • IPv6割り当てヒント: 0
  • IPv6 prefix filter: wan6(プロトコル: DHCPv6クライアントのやつ)
  • IPv6サフィックス: 契約書類のインターフェイスID
    image.png

DHCPサーバータブ

画像の通り
image.png

wan DHCPv6クライアント

詳細設定タブ

  • IPv6割り当て長: 無効
    image.png

DHCPサーバータブ

  • Designated master: チェック
  • RA-Service: 無効
  • DHCP-v6 サービス: 無効
  • NDP プロキシ: 無効
    image.png

br-lan LANインターフェース

詳細設定タブ

  • IPv6割り当て長: 64
  • IPv6割り当てヒント: 1
    image.png

DHCPサーバータブ

  • IPv6設定 -> RA-Service: サーバーモード

  • IPv6設定 -> DHCP-v6 サービス: サーバーモード

  • IPv6設定 -> NDPプロキシ: 無効
    image.png

  • IPv6 RA設定 -> RAフラグ: managed config・other configに設定
    image.png

動作確認

インターネット

  • 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になっているか
  • ファームは最新か