完善routerkey和aspa功能
This commit is contained in:
@@ -7,7 +7,7 @@ use anyhow::{anyhow, Context, Result};
|
||||
|
||||
use crate::data_model::resources::as_resources::Asn;
|
||||
use crate::data_model::resources::ip_resources::{IPAddress, IPAddressPrefix};
|
||||
use crate::rtr::payload::{Payload, RouteOrigin};
|
||||
use crate::rtr::payload::{Aspa, Payload, RouteOrigin, RouterKey, Ski};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ParsedVrp {
|
||||
@@ -17,6 +17,19 @@ pub struct ParsedVrp {
|
||||
pub asn: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ParsedAspa {
|
||||
pub customer_asn: u32,
|
||||
pub provider_asns: Vec<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ParsedRouterKey {
|
||||
pub ski: [u8; 20],
|
||||
pub asn: u32,
|
||||
pub spki: Vec<u8>,
|
||||
}
|
||||
|
||||
/// 从文本文件中加载 VRP,并转换成 RTR Payload::RouteOrigin。
|
||||
///
|
||||
/// 文件格式:
|
||||
@@ -52,6 +65,56 @@ pub fn load_vrps_from_file(path: impl AsRef<Path>) -> Result<Vec<Payload>> {
|
||||
Ok(payloads)
|
||||
}
|
||||
|
||||
pub fn load_aspas_from_file(path: impl AsRef<Path>) -> Result<Vec<Payload>> {
|
||||
let path = path.as_ref();
|
||||
|
||||
let content = fs::read_to_string(path)
|
||||
.with_context(|| format!("failed to read ASPA file: {}", path.display()))?;
|
||||
|
||||
let mut payloads = Vec::new();
|
||||
|
||||
for (idx, raw_line) in content.lines().enumerate() {
|
||||
let line_no = idx + 1;
|
||||
let line = raw_line.trim();
|
||||
|
||||
if line.is_empty() || line.starts_with('#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
let aspa = parse_aspa_line(line)
|
||||
.with_context(|| format!("invalid ASPA line {}: {}", line_no, raw_line))?;
|
||||
|
||||
payloads.push(Payload::Aspa(build_aspa(aspa)?));
|
||||
}
|
||||
|
||||
Ok(payloads)
|
||||
}
|
||||
|
||||
pub fn load_router_keys_from_file(path: impl AsRef<Path>) -> Result<Vec<Payload>> {
|
||||
let path = path.as_ref();
|
||||
|
||||
let content = fs::read_to_string(path)
|
||||
.with_context(|| format!("failed to read Router Key file: {}", path.display()))?;
|
||||
|
||||
let mut payloads = Vec::new();
|
||||
|
||||
for (idx, raw_line) in content.lines().enumerate() {
|
||||
let line_no = idx + 1;
|
||||
let line = raw_line.trim();
|
||||
|
||||
if line.is_empty() || line.starts_with('#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
let router_key = parse_router_key_line(line)
|
||||
.with_context(|| format!("invalid Router Key line {}: {}", line_no, raw_line))?;
|
||||
|
||||
payloads.push(Payload::RouterKey(build_router_key(router_key)?));
|
||||
}
|
||||
|
||||
Ok(payloads)
|
||||
}
|
||||
|
||||
/// 解析单行 VRP。
|
||||
///
|
||||
/// 格式:
|
||||
@@ -93,6 +156,59 @@ pub fn parse_vrp_line(line: &str) -> Result<ParsedVrp> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_aspa_line(line: &str) -> Result<ParsedAspa> {
|
||||
let parts: Vec<_> = line.split(',').map(|s| s.trim()).collect();
|
||||
if parts.len() != 2 {
|
||||
return Err(anyhow!(
|
||||
"expected format: <customer_asn>,<provider_asn> [provider_asn ...]"
|
||||
));
|
||||
}
|
||||
|
||||
let customer_asn = u32::from_str(parts[0])
|
||||
.with_context(|| format!("invalid customer_asn: {}", parts[0]))?;
|
||||
|
||||
let provider_asns = parts[1]
|
||||
.split_whitespace()
|
||||
.map(|provider| {
|
||||
u32::from_str(provider)
|
||||
.with_context(|| format!("invalid provider_asn: {}", provider))
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
validate_aspa(customer_asn, &provider_asns)?;
|
||||
|
||||
Ok(ParsedAspa {
|
||||
customer_asn,
|
||||
provider_asns,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_router_key_line(line: &str) -> Result<ParsedRouterKey> {
|
||||
let parts: Vec<_> = line.split(',').map(|s| s.trim()).collect();
|
||||
if parts.len() != 3 {
|
||||
return Err(anyhow!(
|
||||
"expected format: <ski_hex>,<asn>,<spki_hex>"
|
||||
));
|
||||
}
|
||||
|
||||
let ski_vec = decode_hex(parts[0])
|
||||
.with_context(|| format!("invalid SKI hex: {}", parts[0]))?;
|
||||
if ski_vec.len() != 20 {
|
||||
return Err(anyhow!("SKI must be exactly 20 bytes"));
|
||||
}
|
||||
let mut ski = [0u8; 20];
|
||||
ski.copy_from_slice(&ski_vec);
|
||||
|
||||
let asn = u32::from_str(parts[1])
|
||||
.with_context(|| format!("invalid asn: {}", parts[1]))?;
|
||||
let spki = decode_hex(parts[2])
|
||||
.with_context(|| format!("invalid SPKI hex: {}", parts[2]))?;
|
||||
|
||||
validate_router_key(asn, &spki)?;
|
||||
|
||||
Ok(ParsedRouterKey { ski, asn, spki })
|
||||
}
|
||||
|
||||
fn validate_vrp(prefix_addr: IpAddr, prefix_len: u8, max_len: u8) -> Result<()> {
|
||||
match prefix_addr {
|
||||
IpAddr::V4(_) => {
|
||||
@@ -121,6 +237,33 @@ fn validate_vrp(prefix_addr: IpAddr, prefix_len: u8, max_len: u8) -> Result<()>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_aspa(customer_asn: u32, provider_asns: &[u32]) -> Result<()> {
|
||||
if customer_asn == 0 {
|
||||
return Err(anyhow!("customer_asn must not be AS0"));
|
||||
}
|
||||
|
||||
if provider_asns.is_empty() {
|
||||
return Err(anyhow!("provider list must not be empty"));
|
||||
}
|
||||
|
||||
if provider_asns.iter().any(|asn| *asn == 0) {
|
||||
return Err(anyhow!("provider list must not contain AS0"));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_router_key(asn: u32, spki: &[u8]) -> Result<()> {
|
||||
crate::rtr::payload::RouterKey::new(
|
||||
Ski::default(),
|
||||
Asn::from(asn),
|
||||
spki.to_vec(),
|
||||
)
|
||||
.validate()
|
||||
.map_err(|err| anyhow!(err.to_string()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn build_route_origin(vrp: ParsedVrp) -> Result<RouteOrigin> {
|
||||
let address = match vrp.prefix_addr {
|
||||
IpAddr::V4(addr) => IPAddress::from_ipv4(addr),
|
||||
@@ -133,53 +276,37 @@ pub fn build_route_origin(vrp: ParsedVrp) -> Result<RouteOrigin> {
|
||||
Ok(RouteOrigin::new(prefix, vrp.max_len, asn))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
pub fn build_aspa(aspa: ParsedAspa) -> Result<Aspa> {
|
||||
let customer_asn = Asn::from(aspa.customer_asn);
|
||||
let provider_asns = aspa
|
||||
.provider_asns
|
||||
.into_iter()
|
||||
.map(Asn::from)
|
||||
.collect::<Vec<_>>();
|
||||
let aspa = Aspa::new(customer_asn, provider_asns);
|
||||
aspa.validate_announcement()?;
|
||||
Ok(aspa)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_ipv4_vrp_line() {
|
||||
let got = parse_vrp_line("10.0.0.0/24,24,65001").unwrap();
|
||||
assert_eq!(
|
||||
got,
|
||||
ParsedVrp {
|
||||
prefix_addr: IpAddr::from_str("10.0.0.0").unwrap(),
|
||||
prefix_len: 24,
|
||||
max_len: 24,
|
||||
asn: 65001,
|
||||
}
|
||||
);
|
||||
pub fn build_router_key(router_key: ParsedRouterKey) -> Result<RouterKey> {
|
||||
let asn = Asn::from(router_key.asn);
|
||||
let ski = Ski::from_bytes(router_key.ski);
|
||||
let router_key = RouterKey::new(ski, asn, router_key.spki);
|
||||
Ok(router_key)
|
||||
}
|
||||
|
||||
fn decode_hex(input: &str) -> Result<Vec<u8>> {
|
||||
let trimmed = input.trim();
|
||||
if trimmed.len() % 2 != 0 {
|
||||
return Err(anyhow!("hex string must have even length"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_ipv6_vrp_line() {
|
||||
let got = parse_vrp_line("2001:db8::/32,48,65003").unwrap();
|
||||
assert_eq!(
|
||||
got,
|
||||
ParsedVrp {
|
||||
prefix_addr: IpAddr::from_str("2001:db8::").unwrap(),
|
||||
prefix_len: 32,
|
||||
max_len: 48,
|
||||
asn: 65003,
|
||||
}
|
||||
);
|
||||
}
|
||||
(0..trimmed.len())
|
||||
.step_by(2)
|
||||
.map(|idx| {
|
||||
u8::from_str_radix(&trimmed[idx..idx + 2], 16)
|
||||
.map_err(|err| anyhow!("invalid hex at byte {}: {}", idx / 2, err))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rejects_invalid_max_len() {
|
||||
let err = parse_vrp_line("10.0.0.0/24,16,65001").unwrap_err();
|
||||
assert!(err.to_string().contains("max_len"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rejects_invalid_ip() {
|
||||
let err = parse_vrp_line("10.0.0.999/24,24,65001").unwrap_err();
|
||||
assert!(err.to_string().contains("invalid IP"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_rejects_invalid_format() {
|
||||
let err = parse_vrp_line("10.0.0.0/24,24").unwrap_err();
|
||||
assert!(err.to_string().contains("expected format"));
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ use std::time::Duration;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::data_model::resources::as_resources::Asn;
|
||||
use crate::data_model::resources::ip_resources::IPAddressPrefix;
|
||||
use x509_parser::prelude::FromDer;
|
||||
use x509_parser::x509::SubjectPublicKeyInfo;
|
||||
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
@@ -23,6 +25,12 @@ impl AsRef<[u8]> for Ski {
|
||||
}
|
||||
}
|
||||
|
||||
impl Ski {
|
||||
pub fn from_bytes(bytes: [u8; 20]) -> Self {
|
||||
Self(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
|
||||
pub struct RouteOrigin {
|
||||
prefix: IPAddressPrefix,
|
||||
@@ -80,6 +88,42 @@ impl RouterKey {
|
||||
pub fn spki(&self) -> &[u8] {
|
||||
&self.subject_public_key_info
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> Result<(), io::Error> {
|
||||
if self.asn.into_u32() == 0 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"RouterKey ASN must not be AS0",
|
||||
));
|
||||
}
|
||||
|
||||
if self.subject_public_key_info.is_empty() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"RouterKey SPKI must not be empty",
|
||||
));
|
||||
}
|
||||
|
||||
let (rem, _) = SubjectPublicKeyInfo::from_der(&self.subject_public_key_info)
|
||||
.map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
format!("RouterKey SPKI is not valid DER: {err}"),
|
||||
)
|
||||
})?;
|
||||
|
||||
if !rem.is_empty() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
format!(
|
||||
"RouterKey SPKI DER has trailing bytes: {}",
|
||||
rem.len()
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
|
||||
|
||||
218
src/rtr/pdu.rs
218
src/rtr/pdu.rs
@@ -333,6 +333,8 @@ impl HeaderWithFlags {
|
||||
|
||||
pub fn flags(self) -> Flags{Flags(self.flags)}
|
||||
|
||||
pub fn zero(self) -> u8 { self.zero }
|
||||
|
||||
pub fn length(self) -> u32{u32::from_be(self.length)}
|
||||
}
|
||||
|
||||
@@ -968,6 +970,58 @@ impl RouterKey {
|
||||
pub const PDU: u8 = 9;
|
||||
const BASE_LEN: usize = HEADER_LEN + 20 + 4;
|
||||
|
||||
pub async fn read<Sock: AsyncRead + Unpin>(
|
||||
sock: &mut Sock
|
||||
) -> Result<Self, io::Error> {
|
||||
let header = HeaderWithFlags::read(sock)
|
||||
.await
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string()))?;
|
||||
if header.pdu() != Self::PDU {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"PDU type mismatch when expecting RouterKey",
|
||||
));
|
||||
}
|
||||
Self::read_payload(header, sock).await
|
||||
}
|
||||
|
||||
pub async fn read_payload<Sock: AsyncRead + Unpin>(
|
||||
header: HeaderWithFlags,
|
||||
sock: &mut Sock,
|
||||
) -> Result<Self, io::Error> {
|
||||
let total_len = usize::try_from(header.length()).map_err(|_| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"RouterKey PDU too large for this system to handle",
|
||||
)
|
||||
})?;
|
||||
if total_len < Self::BASE_LEN {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"invalid length for RouterKey PDU",
|
||||
));
|
||||
}
|
||||
|
||||
let body_len = total_len - HEADER_LEN;
|
||||
let mut body = vec![0u8; body_len];
|
||||
sock.read_exact(&mut body).await?;
|
||||
|
||||
let mut ski = [0u8; 20];
|
||||
ski.copy_from_slice(&body[..20]);
|
||||
let asn = Asn::from(u32::from_be_bytes(body[20..24].try_into().unwrap()));
|
||||
let subject_public_key_info = Arc::<[u8]>::from(body[24..].to_vec());
|
||||
|
||||
let res = Self {
|
||||
header,
|
||||
flags: header.flags(),
|
||||
ski: Ski::from_bytes(ski),
|
||||
asn,
|
||||
subject_public_key_info,
|
||||
};
|
||||
res.validate()?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub async fn write<A: AsyncWrite + Unpin>(
|
||||
&self,
|
||||
w: &mut A,
|
||||
@@ -1024,6 +1078,46 @@ impl RouterKey {
|
||||
pub fn spki(&self) -> &[u8] {
|
||||
&self.subject_public_key_info
|
||||
}
|
||||
|
||||
fn validate(&self) -> Result<(), io::Error> {
|
||||
if self.header.pdu() != Self::PDU {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"unexpected PDU type for RouterKey",
|
||||
));
|
||||
}
|
||||
if usize::try_from(self.header.length()).unwrap_or(0) < Self::BASE_LEN {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"RouterKey PDU shorter than fixed wire size",
|
||||
));
|
||||
}
|
||||
if self.header.zero() != 0 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"RouterKey reserved zero octet must be zero",
|
||||
));
|
||||
}
|
||||
if self.header.flags().into_u8() & !0x01 != 0 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"RouterKey flags use reserved bits",
|
||||
));
|
||||
}
|
||||
if self.asn.into_u32() == 0 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"RouterKey ASN must not be AS0",
|
||||
));
|
||||
}
|
||||
if self.subject_public_key_info.is_empty() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"RouterKey SPKI must not be empty",
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1041,6 +1135,63 @@ impl Aspa {
|
||||
pub const PDU: u8 = 11;
|
||||
const BASE_LEN: usize = HEADER_LEN + 4;
|
||||
|
||||
pub async fn read<Sock: AsyncRead + Unpin>(
|
||||
sock: &mut Sock
|
||||
) -> Result<Self, io::Error> {
|
||||
let header = HeaderWithFlags::read(sock)
|
||||
.await
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err.to_string()))?;
|
||||
if header.pdu() != Self::PDU {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"PDU type mismatch when expecting ASPA",
|
||||
));
|
||||
}
|
||||
Self::read_payload(header, sock).await
|
||||
}
|
||||
|
||||
pub async fn read_payload<Sock: AsyncRead + Unpin>(
|
||||
header: HeaderWithFlags,
|
||||
sock: &mut Sock,
|
||||
) -> Result<Self, io::Error> {
|
||||
let total_len = usize::try_from(header.length()).map_err(|_| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"ASPA PDU too large for this system to handle",
|
||||
)
|
||||
})?;
|
||||
if total_len < Self::BASE_LEN {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"invalid length for ASPA PDU",
|
||||
));
|
||||
}
|
||||
if (total_len - Self::BASE_LEN) % 4 != 0 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"ASPA provider list length must be a multiple of four octets",
|
||||
));
|
||||
}
|
||||
|
||||
let body_len = total_len - HEADER_LEN;
|
||||
let mut body = vec![0u8; body_len];
|
||||
sock.read_exact(&mut body).await?;
|
||||
|
||||
let customer_asn = u32::from_be_bytes(body[..4].try_into().unwrap());
|
||||
let mut provider_asns = Vec::with_capacity((body.len() - 4) / 4);
|
||||
for chunk in body[4..].chunks_exact(4) {
|
||||
provider_asns.push(u32::from_be_bytes(chunk.try_into().unwrap()));
|
||||
}
|
||||
|
||||
let res = Self {
|
||||
header,
|
||||
customer_asn,
|
||||
provider_asns,
|
||||
};
|
||||
res.validate()?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub async fn write<A: AsyncWrite + Unpin>(
|
||||
&self,
|
||||
w: &mut A,
|
||||
@@ -1086,6 +1237,73 @@ impl Aspa {
|
||||
}
|
||||
}
|
||||
|
||||
fn validate(&self) -> Result<(), io::Error> {
|
||||
if self.header.pdu() != Self::PDU {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"unexpected PDU type for ASPA",
|
||||
));
|
||||
}
|
||||
let total_len = usize::try_from(self.header.length()).unwrap_or(0);
|
||||
if total_len < Self::BASE_LEN {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"ASPA PDU shorter than fixed wire size",
|
||||
));
|
||||
}
|
||||
if (total_len - Self::BASE_LEN) % 4 != 0 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"ASPA provider list length must be a multiple of four octets",
|
||||
));
|
||||
}
|
||||
if self.header.zero() != 0 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"ASPA reserved zero octet must be zero",
|
||||
));
|
||||
}
|
||||
if self.header.flags().into_u8() & !0x01 != 0 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"ASPA flags use reserved bits",
|
||||
));
|
||||
}
|
||||
if self.customer_asn == 0 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"ASPA customer ASN must not be AS0",
|
||||
));
|
||||
}
|
||||
|
||||
let is_announcement = self.header.flags().is_announce();
|
||||
if is_announcement && self.provider_asns.is_empty() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"ASPA announcement must contain at least one provider ASN",
|
||||
));
|
||||
}
|
||||
if !is_announcement && !self.provider_asns.is_empty() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"ASPA withdrawal must not contain provider ASNs",
|
||||
));
|
||||
}
|
||||
if self.provider_asns.iter().any(|asn| *asn == 0) {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"ASPA provider list must not contain AS0",
|
||||
));
|
||||
}
|
||||
if self.provider_asns.windows(2).any(|pair| pair[0] >= pair[1]) {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"ASPA provider ASNs must be strictly increasing",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -98,9 +98,6 @@ impl RtrServer {
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) = stream.set_nodelay(true) {
|
||||
warn!("failed to enable TCP_NODELAY for {}: {}", peer_addr, err);
|
||||
}
|
||||
if let Err(err) = apply_keepalive(&stream, self.config.tcp_keepalive) {
|
||||
warn!("failed to configure TCP keepalive for {}: {}", peer_addr, err);
|
||||
}
|
||||
@@ -209,9 +206,6 @@ impl RtrServer {
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) = stream.set_nodelay(true) {
|
||||
warn!("failed to enable TCP_NODELAY for {}: {}", peer_addr, err);
|
||||
}
|
||||
if let Err(err) = apply_keepalive(&stream, self.config.tcp_keepalive) {
|
||||
warn!("failed to configure TCP keepalive for {}: {}", peer_addr, err);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::time::{Duration, Instant};
|
||||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use tokio::io;
|
||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite};
|
||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||
use tokio::sync::{broadcast, watch};
|
||||
use tokio::time::timeout;
|
||||
use tracing::{debug, error, info, warn};
|
||||
@@ -77,6 +77,12 @@ where
|
||||
}
|
||||
|
||||
pub async fn run(mut self) -> Result<()> {
|
||||
let result = self.run_inner().await;
|
||||
self.close_transport().await;
|
||||
result
|
||||
}
|
||||
|
||||
async fn run_inner(&mut self) -> Result<()> {
|
||||
info!(
|
||||
"RTR session started: {}",
|
||||
self.session_summary()
|
||||
@@ -251,6 +257,18 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
async fn close_transport(&mut self) {
|
||||
if let Err(err) = self.stream.shutdown().await {
|
||||
debug!(
|
||||
"RTR session transport shutdown returned error: err={}, {}",
|
||||
err,
|
||||
self.session_summary()
|
||||
);
|
||||
} else {
|
||||
debug!("RTR session transport shutdown completed: {}", self.session_summary());
|
||||
}
|
||||
}
|
||||
|
||||
async fn negotiate_version(&mut self, router_version: u8) -> io::Result<u8> {
|
||||
if let Some(current) = self.version {
|
||||
if current == router_version {
|
||||
@@ -958,6 +976,7 @@ where
|
||||
|
||||
async fn send_router_key(&mut self, key: &RouterKey, announce: bool) -> Result<()> {
|
||||
let version = self.version()?;
|
||||
key.validate()?;
|
||||
|
||||
let flags = Flags::new(if announce {
|
||||
ANNOUNCE_FLAG
|
||||
|
||||
Reference in New Issue
Block a user