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
527 changes: 458 additions & 69 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,6 @@ features = ["tokio", "tracing"]
version = "0.20.0"

[workspace.dependencies.rand]
version = "0.9"
version = "0.10"
default-features = false
features = ["std", "std_rng", "os_rng"]
features = ["std", "std_rng", "sys_rng"]
11 changes: 8 additions & 3 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,15 @@ deny = [
# aws-lc-rs should be used instead.
{ name = "ring" }
]
skip = []
skip = [
{ name = "getrandom", version = "0.2.17" },
{ name = "cpufeatures", version = "0.2.17" }
]
skip-tree = [
# rand v0.9 is still propagating through the ecosystem
{ name = "rand", version = "0.8" },
# rand v0.10 is still propagating through the ecosystem
#
# see https://github.com/open-telemetry/opentelemetry-rust/pull/3536.
{ name = "rand", version = "0.9" },
# `pprof` uses a number of old dependencies. for now, we skip its subtree.
{ name = "pprof" },
# zerocopy v0.8 is still propagating through the ecosystem
Expand Down
2 changes: 1 addition & 1 deletion linkerd/distribute/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ publish = { workspace = true }
ahash = "0.8"
linkerd-stack = { path = "../stack" }
parking_lot = "0.12"
rand = { workspace = true, features = ["small_rng", "thread_rng"] }
rand = { workspace = true, features = ["thread_rng"] }
tracing = { workspace = true }

[dev-dependencies]
Expand Down
2 changes: 1 addition & 1 deletion linkerd/dns/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ edition = { workspace = true }
publish = { workspace = true }

[dependencies]
hickory-resolver = "0.25.2"
hickory-resolver = "0.26"
linkerd-dns-name = { path = "./name" }
prometheus-client = { workspace = true }
thiserror = "2"
Expand Down
63 changes: 34 additions & 29 deletions linkerd/dns/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ struct InvalidSrv(rdata::SRV);

#[derive(Debug, Error)]
#[error("failed to resolve A record: {0}")]
struct ARecordError(#[from] hickory_resolver::ResolveError);
struct ARecordError(#[from] hickory_resolver::net::NetError);

#[derive(Debug, Error)]
enum SrvRecordError {
#[error("{0}")]
Invalid(#[from] InvalidSrv),
#[error("failed to resolve SRV record: {0}")]
Resolve(#[from] hickory_resolver::ResolveError),
Resolve(#[from] hickory_resolver::net::NetError),
}

#[derive(Debug, Error)]
Expand All @@ -67,32 +67,30 @@ impl Resolver {
///
/// Either a new `Resolver` or an error if the system configuration
/// could not be parsed.
///
/// TODO: This should be infallible like it is in the `domain` crate.
pub fn from_system_config_with<C: ConfigureResolver>(c: &C) -> std::io::Result<Self> {
pub fn from_system_config_with<C: ConfigureResolver>(
c: &C,
) -> Result<Self, hickory_resolver::net::NetError> {
let (config, mut opts) = system_conf::read_system_conf()?;
c.configure_resolver(&mut opts);
trace!("DNS config: {:?}", &config);
trace!("DNS opts: {:?}", &opts);
Ok(Self::new(config, opts))
Self::new(config, opts)
}

pub fn new(config: ResolverConfig, mut opts: ResolverOpts) -> Self {
pub fn new(
config: ResolverConfig,
mut opts: ResolverOpts,
) -> Result<Self, hickory_resolver::net::NetError> {
// Disable Hickory-resolver's caching.
opts.cache_size = 0;
// This function is synchronous, but needs to be called within the Tokio
// 0.2 runtime context, since it gets a handle.
let provider = hickory_resolver::name_server::TokioConnectionProvider::default();
let mut builder = hickory_resolver::Resolver::builder_with_config(config, provider);
*builder.options_mut() = opts;
let dns = builder.build();
/* TODO(kate): this can be used if/when hickory-dns/hickory-dns#2877 is released.
let provider = hickory_resolver::net::runtime::TokioRuntimeProvider::default();
let dns = hickory_resolver::Resolver::builder_with_config(config, provider)
.with_options(opts)
.build();
*/
.build()?;

Resolver { dns, metrics: None }
Ok(Resolver { dns, metrics: None })
}

/// Installs a counter tracking the number of A/AAAA records resolved.
Expand Down Expand Up @@ -157,11 +155,18 @@ impl Resolver {
debug!(%name, "Resolving a SRV record");
let srv = self.dns.srv_lookup(name.as_str()).await?;

let valid_until = Instant::from_std(srv.as_lookup().valid_until());
let valid_until = Instant::from_std(srv.valid_until());
let addrs = srv
.into_iter()
.answers()
.iter()
.map(|record| &record.data)
.filter_map(|rdata| match rdata {
hickory_resolver::proto::rr::RData::SRV(srv) => Some(srv),
_ => None,
})
.map(Self::srv_to_socket_addr)
.collect::<Result<_, InvalidSrv>>()?;
Comment thread
cratelyn marked this conversation as resolved.

debug!(ttl = ?valid_until - Instant::now(), ?addrs);

Ok((addrs, valid_until))
Expand All @@ -174,19 +179,19 @@ impl Resolver {
// instead of dots/colons. We can alternatively do another lookup
// on the pod's DNS but it seems unnecessary since the pod's
// ip is in the target of the SRV record.
fn srv_to_socket_addr(srv: rdata::SRV) -> Result<net::SocketAddr, InvalidSrv> {
if let Some(first_label) = srv.target().iter().next() {
fn srv_to_socket_addr(srv: &rdata::SRV) -> Result<net::SocketAddr, InvalidSrv> {
if let Some(first_label) = srv.target.iter().next() {
if let Ok(utf8) = std::str::from_utf8(first_label) {
let mut res = utf8.replace('-', ".").parse::<std::net::IpAddr>();
if res.is_err() {
res = utf8.replace('-', ":").parse::<std::net::IpAddr>();
}
if let Ok(ip) = res {
return Ok(net::SocketAddr::new(ip, srv.port()));
return Ok(net::SocketAddr::new(ip, srv.port));
}
}
}
Err(InvalidSrv(srv))
Err(InvalidSrv(srv.clone()))
}
}

Expand Down Expand Up @@ -220,16 +225,16 @@ impl ResolveError {
}
}

/// Returns the negative TTL [`time::Duration`] of a [`hickory_resolver::ResolveError`].
/// Returns the negative TTL [`time::Duration`] of a [`hickory_resolver::net::NetError`].
///
/// This function will defensively enforce a minimum negative TTL.
fn negative_ttl_of(error: &hickory_resolver::ResolveError) -> Option<time::Duration> {
use hickory_resolver::proto::{ProtoError, ProtoErrorKind};
fn negative_ttl_of(error: &hickory_resolver::net::NetError) -> Option<time::Duration> {
Comment thread
cratelyn marked this conversation as resolved.
use hickory_resolver::net::{DnsError, NetError, NoRecords};

let Some(ProtoErrorKind::NoRecordsFound {
let NetError::Dns(DnsError::NoRecordsFound(NoRecords {
negative_ttl: Some(ttl_secs),
..
}) = error.proto().map(ProtoError::kind)
})) = error
else {
return None;
};
Expand Down Expand Up @@ -373,7 +378,7 @@ mod tests {
let name = "foobar.linkerd-dst-headless.linkerd.svc.cluster.local.";
let target = domain::Name::from_str(name).unwrap();
let srv = rdata::SRV::new(1, 1, 8086, target);
assert!(Resolver::srv_to_socket_addr(srv).is_err());
assert!(Resolver::srv_to_socket_addr(&srv).is_err());
}

#[test]
Expand All @@ -399,15 +404,15 @@ mod tests {
] {
let target = domain::Name::from_str(case.input).unwrap();
let srv = rdata::SRV::new(1, 1, 8086, target);
let socket = Resolver::srv_to_socket_addr(srv).unwrap();
let socket = Resolver::srv_to_socket_addr(&srv).unwrap();
assert_eq!(socket.ip(), net::IpAddr::from_str(case.output).unwrap());
}
}

#[test]
fn srv_record_reports_cause_correctly() {
let srv = "foobar.linkerd-dst-headless.linkerd.svc.cluster.local."
.parse::<hickory_resolver::Name>()
.parse::<domain::Name>()
.map(|name| rdata::SRV::new(1, 1, 8086, name))
.expect("a valid domain name");

Expand Down
2 changes: 1 addition & 1 deletion linkerd/exp-backoff/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ publish = { workspace = true }

[dependencies]
futures = { version = "0.3", default-features = false }
rand = { workspace = true, features = ["small_rng", "thread_rng"] }
rand = { workspace = true, features = ["thread_rng"] }
thiserror = "2"
tokio = { version = "1", features = ["time"] }
pin-project = "1"
Expand Down
1 change: 1 addition & 0 deletions linkerd/exp-backoff/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ impl ExponentialBackoff {
if self.jitter == 0.0 {
time::Duration::default()
} else {
use rand::RngExt;
let jitter_factor = rng.random::<f64>();
debug_assert!(
jitter_factor > 0.0,
Expand Down
2 changes: 1 addition & 1 deletion linkerd/pool/p2c/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ publish = { workspace = true }
ahash = "0.8"
futures = { version = "0.3", default-features = false }
prometheus-client = { workspace = true }
rand = { workspace = true, features = ["small_rng", "thread_rng"] }
rand = { workspace = true, features = ["thread_rng"] }
tracing = { workspace = true }

linkerd-error = { path = "../../error" }
Expand Down
4 changes: 3 additions & 1 deletion linkerd/pool/p2c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use linkerd_error::Error;
use linkerd_metrics::prom;
use linkerd_pool::Pool;
use linkerd_stack::{NewService, Service};
use rand::{rngs::SmallRng, Rng, SeedableRng};
use rand::{rngs::SmallRng, SeedableRng};
use std::{
collections::hash_map::Entry,
net::SocketAddr,
Expand Down Expand Up @@ -117,6 +117,8 @@ where
}

fn gen_pair(rng: &mut SmallRng, len: usize) -> (usize, usize) {
use rand::RngExt;

debug_assert!(len >= 2, "must have at least two endpoints");
// Get two distinct random indexes (in a random order) and
// compare the loads of the service at each index.
Expand Down
2 changes: 2 additions & 0 deletions linkerd/trace-context/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ impl<K: SpanSink> SpanSink for Option<K> {

impl Id {
fn new_span_id<R: Rng>(rng: &mut R) -> Self {
use rand::RngExt;

let mut bytes = vec![0; SPAN_ID_LEN];
rng.fill(bytes.as_mut_slice());
Self(bytes)
Expand Down
Loading