fix(connlib): only send DNS through tunnel if upstream DNS is configured (#5819)

Extracted out of #5797.

This is a problem that becomes evident as
https://github.com/firezone/firezone/issues/2667 is implemented:

Whenever connlib sees a DNS packet where the sentinel DNS is a resource,
it's forwarded to the resource instead of requests being resolved
locally. This doesn't work well with system's DNS servers since many
times those are provided by the DHCP to be a local resolver which can't
be reached from a gateway. Meaning that with full route this request
will be just dropped. Preventing all internet connections outside of
Firezone.

Most of the times when an administrator actually wants to forward all
DNS request they will add explicitly an upstream DNS server which makes
sense since depending on what the local DHCP configures isn't a good
idea if you want to tunnel DNS requests.

This makes this behavior explicit and docs and UI should be updated
accordingly.

Co-authored-by: Gabi <gabrielalejandro7@gmail.com>

---------

Co-authored-by: Gabi <gabrielalejandro7@gmail.com>
This commit is contained in:
Thomas Eizinger
2024-07-21 03:14:18 +10:00
committed by GitHub
parent dd19563c41
commit ab8d6dca1e
3 changed files with 13 additions and 2 deletions

File diff suppressed because one or more lines are too long

View File

@@ -583,6 +583,14 @@ impl ClientState {
})));
}
fn is_upstream_set_by_the_portal(&self) -> bool {
let Some(interface) = &self.interface_config else {
return false;
};
!interface.upstream_dns.is_empty()
}
/// Attempt to handle the given packet as a DNS packet.
///
/// Returns `Ok` if the packet is in fact a DNS query with an optional response to send back.
@@ -599,13 +607,14 @@ impl ClientState {
Some(dns::ResolveStrategy::ForwardQuery(query)) => {
// There's an edge case here, where the resolver's ip has been resolved before as
// a dns resource... we will ignore that weird case for now.
// Assuming a single upstream dns until #3123 lands
if let Some(upstream_dns) = self.dns_mapping.get_by_left(&query.query.destination())
{
let ip = upstream_dns.ip();
// In case the DNS server is a CIDR resource, it needs to go through the tunnel.
if self.cidr_resources.longest_match(ip).is_some() {
if self.is_upstream_set_by_the_portal()
&& self.cidr_resources.longest_match(ip).is_some()
{
return Err((packet, ip));
}
}

View File

@@ -323,6 +323,7 @@ impl ReferenceStateMachine for ReferenceState {
{
Some(resource)
if !state.client.inner().is_connected_to_cidr(resource)
&& !state.client.inner().upstream_dns_resolvers.is_empty()
&& !state.client.inner().is_known_host(&domain.to_string()) =>
{
state