feat(core): add REALITY target scanner#695
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughAdds a REALITY target scanning workflow across backend models, public-network TLS probing, authenticated API handling, frontend service integration, editor controls, result visualization, and unit coverage. ChangesReality scan workflow
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant XrayInboundsSection
participant RealityScanDialog
participant BackendAPI
participant scan_reality_target
participant TLSProbes
XrayInboundsSection->>RealityScanDialog: Open with target and initial SNI
RealityScanDialog->>BackendAPI: Submit target, SNI, and timeout
BackendAPI->>scan_reality_target: Resolve and scan target
scan_reality_target->>TLSProbes: Run TLS, group, and HTTP/3 probes
TLSProbes-->>scan_reality_target: Negotiation and certificate metadata
scan_reality_target-->>BackendAPI: RealityScanResult
BackendAPI-->>RealityScanDialog: Return scan result
RealityScanDialog-->>XrayInboundsSection: Render feasibility and probe details
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Note Unit test generation is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it. Generating unit tests... This may take up to 20 minutes. |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/utils/reality_scan.py`:
- Around line 549-554: Move _resolve_public_ip_async inside the
_get_scan_semaphore context in scan_reality_target, keeping DNS_TIMEOUT clamping
and the subsequent _scan_sync call intact. Update
tests/test_reality_scan_unit.py lines 390-406 in test_scan_concurrency_is_capped
to track and assert resolver concurrency is capped by the same semaphore.
In `@dashboard/src/features/core-editor/components/xray/reality-scan-dialog.tsx`:
- Around line 62-69: Update the dialog reset effect and runScan flow to cancel
any in-flight scan when the dialog closes or resets. Reuse the existing signal
parameter in runScan, abort the previous request before clearing state, and
ensure stale scan completions cannot update result, errorMessage, or isScanning
for the new target.
In
`@dashboard/src/features/core-editor/components/xray/xray-inbounds-section.tsx`:
- Around line 4012-4016: The REALITY scanner must preserve the configured SNI
when scanning a target. In
dashboard/src/features/core-editor/components/xray/xray-inbounds-section.tsx
lines 4012-4016, extract the configured server name alongside the target and
pass it when opening the scanner; in
dashboard/src/features/core-editor/components/xray/reality-scan-dialog.tsx lines
71-81, accept that SNI and include it in the scanRealityTarget request.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 71c9437b-f3a3-4b3d-9741-832ce2e49795
📒 Files selected for processing (8)
app/models/reality_scan.pyapp/operation/core.pyapp/routers/core.pyapp/utils/reality_scan.pydashboard/src/features/core-editor/components/xray/reality-scan-dialog.tsxdashboard/src/features/core-editor/components/xray/xray-inbounds-section.tsxdashboard/src/service/reality-scan.tstests/test_reality_scan_unit.py
|
Request timed out after 900000ms (requestId=715f7044-de8a-4e6d-8556-e73d11375206) |
Add a POST /api/core/reality-scan endpoint and a "Scan target" button in the Xray inbound editor to probe a candidate REALITY dest and report whether it is a good decoy: TLS 1.3, HTTP/2 (ALPN), X25519 / post-quantum (X25519MLKEM768) key exchange, HTTP/3 advertisement, certificate validity and SANs, plus handshake latency. Security: every target is resolved and pinned to a public IP, so private, loopback, link-local, reserved and cloud-metadata addresses are rejected and the pinned connection cannot be bypassed by DNS rebinding. DNS and concurrent scans are bounded, and each sub-probe is isolated so a partial failure degrades a single field to "unknown" instead of failing the scan. The key-group probe is a self-contained raw TLS 1.3 ClientHello/ServerHello parser, so it detects MLKEM even where the panel's OpenSSL predates it. Gated behind the cores:read permission. Includes backend unit tests.
17381e7 to
0a94cd8
Compare
|
@coderabbitai review |
✅ Action performedReview finished.
|
- _h3_probe: bound the response read with an absolute deadline (was a per-recv timeout only) and cap the whole scan with asyncio.wait_for, so a slowloris target cannot pin a scan slot/thread for a long time. - parse_target: reject control characters (CR/LF/NUL/tab) in target and sni, preventing header injection into the h3 probe request. - dashboard: coerce a non-string FastAPI 422 detail (array/object) to text in getErrorMessage so a validation error cannot crash the dialog render. - dashboard: when every REALITY serverName is a wildcard, scan without an SNI instead of sending an invalid "*.host" SNI.
Turn the REALITY scanner into a batch tool: add targets as chips (type and press space, comma, or enter; paste a whitespace/comma/newline list) and each is probed against the existing /api/core/reality-scan endpoint, bounded to a small client-side concurrency pool (the backend semaphore already caps real concurrency). Results stream in as compact per-target rows (verdict, TLS 1.3 / HTTP/2 badges, latency) that expand to the full detail card, with a "suitable only" filter and a running suitable/total count. A single target keeps the original detailed view. Frontend-only; no new endpoint or backend change, and reuses the abort/request-owner guard.
- Stop now optimistically clears the scanning state (and detaches the run) so control returns immediately even though the shared fetch client drops the abort signal; the request-owner guard still ignores any late results. - The targets chip input is fully inert during a scan: the text input and each chip's remove button are disabled, not just pointer-events, so a chip cannot be removed by keyboard mid-scan. - The input stays editable at the target cap (no frozen draft) and a hint shows when the maximum is reached.
|
@coderabbitai full review |
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@dashboard/src/features/core-editor/components/xray/reality-scan-dialog.tsx`:
- Around line 361-374: Update the effect watching open in RealityScanDialog so
transitioning to false aborts the active controller and clears abortRef.current.
Preserve the existing reset behavior when open is true, ensuring scans stop
immediately on close while retaining unmount cleanup as a safeguard.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f5fb7057-21f6-4ace-b549-cf0527a2d174
📒 Files selected for processing (8)
app/models/reality_scan.pyapp/operation/core.pyapp/routers/core.pyapp/utils/reality_scan.pydashboard/src/features/core-editor/components/xray/reality-scan-dialog.tsxdashboard/src/features/core-editor/components/xray/xray-inbounds-section.tsxdashboard/src/service/reality-scan.tstests/test_reality_scan_unit.py
The reset effect only aborted the running scan when the dialog opened; on close the parent keeps the component mounted, so the unmount cleanup never ran and probes kept hitting targets and patching state in the background. Abort and clear the scanning state on open -> false too.
|
@coderabbitai review |
✅ Action performedReview finished.
|
Summary
Adds a REALITY target scanner: a "Scan target" button in the Xray inbound
editor (next to a REALITY
dest/targetfield) that probes a candidatehandshake target and reports whether it is a good REALITY decoy, plus a
POST /api/core/reality-scanendpoint behind it.For a given host it checks:
(surfaced as suggested valid SNIs)
The verdict (
feasible) requires the hard REALITY requirements: TLS 1.3 +HTTP/2 + a valid certificate, and it is not vetoed unless a non-X25519 group
was definitively observed. Post-quantum and HTTP/3 are reported as extras and
never fail the scan.
How it works
Three isolated probes, so a partial failure degrades one field to "unknown"
instead of failing the whole scan:
ssl(TLS version, ALPN/H2, certificate parsedwith
cryptography).negotiated key group. This is done by hand because the panel's OpenSSL 3.0
predates X25519MLKEM768 (OpenSSL 3.5), so it cannot rely on the local stack.
Alt-Svcheader.Security
The endpoint could otherwise be an SSRF primitive, so:
link-local, reserved and cloud-metadata addresses are rejected.
the DNS-rebinding hole.
cores:readpermission.API
POST /api/core/reality-scan->RealityScanResultRequest:
{ target, sni?, timeout? }(timeout clamped to 1-20s, default 10).Tests
Backend unit tests in
tests/test_reality_scan_unit.pycover target parsing,the SSRF public-host guard, the ClientHello/ServerHello group probe,
certificate/SAN parsing, and the feasibility logic (no network required; one
opt-in network integration test behind
REALITY_SCAN_NETWORK_TEST=1).Notes
t(key, { defaultValue: '...' }), so they render in English and fall backcleanly with translations missing. Adding
fa/zh/ruentries undercoreEditor.realityScan.*(andcoreConfigModal.scanRealityTarget) is agood follow-up.
service/reality-scan.ts)instead of the generated one, mirroring the generated call shape. It can be
folded into the generated API client once codegen is re-run.
Summary by CodeRabbit
/api/core/reality-scan), returning structured TLS/HTTP/feasibility and certificate metadata.