Skip to content

feat: QUIC ハンドシェイク RTT で死活監視する via=quic モードを追加#13

Merged
yuu61 merged 4 commits into
masterfrom
feature/quic-ping
Jun 11, 2026
Merged

feat: QUIC ハンドシェイク RTT で死活監視する via=quic モードを追加#13
yuu61 merged 4 commits into
masterfrom
feature/quic-ping

Conversation

@yuu61

@yuu61 yuu61 commented Jun 11, 2026

Copy link
Copy Markdown
Owner

概要

ping over QUIC モード(via=quic)を追加します。upstream 作者の qping に着想を得たもので、毎プローブで新規 QUIC(TLS1.3)ハンドシェイクを張り、dial→確立完了までの壁時計を RTT として測ります。deadman のステートレス単発 Send 契約にそのまま収まる、tcp= 接続プローブの in-process な兄弟です。

設定(README も同時更新)

name ADDR via=quic [port=443] [alpn=h3] [sni=NAME] [verify=on] [resolve_family=ipv4|ipv6]
  • verify は既定 OFFInsecureSkipVerify)。QUIC プローブは IP アドレスを直接対象にすることが多く、証明書/SAN 検査でほぼ毎回失敗するため(routeros とは既定が逆)。verify=on でオプトイン。
  • source= は非対応DialAddr[::]:0 を bind するため)。指定すると無視+起動時警告。
  • resolve_family は直接 ICMP と via=quic で有効(A/AAAA 固定)。IP リテラルは対象外。
  • 既定ポート 443・ALPN h3。SNI は省略時ホスト名、IP リテラルは空(ゾーン付き IPv6 も literal 判定)。

RTT の意味

これはセッション確立 RTT で、TLS1.3 の暗号処理を含むため ICMP よりやや高めに出ます。qping の「確立済み接続上で PING フレームを撃つ定常 RTT」とは別物です(quic-go の公開 API にオンデマンドで PING を撃つ手段が無く、ステートレス契約に綺麗に収まる確立 RTT を採用しました)。README に明記しています。

依存

  • github.com/quic-go/quic-go v0.60.0(基盤 quic パッケージのみ使用、qpack は不要)。
  • バイナリ増分は 約 +1.2MB(7.86 → 9.0MB, stripped)。go 1.25.0 据え置き。

内部設計

  • 失敗は error ではなく Result.Code(既存契約を踏襲、X グリフ)。
  • ディスパッチを methodRegistrymap[Method]{build, name, sourceUnsupported})に集約。New / SourceUnsupported / 起動時の source 無効警告のモード一覧を単一ソースから導出し、文言 drift を構造的に防止。Describe は Spec 依存ラベルのため switch 据え置き。

テスト・検証

  • 単体: verify 既定反転 / SNI / port 構築時検証 / ゾーン付き IPv6 / resolve_family 配線 / 設定パース。
  • 手動(//go:build manual): 到達(dns.google・1.1.1.1+sni)/ 不達(TEST-NET タイムアウト)/ リーク監視(30 プローブで goroutine・fd 増分ゼロ)
  • make check(tidy-check / fmt-check / vet / lint 0 issues / test)green、make cross(6 OS×arch)green。

備考

  • lint 設定に goconst: ignore-tests: true を追加(レジストリの name がテストのケース名と綴り重複する誤検知の回避。既存の test 除外方針の完成形)。
  • 本ブランチのコミットは署名なしです(開発環境の WSL から Windows 側 gpg を実行できないため)。必要なら merge 前に署名し直してください。

yuu61 added 3 commits June 11, 2026 19:16
毎プローブで新規 QUIC(TLS1.3) ハンドシェイクを張り、dial→確立完了までの
壁時計を RTT とする。ステートレス単発 Send 契約のままで、tcp= 接続プローブの
in-process な兄弟。CloseWithError で毎回ソケットを回収し、連続運用でも
goroutine/fd をリークしないことを手動テストで確認。

設定: via=quic [port=443] [alpn=h3] [sni=NAME] [verify=on]。
TLS 証明書検証は既定 OFF(IP 宛プローブ向け、routeros と逆)。source= は
DialAddr が [::]:0 を bind するため非対応(無視+起動時警告)。

依存: github.com/quic-go/quic-go v0.60.0(基盤 quic パッケージのみ使用、
qpack は不要)。バイナリ増分は約 +1.2MB。

テスト: 単体(verify 既定反転・SNI/port/alpn)、config パース、手動
(到達/不達/リーク監視)を追加。README と deadman.conf を更新。
- RTT 計測窓から DNS 解決を分離: ホスト名は Send 直前に解決し、計測は
  handshake のみにする(直接 ICMP と同じ。dns.google 実測で 62ms→25ms)。
- port= を構築時に検証: 無効値(abc/0/99999 等)は起動時警告+永続 X 行と
  なり、サイレント X のデバッグを回避(routeros の username 検証と同様)。
- ゾーン付き IPv6 リテラル fe80::1%eth0 を netip.ParseAddr で literal 判定し、
  ゾーンが SNI に漏れないようにする(icmp_linux.go と同じ理由)。
- source= 無視の警告文言とテストコメントに quic を追加(本 PR の取りこぼし)。
- README: resolve_family が quic で無視される理由文を訂正(quic はローカル解決)。
- 単体テスト追加: 無効 port/ゾーン IPv6 の SNI 空/literal の resolveAddr。

見送り(理由): 永続 Transport 化=Pinger に Close() が無くリロード時に socket
リーク/t グリフ=in-process 系は X に統一する既存方針/per-mode キー集合・
Method→capability テーブル=本 PR の範囲外(follow-up 候補)。
…honor

follow-up 対応(コードレビュー #10 / #4):

#10 source 可否の二重管理を解消:
- Method ごとの {build, name, sourceUnsupported} を methodRegistry に集約。
  New はテーブル参照になり、先の gocyclo/cyclop nolint を解消。
- SourceUnsupported とその起動時警告のモード一覧を同一レジストリから導出し、
  文言の取りこぼし(本 PR で起きた #2)を構造的に防止。SourceUnsupportedModeNames
  を公開し parse_warn が自動生成。Describe は Spec 依存のため switch 据え置き。

#4(B) via=quic で resolve_family を honor:
- quicPinger に解決ネットワークを持たせ LookupNetIP に反映(A/AAAA 固定)。
  IP リテラルはファミリー確定済みのため対象外。README 契約を
  「direct ICMP と via=quic で有効」に更新。

lint:
- goconst を ignore-tests に(モード名とテストのケース名の綴り重複による誤検知を
  回避。既存の test 除外方針の完成)。不要になった config の //nolint:goconst を削除。

テスト追加: TestSourceModeNames / TestNewQUICPingerResolveFamily。

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 166755dd85

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/ping/quic.go
@claude

claude Bot commented Jun 11, 2026

Copy link
Copy Markdown

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

コードレビューの P1 指摘(IPv6 ターゲットで DialAddr が機能しない)を実測検証。
quic-go の net.ListenUDP("udp", {IP: net.IPv4zero}) は IPv4zero が wildcard の
ため Go が [::] の dual-stack ソケットを開き、IPv6 にも届く(実測: LocalAddr=[::]、
IPv6/IPv4 とも WriteToUDP 成功、IPv6 リテラル h3 へのハンドシェイクも rtt~50ms で
成立)。よって family 別 PacketConn 化は不要。TestQUICReachableIPv6 で回帰を固定。
@yuu61 yuu61 merged commit 3e456e0 into master Jun 11, 2026
5 checks passed
@yuu61 yuu61 deleted the feature/quic-ping branch June 11, 2026 13:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant