Skip to content

fronted: apply "default" SNI bucket when no country code is set#7

Merged
myleshorton merged 1 commit into
mainfrom
fisk/fronted-default-bucket-empty-cc
Jun 25, 2026
Merged

fronted: apply "default" SNI bucket when no country code is set#7
myleshorton merged 1 commit into
mainfrom
fisk/fronted-default-bucket-empty-cc

Conversation

@myleshorton

@myleshorton myleshorton commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

flint-fronted::Provider::expanded was ported from the old getlantern/fronted country-code rule, which gates the SNIConfig lookup behind a non-empty country code. The newer getlantern/domainfront deliberately removed that gate (see domainfront/config.go::ExpandedProvider, whose comment spells out why) so the "default" arbitrary-SNI bucket applies to the production client, which passes no country code.

This bites the brand-new first-class aliyun provider in domainfront/fronted.yaml.gz (providers: akamai, aliyun, cloudfront). Aliyun's only frontingsnis bucket is default with usearbitrarysnis: true (img.alicdn.com / gw.alicdn.com / a.alicdn.com). Under the old gate, an empty country code selected no SNIConfig → generate_sni returned "" → flint dialed Aliyun edges with no SNI, losing the *.tbcdn.cn-cert guarantee (aliyun-provider.yaml constraint #1: "the edge node must hold a cert valid for the SNI you present. img.alicdn.com is ideal"). The fronted dial then fails certificate verification.

Root cause (the wrong branch fires)

sequenceDiagram
    autonumber
    participant App as Client<br/>no country code
    participant Pool as FrontPool::new<br/>flint-fronted/lib.rs
    participant Exp as Provider::expanded<br/>flint-fronted/lib.rs:123
    participant Gen as generate_sni<br/>flint-fronted/lib.rs:1082
    participant Conn as connect_with<br/>flint-tls/connector.rs:107
    participant Edge as Aliyun CDN edge

    App->>Pool: dial config.fetch with country_code = ""
    Pool->>Exp: expanded("")
    rect rgba(255, 200, 200, 0.3)
        Note over Exp: BEFORE — country_code.is_empty so sni_cfg = None ⚠️ 🐛
    end
    Exp->>Gen: generate_sni(None, ip)
    Gen-->>Exp: "" empty SNI
    Exp-->>Pool: masquerade.sni = ""
    Pool->>Conn: boring_chrome(addr, sni="")
    Conn->>Edge: ClientHello with NO SNI
    Edge-->>Conn: default cert, not *.tbcdn.cn
    Conn-->>App: certificate verification FAILS
    Note over App,Edge: AFTER — get("") falls back to "default" bucket ✅
    Note over Gen: returns img.alicdn.com so the edge serves *.tbcdn.cn and verify passes
Loading

Fix

Match domainfront::ExpandedProvider exactly:

  • an empty country code now selects the "default" bucket (an unknown non-empty code still falls back to "default" as before);
  • a generated arbitrary SNI takes precedence, but a per-masquerade sni baked into the config is preserved rather than clobbered with an empty string.

Tests

  • default_sni_bucket_applies_with_empty_country_code — the aliyun-shaped default-bucket-with-empty-CC case (would have failed before).
  • baked_in_masquerade_sni_is_preserved_without_arbitrary_snis — per-masquerade pinned SNI survives expansion.
  • Verified the real domainfront/fronted.yaml.gz (with the aliyun provider) parses end-to-end via the gated parses_real_lantern_fronted_config test.
  • cargo test -p flint-fronted green (24 pass), cargo clippy/cargo fmt clean.

Why this matters

This unblocks routing spark's config-fetch / cold-start bootstrap through flint-kindling's fronted transport using the Alibaba Cloud provider — the production client passes no country code, so without this fix the alibaba fronting would be silently inert.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EztFQJYZxiWTk2PQwo9qWh

Summary by CodeRabbit

  • Bug Fixes
    • Provider selection now includes the default SNI bucket even when no country code is set.
    • Existing SNI values are preserved when no generated SNI is available, preventing them from being overwritten.
    • Added regression coverage for default-bucket behavior and SNI preservation.

`Provider::expanded` was ported from the old getlantern/fronted country-code
rule, which gated the SNIConfig lookup behind a non-empty country code. The
newer getlantern/domainfront deliberately removed that gate so the "default"
arbitrary-SNI bucket applies to the production client, which passes no country
code. Without this, the new first-class `aliyun` provider — whose only
frontingsnis bucket is "default" (usearbitrarysnis: true) — would dial Aliyun
CDN edges with an empty SNI, losing the img.alicdn.com camouflage that lets the
edge serve its *.tbcdn.cn certificate. The fronted dial would then fail
certificate verification.

Match domainfront::ExpandedProvider exactly:
- an empty country code now selects the "default" bucket (an unknown non-empty
  code still falls back to "default" as before);
- a generated arbitrary SNI takes precedence, but a per-masquerade SNI baked
  into the config is preserved rather than clobbered with an empty string.

Add regression tests for the aliyun-shaped default-bucket-with-empty-CC case
and for baked-in masquerade SNI preservation. Verified the real
domainfront/fronted.yaml.gz (with the aliyun provider) parses end-to-end.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EztFQJYZxiWTk2PQwo9qWh
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8b830c8e-50ef-4471-9d6f-9ac4e859b858

📥 Commits

Reviewing files that changed from the base of the PR and between 5ec56d2 and 4e60fa5.

📒 Files selected for processing (1)
  • crates/flint-fronted/src/lib.rs

📝 Walkthrough

Walkthrough

Provider::expanded now uses the default fronting-SNI bucket even with an empty country code, and masquerade expansion keeps an existing SNI when generated SNI is empty. Two regression tests cover both behaviors.

Changes

Fronting SNI expansion behavior

Layer / File(s) Summary
Default bucket lookup
crates/flint-fronted/src/lib.rs
Provider::expanded now falls back to fronting_snis["default"] even when country_code is empty.
Preserve existing masquerade SNI
crates/flint-fronted/src/lib.rs
Masquerade expansion only assigns generated SNI when it is non-empty, and new tests cover the default-bucket and pinned-SNI cases.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I hopped through SNI, soft and bright,
The default bucket found its light.
When empty winds made strings too thin,
I kept the pinned SNI within.
A tiny hop, a tidy trace—
Lantern paths now hold their place.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main behavior change around applying the default SNI bucket when country code is empty.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fisk/fronted-default-bucket-empty-cc

Comment @coderabbitai help to get the list of available commands.

@myleshorton myleshorton merged commit 2cdb9c7 into main Jun 25, 2026
2 checks passed
@myleshorton myleshorton deleted the fisk/fronted-default-bucket-empty-cc branch June 25, 2026 14:18
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