Armbian に sing-box TUN をデプロイした後、少し分かりにくい問題が発生しました:IPv6 の ping は通るのに、auto_redirect を有効化すると IPv6 の HTTPS 接続がタイムアウトする的情况です。

调查结果、障害の原因は IPv6 の公網ルートやプロキシノードではなく、Linux のループバックインターフェース lo に ::1/128 アドレスが存在しないことでした。本稿では、その切り分け Processes .Ordinal and 修正方法を記録します。

環境

  • Linux:Armbian、ARM64、6.18 系カーネル
  • sing-box:1.14.x
  • ネットワーク管理:Netplan + NetworkManager
  • 透過プロキシ:TUN、auto_route: true、auto_redirect: true
  • IPv6:上位ネットワークから自動設定され、インターフェースにはグローバル IPv6 アドレスと RA によるデフォルトルートが設定済み

プライバシーを保護するため、実際の公衆アドレス、MAC アドレス、ルーターアドレス、ドメイン名、およびカスタム内部ルーティングテーブル番号は省略しています。以下の例にある ULA アドレスとテスト対象は説明용です。

障害的现象

IPv6 HTTPS を直接テストします。

curl --noproxy '*' -6 -v --connect-timeout 5 \
  --resolve 'cloudflare.com:443:[2606:4700::6810:85e5]' \
  https://cloudflare.com/

sing-box を有効化した後:

* Trying [2606:4700::6810:85e5]:443...
* Connection timed out after 5002 milliseconds
curl: (28) Connection timed out

比較テスト:

状態IPv6 HTTPS
sing-box 停止中正常
auto_redirect: trueタイムアウト
auto_redirect: false正常

ただし、単純な ping -6 テストは成功する場合があります。ICMP の疎通確認だけでは、TCP/HTTPS のテストを代替できません。

切り分け Processes.Ordinal

1. IPv6 アドレスとデフォルトルートの問題を排除

ip -6 addr show dev eth0 scope global
ip -6 route show default

インターフェースにはすでにグローバル IPv6 アドレスがあり、デフォルトルートは RA によって学習されています。形式は次のとおりです。

default via fe80::... dev eth0 proto ra

NetworkManager が IPv6 を管理している場合、net.ipv6.conf.eth0.accept_ra の値だけで RA が正常に機能しているかを判断してはいけません。実際のアドレスとルートを併せて確認する必要があります。

2. TCP が tun0 または eth0 に直接現れないことを 발견

HTTPS 対象をパケットキャプチャで確認します。

sudo tcpdump -ni tun0 'ip6 and tcp port 443'
sudo tcpdump -ni eth0 'ip6 and tcp port 443'

auto_redirect を有効化している場合、想定される宛先への IPv6 TCP SYN が確認できませんでした。これは必ずパケット損失を意味しません。sing-box の nftables ルールが、TCP をまずローカルポートへリダイレクトしている可能性があります。

3. nftables のローカル REDIRECT を確認

sudo nft -a list table inet sing-box

ルールには次のような内容が存在しました。

meta l4proto tcp ... queue flags bypass to 100
meta l4proto tcp ... redirect to :23457 return

ここでのポートは、今回の切り分け環境における内部リスニングポートです。別のバージョンや設定では異なる場合があります。IPv6 のリスニング状態を確認します。

sudo ss -6 -lntp '( sport = :23457 )'

確かに sing-box はそのポートをリスニングしていました。

続いてループバックインターフェースもキャプチャします。

sudo tcpdump -ni lo -vv 'tcp port 23457'

このとき、重要なパケットは次の形式でした。

IP6 2001:db8::1234.4210 > ::1.23457: Flags [S]
IP6 2001:db8::1234.4210 > ::1.23457: Flags [S]
IP6 2001:db8::1234.4210 > ::1.23457: Flags [S]

上記の 2001:db8::/32 は文書専用の IPv6 プレフィックスであり、実際の公衆アドレスではありません。

SYN が繰り返し再送され、SYN-ACK が返っていません。これは、接続がローカル ::1 へリダイレクトされているものの、ローカル TCP ハンドシェイクが完了していないことを示しています。

4. 根本原因を特定:ループバックインターフェースに IPv6 アドレスがない

ip -6 addr show dev lo

出力は驚くほど空でした。正常な場合、ループバックインターフェースには次が存在するはずです。

inet6 ::1/128 scope host

::1/128 が存在しないため、IPv6 TCP REDIRECT でローカル ::1 を指定しても、接続を正常に確立できませんでした。これは、繰り返し送信された SYN と SYN-ACK がない現象と一致しています。

修正方法

まず lo の IPv6 状態を確認します。

ip link show lo
sysctl net.ipv6.conf.lo.disable_ipv6
ip -6 addr show dev lo

IPv6 が無効になっている場合:

sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=0

ループバックインターフェースが有効になっていることを確認します。

sudo ip link set lo up

::1/128 がまだ表示されない場合は、手動で追加します。

sudo ip -6 addr add ::1/128 dev lo

検証します。

ip -6 addr show dev lo
ping -6 -c 2 ::1
curl --noproxy '*' -6 --connect-timeout 5 https://api6.ipify.org

auto_redirect: true の状態でも HTTPS が正常であることを確認して、ようやく障害が解決したといえることになります。

問題が再起動後に発生する場合は、/etc/sysctl.d/ に lo の IPv6 を無効化する設定が存在しないか確認し、sysctl 設定ファイルで明示的に次のように設定できます。

net.ipv6.conf.lo.disable_ipv6 = 0

注意点として、この設定は lo の IPv6 が無効化されていないことを保証するだけにすぎ、::1/128 が常に存在することを自動的に保証するわけではありません。再起動後にアドレスが再び消えた場合は、起動順序や lo を管理するサービスの調査を継続する必要があります。

まとめ

  • IPv6 の ping が成功しても、IPv6 TCP プロキシが正常であるとは限らないため、実際の HTTPS リクエストで検証する必要があります。
  • sing-box の auto_redirect を有効化すると、一部の TCP トラフィックが nftables によってローカルポートへリダイレクトされます。eth0 または tun0 だけをキャプチャしても、想定した宛先へのトラフィックを確認できない場合があります。
  • ss でリスニング状態を確認し、tcpdump -i lo で SYN の再送信 발견することが、今回の切り分けにおける鍵となりました。
  • 最終的な障害点は、lo に IPv6 ループバックアドレス ::1/128 が欠落していたことでした。
  • auto_redirect を一時的に無効化すれば問題を回避できますが、今回の障害に対する本来の実質的な修正は、ループバックインターフェースを修正することです。

診断コマンド早見表

ip -6 addr show dev lo
sysctl net.ipv6.conf.lo.disable_ipv6
ip -6 route show default
sudo nft -a list table inet sing-box
sudo ss -6 -lntp '( sport = :23457 )'
sudo tcpdump -ni lo 'tcp port 23457'

補足:UFW を有効化した後、下流デバイスからインターネットに接続できない問題

IPv6 のループバック問題륧解決した後、Armbian で UFW を有効化したところ、新たな現象が発生しました:Armbian 本体はネットワークへ正常にアクセスできるのに、Armbian を経由している下流デバイスからはネットワークへ正常にアクセスできないという問題です。

まず、UFW のブロックログを確認します。

sudo ufw logging medium
sudo journalctl -k -f -o cat | grep --line-buffered 'UFW BLOCK'

以下は匿名化済みの代表的なログです。IP アドレスには RFC 5737 の文書用サンプルアドレスを使用しているため、実際のネットワーク設定へそのまま転用することはできません。

[UFW BLOCK] IN=eth0 OUT= SRC=192.0.2.20 DST=192.0.2.254 PROTO=TCP DPT=9091 SYN
[UFW BLOCK] IN=eth0 OUT= SRC=192.0.2.20 DST=192.0.2.254 PROTO=TCP DPT=22703 SYN

ここで OUT= が空で、宛先がローカルアドレスになっているため、これらのリクエストは通常の FORWARD ではなく、**INPUT(Armbian 本体へのアクセス)**として识别されています。之前に deny routed を直接疑っただけでは、説明が完全ではありませんでした。

続いて、次のコマンドでリスニングプロセスを確認します。

sudo ss -lntup | grep -E ':(9091|22703)\b'

結果では、2 つの TCP ポートのいずれも sing-box がリスニングしており、一方は LAN の IPv4 アドレス、もう一方はワイルドカードアドレスにバインドされていました。該当する inbound ポートを許可すると、下流デバイスからインターネットへ接続 Again became possible. ただし強調すべき点があります。これはポートの到達可能性と障害が関係することを証明しますが、リスニング結果だけから、これらが TUN ポートや特定機能のものであるとは推定できません。sing-box の設定を確認して、具体的な用途を特定する必要があります。

サービスが LAN 内でのみ使用される場合、UFW のルール在实际の LAN アドレスとサブネットに限定するようにできます。以下は RFC 5737 のサンプルサブネットを使用するルールテンプレートであり、実際の値に置き換える必要があります。

sudo ufw allow in on eth0 from 192.0.2.0/24 to 192.0.2.254 port 9091 proto tcp
sudo ufw allow in on eth0 from 192.0.2.0/24 to 192.0.2.254 port 22703 proto tcp

セキュリティ上の注意:送信元を制限していない ufw allow 22703/tcp の直接実行は推奨しません。ポートがワイルドカードアドレスでリスニングされている場合には、公衆 IPv6 へ意図せず公開されていないか特に確認してください。また、下流デバイスからインターネットへ接続できない状態を解消するため、すべての routed トラフィックを恒久的にデフォルト許可にするのも 바람직하지 않습니다。

今回の補足における切り分けの要点は、まず IN / OUT で INPUT と FORWARD を区別し、次にリスニングプロセスを確認し、最後に実際の送信元に基づいて精密に許可することです。UFW のステータスページは nft list ruleset の代替にはなりません。sing-box の auto_redirect には 별도의 nftables ルールが存在するためです。