Skip to content

Commit 70695c4

Browse files
committed
[Monitor] Implemented SRV monitoring.
1 parent efd4c48 commit 70695c4

File tree

6 files changed

+158
-24
lines changed

6 files changed

+158
-24
lines changed

nts-pool-management/src/routes/monitoring.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,15 @@ pub async fn get_work(
3030
ProbeTimesourceInfo {
3131
uuid: ts.id.to_string(),
3232
domain: None,
33+
port: None,
3334
},
3435
),
3536
(
3637
IpVersion::Ipv6,
3738
ProbeTimesourceInfo {
3839
uuid: ts.id.to_string(),
3940
domain: None,
41+
port: None,
4042
},
4143
),
4244
]

nts-pool-monitor/src/control.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,13 @@ impl ProbeExecutor for Probe {
8080
self: Arc<Self>,
8181
timesource: (IpVersion, ProbeTimesourceInfo),
8282
) -> Result<Self::Output, eyre::Error> {
83-
self.probe(timesource.1.uuid, timesource.0).await
83+
self.probe(
84+
timesource.1.uuid,
85+
timesource.1.domain.as_deref().unwrap_or(""),
86+
timesource.1.port.unwrap_or(4460),
87+
timesource.0,
88+
)
89+
.await
8490
}
8591
}
8692

@@ -525,13 +531,15 @@ mod tests {
525531
ProbeTimesourceInfo {
526532
uuid: "A".to_string(),
527533
domain: None,
534+
port: None,
528535
},
529536
),
530537
(
531538
IpVersion::Ipv4,
532539
ProbeTimesourceInfo {
533540
uuid: "B".to_string(),
534541
domain: None,
542+
port: None,
535543
},
536544
),
537545
]
@@ -615,13 +623,15 @@ mod tests {
615623
ProbeTimesourceInfo {
616624
uuid: "A".to_string(),
617625
domain: None,
626+
port: None,
618627
},
619628
),
620629
(
621630
IpVersion::Ipv4,
622631
ProbeTimesourceInfo {
623632
uuid: "B".to_string(),
624633
domain: None,
634+
port: None,
625635
},
626636
),
627637
]
@@ -644,6 +654,7 @@ mod tests {
644654
ProbeTimesourceInfo {
645655
uuid: "B".to_string(),
646656
domain: None,
657+
port: None,
647658
},
648659
)]
649660
.into(),
@@ -664,13 +675,15 @@ mod tests {
664675
ProbeTimesourceInfo {
665676
uuid: "B".to_string(),
666677
domain: None,
678+
port: None,
667679
},
668680
),
669681
(
670682
IpVersion::Ipv4,
671683
ProbeTimesourceInfo {
672684
uuid: "C".to_string(),
673685
domain: None,
686+
port: None,
674687
},
675688
),
676689
]

nts-pool-monitor/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ async fn resolve_as_version<T: tokio::net::ToSocketAddrs>(
2929

3030
for candidate in resolved {
3131
match (ipprot, candidate) {
32-
(IpVersion::Ipv4, SocketAddr::V4(_)) | (IpVersion::Ipv6, SocketAddr::V6(_)) => {
32+
(IpVersion::Ipv4 | IpVersion::Srvv4, SocketAddr::V4(_))
33+
| (IpVersion::Ipv6 | IpVersion::Srvv6, SocketAddr::V6(_)) => {
3334
return Ok(candidate);
3435
}
3536
_ => {}

nts-pool-monitor/src/nts.rs

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -265,25 +265,45 @@ impl KeyExchangeClient {
265265
&self,
266266
io: impl AsyncRead + AsyncWrite + Unpin,
267267
server_name: String,
268-
uuid: impl AsRef<str>,
268+
uuid: Option<impl AsRef<str>>,
269269
) -> Result<KeyExchangeResult, NtsError> {
270-
let request = ClientRequest::Uuid {
271-
algorithms: self
272-
.algorithms
273-
.iter()
274-
.copied()
275-
.map(|v| v.into())
276-
.collect::<Vec<AlgorithmId>>()
277-
.into(),
278-
protocols: self
279-
.protocols
280-
.iter()
281-
.copied()
282-
.map(|v| v.into())
283-
.collect::<Vec<ProtocolId>>()
284-
.into(),
285-
key: self.authorization_key.as_str().into(),
286-
uuid: uuid.as_ref().into(),
270+
let request = if let Some(ref uuid) = uuid {
271+
ClientRequest::Uuid {
272+
algorithms: self
273+
.algorithms
274+
.iter()
275+
.copied()
276+
.map(|v| v.into())
277+
.collect::<Vec<AlgorithmId>>()
278+
.into(),
279+
protocols: self
280+
.protocols
281+
.iter()
282+
.copied()
283+
.map(|v| v.into())
284+
.collect::<Vec<ProtocolId>>()
285+
.into(),
286+
key: self.authorization_key.as_str().into(),
287+
uuid: uuid.as_ref().into(),
288+
}
289+
} else {
290+
ClientRequest::Ordinary {
291+
algorithms: self
292+
.algorithms
293+
.iter()
294+
.copied()
295+
.map(|v| v.into())
296+
.collect::<Vec<AlgorithmId>>()
297+
.into(),
298+
protocols: self
299+
.protocols
300+
.iter()
301+
.copied()
302+
.map(|v| v.into())
303+
.collect::<Vec<ProtocolId>>()
304+
.into(),
305+
denied_servers: vec![],
306+
}
287307
};
288308

289309
let mut io = self

nts-pool-monitor/src/probe.rs

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,13 @@ impl Probe {
5959
pub async fn probe(
6060
&self,
6161
uuid: impl AsRef<str>,
62+
domain: impl AsRef<str>,
63+
port: u16,
6264
ipprot: IpVersion,
6365
) -> Result<ProbeResult, eyre::Error> {
6466
let uuid = uuid.as_ref();
6567
tracing::debug!("Probing {}", uuid);
66-
let (keyexchange, next) = self.probe_keyexchange(uuid, ipprot).await?;
68+
let (keyexchange, next) = self.probe_keyexchange(uuid, domain, port, ipprot).await?;
6769
tracing::debug!("Keyexchange result: {:?}", keyexchange);
6870

6971
let (ntp_with_ke_cookie, next) = match next {
@@ -90,9 +92,62 @@ impl Probe {
9092
async fn probe_keyexchange(
9193
&self,
9294
uuid: impl AsRef<str>,
95+
domain: impl AsRef<str>,
96+
port: u16,
9397
ipprot: IpVersion,
9498
) -> Result<(KeyExchangeProbeResult, Option<NtpInputs>), eyre::Error> {
95-
let addr = resolve_as_version((self.poolke.as_str(), 4460), ipprot).await?;
99+
let (domain, addr) = if ipprot.is_srv() {
100+
match resolve_as_version((domain.as_ref(), port), ipprot).await {
101+
Ok(addr) => (domain.as_ref().to_owned(), addr),
102+
Err(e)
103+
if e.kind() == std::io::ErrorKind::NotFound || e.raw_os_error().is_none() =>
104+
{
105+
if resolve_as_version((domain.as_ref(), port), ipprot.other_ip_protocol())
106+
.await
107+
.is_ok()
108+
{
109+
return Ok((
110+
KeyExchangeProbeResult {
111+
status: match ipprot {
112+
IpVersion::Ipv4 => KeyExchangeStatus::Failed,
113+
IpVersion::Ipv6 => KeyExchangeStatus::Failed,
114+
IpVersion::Srvv4 => KeyExchangeStatus::SrvIpv6Only,
115+
IpVersion::Srvv6 => KeyExchangeStatus::SrvIpv4Only,
116+
},
117+
description: "Only resolvable over other IP version".into(),
118+
exchange_start: SystemTime::now()
119+
.duration_since(SystemTime::UNIX_EPOCH)
120+
.unwrap_or_default()
121+
.as_secs(),
122+
exchange_duration: 0.0,
123+
num_cookies: 0,
124+
},
125+
None,
126+
));
127+
} else {
128+
return Ok((
129+
KeyExchangeProbeResult {
130+
status: KeyExchangeStatus::Failed,
131+
description: "Domain name not resolvable".into(),
132+
exchange_start: SystemTime::now()
133+
.duration_since(SystemTime::UNIX_EPOCH)
134+
.unwrap_or_default()
135+
.as_secs(),
136+
exchange_duration: 0.0,
137+
num_cookies: 0,
138+
},
139+
None,
140+
));
141+
}
142+
}
143+
Err(e) => return Err(e.into()),
144+
}
145+
} else {
146+
(
147+
self.poolke.clone(),
148+
resolve_as_version((self.poolke.as_str(), 4460), ipprot).await?,
149+
)
150+
};
96151
let io = TcpStream::connect(addr).await?;
97152

98153
let exchange_start = SystemTime::now()
@@ -102,12 +157,12 @@ impl Probe {
102157
let start_time = Instant::now();
103158
let ke_result = match timeout(
104159
self.nts_timeout,
105-
self.ntske.exchange_keys(io, self.poolke.clone(), uuid),
160+
self.ntske.exchange_keys(io, domain, Some(uuid)),
106161
)
107162
.await
108163
{
109164
Ok(Ok(result)) => result,
110-
Ok(Err(NtsError::Error(pool_nts::ErrorCode::NoSuchServer))) => {
165+
Ok(Err(NtsError::Error(pool_nts::ErrorCode::NoSuchServer))) if !ipprot.is_srv() => {
111166
return Err(eyre::eyre!("Server not known (yet)"));
112167
}
113168
Ok(Err(e)) => {
@@ -405,6 +460,34 @@ mod tests {
405460

406461
use super::*;
407462

463+
#[tokio::test]
464+
async fn test_nts_keyexchange_dns() {
465+
test_init();
466+
let probe = Probe::new(ProbeConfig {
467+
poolke: "".into(),
468+
nts_config: NtsClientConfig {
469+
certificates: [].into(),
470+
protocol_version: crate::NtpVersion::V4,
471+
authorization_key: "".into(),
472+
},
473+
nts_timeout: Duration::from_secs(1),
474+
ntp_timeout: Duration::from_secs(1),
475+
})
476+
.unwrap();
477+
478+
let findings = probe
479+
.probe_keyexchange("UUID", "doesnotexist", 4460, IpVersion::Srvv4)
480+
.await
481+
.unwrap();
482+
assert_eq!(findings.0.status, KeyExchangeStatus::Failed);
483+
484+
let findings = probe
485+
.probe_keyexchange("UUID", "127.0.0.1", 4460, IpVersion::Srvv6)
486+
.await
487+
.unwrap();
488+
assert_eq!(std::dbg!(findings.0).status, KeyExchangeStatus::SrvIpv4Only);
489+
}
490+
408491
#[tokio::test]
409492
async fn test_ntp_dns_failed() {
410493
test_init();

nts-pool-shared/src/monitoring.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,21 @@ pub enum IpVersion {
1313
Srvv6,
1414
}
1515

16+
impl IpVersion {
17+
pub fn is_srv(self) -> bool {
18+
matches!(self, IpVersion::Srvv4 | IpVersion::Srvv6)
19+
}
20+
21+
pub fn other_ip_protocol(self) -> Self {
22+
match self {
23+
IpVersion::Ipv4 => IpVersion::Ipv6,
24+
IpVersion::Ipv6 => IpVersion::Ipv4,
25+
IpVersion::Srvv4 => IpVersion::Srvv6,
26+
IpVersion::Srvv6 => IpVersion::Srvv4,
27+
}
28+
}
29+
}
30+
1631
impl std::fmt::Display for IpVersion {
1732
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1833
match self {

0 commit comments

Comments
 (0)