Skip to main content

chrony_confile/ast/
source.rs

1//! NTP source configuration types.
2//!
3//! This module defines types for time source directives: [`ServerConfig`] (also used for `peer`),
4//! [`PoolConfig`], [`RefClockConfig`], [`InitStepSlewConfig`], [`AllowDenyConfig`],
5//! [`RateLimitConfig`], [`SmoothTimeConfig`], [`BroadcastConfig`], and [`LocalConfig`].
6//!
7//! [`ServerConfig`] is the largest configuration struct with ~30 fields covering NTP source
8//! options like polling intervals, authentication, select options, and delay constraints.
9
10use crate::values::*;
11
12// --- Select options bitflags ---
13
14/// Bit flags for source selection options (`prefer`, `noselect`, `trust`, `require`).
15///
16/// Used by [`ServerConfig`] and [`RefClockConfig`] to track which selection options
17/// are active for a given source.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
19pub struct SelectOptions(u8);
20
21impl SelectOptions {
22    /// The `noselect` flag: this source should not be selected.
23    pub const NOSELECT: u8 = 0x1;
24    /// The `prefer` flag: prefer this source over others of equal stratum.
25    pub const PREFER: u8 = 0x2;
26    /// The `trust` flag: trust this source even when its measurement is unusual.
27    pub const TRUST: u8 = 0x4;
28    /// The `require` flag: require this source to be reachable for synchronization.
29    pub const REQUIRE: u8 = 0x8;
30
31    /// Set a specific flag.
32    pub fn set(&mut self, flag: u8) {
33        self.0 |= flag;
34    }
35    /// Returns `true` if the given flag is set.
36    pub fn has(&self, flag: u8) -> bool {
37        self.0 & flag != 0
38    }
39    /// Returns `true` if no flags are set.
40    pub fn is_empty(&self) -> bool {
41        self.0 == 0
42    }
43}
44
45// --- Source connectivity ---
46
47/// Whether a source should be taken online or offline initially.
48#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
49pub enum SourceConnectivity {
50    #[default]
51    Online,
52    Offline,
53}
54
55// --- Address family ---
56
57/// IP address family preference for a source.
58#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
59pub enum AddressFamily {
60    #[default]
61    Unspec,
62    Inet4,
63    Inet6,
64}
65
66// --- Refclock driver kind ---
67
68/// The type of reference clock driver.
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70pub enum RefClockDriverKind {
71    Pps,
72    Sock,
73    Shm,
74    Phc,
75}
76
77// --- ServerConfig (main NTP source config, ~30 fields) ---
78
79/// Configuration for an NTP server source (or peer).
80///
81/// This is the largest configuration struct in the crate, with ~30 fields covering all
82/// chrony options for the `server` and `peer` directives: polling intervals, selection
83/// options, authentication, NTS, delay constraints, and address family preferences.
84///
85/// Default values mirror chrony's built-in defaults.
86///
87/// # Examples
88///
89/// ```rust
90/// use chrony_confile::ast::ServerConfig;
91///
92/// let config = ServerConfig {
93///     hostname: "ntp.example.com".to_string(),
94///     iburst: true,
95///     ..Default::default()
96/// };
97///
98/// assert!(config.iburst);
99/// assert_eq!(config.minpoll.get(), 6);
100/// ```
101#[derive(Debug, Clone, PartialEq)]
102pub struct ServerConfig {
103    pub hostname: String,
104    pub port: UdpPort,
105    pub minpoll: PollInterval,
106    pub maxpoll: PollInterval,
107    pub connectivity: SourceConnectivity,
108    pub auto_offline: bool,
109    pub presend: PollInterval,
110    pub burst: bool,
111    pub iburst: bool,
112    pub min_stratum: Stratum,
113    pub poll_target: PollTarget,
114    pub version: Option<NtpVersion>,
115    pub min_samples: Option<u32>,
116    pub max_samples: Option<u32>,
117    pub filter: Option<u32>,
118    pub interleaved: bool,
119    pub select_opts: SelectOptions,
120    pub nts: bool,
121    pub nts_port: UdpPort,
122    pub copy: bool,
123    pub ext_fields: u32,
124    pub authkey: u32,
125    pub cert_set: u32,
126    pub max_delay: f64,
127    pub max_delay_ratio: f64,
128    pub max_delay_dev_ratio: f64,
129    pub max_delay_quant: f64,
130    pub min_delay: f64,
131    pub asymmetry: f64,
132    pub offset: f64,
133    pub family: AddressFamily,
134}
135
136impl Default for ServerConfig {
137    fn default() -> Self {
138        Self {
139            hostname: String::new(),
140            port: UdpPort::new_unchecked(123),
141            minpoll: PollInterval::new_unchecked(6),
142            maxpoll: PollInterval::new_unchecked(10),
143            connectivity: SourceConnectivity::Online,
144            auto_offline: false,
145            presend: PollInterval::new_unchecked(0),
146            burst: false,
147            iburst: false,
148            min_stratum: Stratum::new_unchecked(0),
149            poll_target: PollTarget::new_unchecked(8),
150            version: None,
151            min_samples: None,
152            max_samples: None,
153            filter: None,
154            interleaved: false,
155            select_opts: SelectOptions::default(),
156            nts: false,
157            nts_port: UdpPort::new_unchecked(4460),
158            copy: false,
159            ext_fields: 0,
160            authkey: 0,
161            cert_set: 0,
162            max_delay: 3.0,
163            max_delay_ratio: 0.0,
164            max_delay_dev_ratio: 10.0,
165            max_delay_quant: 0.0,
166            min_delay: 0.0,
167            asymmetry: 1.0,
168            offset: 0.0,
169            family: AddressFamily::Unspec,
170        }
171    }
172}
173
174impl ServerConfig {
175    /// Returns `true` if the `prefer` option is set.
176    pub fn prefer(&self) -> bool {
177        self.select_opts.has(SelectOptions::PREFER)
178    }
179    /// Returns `true` if the `noselect` option is set.
180    pub fn noselect(&self) -> bool {
181        self.select_opts.has(SelectOptions::NOSELECT)
182    }
183    /// Returns `true` if the `trust` option is set.
184    pub fn trust(&self) -> bool {
185        self.select_opts.has(SelectOptions::TRUST)
186    }
187    /// Returns `true` if the `require` option is set.
188    pub fn require(&self) -> bool {
189        self.select_opts.has(SelectOptions::REQUIRE)
190    }
191    /// Returns `true` if interleaved mode (`xleave`) is enabled.
192    pub fn xleave(&self) -> bool {
193        self.interleaved
194    }
195}
196
197// --- PoolConfig ---
198
199/// Configuration for a `pool` directive.
200///
201/// A pool resolves to multiple NTP servers. The `max_sources` field limits how many
202/// servers from the pool are used simultaneously. The `source` field contains the
203/// shared server options (hostname, polling, selection, etc.).
204#[derive(Debug, Clone, PartialEq)]
205pub struct PoolConfig {
206    /// The underlying server configuration (hostname, options, etc.).
207    pub source: ServerConfig,
208    /// Maximum number of sources to use from this pool (default: 4).
209    pub max_sources: u32,
210}
211
212impl Default for PoolConfig {
213    fn default() -> Self {
214        Self {
215            source: ServerConfig::default(),
216            max_sources: 4,
217        }
218    }
219}
220
221// --- PeerConfig = same as ServerConfig ---
222pub type PeerConfig = ServerConfig;
223
224// --- InitStepSlew ---
225
226/// Configuration for the `initstepslew` directive.
227///
228/// Specifies a threshold and a list of hostnames to step the clock at chrony startup
229/// if the offset exceeds the threshold.
230#[derive(Debug, Clone, PartialEq)]
231pub struct InitStepSlewConfig {
232    pub threshold: f64,
233    pub hostnames: Vec<String>,
234}
235
236// --- RefClockConfig ---
237
238/// Configuration for a `refclock` directive (local reference clock).
239#[derive(Debug, Clone, PartialEq)]
240pub struct RefClockConfig {
241    pub driver: RefClockDriverKind,
242    pub parameter: String,
243    pub poll: PollInterval,
244    pub dpoll: PollInterval,
245    pub filter_length: u32,
246    pub local: bool,
247    pub pps_forced: bool,
248    pub pps_rate: PpsRate,
249    pub min_samples: Option<u32>,
250    pub max_samples: Option<u32>,
251    pub max_unreach: u32,
252    pub max_lock_age: u32,
253    pub select_opts: SelectOptions,
254    pub stratum: Stratum,
255    pub tai: bool,
256    pub offset: f64,
257    pub delay: f64,
258    pub precision: f64,
259    pub max_dispersion: f64,
260    pub pulse_width: f64,
261    pub ref_id: u32,
262    pub lock_ref_id: u32,
263}
264
265impl Default for RefClockConfig {
266    fn default() -> Self {
267        Self {
268            driver: RefClockDriverKind::Pps,
269            parameter: String::new(),
270            poll: PollInterval::new_unchecked(4),
271            dpoll: PollInterval::new_unchecked(0),
272            filter_length: 64,
273            local: false,
274            pps_forced: false,
275            pps_rate: PpsRate::new_unchecked(1),
276            min_samples: None,
277            max_samples: None,
278            max_unreach: 100000,
279            max_lock_age: 2,
280            select_opts: SelectOptions::default(),
281            stratum: Stratum::new_unchecked(0),
282            tai: false,
283            offset: 0.0,
284            delay: 1e-9,
285            precision: 0.0,
286            max_dispersion: 0.0,
287            pulse_width: 0.0,
288            ref_id: 0,
289            lock_ref_id: 0,
290        }
291    }
292}
293
294// --- AllowDeny ---
295
296/// Configuration for `allow`, `deny`, `cmdallow`, and `cmddeny` directives.
297///
298/// Controls NTP client access or command access to chronyd.
299#[derive(Debug, Clone, PartialEq)]
300pub struct AllowDenyConfig {
301    pub all: bool,
302    pub subnet: Option<String>,
303}
304
305// --- RateLimit ---
306
307/// Configuration for the `ratelimit` directive (NTP client rate limiting).
308#[derive(Debug, Clone, PartialEq)]
309pub struct RateLimitConfig {
310    pub interval: i32,
311    pub burst: i32,
312    pub leak: i32,
313    pub kod: Option<i32>,
314}
315
316impl Default for RateLimitConfig {
317    fn default() -> Self {
318        Self {
319            interval: 3,
320            burst: 8,
321            leak: 2,
322            kod: None,
323        }
324    }
325}
326
327// --- NtsRateLimit ---
328
329/// Configuration for the `ntsratelimit` directive (NTS rate limiting).
330#[derive(Debug, Clone, PartialEq)]
331pub struct NtsRateLimitConfig {
332    pub interval: i32,
333    pub burst: i32,
334    pub leak: i32,
335}
336
337impl Default for NtsRateLimitConfig {
338    fn default() -> Self {
339        Self {
340            interval: 6,
341            burst: 8,
342            leak: 2,
343        }
344    }
345}
346
347// --- SmoothTime ---
348
349/// Configuration for the `smoothtime` directive (slew-based time smoothing).
350#[derive(Debug, Clone, PartialEq)]
351pub struct SmoothTimeConfig {
352    pub max_freq: f64,
353    pub max_wander: f64,
354    pub leap_only: bool,
355}
356
357// --- Broadcast ---
358
359/// Configuration for the `broadcast` directive (NTP broadcast server).
360#[derive(Debug, Clone, PartialEq)]
361pub struct BroadcastConfig {
362    pub interval: u32,
363    pub address: String,
364    pub port: UdpPort,
365}
366
367// --- Local ---
368
369/// Configuration for the `local` directive (local stratum reference).
370#[derive(Debug, Clone, PartialEq)]
371pub struct LocalConfig {
372    pub stratum: Stratum,
373    pub orphan: bool,
374    pub distance: f64,
375    pub activate: f64,
376    pub wait_synced: f64,
377    pub wait_unsynced: f64,
378}
379
380impl Default for LocalConfig {
381    fn default() -> Self {
382        Self {
383            stratum: Stratum::new_unchecked(10),
384            orphan: false,
385            distance: 1.0,
386            activate: 0.0,
387            wait_synced: 0.0,
388            wait_unsynced: -1.0,
389        }
390    }
391}