Repository navigation
Multi-interface support: interface-bound providers and detection groups (#248) - #305
Open
timothymiller wants to merge 4 commits into
Open
timothymiller wants to merge 4 commits into
timothymiller wants to merge 4 commits into
Conversation
HTTP providers (cloudflare.trace, cloudflare.doh, ipify, url:) accept an @<interface> suffix that binds the detection request to that interface: SO_BINDTODEVICE on Linux/Android, IP_BOUND_IF on Apple/Solaris/illumos, and a source-address bind elsewhere. Part of #248.
DOMAINS_N / IP4_DOMAINS_N / IP6_DOMAINS_N with IP4_PROVIDER_N / IP6_PROVIDER_N (N >= 2) define extra detection groups. Each group detects its own addresses and updates its own domains; a family without a group provider inherits the default group's. Identical provider/family pairs are detected once per cycle, WAF lists receive the union of all groups' addresses, and a record configured in two groups is a startup error. Without numbered variables behavior is unchanged.
There was a problem hiding this comment.
🟡 Changes recommended
Disabled families can still have DNS records deleted, and ignored groups may incorrectly fail startup.
3 open findings
What changed in this PR
Adds multi-interface IP detection and per-domain detection groups.
Changes:
- Adds interface-bound HTTP providers.
- Adds numbered detection groups with provider inheritance and caching.
- Updates DNS/WAF handling, tests, and documentation.
| File | Description |
|---|---|
src/provider.rs |
Implements interface binding and provider parsing. |
src/config.rs |
Parses and validates detection groups. |
src/updater.rs |
Updates records and WAF lists per group. |
docs/multi-interface.md |
Documents configuration and platform behavior. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+485
to
+486
| if !matches!(provider, ProviderType::None) { | ||
| providers.insert(ip_type, provider); |
Comment on lines
+473
to
+496
| let domains = read_domains_with_suffix(&suffix); | ||
|
|
||
| let mut providers = HashMap::new(); | ||
| for (ip_type, var) in [(IpType::V4, "IP4_PROVIDER"), (IpType::V6, "IP6_PROVIDER")] { | ||
| let key = format!("{var}{suffix}"); | ||
| let provider = match getenv(&key) { | ||
| Some(s) => ProviderType::parse(&s).map_err(|e| format!("Invalid {key}: {e}"))?, | ||
| None => match default_providers.get(&ip_type) { | ||
| Some(p) => p.clone(), | ||
| None => ProviderType::None, | ||
| }, | ||
| }; | ||
| if !matches!(provider, ProviderType::None) { | ||
| providers.insert(ip_type, provider); | ||
| } | ||
| } | ||
|
|
||
| if domains.is_empty() { | ||
| ppfmt.warningf( | ||
| pp::EMOJI_WARNING, | ||
| &format!("Detection group {n} has no DOMAINS{suffix}, IP4_DOMAINS{suffix} or IP6_DOMAINS{suffix}; ignoring it"), | ||
| ); | ||
| continue; | ||
| } |
Comment on lines
+415
to
+419
| fn bind_interface( | ||
| builder: reqwest::ClientBuilder, | ||
| iface: &str, | ||
| ip_type: IpType, | ||
| ) -> Result<reqwest::ClientBuilder, String> { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Implements the RFC in #248. Stacked on #303 (base is
fix/reliability-2.2.1); retarget tomasterafter #303 merges.Closes #248.
Interface-bound providers
cloudflare.trace,cloudflare.doh,ipifyandurl:accept an@<iface>suffix (IP4_PROVIDER=cloudflare.trace@ens5). The detection request is bound to that interface viareqwest::ClientBuilder::interface(SO_BINDTODEVICEon Linux/Android,IP_BOUND_IFon Apple/Solaris/illumos), or via a source-address bind elsewhere. No new crates are needed.@, and only when the suffix is a valid interface name. URLs with@elsewhere (e.g. in the path) keep working.@ifaceis an error that points tolocal.iface:.Detection groups
DOMAINS_N,IP4_DOMAINS_N,IP6_DOMAINS_N,IP4_PROVIDER_NandIP6_PROVIDER_N(N ≥ 2) add groups. The unsuffixed variables are the default group, so behavior is unchanged when no numbered variables are set.nonedisables the family in that group._1/_01are rejected.DELETE_ON_STOPcovers every group. Legacy mode is not extended.Open questions resolved as proposed
@ifacesuffix._2._1is rejected with a message rather than aliased.Docs
docs/multi-interface.md. After #304 merges, link it from the README configuration section and add a CHANGELOG entry.Testing
cargo test: 421 passing. New tests:_1rejection, overlap rejectionDOMAINS_2aloneNot verified locally: the non-Unix (
local_address) path, because only the macOS target is installed. CI only builds Linux.