feat(connlib): short-circuit access request to DNS resources (#5438)

Currently, we always emit a connection intent whenever we see a DNS
query for a domain of one of our DNS resources. However, especially for
wildcard DNS resources, we are very likely already connected to the
corresponding gateway. In that case, sending a connection intent
triggers another handshake with the portal only to learn that - surprise
- we should reuse a connection that we already have to that gateway.

We can short-circuit this by checking if we are already connected to the
gateway for this resource and directly requested access for the domain
name in question. We reuse the same event here as we do for refreshing
DNS resources. At a later stage, we should rename this to something else
to make this clearer.

Co-authored-by: Gabi <gabrielalejandro7@gmail.com>
This commit is contained in:
Thomas Eizinger
2024-06-20 10:36:11 +10:00
committed by GitHub
parent 97cfb90cae
commit dabe493e9e
3 changed files with 75 additions and 15 deletions

View File

@@ -801,9 +801,22 @@ impl ClientState {
Ok(None)
}
Some(dns::ResolveStrategy::DeferredResponse((resource, r_type))) => {
self.on_not_connected_resource(resource.id, Some(resource.address.clone()), now);
self.deferred_dns_queries
.insert((resource, r_type), packet.as_immutable().to_owned());
.insert((resource.clone(), r_type), packet.as_immutable().to_owned());
let Some(peer) = self.peer_by_resource(resource.id) else {
self.on_not_connected_resource(resource.id, Some(resource.address), now);
return Ok(None);
};
self.buffered_events
.push_back(ClientEvent::RefreshResources {
connections: vec![ReuseConnection {
resource_id: resource.id,
gateway_id: peer.id(),
payload: Some(resource.address),
}],
});
Ok(None)
}

View File

@@ -275,6 +275,7 @@ pub enum ClientEvent {
resource: ResourceId,
connected_gateway_ids: HashSet<GatewayId>,
},
// FIXME: Refactor this to "request-access" or something similar.
RefreshResources {
connections: Vec<ReuseConnection>,
},

View File

@@ -703,39 +703,85 @@ impl TunnelTest {
.unwrap();
}
Request::ReuseConnection(reuse_connection) => {
if let (Ok(()), Some(name)) = (
self.gateway.span.in_scope(|| {
let domain = reuse_connection.payload;
self.gateway
.span
.in_scope(|| {
self.gateway.state.allow_access(
resource,
self.client.id,
None,
reuse_connection
.payload
.as_ref()
.map(|d| (d.clone(), Vec::new())),
domain.clone().map(|d| (d, Vec::new())),
now,
)
}),
reuse_connection.payload,
) {
})
.unwrap();
if let Some(domain) = domain {
self.client
.span
.in_scope(|| {
self.client.state.received_domain_parameters(
resource_id,
DomainResponse {
domain: name.clone(),
domain,
address: resolved_ips,
},
)
})
.unwrap();
};
}
}
};
}
ClientEvent::RefreshResources { .. } => {
tracing::warn!("Unimplemented");
ClientEvent::RefreshResources { connections } => {
for reuse_connection in connections {
let domain = reuse_connection.payload.clone();
let resource_id = reuse_connection.resource_id;
let resolved_ips = reuse_connection
.payload
.into_iter()
.flat_map(|domain| global_dns_records.get(&domain).cloned())
.flatten()
.collect::<Vec<_>>();
let resource = map_client_resource_to_gateway_resource(
client_cidr_resources,
client_dns_resource,
resolved_ips.clone(),
resource_id,
);
self.gateway
.span
.in_scope(|| {
self.gateway.state.allow_access(
resource,
self.client.id,
None,
domain.clone().map(|d| (d, Vec::new())),
now,
)
})
.unwrap();
if let Some(domain) = domain {
self.client
.span
.in_scope(|| {
self.client.state.received_domain_parameters(
resource_id,
DomainResponse {
domain,
address: resolved_ips,
},
)
})
.unwrap();
}
}
}
ClientEvent::ResourcesChanged { .. } => {
tracing::warn!("Unimplemented");