Zebra/zebra-network/src/meta_addr/tests/check.rs

94 lines
3.5 KiB
Rust

//! Shared test checks for MetaAddr
use std::net::SocketAddr;
use super::super::MetaAddr;
use crate::{constants::TIMESTAMP_TRUNCATION_SECONDS, types::PeerServices};
/// Check that:
/// - the only times that are included in serialized `MetaAddr`s are the last
/// responded time, and the untrusted last seen time, and
/// - `sanitized_addr` has less time and state metadata than `original_addr`.
///
/// Also checks that the time hasn't changed too much.
pub(crate) fn sanitize_avoids_leaks(original: &MetaAddr, sanitized: &MetaAddr) {
// check that irrelevant times are cleared by sanitization
assert_eq!(sanitized.last_attempt, None);
assert_eq!(sanitized.last_failure, None);
// check that the last seen and responded times end up in the untrusted field
// (but ignore their values for now - those checks are next)
assert_eq!(sanitized.last_response, None);
assert_eq!(
sanitized.untrusted_last_seen.is_some(),
original
.last_response
.or(original.untrusted_last_seen)
.is_some()
);
// Check the responded field overrides the untrusted field
assert_eq!(
original.last_seen(),
original.last_response.or(original.untrusted_last_seen)
);
// check for time truncation
if let Some(sanitized_last_seen) = sanitized.last_seen() {
// We want the sanitized timestamp to:
// - be a multiple of the truncation interval,
// - have a zero nanoseconds component, and
// - be within the truncation interval of the original timestamp.
assert_eq!(
sanitized_last_seen.timestamp() % TIMESTAMP_TRUNCATION_SECONDS,
0
);
// check that the times haven't changed too much
let original_last_seen = original
.last_seen()
.expect("unexpected missing original last seen when sanitized last seen is Some");
// handle underflow and overflow by skipping the check
// the other check will ensure correctness
let lowest_time = original_last_seen
.timestamp()
.checked_sub(TIMESTAMP_TRUNCATION_SECONDS);
let highest_time = original_last_seen
.timestamp()
.checked_add(TIMESTAMP_TRUNCATION_SECONDS);
if let Some(lowest_time) = lowest_time {
assert!(sanitized_last_seen.timestamp() > lowest_time);
}
if let Some(highest_time) = highest_time {
assert!(sanitized_last_seen.timestamp() < highest_time);
}
}
// check the other fields
// Sanitize to the the default state, even though it's not serialized
assert_eq!(sanitized.last_connection_state, Default::default());
// Sanitize to known flags
let sanitized_peer_services = original.services & PeerServices::all();
assert_eq!(sanitized.services, sanitized_peer_services);
// Remove IPv6 scope ID and flow information
let sanitized_socket_addr = SocketAddr::new(original.addr.ip(), original.addr.port());
assert_eq!(sanitized.addr.ip(), original.addr.ip());
assert_eq!(sanitized.addr.port(), original.addr.port());
assert_eq!(sanitized.addr, sanitized_socket_addr);
// We want any other fields to be their defaults
assert_eq!(
sanitized,
&MetaAddr::new_gossiped_meta_addr(
sanitized_socket_addr,
sanitized_peer_services,
sanitized
.last_seen()
.expect("unexpected missing last seen time in sanitized MetaAddr")
),
);
}