mirror of
https://github.com/lexmount/moli.git
synced 2026-09-25 00:01:28 +00:00
docs: explain DNS and proxy invariants
This commit is contained in:
@@ -105,6 +105,9 @@ impl CurlDnsResolution {
|
||||
resolution
|
||||
.address_policy
|
||||
.check_addresses(addresses, &resolution.policy_target)?;
|
||||
// Preserve the complete checked answer. Filtering forbidden addresses
|
||||
// would change curl's selection/fallback semantics, while resolving a
|
||||
// second time would reopen the DNS-rebinding TOCTOU window.
|
||||
let mut resolve = List::new();
|
||||
for entry in &resolution.static_entries {
|
||||
resolve
|
||||
@@ -129,6 +132,9 @@ impl CurlDnsResolution {
|
||||
})?;
|
||||
easy.resolve(resolve)
|
||||
.context("failed to install shared DNS result on curl request")?;
|
||||
// CURLOPT_RESOLVE entries without `+` are permanent for this easy
|
||||
// handle. Consuming the endpoint also prevents a requeued job from
|
||||
// issuing a second lookup before it enters curl.
|
||||
self.endpoint = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -15,6 +15,12 @@ struct HostResolveEntry {
|
||||
}
|
||||
|
||||
impl HostResolveOverrides {
|
||||
/// Parse only permanent address overrides owned by Moli.
|
||||
///
|
||||
/// libcurl also accepts `+` temporary cache entries and `-` removals. Moli
|
||||
/// deliberately excludes both: expiry or removal could return a direct
|
||||
/// request hostname to libcurl's resolver after the routing and address
|
||||
/// admission decision was made.
|
||||
pub fn parse(entries: &[String]) -> Result<Self> {
|
||||
entries
|
||||
.iter()
|
||||
|
||||
@@ -264,6 +264,9 @@ impl<H: Handler, C> HttpRegistry<H, C> {
|
||||
enqueue_existing_pending_job(&mut self.pending, pending);
|
||||
}
|
||||
Err(error) => {
|
||||
// DNS failure is terminal while the easy handle still resides
|
||||
// outside the Multi. Do not requeue it: that would let curl
|
||||
// resolve or connect independently of the failed shared lookup.
|
||||
let CurlPendingJob {
|
||||
transfer_id, job, ..
|
||||
} = pending;
|
||||
|
||||
@@ -78,6 +78,12 @@ impl SelectedProxy {
|
||||
};
|
||||
let url = Url::parse(&normalized)
|
||||
.with_context(|| format!("failed to parse proxy URL `{raw}`"))?;
|
||||
// Chromium's public `socks`/`socks5` spelling always sends the target
|
||||
// hostname to the proxy. libcurl assigns local-DNS semantics to
|
||||
// `socks5`, so use its explicit `socks5h` spelling internally. The
|
||||
// analogous SOCKS4 hostname form is `socks4a`. Keeping `url` unchanged
|
||||
// preserves useful diagnostics while `curl_url` carries this semantic
|
||||
// translation to the transport.
|
||||
let (scheme, curl_scheme) = match url.scheme() {
|
||||
"http" => (ProxyScheme::Http, "http"),
|
||||
"https" => (ProxyScheme::Https, "https"),
|
||||
@@ -200,6 +206,11 @@ impl ProxyRoute {
|
||||
Ok(None)
|
||||
}
|
||||
Self::Proxy(proxy) => {
|
||||
// A target override cannot influence a remote-DNS proxy. Fail
|
||||
// instead of silently giving the caller a false pinning
|
||||
// guarantee. The one exception is when target and proxy are
|
||||
// literally the same endpoint, where the entry pins the local
|
||||
// proxy connection itself.
|
||||
let proxy_is_request_endpoint =
|
||||
proxy.endpoint_host().eq_ignore_ascii_case(request_host)
|
||||
&& proxy.endpoint_port() == request_port;
|
||||
|
||||
@@ -142,6 +142,8 @@ impl WebSocketRegistry {
|
||||
});
|
||||
match result {
|
||||
Ok(()) => self.start(pending, multi),
|
||||
// As with HTTP, a failed lookup or address-policy check ends
|
||||
// the request before Session::attach can add curl to Multi.
|
||||
Err(error) => pending.io.finish(Err(error)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ pub(crate) async fn open_websocket_connection(
|
||||
let proxy_route = websocket_proxy_route(&request.url, context)?;
|
||||
let host_resolve = HostResolveOverrides::parse(&context.http_host_resolve)
|
||||
.map_err(|error| error.to_string())?;
|
||||
// Resolve exactly the endpoint this process will connect to: the target
|
||||
// when direct, or the proxy when target DNS belongs to that proxy.
|
||||
let dns_endpoint = proxy_route
|
||||
.connection_dns_endpoint(&request.url, &host_resolve)
|
||||
.map_err(|error| error.to_string())?;
|
||||
|
||||
Reference in New Issue
Block a user