Add isolated connectivity checker that probes the resolved proxy#4
Merged
elielgordondensity merged 6 commits intoMay 13, 2026
Merged
Conversation
VintageNet's per-interface `connection` property answers "does this interface have direct internet reachability." On corporate networks that resolve a proxy via WPAD/PAC, that's the wrong signal to gate application traffic on — the interface is healthy but direct egress is firewalled and outbound HTTP only works through the proxy. `VintageNetProxy.Connectivity` reports the second signal. It probes whether the resolved proxy is actually carrying outbound traffic and publishes the result at `["proxy", "connectivity"]` so consumers can subscribe. The checker is mounted as a sibling of the main supervisor so a crash in either tree doesn't cascade, and is off by default — flip on with `config :vintage_net_proxy, connectivity: [...]`. Probes: TCP-connect for `:direct`, HTTP `CONNECT` for HTTP/HTTPS proxies, `:socks_not_supported` for SOCKS. `:auto` is resolved against the probe URL first, then dispatched. Triggers: startup, periodic, and any change to the published proxy.
2f2509e to
617e84d
Compare
When the active interface re-fetches its PAC script and the body has changed but the effective URL stayed the same, the published `config` property goes :auto -> :auto and no event fires. The connectivity checker would miss the change until the next periodic probe. Add a `["proxy", "pac_revision"]` tick the Selector publishes when an iface's pac_script content changes from one non-nil value to a different non-nil value. nil <-> non-nil transitions already show up on `config` (as :auto <-> :unset), so this fires only in the narrow case the existing signal can't observe. Connectivity subscribes to the tick and re-probes on receipt. No change to `["proxy", "config"]` semantics or `resolve/1` behavior.
On corporate WPAD networks VintageNet's direct internet probe fails (the firewall only allows proxy traffic), so the interface stays at :lan. Gating proxy publication on :internet would never publish on the exact networks the library is designed for, hence :lan is treated equivalently to :internet for proxy resolution. The connectivity checker is the authoritative "outbound works" signal — it routes through the resolved proxy, not directly.
A single probe target is a SPOF: if it goes down everywhere, every device reports "offline" even though the proxy is fine. Replace the scalar `probe_url` config with `probe_urls` (a list) and try each in order, halting on the first :ok. Default to three captive-portal probe endpoints across different administrative domains (Google / Mozilla / Microsoft) so a single-vendor outage doesn't take a fleet down. Under normal operation only the first URL is probed, so the fallbacks add no steady-state traffic. The accumulator in reduce_while is the most recent error, so the surfaced reason is a concrete failure rather than a synthetic aggregate.
Three cleanups from a review pass:
* Merge the identical handle_info clauses for `["proxy", "config"]`
and `["proxy", "pac_revision"]` behind an `in` guard; one body,
one comment explaining why both feed the same re-probe path.
* Hoist `Publisher.get()` out of the probe loop — with a fallback
list we were re-reading the property table per URL. Per-URL
resolution stays inside the loop because PAC results genuinely
differ per URL.
* Drop the unreachable `_ -> :direct` catch-all in `decide/2` and
the unreachable `:no_probes_attempted` initial accumulator. The
cases the decider can hit are documented in
`t:VintageNetProxy.proxy/0`.
Module attributes for `@config_path` and `@pac_revision_path` let
pattern heads reference the same paths used by `VintageNet.subscribe`,
killing a stringly-typed literal duplication inside this module.
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.
VintageNet's per-interface
connectionproperty answers "does thisinterface have direct internet reachability." On corporate networks
that resolve a proxy via WPAD/PAC, that's the wrong signal to gate
application traffic on — the interface is healthy but direct egress
is firewalled and outbound HTTP only works through the proxy.
VintageNetProxy.Connectivityreports the second signal. It probeswhether the resolved proxy is actually carrying outbound traffic and
publishes the result at
["proxy", "connectivity"]so consumers cansubscribe. The checker is mounted as a sibling of the main supervisor
so a crash in either tree doesn't cascade, and is off by default —
flip on with
config :vintage_net_proxy, connectivity: [...].Probes: TCP-connect for
:direct, HTTPCONNECTfor HTTP/HTTPSproxies,
:socks_not_supportedfor SOCKS.:autois resolvedagainst the probe URL first, then dispatched. Triggers: startup,
periodic, and any change to the published proxy.