1use bytes::{Buf, BufMut};
9use chrony_candm_derive::{ChronyMessage, ChronySerialize};
10use num_enum::{IntoPrimitive, TryFromPrimitive};
11use std::{convert::TryInto, time::SystemTime};
12
13use crate::common::*;
14use crate::reply;
15
16#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
17pub struct Online {
18 pub mask: ChronyAddr,
19 pub address: ChronyAddr,
20}
21
22#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
23pub struct Offline {
24 pub mask: ChronyAddr,
25 pub address: ChronyAddr,
26}
27
28#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
29pub struct Burst {
30 pub mask: ChronyAddr,
31 pub address: ChronyAddr,
32 pub n_good_samples: i32,
33 pub n_total_samples: i32,
34}
35#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
36pub struct ModifyMinPoll {
37 pub address: ChronyAddr,
38 pub new_minpoll: i32,
39}
40#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
41pub struct ModifyMaxPoll {
42 pub address: ChronyAddr,
43 pub new_maxpoll: i32,
44}
45
46#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
47pub struct ModifyMaxDelay {
48 pub address: ChronyAddr,
49 pub new_max_delay: ChronyFloat,
50}
51
52#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
53pub struct ModifyMaxDelayRatio {
54 pub address: ChronyAddr,
55 pub new_max_delay_ratio: ChronyFloat,
56}
57
58#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
59pub struct ModifyMaxDelayDevRatio {
60 pub address: ChronyAddr,
61 pub new_max_delay_dev_ratio: ChronyFloat,
62}
63
64#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
65pub struct ModifyMinStratum {
66 pub address: ChronyAddr,
67 pub new_min_stratum: i32,
68}
69
70#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
71pub struct ModifyPollTarget {
72 pub address: ChronyAddr,
73 pub new_poll_target: i32,
74}
75
76#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
77pub struct ModifyMaxUpdateSkew {
78 pub new_max_update_skew: ChronyFloat,
79}
80
81#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
82pub struct ModifyMakeStep {
83 pub limit: i32,
84 pub threshold: ChronyFloat,
85}
86
87#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
88pub struct Logon {
89 pub ts: SystemTime,
90}
91
92#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
93pub struct SetTime {
94 pub ts: SystemTime,
95}
96
97#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
98pub struct Local {
99 pub on_off: i32,
100 pub stratum: i32,
101 pub distance: ChronyFloat,
102 pub orphan: i32,
103}
104
105#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
106pub struct Manual {
107 pub option: i32,
108}
109
110#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
111pub struct SourceData {
112 pub index: i32,
113}
114
115#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
116pub struct AllowDeny {
117 pub ip: ChronyAddr,
118 pub subnet_bits: i32,
119}
120
121#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
122pub struct AcCheck {
123 pub ip: ChronyAddr,
124}
125
126#[repr(u32)]
127#[derive(
128 Debug,
129 Copy,
130 Clone,
131 PartialEq,
132 Eq,
133 Ord,
134 PartialOrd,
135 Hash,
136 IntoPrimitive,
137 TryFromPrimitive,
138 ChronySerialize,
139)]
140pub enum AddSrcType {
141 Server = 1,
142 Peer = 2,
143 Pool = 3,
144}
145
146#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
147pub struct NtpSource {
148 pub src_type: AddSrcType,
149 pub name: [u8; 256],
150 pub port: u32,
151 pub minpoll: i32,
152 pub maxpoll: i32,
153 pub presend_minpoll: i32,
154 pub min_stratum: i32,
155 pub poll_target: u32,
156 pub version: u32,
157 pub max_sources: u32,
158 pub min_samples: u32,
159 pub max_samples: u32,
160 pub authkey: u32,
161 pub nts_port: u32,
162 pub max_delay: ChronyFloat,
163 pub max_delay_ratio: ChronyFloat,
164 pub max_delay_dev_ratio: ChronyFloat,
165 pub min_delay: ChronyFloat,
166 pub asymmetry: ChronyFloat,
167 #[pad = 2]
171 pub offset: ChronyFloat,
172 pub flags: SourceFlags,
173 pub filter_length: i32,
174 #[pad = 8]
175 pub cert_set: i32,
176}
177
178#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
179pub struct DelSource {
180 pub ip_addr: ChronyAddr,
181}
182
183#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
184pub struct DFreq {
185 pub dfreq: ChronyFloat,
186}
187
188#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
189pub struct DOffset {
190 pub doffset: ChronyFloat,
191}
192
193#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
194pub struct SourceStats {
195 pub index: u32,
196}
197
198#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
199pub struct ClientAccessesByIndex {
200 pub first_index: u32,
201 pub n_clients: u32,
202 pub min_hits: u32,
203 pub reset: u32,
204}
205
206#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
207pub struct ManualDelete {
208 pub index: u32,
209}
210
211#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
212pub struct ReselectDistance {
213 pub distance: ChronyFloat,
214}
215
216#[repr(i32)]
217#[derive(
218 Debug,
219 Copy,
220 Clone,
221 PartialEq,
222 Eq,
223 Ord,
224 PartialOrd,
225 Hash,
226 IntoPrimitive,
227 TryFromPrimitive,
228 ChronySerialize,
229)]
230pub enum SmoothTimeOption {
231 Reset,
232 Activate,
233}
234
235#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
236pub struct SmoothTime {
237 pub option: SmoothTimeOption,
238}
239
240#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
241pub struct NtpData {
242 pub ip_addr: ChronyAddr,
243}
244
245#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
246pub struct NtpSourceName {
247 pub ip_addr: ChronyAddr,
248}
249
250#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
251pub struct AuthData {
252 pub ip_addr: ChronyAddr,
253}
254
255#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronySerialize)]
256pub struct SelectData {
257 pub index: u32,
258}
259
260#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, ChronyMessage)]
261pub enum RequestBody {
262 Null,
263 Online(Online),
264 Offline(Offline),
265 Burst(Burst),
266 ModifyMinPoll(ModifyMinPoll),
267 ModifyMaxPoll(ModifyMaxPoll),
268 #[pad = 4]
269 Dump,
270 ModifyMaxDelay(ModifyMaxDelay),
271 ModifyMaxDelayRatio(ModifyMaxDelayRatio),
272 ModifyMaxUpdateSkew(ModifyMaxUpdateSkew),
273 Logon(Logon),
274 SetTime(SetTime),
275 #[cmd = 13]
276 Manual(Manual),
277 NSources,
278 SourceData(SourceData),
279 Rekey,
280 Allow(AllowDeny),
281 AllowAll(AllowDeny),
282 Deny(AllowDeny),
283 DenyAll(AllowDeny),
284 CmdAllow(AllowDeny),
285 CmdAllowAll(AllowDeny),
286 CmdDeny(AllowDeny),
287 CmdDenyAll(AllowDeny),
288 AcCheck(AcCheck),
289 CmdAcCheck(AcCheck),
290 #[cmd = 29]
291 DelSource(DelSource),
292 WriteRtc,
293 DFreq(DFreq),
294 #[cmd = 33]
295 Tracking,
296 SourceStats(SourceStats),
297 RtcReport,
298 TrimRtc,
299 CycleLogs,
300 #[cmd = 41]
301 ManualList,
302 ManualDelete(ManualDelete),
303 MakeStep,
304 Activity,
305 ModifyMinStratum(ModifyMinStratum),
306 ModifyPollTarget(ModifyPollTarget),
307 ModifyMaxDelayDevRatio(ModifyMaxDelayDevRatio),
308 Reselect,
309 ReselectDistance(ReselectDistance),
310 ModifyMakeStep(ModifyMakeStep),
311 Smoothing,
312 SmoothTime(SmoothTime),
313 Refresh,
314 ServerStats,
315 #[cmd = 56]
316 Local2(Local),
317 NtpData(NtpData),
318 #[cmd = 62]
319 Shutdown,
320 OnOffline,
321 AddSource(NtpSource),
322 NtpSourceName(NtpSourceName),
323 ResetSources,
324 AuthData(AuthData),
325 ClientAccessesByIndex3(ClientAccessesByIndex),
326 SelectData(SelectData),
327 ReloadSources,
328 DOffset2(DOffset),
329}
330
331impl RequestBody {
332 pub(crate) fn reply_body_length(&self) -> usize {
333 match self {
334 Self::Null => 0,
335 Self::Online(_) => 0,
336 Self::Offline(_) => 0,
337 Self::Burst(_) => 0,
338 Self::ModifyMinPoll(_) => 0,
339 Self::ModifyMaxPoll(_) => 0,
340 Self::Dump => 0,
341 Self::ModifyMaxDelay(_) => 0,
342 Self::ModifyMaxDelayRatio(_) => 0,
343 Self::ModifyMaxUpdateSkew(_) => 0,
344 Self::Logon(_) => 0,
345 Self::SetTime(_) => reply::ManualTimestamp::length(),
346 Self::Manual(_) => 0,
347 Self::NSources => reply::NSources::length(),
348 Self::SourceData(_) => reply::SourceData::length(),
349 Self::Rekey => 0,
350 Self::Allow(_) => 0,
351 Self::AllowAll(_) => 0,
352 Self::Deny(_) => 0,
353 Self::DenyAll(_) => 0,
354 Self::CmdAllow(_) => 0,
355 Self::CmdAllowAll(_) => 0,
356 Self::CmdDeny(_) => 0,
357 Self::CmdDenyAll(_) => 0,
358 Self::AcCheck(_) => 0,
359 Self::CmdAcCheck(_) => 0,
360 Self::DelSource(_) => 0,
361 Self::WriteRtc => 0,
362 Self::DFreq(_) => 0,
363 Self::Tracking => reply::Tracking::length(),
364 Self::SourceStats(_) => reply::SourceStats::length(),
365 Self::RtcReport => reply::Rtc::length(),
366 Self::TrimRtc => 0,
367 Self::CycleLogs => 0,
368 Self::ManualList => reply::ManualList::length(),
369 Self::ManualDelete(_) => 0,
370 Self::MakeStep => 0,
371 Self::Activity => reply::Activity::length(),
372 Self::ModifyMinStratum(_) => 0,
373 Self::ModifyPollTarget(_) => 0,
374 Self::ModifyMaxDelayDevRatio(_) => 0,
375 Self::Reselect => 0,
376 Self::ReselectDistance(_) => 0,
377 Self::ModifyMakeStep(_) => 0,
378 Self::Smoothing => reply::Smoothing::length(),
379 Self::SmoothTime(_) => 0,
380 Self::Refresh => 0,
381 Self::ServerStats => reply::ServerStats4::length(),
382 Self::Local2(_) => 0,
383 Self::NtpData(_) => reply::NtpData::length(),
384 Self::Shutdown => 0,
385 Self::OnOffline => 0,
386 Self::AddSource(_) => 0,
387 Self::NtpSourceName(_) => reply::NtpSourceName::length(),
388 Self::ResetSources => 0,
389 Self::AuthData(_) => reply::AuthData::length(),
390 Self::ClientAccessesByIndex3(_) => reply::ClientAccessesByIndex::length(),
391 Self::SelectData(_) => reply::SelectData::length(),
392 Self::ReloadSources => 0,
393 Self::DOffset2(_) => 0,
394 }
395 }
396}
397
398#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
400pub struct Request {
401 pub sequence: u32,
403 pub attempt: u16,
405 pub body: RequestBody,
407}
408
409impl Request {
410 pub fn length(&self) -> usize {
411 std::cmp::max(
412 self.body.body_length() + REQUEST_HEADER_LENGTH,
413 self.body.reply_body_length() + REPLY_HEADER_LENGTH,
414 )
415 }
416
417 pub fn serialize<B: BufMut>(&self, buf: &mut B) {
418 let cmd = self.body.cmd();
419 let body_length = self.body.body_length();
420 let reply_body_length = self.body.reply_body_length();
421 let padding_length = std::cmp::max(
422 body_length + REQUEST_HEADER_LENGTH,
423 reply_body_length + REPLY_HEADER_LENGTH,
424 ) - REQUEST_HEADER_LENGTH
425 - body_length;
426
427 buf.put_u8(6); buf.put_u8(1); buf.put_u8(0); buf.put_u8(0); buf.put_u16(cmd);
432 buf.put_u16(self.attempt);
433 buf.put_u32(self.sequence);
434 buf.put_u32(0); buf.put_u32(0); self.body.serialize_body(buf);
437 buf.put_slice(vec![0u8; padding_length].as_slice());
438 }
439
440 pub fn deserialize<B: Buf>(buf: &mut B) -> Result<Self, DeserializationError> {
441 if buf.remaining() < REQUEST_HEADER_LENGTH {
442 return Err(DeserializationError::new("message too short"));
443 }
444 if buf.get_u8() != 6 {
445 return Err(DeserializationError::new("unsupported version"));
447 }
448
449 if buf.get_u8() != 1 {
450 return Err(DeserializationError::new("wrong packet type"));
452 }
453
454 buf.get_u8(); buf.get_u8(); let cmd = buf.get_u16();
457 let attempt = buf.get_u16();
458 let sequence = buf.get_u32();
459 buf.get_u32(); buf.get_u32(); let body = RequestBody::deserialize_body(cmd, buf)?;
462
463 let body_length = body.body_length();
464 let reply_body_length = body.reply_body_length();
465 let padding_length = std::cmp::max(body_length, reply_body_length) - body_length;
466 if buf.remaining() < padding_length {
467 return Err(DeserializationError::new("insufficient padding"));
468 }
469 buf.advance(padding_length);
470 Ok(Self {
471 sequence,
472 attempt,
473 body,
474 })
475 }
476
477 pub fn cmd(&self) -> u16 {
478 self.body.cmd()
479 }
480}
481
482pub fn increment_attempt(buf: &mut [u8]) {
483 let old_attempt = u16::from_be_bytes(buf[6..8].try_into().unwrap());
484 let new_attempt = old_attempt + 1;
485 buf[6..8].copy_from_slice(&new_attempt.to_be_bytes());
486}