Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docker/Dockerfile.proxy-dumper
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ FROM ${APP_IMAGE}
# For local builds, the regular Ubuntu application image needs to have the CA certificates installed, but it also uses
# the `root` user, so we can install them without issue. Use the repository's available version because Ubuntu
# repositories do not retain old exact package versions indefinitely.
RUN test -d /usr/local/share/ca-certificates || apt-get update && \
RUN test -d /usr/share/ca-certificates || (apt-get update && \
apt-get install -y --no-install-recommends ca-certificates && \
apt-get clean
apt-get clean && rm -rf /var/lib/apt/lists)
COPY --from=builder /src/app/target/proxy-dumper /proxy-dumper

EXPOSE 8081
Expand Down
20 changes: 0 additions & 20 deletions docker/scripts/agent-data-plane/app/00-install-ca-certs.sh

This file was deleted.

48 changes: 44 additions & 4 deletions lib/datadog-agent/commons/src/ipc/client/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Helpers for interacting with the Datadog Agent.

use std::time::Duration;
use std::{net::IpAddr, time::Duration};

use backon::Retryable as _;
use datadog_protos::agent::v1::{RefreshRemoteAgentRequest, RegisterRemoteAgentRequest, RegisterRemoteAgentResponse};
Expand All @@ -15,7 +15,7 @@ use saluki_error::{generic_error, ErrorContext as _, GenericError};
use saluki_io::net::client::http::HttpsCapableConnectorBuilder;
use tonic::{
service::interceptor::InterceptedService,
transport::{Channel, Endpoint},
transport::{Channel, Endpoint, Uri},
Code, Request, Response,
};
use tracing::warn;
Expand Down Expand Up @@ -59,15 +59,20 @@ impl RemoteAgentClient {
let auth_interceptor = BearerAuthInterceptor::from_file(&config.auth().auth_token_file_path()).await?;
let ipc_cert_file_path = config.auth().ipc_cert_file_path();
let client_tls_config = build_ipc_client_ipc_tls_config(ipc_cert_file_path).await?;
let connector_builder = HttpsCapableConnectorBuilder::default().without_dns_resolution();
let endpoint = config.endpoint()?;
let connector_builder = HttpsCapableConnectorBuilder::default();
let connector_builder = if endpoint_requires_dns_resolution(&endpoint) {
connector_builder
} else {
connector_builder.without_dns_resolution()
};
#[cfg(target_os = "linux")]
let connector_builder = if let Some(addr) = config.vsock_addr()? {
connector_builder.with_vsock_addr(addr)
} else {
connector_builder
};
let https_connector = connector_builder.build(client_tls_config)?;
let endpoint = config.endpoint()?;
let channel = Endpoint::from(endpoint.clone())
.connect_timeout(Duration::from_secs(2))
.connect_with_connector(https_connector)
Expand Down Expand Up @@ -231,6 +236,19 @@ impl RemoteAgentClient {
}
}

fn endpoint_requires_dns_resolution(endpoint: &Uri) -> bool {
match endpoint.host() {
Some(host) => {
let host = host
.strip_prefix('[')
.and_then(|host| host.strip_suffix(']'))
.unwrap_or(host);
host.parse::<IpAddr>().is_err()
}
None => false,
}
}

async fn try_query_agent_api(
client: &mut AgentSecureClient<InterceptedService<Channel, BearerAuthInterceptor>>,
) -> Result<(), GenericError> {
Expand All @@ -251,3 +269,25 @@ async fn try_query_agent_api(
},
}
}

#[cfg(test)]
mod tests {
use tonic::transport::Uri;

use super::endpoint_requires_dns_resolution;

#[test]
fn hostname_endpoint_requires_dns_resolution() {
let endpoint = "https://datadog-agent:5001".parse::<Uri>().expect("valid URI");
assert!(endpoint_requires_dns_resolution(&endpoint));
}

#[test]
fn literal_ip_endpoints_do_not_require_dns_resolution() {
let ipv4_endpoint = "https://127.0.0.1:5001".parse::<Uri>().expect("valid URI");
assert!(!endpoint_requires_dns_resolution(&ipv4_endpoint));

let ipv6_endpoint = "https://[::1]:5001".parse::<Uri>().expect("valid URI");
assert!(!endpoint_requires_dns_resolution(&ipv6_endpoint));
}
}
2 changes: 1 addition & 1 deletion lib/saluki-io/src/net/client/http/conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ impl HttpsCapableConnectorBuilder {
/// DNS, such as Unix sockets, vsock, or literal-IP TCP endpoints. Hostname-based TCP
/// destinations will fail to resolve when this is enabled.
///
/// Defaults to enabled.
/// DNS resolution is enabled by default.
pub fn without_dns_resolution(mut self) -> Self {
self.dns_resolution_disabled = true;
self
Expand Down
20 changes: 5 additions & 15 deletions test/integration/cases/adp-ipc-no-dns/config.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
# Issue: ADP/Core Agent IPC must not require system DNS.
#
# The Core Agent IPC endpoint is a literal loopback address (`https://127.0.0.1:<cmd_port>`),
# so ADP should not need to load `/etc/resolv.conf` just to register with the Core Agent or
# receive its initial configuration. This test clears the resolver config at container startup to
# reproduce hosts where Hickory cannot load system DNS configuration.
#
# The test currently runs ADP in standalone mode until converged OTLP proxy endpoint ownership is
# configurable; see the standalone-mode env comment below.

type: integration
name: "adp-ipc-no-dns"
description: "Verifies ADP can start when /etc/resolv.conf has no nameservers"
Expand Down Expand Up @@ -35,17 +25,17 @@ container:
exposed_ports:
- "58125/udp"

procedure:
assertions:
- parallel:
- assertion: process_stable_for
- type: process_stable_for
duration: 10s
- assertion: log_contains
- type: log_contains
pattern: "Topology healthy"
timeout: 60s
- assertion: log_not_contains
- type: log_not_contains
pattern: "Failed to load system DNS configuration when creating DNS resolver for HTTP client"
during: 10s
- assertion: log_not_contains
- type: log_not_contains
pattern: "panic|PANIC"
regex: true
during: 10s