Skip to content

Commit

Permalink
DNS lookup bypassed when requested (node,service) is filtered out by …
Browse files Browse the repository at this point in the history
…outgoing filter
  • Loading branch information
Razz4780 committed Jul 9, 2024
1 parent d2d4281 commit 2ef4264
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 1 deletion.
4 changes: 4 additions & 0 deletions mirrord/layer/src/detour.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ pub(crate) enum Bypass {
/// Hostname should be resolved locally.
/// Currently this is the case only when the layer operates in the `trace only` mode.
LocalHostname,

/// DNS resolution was bypassed, because requested (node,service) combination matched filtered
/// out by outgoing local filter.
DnsFilteredByOutgoing,
}

/// [`ControlFlow`](std::ops::ControlFlow)-like enum to be used by hooks.
Expand Down
42 changes: 41 additions & 1 deletion mirrord/layer/src/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,45 @@ impl OutgoingSelector {
.next()
.ok_or(HookError::DNSNoName)
}

#[mirrord_layer_macro::instrument(level = "trace", ret)]
fn use_local_dns(&self, node: &str, port: u16) -> bool {
let (filters, selector_is_local) = match self {
Self::Unfiltered => return false,
Self::Local(filters) => (filters, true),
Self::Remote(filters) => (filters, false),
};

let addr = node.parse::<IpAddr>().ok();
let matched = filters
.iter()
.filter_map(|filter| {
(filter.protocol == ProtocolFilter::Any).then_some(&filter.address)
})
.any(|filter| match (filter, addr) {
(AddressFilter::Name((filter_name, filter_port)), None) => {
node == filter_name && port == *filter_port
}
(AddressFilter::Socket(filter_addr), Some(addr)) => {
filter_addr.port() == port
&& ((filter_addr.ip().is_unspecified()
&& filter_addr.is_ipv4() == addr.is_ipv4())
|| filter_addr.ip() == addr)
}
(AddressFilter::Subnet((filter_subnet, filter_port)), Some(addr)) => {
filter_subnet.contains(&addr) && port == *filter_port
}
(AddressFilter::Name(..), Some(..)) => false,
(AddressFilter::Socket(..), None) => false,
(AddressFilter::Subnet(..), None) => false,
});

if matched {
selector_is_local
} else {
!selector_is_local
}
}
}

/// [`OutgoingFilter`] extension.
Expand Down Expand Up @@ -421,7 +460,8 @@ impl OutgoingFilterExt for OutgoingFilter {
Ok(resolved_ips.into_iter().any(|ip| ip == address.ip()))
}
AddressFilter::Socket(addr)
if addr.ip().is_unspecified() || addr.ip() == address.ip() =>
if (addr.ip().is_unspecified() && addr.is_ipv4() == address.is_ipv4())
|| addr.ip() == address.ip() =>
{
Ok(true)
}
Expand Down
11 changes: 11 additions & 0 deletions mirrord/layer/src/socket/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,13 @@ pub(super) fn getaddrinfo(
// name is "" because that's what happens in real flow.
vec![("".to_string(), IpAddr::V4(Ipv4Addr::UNSPECIFIED))]
} else {
if crate::setup()
.outgoing_selector()
.use_local_dns(&node, service)
{
return Detour::Bypass(Bypass::DnsFilteredByOutgoing);
}

remote_getaddrinfo(node.clone())?
};

Expand Down Expand Up @@ -1003,6 +1010,10 @@ pub(super) fn gethostbyname(raw_name: Option<&CStr>) -> Detour<*mut hostent> {
})?
.into();

if crate::setup().outgoing_selector().use_local_dns(&name, 0) {
return Detour::Bypass(Bypass::DnsFilteredByOutgoing);
}

let hosts_and_ips = remote_getaddrinfo(name.clone())?;

// We could `unwrap` here, as this would have failed on the previous conversion.
Expand Down

0 comments on commit 2ef4264

Please sign in to comment.