492 lines
17 KiB
Rust
492 lines
17 KiB
Rust
mod common;
|
|
|
|
use std::collections::VecDeque;
|
|
use std::net::{Ipv4Addr, Ipv6Addr};
|
|
use std::sync::{Arc, RwLock};
|
|
|
|
use tokio::net::TcpListener;
|
|
use tokio::sync::{broadcast, watch};
|
|
|
|
use common::test_helper::{
|
|
dump_cache_reset, dump_cache_response, dump_eod_v1, dump_ipv4_prefix, dump_ipv6_prefix,
|
|
RtrDebugDumper,
|
|
};
|
|
|
|
use rpki::data_model::resources::ip_resources::{IPAddress, IPAddressPrefix};
|
|
use rpki::rtr::cache::{Delta, SharedRtrCache, RtrCacheBuilder, Snapshot};
|
|
use rpki::rtr::payload::{Payload, RouteOrigin, Timing};
|
|
use rpki::rtr::pdu::{
|
|
CacheResponse, CacheReset, EndOfDataV1, IPv4Prefix, IPv6Prefix, ResetQuery, SerialQuery,
|
|
};
|
|
use rpki::rtr::session::RtrSession;
|
|
|
|
fn shared_cache(cache: rpki::rtr::cache::RtrCache) -> SharedRtrCache {
|
|
Arc::new(RwLock::new(cache))
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn reset_query_returns_snapshot_and_end_of_data() {
|
|
let prefix = IPAddressPrefix {
|
|
address: IPAddress::from_ipv4(Ipv4Addr::new(192, 0, 2, 0)),
|
|
prefix_length: 24,
|
|
};
|
|
let origin = RouteOrigin::new(prefix, 24, 64496u32.into());
|
|
|
|
let snapshot = Snapshot::from_payloads(vec![Payload::RouteOrigin(origin)]);
|
|
let cache = RtrCacheBuilder::new()
|
|
.session_id(42)
|
|
.serial(100)
|
|
.timing(Timing::new(600, 600, 7200))
|
|
.snapshot(snapshot)
|
|
.build();
|
|
|
|
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
|
let addr = listener.local_addr().unwrap();
|
|
|
|
let server_cache = shared_cache(cache);
|
|
let (_notify_tx, notify_rx) = broadcast::channel(16);
|
|
let (_shutdown_tx, shutdown_rx) = watch::channel(false);
|
|
|
|
tokio::spawn(async move {
|
|
let (stream, _) = listener.accept().await.unwrap();
|
|
let session = RtrSession::new(server_cache, stream, notify_rx, shutdown_rx);
|
|
session.run().await.unwrap();
|
|
});
|
|
|
|
let mut client = tokio::net::TcpStream::connect(addr).await.unwrap();
|
|
ResetQuery::new(1).write(&mut client).await.unwrap();
|
|
|
|
let mut dump = RtrDebugDumper::new();
|
|
|
|
let response = CacheResponse::read(&mut client).await.unwrap();
|
|
dump.push_value(response.pdu(), dump_cache_response(&response));
|
|
assert_eq!(response.pdu(), 3);
|
|
assert_eq!(response.version(), 1);
|
|
assert_eq!(response.session_id(), 42);
|
|
|
|
let prefix = IPv4Prefix::read(&mut client).await.unwrap();
|
|
dump.push_value(prefix.pdu(), dump_ipv4_prefix(&prefix));
|
|
assert_eq!(prefix.pdu(), 4);
|
|
assert_eq!(prefix.version(), 1);
|
|
assert!(prefix.flag().is_announce());
|
|
assert_eq!(prefix.prefix_len(), 24);
|
|
assert_eq!(prefix.max_len(), 24);
|
|
assert_eq!(prefix.prefix(), Ipv4Addr::new(192, 0, 2, 0));
|
|
assert_eq!(prefix.asn(), 64496u32.into());
|
|
|
|
let eod = EndOfDataV1::read(&mut client).await.unwrap();
|
|
dump.push_value(eod.pdu(), dump_eod_v1(&eod));
|
|
assert_eq!(eod.pdu(), 7);
|
|
assert_eq!(eod.version(), 1);
|
|
assert_eq!(eod.session_id(), 42);
|
|
assert_eq!(eod.serial_number(), 100);
|
|
let timing = eod.timing();
|
|
assert_eq!(timing.refresh, 600);
|
|
assert_eq!(timing.retry, 600);
|
|
assert_eq!(timing.expire, 7200);
|
|
|
|
dump.print_pretty("reset_query_returns_snapshot_and_end_of_data");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn serial_query_returns_end_of_data_when_up_to_date() {
|
|
let cache = RtrCacheBuilder::new()
|
|
.session_id(42)
|
|
.serial(100)
|
|
.timing(Timing {
|
|
refresh: 600,
|
|
retry: 600,
|
|
expire: 7200,
|
|
})
|
|
.build();
|
|
|
|
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
|
let addr = listener.local_addr().unwrap();
|
|
|
|
let server_cache = shared_cache(cache);
|
|
let (_notify_tx, notify_rx) = broadcast::channel(16);
|
|
let (_shutdown_tx, shutdown_rx) = watch::channel(false);
|
|
|
|
tokio::spawn(async move {
|
|
let (stream, _) = listener.accept().await.unwrap();
|
|
let session = RtrSession::new(server_cache, stream, notify_rx, shutdown_rx);
|
|
session.run().await.unwrap();
|
|
});
|
|
|
|
let mut client = tokio::net::TcpStream::connect(addr).await.unwrap();
|
|
SerialQuery::new(1, 42, 100).write(&mut client).await.unwrap();
|
|
|
|
let mut dump = RtrDebugDumper::new();
|
|
|
|
let eod = EndOfDataV1::read(&mut client).await.unwrap();
|
|
dump.push_value(eod.pdu(), dump_eod_v1(&eod));
|
|
assert_eq!(eod.pdu(), 7);
|
|
assert_eq!(eod.version(), 1);
|
|
assert_eq!(eod.session_id(), 42);
|
|
assert_eq!(eod.serial_number(), 100);
|
|
|
|
let timing = eod.timing();
|
|
assert_eq!(timing.refresh, 600);
|
|
assert_eq!(timing.retry, 600);
|
|
assert_eq!(timing.expire, 7200);
|
|
|
|
dump.print_pretty("serial_query_returns_end_of_data_when_up_to_date");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn serial_query_returns_cache_reset_when_session_id_mismatch() {
|
|
let cache = RtrCacheBuilder::new()
|
|
.session_id(42)
|
|
.serial(100)
|
|
.timing(Timing {
|
|
refresh: 600,
|
|
retry: 600,
|
|
expire: 7200,
|
|
})
|
|
.build();
|
|
|
|
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
|
let addr = listener.local_addr().unwrap();
|
|
|
|
let server_cache = shared_cache(cache);
|
|
let (_notify_tx, notify_rx) = broadcast::channel(16);
|
|
let (_shutdown_tx, shutdown_rx) = watch::channel(false);
|
|
|
|
tokio::spawn(async move {
|
|
let (stream, _) = listener.accept().await.unwrap();
|
|
let session = RtrSession::new(server_cache, stream, notify_rx, shutdown_rx);
|
|
session.run().await.unwrap();
|
|
});
|
|
|
|
let mut client = tokio::net::TcpStream::connect(addr).await.unwrap();
|
|
SerialQuery::new(1, 999, 100).write(&mut client).await.unwrap();
|
|
|
|
let mut dump = RtrDebugDumper::new();
|
|
|
|
let reset = CacheReset::read(&mut client).await.unwrap();
|
|
dump.push_value(reset.pdu(), dump_cache_reset(reset.version(), reset.pdu()));
|
|
assert_eq!(reset.pdu(), 8);
|
|
assert_eq!(reset.version(), 1);
|
|
|
|
dump.print_pretty("serial_query_returns_cache_reset_when_session_id_mismatch");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn serial_query_returns_deltas_when_incremental_update_available() {
|
|
let prefix = IPAddressPrefix {
|
|
address: IPAddress::from_ipv4(Ipv4Addr::new(192, 0, 2, 0)),
|
|
prefix_length: 24,
|
|
};
|
|
let origin = RouteOrigin::new(prefix, 24, 64496u32.into());
|
|
|
|
let delta = Arc::new(Delta::new(
|
|
101,
|
|
vec![Payload::RouteOrigin(origin)],
|
|
vec![],
|
|
));
|
|
|
|
let mut deltas = VecDeque::new();
|
|
deltas.push_back(delta);
|
|
|
|
let cache = RtrCacheBuilder::new()
|
|
.session_id(42)
|
|
.serial(101)
|
|
.timing(Timing {
|
|
refresh: 600,
|
|
retry: 600,
|
|
expire: 7200,
|
|
})
|
|
.deltas(deltas)
|
|
.build();
|
|
|
|
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
|
let addr = listener.local_addr().unwrap();
|
|
|
|
let server_cache = shared_cache(cache);
|
|
let (_notify_tx, notify_rx) = broadcast::channel(16);
|
|
let (_shutdown_tx, shutdown_rx) = watch::channel(false);
|
|
|
|
tokio::spawn(async move {
|
|
let (stream, _) = listener.accept().await.unwrap();
|
|
let session = RtrSession::new(server_cache, stream, notify_rx, shutdown_rx);
|
|
session.run().await.unwrap();
|
|
});
|
|
|
|
let mut client = tokio::net::TcpStream::connect(addr).await.unwrap();
|
|
SerialQuery::new(1, 42, 100).write(&mut client).await.unwrap();
|
|
|
|
let mut dump = RtrDebugDumper::new();
|
|
|
|
let response = CacheResponse::read(&mut client).await.unwrap();
|
|
dump.push_value(response.pdu(), dump_cache_response(&response));
|
|
assert_eq!(response.pdu(), 3);
|
|
assert_eq!(response.version(), 1);
|
|
assert_eq!(response.session_id(), 42);
|
|
|
|
let prefix = IPv4Prefix::read(&mut client).await.unwrap();
|
|
dump.push_value(prefix.pdu(), dump_ipv4_prefix(&prefix));
|
|
assert_eq!(prefix.pdu(), 4);
|
|
assert_eq!(prefix.version(), 1);
|
|
assert!(prefix.flag().is_announce());
|
|
assert_eq!(prefix.prefix_len(), 24);
|
|
assert_eq!(prefix.max_len(), 24);
|
|
assert_eq!(prefix.prefix(), Ipv4Addr::new(192, 0, 2, 0));
|
|
assert_eq!(prefix.asn(), 64496u32.into());
|
|
|
|
let eod = EndOfDataV1::read(&mut client).await.unwrap();
|
|
dump.push_value(eod.pdu(), dump_eod_v1(&eod));
|
|
assert_eq!(eod.pdu(), 7);
|
|
assert_eq!(eod.version(), 1);
|
|
assert_eq!(eod.session_id(), 42);
|
|
assert_eq!(eod.serial_number(), 101);
|
|
|
|
let timing = eod.timing();
|
|
assert_eq!(timing.refresh, 600);
|
|
assert_eq!(timing.retry, 600);
|
|
assert_eq!(timing.expire, 7200);
|
|
|
|
dump.print_pretty("serial_query_returns_deltas_when_incremental_update_available");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn reset_query_returns_payloads_in_rtr_order() {
|
|
let v4_low_prefix = IPAddressPrefix {
|
|
address: IPAddress::from_ipv4(Ipv4Addr::new(192, 0, 2, 0)),
|
|
prefix_length: 24,
|
|
};
|
|
let v4_low_origin = RouteOrigin::new(v4_low_prefix, 24, 64496u32.into());
|
|
|
|
let v4_high_prefix = IPAddressPrefix {
|
|
address: IPAddress::from_ipv4(Ipv4Addr::new(198, 51, 100, 0)),
|
|
prefix_length: 24,
|
|
};
|
|
let v4_high_origin = RouteOrigin::new(v4_high_prefix, 24, 64497u32.into());
|
|
|
|
let v6_prefix = IPAddressPrefix {
|
|
address: IPAddress::from_ipv6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)),
|
|
prefix_length: 32,
|
|
};
|
|
let v6_origin = RouteOrigin::new(v6_prefix, 48, 64498u32.into());
|
|
|
|
let snapshot = Snapshot::from_payloads(vec![
|
|
Payload::RouteOrigin(v6_origin),
|
|
Payload::RouteOrigin(v4_low_origin),
|
|
Payload::RouteOrigin(v4_high_origin),
|
|
]);
|
|
|
|
let cache = RtrCacheBuilder::new()
|
|
.session_id(42)
|
|
.serial(100)
|
|
.timing(Timing::new(600, 600, 7200))
|
|
.snapshot(snapshot)
|
|
.build();
|
|
|
|
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
|
let addr = listener.local_addr().unwrap();
|
|
|
|
let server_cache = shared_cache(cache);
|
|
let (_notify_tx, notify_rx) = broadcast::channel(16);
|
|
let (_shutdown_tx, shutdown_rx) = watch::channel(false);
|
|
|
|
tokio::spawn(async move {
|
|
let (stream, _) = listener.accept().await.unwrap();
|
|
let session = RtrSession::new(server_cache, stream, notify_rx, shutdown_rx);
|
|
session.run().await.unwrap();
|
|
});
|
|
|
|
let mut client = tokio::net::TcpStream::connect(addr).await.unwrap();
|
|
ResetQuery::new(1).write(&mut client).await.unwrap();
|
|
|
|
let mut dump = RtrDebugDumper::new();
|
|
|
|
let response = CacheResponse::read(&mut client).await.unwrap();
|
|
dump.push_value(response.pdu(), dump_cache_response(&response));
|
|
assert_eq!(response.pdu(), 3);
|
|
assert_eq!(response.version(), 1);
|
|
assert_eq!(response.session_id(), 42);
|
|
|
|
let first = IPv4Prefix::read(&mut client).await.unwrap();
|
|
dump.push_value(first.pdu(), dump_ipv4_prefix(&first));
|
|
assert_eq!(first.pdu(), 4);
|
|
assert_eq!(first.version(), 1);
|
|
assert!(first.flag().is_announce());
|
|
assert_eq!(first.prefix(), Ipv4Addr::new(198, 51, 100, 0));
|
|
assert_eq!(first.prefix_len(), 24);
|
|
assert_eq!(first.max_len(), 24);
|
|
assert_eq!(first.asn(), 64497u32.into());
|
|
|
|
let second = IPv4Prefix::read(&mut client).await.unwrap();
|
|
dump.push_value(second.pdu(), dump_ipv4_prefix(&second));
|
|
assert_eq!(second.pdu(), 4);
|
|
assert_eq!(second.version(), 1);
|
|
assert!(second.flag().is_announce());
|
|
assert_eq!(second.prefix(), Ipv4Addr::new(192, 0, 2, 0));
|
|
assert_eq!(second.prefix_len(), 24);
|
|
assert_eq!(second.max_len(), 24);
|
|
assert_eq!(second.asn(), 64496u32.into());
|
|
|
|
assert!(u32::from(first.prefix()) > u32::from(second.prefix()));
|
|
|
|
let third = IPv6Prefix::read(&mut client).await.unwrap();
|
|
dump.push_value(third.pdu(), dump_ipv6_prefix(&third));
|
|
assert_eq!(third.pdu(), 6);
|
|
assert_eq!(third.version(), 1);
|
|
assert!(third.flag().is_announce());
|
|
assert_eq!(third.prefix(), Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0));
|
|
assert_eq!(third.prefix_len(), 32);
|
|
assert_eq!(third.max_len(), 48);
|
|
assert_eq!(third.asn(), 64498u32.into());
|
|
|
|
let eod = EndOfDataV1::read(&mut client).await.unwrap();
|
|
dump.push_value(eod.pdu(), dump_eod_v1(&eod));
|
|
assert_eq!(eod.pdu(), 7);
|
|
assert_eq!(eod.version(), 1);
|
|
assert_eq!(eod.session_id(), 42);
|
|
assert_eq!(eod.serial_number(), 100);
|
|
|
|
let timing = eod.timing();
|
|
assert_eq!(timing.refresh, 600);
|
|
assert_eq!(timing.retry, 600);
|
|
assert_eq!(timing.expire, 7200);
|
|
|
|
dump.print_pretty("reset_query_returns_payloads_in_rtr_order");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn serial_query_returns_announcements_before_withdrawals() {
|
|
let announced_low_prefix = IPAddressPrefix {
|
|
address: IPAddress::from_ipv4(Ipv4Addr::new(192, 0, 2, 0)),
|
|
prefix_length: 24,
|
|
};
|
|
let announced_low_origin = RouteOrigin::new(announced_low_prefix, 24, 64496u32.into());
|
|
|
|
let announced_high_prefix = IPAddressPrefix {
|
|
address: IPAddress::from_ipv4(Ipv4Addr::new(198, 51, 100, 0)),
|
|
prefix_length: 24,
|
|
};
|
|
let announced_high_origin = RouteOrigin::new(announced_high_prefix, 24, 64497u32.into());
|
|
|
|
let withdrawn_low_prefix = IPAddressPrefix {
|
|
address: IPAddress::from_ipv4(Ipv4Addr::new(10, 0, 0, 0)),
|
|
prefix_length: 24,
|
|
};
|
|
let withdrawn_low_origin = RouteOrigin::new(withdrawn_low_prefix, 24, 64500u32.into());
|
|
|
|
let withdrawn_high_prefix = IPAddressPrefix {
|
|
address: IPAddress::from_ipv4(Ipv4Addr::new(203, 0, 113, 0)),
|
|
prefix_length: 24,
|
|
};
|
|
let withdrawn_high_origin = RouteOrigin::new(withdrawn_high_prefix, 24, 64501u32.into());
|
|
|
|
let delta = Arc::new(Delta::new(
|
|
101,
|
|
vec![
|
|
Payload::RouteOrigin(announced_low_origin),
|
|
Payload::RouteOrigin(announced_high_origin),
|
|
],
|
|
vec![
|
|
Payload::RouteOrigin(withdrawn_high_origin),
|
|
Payload::RouteOrigin(withdrawn_low_origin),
|
|
],
|
|
));
|
|
|
|
let mut deltas = VecDeque::new();
|
|
deltas.push_back(delta);
|
|
|
|
let cache = RtrCacheBuilder::new()
|
|
.session_id(42)
|
|
.serial(101)
|
|
.timing(Timing {
|
|
refresh: 600,
|
|
retry: 600,
|
|
expire: 7200,
|
|
})
|
|
.deltas(deltas)
|
|
.build();
|
|
|
|
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
|
let addr = listener.local_addr().unwrap();
|
|
|
|
let server_cache = shared_cache(cache);
|
|
let (_notify_tx, notify_rx) = broadcast::channel(16);
|
|
let (_shutdown_tx, shutdown_rx) = watch::channel(false);
|
|
|
|
tokio::spawn(async move {
|
|
let (stream, _) = listener.accept().await.unwrap();
|
|
let session = RtrSession::new(server_cache, stream, notify_rx, shutdown_rx);
|
|
session.run().await.unwrap();
|
|
});
|
|
|
|
let mut client = tokio::net::TcpStream::connect(addr).await.unwrap();
|
|
SerialQuery::new(1, 42, 100).write(&mut client).await.unwrap();
|
|
|
|
let mut dump = RtrDebugDumper::new();
|
|
|
|
let response = CacheResponse::read(&mut client).await.unwrap();
|
|
dump.push_value(response.pdu(), dump_cache_response(&response));
|
|
assert_eq!(response.pdu(), 3);
|
|
assert_eq!(response.version(), 1);
|
|
assert_eq!(response.session_id(), 42);
|
|
|
|
let first = IPv4Prefix::read(&mut client).await.unwrap();
|
|
dump.push_value(first.pdu(), dump_ipv4_prefix(&first));
|
|
assert_eq!(first.pdu(), 4);
|
|
assert_eq!(first.version(), 1);
|
|
assert!(first.flag().is_announce());
|
|
assert_eq!(first.prefix(), Ipv4Addr::new(198, 51, 100, 0));
|
|
assert_eq!(first.prefix_len(), 24);
|
|
assert_eq!(first.max_len(), 24);
|
|
assert_eq!(first.asn(), 64497u32.into());
|
|
|
|
let second = IPv4Prefix::read(&mut client).await.unwrap();
|
|
dump.push_value(second.pdu(), dump_ipv4_prefix(&second));
|
|
assert_eq!(second.pdu(), 4);
|
|
assert_eq!(second.version(), 1);
|
|
assert!(second.flag().is_announce());
|
|
assert_eq!(second.prefix(), Ipv4Addr::new(192, 0, 2, 0));
|
|
assert_eq!(second.prefix_len(), 24);
|
|
assert_eq!(second.max_len(), 24);
|
|
assert_eq!(second.asn(), 64496u32.into());
|
|
|
|
assert!(u32::from(first.prefix()) > u32::from(second.prefix()));
|
|
|
|
let third = IPv4Prefix::read(&mut client).await.unwrap();
|
|
dump.push_value(third.pdu(), dump_ipv4_prefix(&third));
|
|
assert_eq!(third.pdu(), 4);
|
|
assert_eq!(third.version(), 1);
|
|
assert!(!third.flag().is_announce());
|
|
assert_eq!(third.prefix(), Ipv4Addr::new(10, 0, 0, 0));
|
|
assert_eq!(third.prefix_len(), 24);
|
|
assert_eq!(third.max_len(), 24);
|
|
assert_eq!(third.asn(), 64500u32.into());
|
|
|
|
let fourth = IPv4Prefix::read(&mut client).await.unwrap();
|
|
dump.push_value(fourth.pdu(), dump_ipv4_prefix(&fourth));
|
|
assert_eq!(fourth.pdu(), 4);
|
|
assert_eq!(fourth.version(), 1);
|
|
assert!(!fourth.flag().is_announce());
|
|
assert_eq!(fourth.prefix(), Ipv4Addr::new(203, 0, 113, 0));
|
|
assert_eq!(fourth.prefix_len(), 24);
|
|
assert_eq!(fourth.max_len(), 24);
|
|
assert_eq!(fourth.asn(), 64501u32.into());
|
|
|
|
assert!(u32::from(third.prefix()) < u32::from(fourth.prefix()));
|
|
assert!(first.flag().is_announce());
|
|
assert!(second.flag().is_announce());
|
|
assert!(!third.flag().is_announce());
|
|
assert!(!fourth.flag().is_announce());
|
|
|
|
let eod = EndOfDataV1::read(&mut client).await.unwrap();
|
|
dump.push_value(eod.pdu(), dump_eod_v1(&eod));
|
|
assert_eq!(eod.pdu(), 7);
|
|
assert_eq!(eod.version(), 1);
|
|
assert_eq!(eod.session_id(), 42);
|
|
assert_eq!(eod.serial_number(), 101);
|
|
|
|
let timing = eod.timing();
|
|
assert_eq!(timing.refresh, 600);
|
|
assert_eq!(timing.retry, 600);
|
|
assert_eq!(timing.expire, 7200);
|
|
|
|
dump.print_pretty("serial_query_returns_announcements_before_withdrawals");
|
|
} |