refactor(client): make authentication explicit and redact HMAC keys

This commit is contained in:
Nils Andreas Svee committed 2026-10-04 16:58:44 +07:00
1 parent 9c703ecff2
commit 156db4c720
16 files changed
+184 -119

No files matched your search

+19 -2
View File
@@ -1,10 +1,10 @@
use std::time::Duration;
use std::{fmt, time::Duration};
use clap::ValueEnum;
use irtt_client::{MAX_DSCP_CODEPOINT, MAX_SERVER_FILL_BYTES, MAX_TTL, MAX_UDP_PAYLOAD_LENGTH};
use irtt_proto::{Clock, ReceivedStats, StampAt};
#[derive(Debug, Clone, clap::Args)]
#[derive(Clone, clap::Args)]
pub struct CommonClientArgs {
/// Probe interval.
#[arg(long, default_value = "1s", value_parser = parse_duration)]
@@ -63,6 +63,23 @@ pub struct CommonClientArgs {
pub loose: bool,
}
impl fmt::Debug for CommonClientArgs {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CommonClientArgs")
.field("interval", &self.interval)
.field("length", &self.length)
.field("hmac", &self.hmac.as_ref().map(|_| "[REDACTED]"))
.field("clock", &self.clock)
.field("tstamp", &self.tstamp)
.field("stats", &self.stats)
.field("server_fill", &self.server_fill)
.field("dscp", &self.dscp)
.field("ttl", &self.ttl)
.field("loose", &self.loose)
.finish()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum ClockArg {
Wall,
+7 -2
View File
@@ -1,6 +1,6 @@
use std::time::Duration;
use irtt_client::{ClientConfig, NegotiationPolicy, SocketConfig};
use irtt_client::{Authentication, ClientConfig, HmacKey, NegotiationPolicy, SocketConfig};
use super::args::CommonClientArgs;
@@ -21,7 +21,12 @@ impl CommonClientArgs {
stamp_at: self.tstamp.into(),
clock: self.clock.into(),
dscp: self.dscp,
hmac_key: self.hmac.as_ref().map(|key| key.as_bytes().to_vec()),
auth: self
.hmac
.as_ref()
.map_or(Authentication::Unauthenticated, |key| {
Authentication::Hmac(HmacKey::new(key.as_bytes()))
}),
server_fill: self.server_fill.clone(),
negotiation_policy: if self.loose {
NegotiationPolicy::Loose
+6 -38
View File
@@ -2,8 +2,8 @@ use std::{collections::HashSet, fmt};
use clap::ValueEnum;
use irtt_client::{
managed::{ManagedPacing, ManagedTargetConfig, TargetId},
ClientAuthConfig,
managed::{ManagedPacing, ManagedTargetConfig, TargetAuth, TargetId},
Authentication, HmacKey,
};
/// One raw positional target captured by Clap.
@@ -35,23 +35,6 @@ pub fn parse_target(input: &str) -> Result<TargetArg, String> {
Ok(TargetArg::new(input))
}
#[derive(Clone, PartialEq, Eq)]
pub enum TargetAuth {
Inherit,
Override(Vec<u8>),
Disable,
}
impl fmt::Debug for TargetAuth {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Inherit => f.write_str("Inherit"),
Self::Override(_) => f.write_str("Override(<redacted>)"),
Self::Disable => f.write_str("Disable"),
}
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct TargetSpec {
pub label: String,
@@ -80,16 +63,7 @@ impl fmt::Debug for PreparedTarget {
f.debug_struct("PreparedTarget")
.field("label", &self.label)
.field("server_addr", &self.managed.server_addr)
.field(
"auth",
&match &self.managed.auth {
None => TargetAuth::Inherit,
Some(ClientAuthConfig { hmac_key: Some(_) }) => {
TargetAuth::Override(Vec::new())
}
Some(ClientAuthConfig { hmac_key: None }) => TargetAuth::Disable,
},
)
.field("auth", &self.managed.auth)
.finish()
}
}
@@ -216,9 +190,9 @@ fn parse_target_syntax(
Some(index) => {
let value = unescape(&input[index + "@hmac=".len()..])?;
let auth = if value.is_empty() {
TargetAuth::Disable
TargetAuth::Override(Authentication::Unauthenticated)
} else {
TargetAuth::Override(value.into_bytes())
TargetAuth::Override(Authentication::Hmac(HmacKey::new(value.into_bytes())))
};
(&input[..index], auth)
}
@@ -287,13 +261,7 @@ pub fn prepare_managed_targets(specs: Vec<TargetSpec>) -> Result<Vec<PreparedTar
let mut targets = Vec::with_capacity(specs.len());
for spec in specs {
let mut managed = ManagedTargetConfig::new(TargetId::from(spec.label.clone()), spec.addr);
managed.auth = match spec.auth {
TargetAuth::Inherit => None,
TargetAuth::Override(hmac_key) => Some(ClientAuthConfig {
hmac_key: Some(hmac_key),
}),
TargetAuth::Disable => Some(ClientAuthConfig { hmac_key: None }),
};
managed.auth = spec.auth;
targets.push(PreparedTarget {
label: spec.label,
managed,
+17 -9
View File
@@ -149,29 +149,37 @@ fn default_client_output_emits_a_packet_summary() {
fn target_authentication_inherits_overrides_or_disables_the_global_key() {
use clap::Parser;
use irtt_app::cmd::client::args::ClientArgs;
use irtt_client::{managed::TargetAuth, Authentication, HmacKey};
let args = ClientArgs::try_parse_from([
"irtt-client",
"--hmac",
"global-test-key",
"CONSPICUOUS_GLOBAL_HMAC_KEY",
"inherit=127.0.0.1:2112",
"override=127.0.0.1:2113@hmac=target-test-key",
"override=127.0.0.1:2113@hmac=CONSPICUOUS_TARGET_HMAC_KEY",
"disable=127.0.0.1:2114@hmac=",
])
.unwrap();
let setup = args.prepare().unwrap();
assert_eq!(
setup.managed_config().client.hmac_key.as_deref(),
Some(b"global-test-key".as_slice())
setup.managed_config().client.auth,
Authentication::Hmac(HmacKey::new(b"CONSPICUOUS_GLOBAL_HMAC_KEY".as_slice()))
);
let targets = setup.managed_targets();
let authentication: Vec<_> = targets
.iter()
.map(|target| target.auth.as_ref().map(|auth| auth.hmac_key.as_deref()))
.collect();
let authentication: Vec<_> = targets.iter().map(|target| target.auth.clone()).collect();
assert_eq!(
authentication,
[None, Some(Some(b"target-test-key".as_slice())), Some(None)]
[
TargetAuth::Inherit,
TargetAuth::Override(Authentication::Hmac(HmacKey::new(
b"CONSPICUOUS_TARGET_HMAC_KEY".as_slice()
))),
TargetAuth::Override(Authentication::Unauthenticated)
]
);
for output in [format!("{args:?}"), format!("{setup:?}")] {
assert!(!output.contains("CONSPICUOUS_GLOBAL_HMAC_KEY"));
assert!(!output.contains("CONSPICUOUS_TARGET_HMAC_KEY"));
}
}
// A real authenticated server detects broken client argument-to-config mapping.
+19
View File
@@ -34,6 +34,25 @@ dependency at all.
See `examples/` in the repository for runnable examples of each tier.
## Authentication
`ClientConfig.auth` is concrete: `Authentication::Unauthenticated` or
`Authentication::Hmac(HmacKey::new(bytes))`. Keys share their bytes across
clones and print only `HmacKey([REDACTED])` through `Debug`. Borrowing key
material requires an explicit `as_bytes()` call. An empty key still selects
HMAC authentication; textual key syntax belongs to the application.
For managed targets, `ManagedTargetConfig.auth` defaults to `TargetAuth::Inherit`.
`TargetAuth::Override(Authentication::Unauthenticated)` disables shared
authentication, and `TargetAuth::Override(Authentication::Hmac(key))` replaces
the shared key. Initial construction and update planning resolve inheritance
into concrete session authentication before execution. Switching between
inheritance and an override replaces the target generation even when their
resolved authentication is equal.
This replaces the former `ClientConfig.hmac_key` and `ClientAuthConfig` API;
there are no compatibility aliases.
## Documentation
Full API documentation is on [docs.rs/irtt-client](https://docs.rs/irtt-client).
+44
View File
@@ -0,0 +1,44 @@
use std::{fmt, sync::Arc};
/// Shared HMAC key bytes. Debug output never includes the bytes or a fingerprint.
///
/// An empty key is still an explicitly configured HMAC key.
#[derive(Clone, PartialEq, Eq)]
pub struct HmacKey(Arc<[u8]>);
impl HmacKey {
/// Store key bytes without interpreting textual key syntax.
pub fn new(bytes: impl Into<Arc<[u8]>>) -> Self {
Self(bytes.into())
}
/// Explicitly borrow the key material for authentication.
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
}
impl fmt::Debug for HmacKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("HmacKey([REDACTED])")
}
}
/// Concrete authentication for a low-level client session.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub enum Authentication {
/// Send and accept packets without HMAC authentication.
#[default]
Unauthenticated,
/// Authenticate packets with this key, including when it is empty.
Hmac(HmacKey),
}
impl Authentication {
pub(crate) fn hmac_key(&self) -> Option<&[u8]> {
match self {
Self::Unauthenticated => None,
Self::Hmac(key) => Some(key.as_bytes()),
}
}
}
+6 -29
View File
@@ -1,5 +1,7 @@
use std::{net::SocketAddr, time::Duration};
use crate::Authentication;
/// Protocol compatibility bound for a requested `server_fill` value, in UTF-8
/// bytes.
///
@@ -118,11 +120,10 @@ pub struct ClientConfig {
/// This is the six-bit DSCP value, not the full traffic-class byte, and
/// must be less than or equal to [`MAX_DSCP_CODEPOINT`].
pub dscp: u8,
/// Optional HMAC key used to authenticate IRTT packets.
/// Concrete authentication for open, echo, and close packets.
///
/// When present, open, echo, and close packets are encoded and decoded with
/// HMAC authentication. The peer must be configured with the same key.
pub hmac_key: Option<Vec<u8>>,
/// HMAC peers must use the same key. An empty HMAC key remains authenticated.
pub auth: Authentication,
/// Optional server payload fill request.
///
/// `None` leaves server fill behavior unspecified. `Some(value)` requests
@@ -155,30 +156,6 @@ pub struct ClientConfig {
pub max_pending_probes: usize,
}
/// Authentication settings used by client sessions.
///
/// `ClientConfig` keeps its existing top-level HMAC field for source
/// compatibility. Managed multi-target callers can use this smaller type for
/// per-target auth overrides without carrying a full independent
/// [`ClientConfig`].
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ClientAuthConfig {
/// Optional HMAC key used to authenticate IRTT packets.
pub hmac_key: Option<Vec<u8>>,
}
impl From<Option<Vec<u8>>> for ClientAuthConfig {
fn from(hmac_key: Option<Vec<u8>>) -> Self {
Self { hmac_key }
}
}
impl From<ClientAuthConfig> for Option<Vec<u8>> {
fn from(auth: ClientAuthConfig) -> Self {
auth.hmac_key
}
}
impl Default for ClientConfig {
fn default() -> Self {
Self {
@@ -190,7 +167,7 @@ impl Default for ClientConfig {
stamp_at: StampAt::Both,
clock: Clock::Both,
dscp: 0,
hmac_key: None,
auth: Authentication::Unauthenticated,
server_fill: None,
open_timeouts: DEFAULT_OPEN_TIMEOUTS.to_vec(),
run_mode: RunMode::Normal,
+4 -2
View File
@@ -34,6 +34,7 @@
#[cfg(feature = "tokio")]
mod async_client;
mod auth;
mod client;
mod config;
mod error;
@@ -49,10 +50,11 @@ mod timing;
#[cfg(feature = "tokio")]
pub use async_client::AsyncClient;
pub use auth::{Authentication, HmacKey};
pub use client::Client;
pub use config::{
ClientAuthConfig, ClientConfig, NegotiationPolicy, RecvBudget, RunMode, SocketConfig,
MAX_DSCP_CODEPOINT, MAX_SERVER_FILL_BYTES, MAX_TTL, MAX_UDP_PAYLOAD_LENGTH,
ClientConfig, NegotiationPolicy, RecvBudget, RunMode, SocketConfig, MAX_DSCP_CODEPOINT,
MAX_SERVER_FILL_BYTES, MAX_TTL, MAX_UDP_PAYLOAD_LENGTH,
};
pub use error::ClientError;
pub use event::{
+26 -4
View File
@@ -2,7 +2,7 @@ use std::{fmt, net::SocketAddr, sync::Arc, time::Duration};
use thiserror::Error;
use crate::{ClientAuthConfig, ClientConfig, ClientError, ClientEvent};
use crate::{Authentication, ClientConfig, ClientError, ClientEvent};
use super::TargetId;
@@ -26,12 +26,34 @@ pub struct TargetInstance {
pub generation: u64,
}
/// Endpoint and optional authentication override for one managed target.
/// Authentication specification for a managed target.
///
/// Equality preserves the specification: inheritance and an explicit override
/// remain distinct even when they currently resolve to the same authentication.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub enum TargetAuth {
/// Use the shared client configuration's authentication.
#[default]
Inherit,
/// Replace shared authentication. `Unauthenticated` explicitly disables it.
Override(Authentication),
}
impl TargetAuth {
pub(crate) fn resolve(&self, shared: &Authentication) -> Authentication {
match self {
Self::Inherit => shared.clone(),
Self::Override(auth) => auth.clone(),
}
}
}
/// Endpoint and authentication specification for one managed target.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ManagedTargetConfig {
pub id: TargetId,
pub server_addr: String,
pub auth: Option<ClientAuthConfig>,
pub auth: TargetAuth,
}
impl ManagedTargetConfig {
@@ -39,7 +61,7 @@ impl ManagedTargetConfig {
Self {
id: id.into(),
server_addr: server_addr.into(),
auth: None,
auth: TargetAuth::Inherit,
}
}
}
+2 -6
View File
@@ -945,9 +945,7 @@ impl ManagedClientTask {
}
let mut client_config = self.config.client.clone();
client_config.server_addr.clone_from(&target.server_addr);
if let Some(auth) = &target.auth {
client_config.hmac_key.clone_from(&auth.hmac_key);
}
client_config.auth = target.auth.resolve(&self.config.client.auth);
validate_target_config(&client_config).map_err(|source| {
ManagedCommandApplyError::InvalidTarget {
id: target.id.clone(),
@@ -2251,9 +2249,7 @@ fn build_task(
.ok_or(ManagedConfigError::GenerationExhausted)?;
let mut client_config = config.client.clone();
client_config.server_addr.clone_from(&target.server_addr);
if let Some(auth) = &target.auth {
client_config.hmac_key.clone_from(&auth.hmac_key);
}
client_config.auth = target.auth.resolve(&config.client.auth);
validate_target_config(&client_config).map_err(|source| {
ManagedConfigError::InvalidTarget {
id: target.id.clone(),
+6 -6
View File
@@ -201,7 +201,7 @@ impl SessionMachine {
}
pub(crate) fn has_hmac(&self) -> bool {
self.config.hmac_key.is_some()
self.config.auth.hmac_key().is_some()
}
pub(crate) fn prepare_open_request(&self) -> Result<PreparedOpenRequest, ClientError> {
@@ -211,7 +211,7 @@ impl SessionMachine {
params: &self.requested,
no_test: self.config.run_mode == RunMode::NoTest,
},
self.config.hmac_key.as_deref(),
self.config.auth.hmac_key(),
)?;
Ok(PreparedOpenRequest {
bytes: bytes.into_boxed_slice(),
@@ -223,7 +223,7 @@ impl SessionMachine {
packet: &[u8],
) -> Result<OpenDatagramDisposition, ClientError> {
self.ensure_connected()?;
match irtt_proto::decode_open_reply(packet, self.config.hmac_key.as_deref()) {
match irtt_proto::decode_open_reply(packet, self.config.auth.hmac_key()) {
Ok(reply) => Ok(OpenDatagramDisposition::Trusted(reply)),
Err(error @ irtt_proto::ProtoError::ZeroToken) => Err(ClientError::Protocol(error)),
Err(
@@ -250,7 +250,7 @@ impl SessionMachine {
let cleanup_close = if !reply_is_close && reply.token != 0 {
let bytes = encode_request(
RequestToEncode::Close { token: reply.token },
self.config.hmac_key.as_deref(),
self.config.auth.hmac_key(),
)
.map_err(ClientError::from)
.map_err(OpenAcceptanceFailure::without_cleanup)?;
@@ -313,7 +313,7 @@ impl SessionMachine {
params: &session.negotiated.params,
payload: &[],
},
self.config.hmac_key.as_deref(),
self.config.auth.hmac_key(),
)?;
Ok(PreparedProbe {
bytes: bytes.into_boxed_slice(),
@@ -679,7 +679,7 @@ impl SessionMachine {
decode_echo_reply(
packet,
&session.negotiated.params,
self.config.hmac_key.as_deref(),
self.config.auth.hmac_key(),
)
.ok()
}
+4 -3
View File
@@ -1,10 +1,11 @@
use super::*;
use irtt_client::{Authentication, HmacKey};
#[test]
fn hmac_open_ignores_missing_hmac_before_valid_reply() {
let key = b"secret".to_vec();
let mut config = default_test_config(SocketAddr::from(([127, 0, 0, 1], 1)));
config.hmac_key = Some(key.clone());
config.auth = Authentication::Hmac(HmacKey::new(key.clone()));
let params = default_params();
let server = start_fake_server(move |socket, tx| {
let (_, peer) = recv_request(&socket, &tx);
@@ -26,7 +27,7 @@ fn hmac_open_ignores_bad_hmac_before_valid_reply() {
let key = b"secret".to_vec();
let wrong_key = b"wrong".to_vec();
let mut config = default_test_config(SocketAddr::from(([127, 0, 0, 1], 1)));
config.hmac_key = Some(key.clone());
config.auth = Authentication::Hmac(HmacKey::new(key.clone()));
let params = default_params();
let server = start_fake_server(move |socket, tx| {
let (_, peer) = recv_request(&socket, &tx);
@@ -47,7 +48,7 @@ fn hmac_open_ignores_bad_hmac_before_valid_reply() {
fn post_token_hmac_negotiation_failure_sends_authenticated_cleanup_close() {
let key = b"secret".to_vec();
let mut config = default_test_config(SocketAddr::from(([127, 0, 0, 1], 1)));
config.hmac_key = Some(key.clone());
config.auth = Authentication::Hmac(HmacKey::new(key.clone()));
let mut returned = default_params();
returned.interval_ns += 1;
let server_key = key.clone();
@@ -1,3 +1,4 @@
use irtt_client::{Authentication, HmacKey};
use std::{
future::Future,
net::UdpSocket,
@@ -54,7 +55,9 @@ fn config(addr: SocketAddr, key: Option<Vec<u8>>, dscp: u8) -> ClientConfig {
received_stats: ReceivedStats::None,
stamp_at: StampAt::None,
dscp,
hmac_key: key,
auth: key.map_or(Authentication::Unauthenticated, |key| {
Authentication::Hmac(HmacKey::new(key))
}),
open_timeouts: vec![Duration::from_millis(200)],
socket_config: SocketConfig {
recv_timeout: Some(Duration::from_millis(200)),
+14 -9
View File
@@ -1,3 +1,4 @@
use irtt_client::{Authentication, HmacKey};
mod support;
use std::time::Duration;
@@ -27,7 +28,7 @@ fn hmac_open_success_negotiates_without_warnings() {
TimestampFields::default(),
Some(key),
|addr| ClientConfig {
hmac_key: Some(config_key),
auth: Authentication::Hmac(HmacKey::new(config_key)),
..config_for_params(addr, &config_params)
},
);
@@ -52,7 +53,7 @@ fn hmac_echo_success_verifies_request_and_accepts_reply() {
let run = run_one_probe_with_config(params.clone(), standard_timestamps(), Some(key), |addr| {
ClientConfig {
hmac_key: Some(config_key),
auth: Authentication::Hmac(HmacKey::new(config_key)),
..config_for_params(addr, &config_params)
}
});
@@ -94,7 +95,7 @@ fn hmac_close_success_sends_authenticated_close_and_closes_session() {
let params = default_params();
let server = start_hmac_close_server(params.clone(), key.clone());
let mut config = config_for_params(server.addr, &params);
config.hmac_key = Some(key);
config.auth = Authentication::Hmac(HmacKey::new(key));
let mut client = Client::connect(config).unwrap();
let outcome = client.open().unwrap();
@@ -135,7 +136,9 @@ fn hmac_required_server_rejects_missing_or_wrong_client_key() {
let server = start_hmac_required_open_drop_server(server_key, Duration::from_millis(250));
let mut config = config_for_params(server.addr, &default_params());
config.open_timeouts = vec![Duration::from_millis(200)];
config.hmac_key = hmac_key;
config.auth = hmac_key.map_or(Authentication::Unauthenticated, |key| {
Authentication::Hmac(HmacKey::new(key))
});
let mut client = Client::connect(config).unwrap();
assert!(matches!(client.open(), Err(ClientError::OpenTimeout)));
@@ -158,7 +161,7 @@ fn bad_hmac_echo_reply_is_rejected_without_echo_reply_event() {
let params = default_params();
let server = start_bad_hmac_echo_reply_server(params.clone(), key.clone());
let mut config = config_for_params(server.addr, &params);
config.hmac_key = Some(key);
config.auth = Authentication::Hmac(HmacKey::new(key));
config.socket_config = SocketConfig {
recv_timeout: Some(Duration::from_millis(500)),
..Default::default()
@@ -205,7 +208,7 @@ fn hmac_open_reply_with_bad_hmac_is_ignored_until_timeout() {
let params = default_params();
let server = support::start_bad_hmac_open_reply_server(params.clone(), key.clone(), wrong_key);
let mut config = config_for_params(server.addr, &params);
config.hmac_key = Some(key);
config.auth = Authentication::Hmac(HmacKey::new(key));
let mut client = Client::connect(config).unwrap();
assert!(matches!(client.open(), Err(ClientError::OpenTimeout)));
@@ -221,7 +224,7 @@ fn non_hmac_client_open_does_not_set_hmac_flag() {
);
let server = support::start_open_server(params.clone(), None);
let mut config = config_for_params(server.addr, &params);
config.hmac_key = None;
config.auth = Authentication::Unauthenticated;
let mut client = Client::connect(config).unwrap();
let outcome = client.open().unwrap();
@@ -278,7 +281,7 @@ fn backend_hmac_correct_key_succeeds() {
let params = default_params();
let peer = BackendPeer::start_open_echo(Some(key.clone()));
let mut config = config_for_params(peer.addr(), &params);
config.hmac_key = Some(key);
config.auth = Authentication::Hmac(HmacKey::new(key));
let mut client = Client::connect(config).unwrap();
let outcome = client.open().unwrap();
@@ -301,7 +304,9 @@ fn backend_hmac_required_rejects_missing_or_wrong_client_key() {
let peer = BackendPeer::start_hmac_required(server_key);
let mut config = config_for_params(peer.addr(), &default_params());
config.open_timeouts = vec![Duration::from_millis(200)];
config.hmac_key = hmac_key;
config.auth = hmac_key.map_or(Authentication::Unauthenticated, |key| {
Authentication::Hmac(HmacKey::new(key))
});
let mut client = Client::connect(config).unwrap();
assert!(matches!(client.open(), Err(ClientError::OpenTimeout)));
@@ -1,3 +1,4 @@
use irtt_client::{Authentication, HmacKey};
use std::{
future::Future,
net::{SocketAddr, UdpSocket},
@@ -14,8 +15,8 @@ use irtt_proto::{
};
use tokio::runtime::{Builder, Runtime};
use irtt_client::RunMode;
use irtt_client::{managed::*, ClientConfig};
use irtt_client::{ClientAuthConfig, RunMode};
use tokio::sync::broadcast;
const TOKEN: u64 = 0x1234_5678_90ab_cdef;
@@ -355,9 +356,7 @@ fn authenticated_peer_close_outcome() {
let key = b"managed-peer-close".to_vec();
let server = start_server(ServerBehavior::PeerClose, Some(key.clone()));
let mut configured = target("peer", server.addr);
configured.auth = Some(ClientAuthConfig {
hmac_key: Some(key),
});
configured.auth = TargetAuth::Override(Authentication::Hmac(HmacKey::new(key)));
let (task, _) =
ManagedClient::task(config(ManagedPacing::Staggered), vec![configured]).unwrap();
let outcome = runtime().block_on(task);
@@ -418,9 +417,7 @@ fn pending_limit_failure_drains_reply_and_closes_session() {
managed.client.max_pending_probes = 1;
managed.final_drain = Duration::from_millis(50);
let mut configured = target("one", server.addr);
configured.auth = Some(ClientAuthConfig {
hmac_key: Some(key),
});
configured.auth = TargetAuth::Override(Authentication::Hmac(HmacKey::new(key)));
let (task, _) = ManagedClient::task(managed, vec![configured]).unwrap();
let outcome = runtime().block_on(async {
tokio::time::timeout(Duration::from_secs(1), task)
@@ -1,3 +1,4 @@
use irtt_client::{Authentication, HmacKey};
mod support;
mod protocol_options {
pub mod backend_smoke;
@@ -148,7 +149,7 @@ fn hmac_rich_mode_uses_negotiated_echo_layout_and_decodes_reply() {
let config_key = key.clone();
let run = run_one_probe_with_config(params.clone(), standard_timestamps(), Some(key), |addr| {
ClientConfig {
hmac_key: Some(config_key),
auth: Authentication::Hmac(HmacKey::new(config_key)),
..config_for_params(addr, &config_params)
}
});