Skip to main content

ntp_proto/
server.rs

1use std::{
2    collections::hash_map::RandomState,
3    fmt::Display,
4    io::Cursor,
5    net::{AddrParseError, IpAddr},
6    sync::Arc,
7    time::{Duration, Instant},
8};
9
10use serde::{Deserialize, Deserializer, de};
11
12use crate::{
13    Cipher, KeySet, NtpClock, NtpPacket, NtpTimestamp, NtpVersion, PacketParsingError,
14    SystemSnapshot, ipfilter::IpFilter,
15};
16
17pub enum ServerAction<'a> {
18    Ignore,
19    Respond { message: &'a [u8] },
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
23pub enum ServerReason {
24    /// Rate limit mechanism kicked in
25    RateLimit,
26    /// Packet could not be parsed because it was malformed in some way
27    ParseError,
28    /// Packet could be parsed but the cryptography was invalid
29    InvalidCrypto,
30    /// Internal error in the server
31    InternalError,
32    /// Configuration was used to decide response
33    Policy,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
37pub enum ServerResponse {
38    /// NTS was invalid (failure to decrypt etc)
39    NTSNak,
40    /// Sent a deny response to client
41    Deny,
42    /// Only for a conscious choice to not respond, error conditions are separate
43    Ignore,
44    /// Accepted packet and provided time to requestor
45    ProvideTime,
46}
47
48pub trait ServerStatHandler {
49    /// Called by the server handle once per packet
50    fn register(&mut self, version: u8, nts: bool, reason: ServerReason, response: ServerResponse);
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize)]
54#[serde(rename_all = "lowercase")]
55pub enum FilterAction {
56    Ignore,
57    Deny,
58}
59
60impl From<FilterAction> for ServerResponse {
61    fn from(value: FilterAction) -> Self {
62        match value {
63            FilterAction::Ignore => ServerResponse::Ignore,
64            FilterAction::Deny => ServerResponse::Deny,
65        }
66    }
67}
68
69#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
70pub struct FilterList {
71    pub filter: Vec<IpSubnet>,
72    pub action: FilterAction,
73}
74
75#[derive(Debug, Clone, PartialEq, Eq, Hash)]
76pub struct ServerConfig {
77    pub denylist: FilterList,
78    pub allowlist: FilterList,
79    pub rate_limiting_cache_size: usize,
80    pub rate_limiting_cutoff: Duration,
81    pub require_nts: Option<FilterAction>,
82    pub accepted_versions: Vec<NtpVersion>,
83}
84
85pub struct Server<C> {
86    config: ServerConfig,
87    clock: C,
88    denyfilter: IpFilter,
89    allowfilter: IpFilter,
90    client_cache: TimestampedCache<IpAddr>,
91    system: SystemSnapshot,
92    keyset: Arc<KeySet>,
93}
94
95// Quick estimation of ntp packet message version without doing full parsing
96fn fallback_message_version(message: &[u8]) -> u8 {
97    message.first().map_or(0, |v| (v & 0b0011_1000) >> 3)
98}
99
100impl<C> Server<C> {
101    /// Create a new server
102    pub fn new(
103        config: ServerConfig,
104        clock: C,
105        system: SystemSnapshot,
106        keyset: Arc<KeySet>,
107    ) -> Self {
108        let denyfilter = IpFilter::new(&config.denylist.filter);
109        let allowfilter = IpFilter::new(&config.allowlist.filter);
110        let client_cache = TimestampedCache::new(config.rate_limiting_cache_size);
111        Self {
112            config,
113            clock,
114            denyfilter,
115            allowfilter,
116            client_cache,
117            system,
118            keyset,
119        }
120    }
121
122    /// Update the [`ServerConfig`] of the server
123    pub fn update_config(&mut self, config: ServerConfig) {
124        if self.config.denylist.filter != config.denylist.filter {
125            self.denyfilter = IpFilter::new(&config.denylist.filter);
126        }
127        if self.config.allowlist.filter != config.allowlist.filter {
128            self.allowfilter = IpFilter::new(&config.allowlist.filter);
129        }
130        if self.config.rate_limiting_cache_size != config.rate_limiting_cache_size {
131            self.client_cache = TimestampedCache::new(config.rate_limiting_cache_size);
132        }
133        self.config = config;
134    }
135
136    /// Provide the server with the latest [`SystemSnapshot`]
137    pub fn update_system(&mut self, system: SystemSnapshot) {
138        self.system = system;
139    }
140
141    /// Provide the server with a new [`KeySet`]
142    pub fn update_keyset(&mut self, keyset: Arc<KeySet>) {
143        self.keyset = keyset;
144    }
145
146    fn intended_action(&mut self, client_ip: IpAddr) -> (ServerResponse, ServerReason) {
147        if self.denyfilter.is_in(&client_ip) {
148            // First apply denylist
149            (self.config.denylist.action.into(), ServerReason::Policy)
150        } else if !self.allowfilter.is_in(&client_ip) {
151            // Then allowlist
152            (self.config.allowlist.action.into(), ServerReason::Policy)
153        } else if !self.client_cache.is_allowed(
154            client_ip,
155            Instant::now(),
156            self.config.rate_limiting_cutoff,
157        ) {
158            // Then ratelimit
159            (ServerResponse::Ignore, ServerReason::RateLimit)
160        } else {
161            // Then accept
162            (ServerResponse::ProvideTime, ServerReason::Policy)
163        }
164    }
165}
166
167pub struct HandleInnerData<'a> {
168    pub action: ServerResponse,
169    pub reason: ServerReason,
170    pub version: NtpVersion,
171    pub nts: bool,
172    pub packet: NtpPacket<'a>,
173    pub cipher: Option<Box<dyn Cipher>>,
174    pub desired_size: Option<usize>,
175}
176
177impl<C: NtpClock> Server<C> {
178    /// Handle a packet sent to the server
179    ///
180    /// If the buffer isn't large enough to encode the reply, this
181    /// will log an error and ignore the incoming packet. A buffer
182    /// as large as the message will always suffice.
183    pub fn handle<'a>(
184        &mut self,
185        client_ip: IpAddr,
186        recv_timestamp: NtpTimestamp,
187        message: &[u8],
188        buffer: &'a mut [u8],
189        stats_handler: &mut impl ServerStatHandler,
190    ) -> ServerAction<'a> {
191        let HandleInnerData {
192            action,
193            reason,
194            version,
195            nts,
196            packet,
197            cipher,
198            desired_size,
199        } = match self.handle_inner(client_ip, recv_timestamp, message, stats_handler) {
200            Ok(value) => value,
201            Err(value) => return value,
202        };
203
204        let mut cursor = Cursor::new(buffer);
205        match packet.serialize(&mut cursor, &cipher.as_deref(), desired_size) {
206            Ok(_) => {
207                stats_handler.register(version.into(), nts, reason, action);
208                let length = cursor.position();
209                ServerAction::Respond {
210                    message: &cursor.into_inner()[..length as _],
211                }
212            }
213            Err(e) => {
214                tracing::debug!("Could not serialize response: {}", e);
215                stats_handler.register(
216                    version.into(),
217                    nts,
218                    ServerReason::InternalError,
219                    ServerResponse::Ignore,
220                );
221                ServerAction::Ignore
222            }
223        }
224    }
225
226    // FIXME: Figure out a way to split this
227    #[expect(clippy::too_many_lines)]
228    fn handle_inner<'a>(
229        &mut self,
230        client_ip: IpAddr,
231        recv_timestamp: NtpTimestamp,
232        message: &'a [u8],
233        stats_handler: &mut impl ServerStatHandler,
234    ) -> Result<HandleInnerData<'a>, ServerAction<'static>> {
235        let (mut action, mut reason) = self.intended_action(client_ip);
236        if action == ServerResponse::Ignore {
237            // Early exit for ignore
238            stats_handler.register(fallback_message_version(message), false, reason, action);
239            return Err(ServerAction::Ignore);
240        }
241
242        // Try and parse the message
243        let (packet, cookie) = match NtpPacket::deserialize(message, self.keyset.as_ref()) {
244            Ok((packet, cookie)) => match packet.mode() {
245                crate::NtpAssociationMode::Client => (packet, cookie),
246                _ => {
247                    stats_handler.register(
248                        fallback_message_version(message),
249                        false,
250                        ServerReason::ParseError,
251                        ServerResponse::Ignore,
252                    );
253                    return Err(ServerAction::Ignore);
254                }
255            },
256            Err(PacketParsingError::DecryptError(packet)) => {
257                // Don't care about decryption errors when denying anyway
258                if action != ServerResponse::Deny {
259                    action = ServerResponse::NTSNak;
260                    reason = ServerReason::InvalidCrypto;
261                }
262                (packet, None)
263            }
264            Err(_) => {
265                stats_handler.register(
266                    fallback_message_version(message),
267                    false,
268                    ServerReason::ParseError,
269                    ServerResponse::Ignore,
270                );
271                return Err(ServerAction::Ignore);
272            }
273        };
274
275        // Generate the appropriate response
276        let version = packet.version();
277
278        if !self.config.accepted_versions.contains(&version) {
279            // handle this packet as if we don't know it
280            stats_handler.register(
281                version.as_u8(),
282                false,
283                ServerReason::Policy,
284                ServerResponse::Ignore,
285            );
286            return Err(ServerAction::Ignore);
287        }
288
289        let nts = cookie.is_some() || action == ServerResponse::NTSNak;
290
291        // ignore non-NTS packets when configured to require NTS
292        if let (false, Some(non_nts_action)) = (nts, self.config.require_nts) {
293            if non_nts_action == FilterAction::Ignore {
294                stats_handler.register(
295                    version.into(),
296                    nts,
297                    ServerReason::Policy,
298                    ServerResponse::Ignore,
299                );
300                return Err(ServerAction::Ignore);
301            }
302            action = ServerResponse::Deny;
303            reason = ServerReason::Policy;
304        }
305
306        let (packet, cipher, desired_size) = match action {
307            ServerResponse::NTSNak => (NtpPacket::nts_nak_response(packet), None, None),
308            ServerResponse::Deny => {
309                if let Some(cookie) = cookie {
310                    (NtpPacket::nts_deny_response(packet), Some(cookie.s2c), None)
311                } else {
312                    (NtpPacket::deny_response(packet), None, None)
313                }
314            }
315            ServerResponse::ProvideTime => {
316                if let Some(cookie) = cookie {
317                    (
318                        NtpPacket::nts_timestamp_response(
319                            &self.system,
320                            packet,
321                            recv_timestamp,
322                            &self.clock,
323                            &cookie,
324                            &self.keyset,
325                        ),
326                        Some(cookie.s2c),
327                        Some(message.len()),
328                    )
329                } else {
330                    (
331                        NtpPacket::timestamp_response(
332                            &self.system,
333                            packet,
334                            recv_timestamp,
335                            &self.clock,
336                        ),
337                        None,
338                        Some(message.len()),
339                    )
340                }
341            }
342            ServerResponse::Ignore => unreachable!(),
343        };
344
345        Ok(HandleInnerData {
346            action,
347            reason,
348            version,
349            nts,
350            packet,
351            cipher,
352            desired_size,
353        })
354    }
355
356    #[cfg(feature = "__internal-fuzz")]
357    pub fn fuzz_handle_inner<'a>(
358        &mut self,
359        client_ip: IpAddr,
360        recv_timestamp: NtpTimestamp,
361        message: &'a [u8],
362        stats_handler: &mut impl ServerStatHandler,
363    ) -> Result<HandleInnerData<'a>, ServerAction<'static>> {
364        self.handle_inner(client_ip, recv_timestamp, message, stats_handler)
365    }
366}
367
368/// A size-bounded cache where each entry is timestamped.
369///
370/// The planned use is in rate limiting: we keep track of when a source last checked in. If it checks
371/// in too often, we issue a rate limiting KISS code.
372///
373/// For this use case we want fast
374///
375/// - lookups: for each incoming IP we must check when it last checked in
376/// - inserts: for each incoming IP we store that its most recent check-in is now
377///
378/// Hence, this data structure is a vector, and we use a simple hash function to turn the incoming
379/// address into an index. Lookups and inserts are therefore O(1).
380///
381/// The likelihood of hash collisions can be controlled by changing the size of the cache. Hash collisions
382/// will happen, so this cache should not be relied on if perfect alerting is deemed critical.
383#[derive(Debug)]
384struct TimestampedCache<T> {
385    randomstate: RandomState,
386    elements: Vec<Option<(T, Instant)>>,
387}
388
389impl<T: std::hash::Hash + Eq> TimestampedCache<T> {
390    fn new(length: usize) -> Self {
391        Self {
392            // looks a bit odd, but prevents a `Clone` constraint
393            elements: std::iter::repeat_with(|| None).take(length).collect(),
394            randomstate: RandomState::new(),
395        }
396    }
397
398    fn index(&self, item: &T) -> usize {
399        use std::hash::BuildHasher;
400
401        self.randomstate.hash_one(item) as usize % self.elements.len()
402    }
403
404    fn is_allowed(&mut self, item: T, timestamp: Instant, cutoff: Duration) -> bool {
405        if self.elements.is_empty() {
406            // cache disabled, always OK
407            return true;
408        }
409
410        let index = self.index(&item);
411
412        // check if the current occupant of this slot is actually the same item
413        let timestamp_if_same = self.elements[index]
414            .as_ref()
415            .and_then(|(v, t)| (&item == v).then_some(t))
416            .copied();
417
418        self.elements[index] = Some((item, timestamp));
419
420        if let Some(old_timestamp) = timestamp_if_same {
421            // old and new are the same; check the time
422            timestamp.duration_since(old_timestamp) >= cutoff
423        } else {
424            // old and new are different; this is always OK
425            true
426        }
427    }
428}
429
430#[derive(Debug, Clone, PartialEq, Eq, Hash)]
431pub struct IpSubnet {
432    pub addr: IpAddr,
433    pub mask: u8,
434}
435
436#[derive(Debug, Clone, PartialEq, Eq)]
437pub enum SubnetParseError {
438    Subnet,
439    Ip(AddrParseError),
440    Mask,
441}
442
443impl std::error::Error for SubnetParseError {}
444
445impl Display for SubnetParseError {
446    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
447        match self {
448            Self::Subnet => write!(f, "Invalid subnet syntax"),
449            Self::Ip(e) => write!(f, "{e} in subnet"),
450            Self::Mask => write!(f, "Invalid subnet mask"),
451        }
452    }
453}
454
455impl From<AddrParseError> for SubnetParseError {
456    fn from(value: AddrParseError) -> Self {
457        Self::Ip(value)
458    }
459}
460
461impl std::str::FromStr for IpSubnet {
462    type Err = SubnetParseError;
463
464    fn from_str(s: &str) -> Result<Self, Self::Err> {
465        let (addr, mask) = s.split_once('/').ok_or(SubnetParseError::Subnet)?;
466        let addr: IpAddr = addr.parse()?;
467        let mask: u8 = mask.parse().map_err(|_| SubnetParseError::Mask)?;
468        let max_mask = match addr {
469            IpAddr::V4(_) => 32,
470            IpAddr::V6(_) => 128,
471        };
472        if mask > max_mask {
473            return Err(SubnetParseError::Mask);
474        }
475        Ok(IpSubnet { addr, mask })
476    }
477}
478
479impl<'de> Deserialize<'de> for IpSubnet {
480    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
481    where
482        D: Deserializer<'de>,
483    {
484        let s = String::deserialize(deserializer)?;
485        std::str::FromStr::from_str(&s).map_err(de::Error::custom)
486    }
487}
488
489#[cfg(test)]
490#[expect(
491    clippy::too_many_lines,
492    reason = "Long tests are not really a big problem"
493)]
494mod tests {
495    use std::net::{Ipv4Addr, Ipv6Addr};
496
497    use crate::{
498        Cipher, DecodedServerCookie, KeySetProvider, NoCipher, NtpDuration, NtpLeapIndicator,
499        PollIntervalLimits, nts::AeadAlgorithm, packet::AesSivCmac256,
500    };
501
502    use super::*;
503
504    #[derive(Debug, Clone, Default)]
505    struct TestClock {
506        cur: NtpTimestamp,
507    }
508
509    impl NtpClock for TestClock {
510        type Error = std::time::SystemTimeError;
511
512        fn now(&self) -> std::result::Result<NtpTimestamp, Self::Error> {
513            Ok(self.cur)
514        }
515
516        fn set_frequency(&self, _freq: f64) -> Result<NtpTimestamp, Self::Error> {
517            panic!("Shouldn't be called by server");
518        }
519
520        fn get_frequency(&self) -> Result<f64, Self::Error> {
521            Ok(0.0)
522        }
523
524        fn step_clock(&self, _offset: NtpDuration) -> Result<NtpTimestamp, Self::Error> {
525            panic!("Shouldn't be called by server");
526        }
527
528        fn disable_ntp_algorithm(&self) -> Result<(), Self::Error> {
529            panic!("Shouldn't be called by server");
530        }
531
532        fn error_estimate_update(
533            &self,
534            _est_error: NtpDuration,
535            _max_error: NtpDuration,
536        ) -> Result<(), Self::Error> {
537            panic!("Shouldn't be called by server");
538        }
539
540        fn status_update(&self, _leap_status: NtpLeapIndicator) -> Result<(), Self::Error> {
541            panic!("Shouldn't be called by source");
542        }
543    }
544
545    #[derive(Debug, Default)]
546    struct TestStatHandler {
547        last_register: Option<(u8, bool, ServerReason, ServerResponse)>,
548    }
549
550    impl ServerStatHandler for TestStatHandler {
551        fn register(
552            &mut self,
553            version: u8,
554            nts: bool,
555            reason: ServerReason,
556            response: ServerResponse,
557        ) {
558            assert!(self.last_register.is_none());
559            self.last_register = Some((version, nts, reason, response));
560        }
561    }
562
563    fn serialize_packet_unencrypted(send_packet: &NtpPacket) -> Vec<u8> {
564        let mut buf = vec![0; 1024];
565        let mut cursor = Cursor::new(buf.as_mut_slice());
566        send_packet.serialize(&mut cursor, &NoCipher, None).unwrap();
567
568        let end = cursor.position() as usize;
569        buf.truncate(end);
570        buf
571    }
572
573    fn serialize_packet_encrypted(send_packet: &NtpPacket, key: &dyn Cipher) -> Vec<u8> {
574        let mut buf = vec![0; 1024];
575        let mut cursor = Cursor::new(buf.as_mut_slice());
576        send_packet.serialize(&mut cursor, key, None).unwrap();
577
578        let end = cursor.position() as usize;
579        buf.truncate(end);
580        buf
581    }
582
583    #[test]
584    fn test_server_allow_filter() {
585        let config = ServerConfig {
586            denylist: FilterList {
587                filter: vec![],
588                action: FilterAction::Deny,
589            },
590            allowlist: FilterList {
591                filter: vec!["127.0.0.0/24".parse().unwrap()],
592                action: FilterAction::Ignore,
593            },
594            rate_limiting_cutoff: Duration::from_secs(1),
595            rate_limiting_cache_size: 0,
596            require_nts: None,
597            accepted_versions: vec![NtpVersion::V4],
598        };
599        let clock = TestClock {
600            cur: NtpTimestamp::from_fixed_int(200),
601        };
602        let mut stats = TestStatHandler::default();
603
604        let mut server = Server::new(
605            config,
606            clock,
607            SystemSnapshot::default(),
608            KeySetProvider::new(1).get(),
609        );
610
611        let (packet, id) = NtpPacket::poll_message(PollIntervalLimits::default().min);
612        let serialized = serialize_packet_unencrypted(&packet);
613
614        let mut buf = [0; 48];
615        let response = server.handle(
616            "127.0.0.1".parse().unwrap(),
617            NtpTimestamp::from_fixed_int(100),
618            &serialized,
619            &mut buf,
620            &mut stats,
621        );
622        assert_eq!(
623            stats.last_register.take(),
624            Some((4, false, ServerReason::Policy, ServerResponse::ProvideTime))
625        );
626        let data = match response {
627            ServerAction::Ignore => panic!("Server ignored packet"),
628            ServerAction::Respond { message } => message,
629        };
630        let packet = NtpPacket::deserialize(data, &NoCipher).unwrap().0;
631        assert_ne!(packet.stratum(), 0);
632        assert!(packet.valid_server_response(id, false));
633        assert_eq!(
634            packet.receive_timestamp(),
635            NtpTimestamp::from_fixed_int(100)
636        );
637        assert_eq!(
638            packet.transmit_timestamp(),
639            NtpTimestamp::from_fixed_int(200)
640        );
641
642        let mut buf = [0; 48];
643        let response = server.handle(
644            "128.0.0.1".parse().unwrap(),
645            NtpTimestamp::from_fixed_int(100),
646            &serialized,
647            &mut buf,
648            &mut stats,
649        );
650        assert_eq!(
651            stats.last_register.take(),
652            Some((4, false, ServerReason::Policy, ServerResponse::Ignore))
653        );
654        assert!(matches!(response, ServerAction::Ignore));
655
656        let config = ServerConfig {
657            denylist: FilterList {
658                filter: vec![],
659                action: FilterAction::Deny,
660            },
661            allowlist: FilterList {
662                filter: vec!["127.0.0.0/24".parse().unwrap()],
663                action: FilterAction::Deny,
664            },
665            rate_limiting_cutoff: Duration::from_secs(1),
666            rate_limiting_cache_size: 0,
667            require_nts: None,
668            accepted_versions: vec![NtpVersion::V4],
669        };
670        server.update_config(config);
671
672        let mut buf = [0; 48];
673        let response = server.handle(
674            "128.0.0.1".parse().unwrap(),
675            NtpTimestamp::from_fixed_int(100),
676            &serialized,
677            &mut buf,
678            &mut stats,
679        );
680        assert_eq!(
681            stats.last_register.take(),
682            Some((4, false, ServerReason::Policy, ServerResponse::Deny))
683        );
684        let data = match response {
685            ServerAction::Ignore => panic!("Server ignored packet"),
686            ServerAction::Respond { message } => message,
687        };
688        let packet = NtpPacket::deserialize(data, &NoCipher).unwrap().0;
689        assert!(packet.valid_server_response(id, false));
690        assert!(packet.is_kiss_deny());
691    }
692
693    #[test]
694    fn test_server_deny_filter() {
695        let config = ServerConfig {
696            denylist: FilterList {
697                filter: vec!["128.0.0.0/24".parse().unwrap()],
698                action: FilterAction::Deny,
699            },
700            allowlist: FilterList {
701                filter: vec!["0.0.0.0/0".parse().unwrap()],
702                action: FilterAction::Ignore,
703            },
704            rate_limiting_cutoff: Duration::from_secs(1),
705            rate_limiting_cache_size: 0,
706            require_nts: None,
707            accepted_versions: vec![NtpVersion::V4],
708        };
709        let clock = TestClock {
710            cur: NtpTimestamp::from_fixed_int(200),
711        };
712        let mut stats = TestStatHandler::default();
713
714        let mut server = Server::new(
715            config,
716            clock,
717            SystemSnapshot::default(),
718            KeySetProvider::new(1).get(),
719        );
720
721        let (packet, id) = NtpPacket::poll_message(PollIntervalLimits::default().min);
722        let serialized = serialize_packet_unencrypted(&packet);
723
724        let mut buf = [0; 48];
725        let response = server.handle(
726            "127.0.0.1".parse().unwrap(),
727            NtpTimestamp::from_fixed_int(100),
728            &serialized,
729            &mut buf,
730            &mut stats,
731        );
732        assert_eq!(
733            stats.last_register.take(),
734            Some((4, false, ServerReason::Policy, ServerResponse::ProvideTime))
735        );
736        let data = match response {
737            ServerAction::Ignore => panic!("Server ignored packet"),
738            ServerAction::Respond { message } => message,
739        };
740        let packet = NtpPacket::deserialize(data, &NoCipher).unwrap().0;
741        assert_ne!(packet.stratum(), 0);
742        assert!(packet.valid_server_response(id, false));
743        assert_eq!(
744            packet.receive_timestamp(),
745            NtpTimestamp::from_fixed_int(100)
746        );
747        assert_eq!(
748            packet.transmit_timestamp(),
749            NtpTimestamp::from_fixed_int(200)
750        );
751
752        let mut buf = [0; 48];
753        let response = server.handle(
754            "128.0.0.1".parse().unwrap(),
755            NtpTimestamp::from_fixed_int(100),
756            &serialized,
757            &mut buf,
758            &mut stats,
759        );
760        assert_eq!(
761            stats.last_register.take(),
762            Some((4, false, ServerReason::Policy, ServerResponse::Deny))
763        );
764        let data = match response {
765            ServerAction::Ignore => panic!("Server ignored packet"),
766            ServerAction::Respond { message } => message,
767        };
768        let packet = NtpPacket::deserialize(data, &NoCipher).unwrap().0;
769        assert!(packet.valid_server_response(id, false));
770        assert!(packet.is_kiss_deny());
771
772        let config = ServerConfig {
773            denylist: FilterList {
774                filter: vec!["128.0.0.0/24".parse().unwrap()],
775                action: FilterAction::Ignore,
776            },
777            allowlist: FilterList {
778                filter: vec!["0.0.0.0/0".parse().unwrap()],
779                action: FilterAction::Ignore,
780            },
781            rate_limiting_cutoff: Duration::from_secs(1),
782            rate_limiting_cache_size: 0,
783            require_nts: None,
784            accepted_versions: vec![NtpVersion::V4],
785        };
786        server.update_config(config);
787
788        let mut buf = [0; 48];
789        let response = server.handle(
790            "128.0.0.1".parse().unwrap(),
791            NtpTimestamp::from_fixed_int(100),
792            &serialized,
793            &mut buf,
794            &mut stats,
795        );
796        assert_eq!(
797            stats.last_register.take(),
798            Some((4, false, ServerReason::Policy, ServerResponse::Ignore))
799        );
800        assert!(matches!(response, ServerAction::Ignore));
801    }
802
803    #[test]
804    fn test_server_rate_limit() {
805        let config = ServerConfig {
806            denylist: FilterList {
807                filter: vec![],
808                action: FilterAction::Deny,
809            },
810            allowlist: FilterList {
811                filter: vec!["0.0.0.0/0".parse().unwrap()],
812                action: FilterAction::Ignore,
813            },
814            rate_limiting_cutoff: Duration::from_millis(100),
815            rate_limiting_cache_size: 32,
816            require_nts: None,
817            accepted_versions: vec![NtpVersion::V4],
818        };
819        let clock = TestClock {
820            cur: NtpTimestamp::from_fixed_int(200),
821        };
822        let mut stats = TestStatHandler::default();
823
824        let mut server = Server::new(
825            config,
826            clock,
827            SystemSnapshot::default(),
828            KeySetProvider::new(1).get(),
829        );
830
831        let (packet, id) = NtpPacket::poll_message(PollIntervalLimits::default().min);
832        let serialized = serialize_packet_unencrypted(&packet);
833
834        let mut buf = [0; 48];
835        let response = server.handle(
836            "127.0.0.1".parse().unwrap(),
837            NtpTimestamp::from_fixed_int(100),
838            &serialized,
839            &mut buf,
840            &mut stats,
841        );
842        assert_eq!(
843            stats.last_register.take(),
844            Some((4, false, ServerReason::Policy, ServerResponse::ProvideTime))
845        );
846        let data = match response {
847            ServerAction::Ignore => panic!("Server ignored packet"),
848            ServerAction::Respond { message } => message,
849        };
850        let packet = NtpPacket::deserialize(data, &NoCipher).unwrap().0;
851        assert_ne!(packet.stratum(), 0);
852        assert!(packet.valid_server_response(id, false));
853        assert_eq!(
854            packet.receive_timestamp(),
855            NtpTimestamp::from_fixed_int(100)
856        );
857        assert_eq!(
858            packet.transmit_timestamp(),
859            NtpTimestamp::from_fixed_int(200)
860        );
861
862        let mut buf = [0; 48];
863        let response = server.handle(
864            "127.0.0.1".parse().unwrap(),
865            NtpTimestamp::from_fixed_int(100),
866            &serialized,
867            &mut buf,
868            &mut stats,
869        );
870        assert_eq!(
871            stats.last_register.take(),
872            Some((4, false, ServerReason::RateLimit, ServerResponse::Ignore))
873        );
874        assert!(matches!(response, ServerAction::Ignore));
875
876        std::thread::sleep(std::time::Duration::from_millis(120));
877
878        let mut buf = [0; 48];
879        let response = server.handle(
880            "127.0.0.1".parse().unwrap(),
881            NtpTimestamp::from_fixed_int(100),
882            &serialized,
883            &mut buf,
884            &mut stats,
885        );
886        assert_eq!(
887            stats.last_register.take(),
888            Some((4, false, ServerReason::Policy, ServerResponse::ProvideTime))
889        );
890        let data = match response {
891            ServerAction::Ignore => panic!("Server ignored packet"),
892            ServerAction::Respond { message } => message,
893        };
894        let packet = NtpPacket::deserialize(data, &NoCipher).unwrap().0;
895        assert_ne!(packet.stratum(), 0);
896        assert!(packet.valid_server_response(id, false));
897        assert_eq!(
898            packet.receive_timestamp(),
899            NtpTimestamp::from_fixed_int(100)
900        );
901        assert_eq!(
902            packet.transmit_timestamp(),
903            NtpTimestamp::from_fixed_int(200)
904        );
905
906        let config = ServerConfig {
907            denylist: FilterList {
908                filter: vec![],
909                action: FilterAction::Deny,
910            },
911            allowlist: FilterList {
912                filter: vec!["0.0.0.0/0".parse().unwrap()],
913                action: FilterAction::Ignore,
914            },
915            rate_limiting_cutoff: Duration::from_millis(100),
916            rate_limiting_cache_size: 0,
917            require_nts: None,
918            accepted_versions: vec![NtpVersion::V4],
919        };
920
921        server.update_config(config);
922
923        let mut buf = [0; 48];
924        let response = server.handle(
925            "127.0.0.1".parse().unwrap(),
926            NtpTimestamp::from_fixed_int(100),
927            &serialized,
928            &mut buf,
929            &mut stats,
930        );
931        assert_eq!(
932            stats.last_register.take(),
933            Some((4, false, ServerReason::Policy, ServerResponse::ProvideTime))
934        );
935        let data = match response {
936            ServerAction::Ignore => panic!("Server ignored packet"),
937            ServerAction::Respond { message } => message,
938        };
939        let packet = NtpPacket::deserialize(data, &NoCipher).unwrap().0;
940        assert_ne!(packet.stratum(), 0);
941        assert!(packet.valid_server_response(id, false));
942        assert_eq!(
943            packet.receive_timestamp(),
944            NtpTimestamp::from_fixed_int(100)
945        );
946        assert_eq!(
947            packet.transmit_timestamp(),
948            NtpTimestamp::from_fixed_int(200)
949        );
950
951        let mut buf = [0; 48];
952        let response = server.handle(
953            "127.0.0.1".parse().unwrap(),
954            NtpTimestamp::from_fixed_int(100),
955            &serialized,
956            &mut buf,
957            &mut stats,
958        );
959        assert_eq!(
960            stats.last_register.take(),
961            Some((4, false, ServerReason::Policy, ServerResponse::ProvideTime))
962        );
963        let data = match response {
964            ServerAction::Ignore => panic!("Server ignored packet"),
965            ServerAction::Respond { message } => message,
966        };
967        let packet = NtpPacket::deserialize(data, &NoCipher).unwrap().0;
968        assert_ne!(packet.stratum(), 0);
969        assert!(packet.valid_server_response(id, false));
970        assert_eq!(
971            packet.receive_timestamp(),
972            NtpTimestamp::from_fixed_int(100)
973        );
974        assert_eq!(
975            packet.transmit_timestamp(),
976            NtpTimestamp::from_fixed_int(200)
977        );
978    }
979
980    #[test]
981    fn test_server_ignores_non_request() {
982        let config = ServerConfig {
983            denylist: FilterList {
984                filter: vec![],
985                action: FilterAction::Deny,
986            },
987            allowlist: FilterList {
988                filter: vec!["0.0.0.0/0".parse().unwrap()],
989                action: FilterAction::Ignore,
990            },
991            rate_limiting_cutoff: Duration::from_millis(100),
992            rate_limiting_cache_size: 0,
993            require_nts: None,
994            accepted_versions: vec![NtpVersion::V4],
995        };
996        let clock = TestClock {
997            cur: NtpTimestamp::from_fixed_int(200),
998        };
999        let mut stats = TestStatHandler::default();
1000
1001        let mut server = Server::new(
1002            config,
1003            clock,
1004            SystemSnapshot::default(),
1005            KeySetProvider::new(1).get(),
1006        );
1007
1008        let (packet, _) = NtpPacket::poll_message(PollIntervalLimits::default().min);
1009        let mut serialized = serialize_packet_unencrypted(&packet);
1010
1011        for version in 0..8 {
1012            for mode in 0..8 {
1013                if mode == 3 {
1014                    // Client mode should be able to get responses
1015                    continue;
1016                }
1017
1018                serialized[0] = (serialized[0] & 0xC0) | (version << 3) | mode;
1019
1020                let mut buf = [0; 48];
1021                let response = server.handle(
1022                    "127.0.0.1".parse().unwrap(),
1023                    NtpTimestamp::from_fixed_int(100),
1024                    &serialized,
1025                    &mut buf,
1026                    &mut stats,
1027                );
1028                stats.last_register.take();
1029
1030                assert!(matches!(response, ServerAction::Ignore));
1031            }
1032        }
1033    }
1034
1035    #[test]
1036    fn test_server_corrupted() {
1037        let config = ServerConfig {
1038            denylist: FilterList {
1039                filter: vec![],
1040                action: FilterAction::Deny,
1041            },
1042            allowlist: FilterList {
1043                filter: vec!["0.0.0.0/0".parse().unwrap()],
1044                action: FilterAction::Ignore,
1045            },
1046            rate_limiting_cutoff: Duration::from_millis(100),
1047            rate_limiting_cache_size: 0,
1048            require_nts: None,
1049            accepted_versions: vec![NtpVersion::V4],
1050        };
1051        let clock = TestClock {
1052            cur: NtpTimestamp::from_fixed_int(200),
1053        };
1054        let mut stats = TestStatHandler::default();
1055
1056        let mut server = Server::new(
1057            config,
1058            clock,
1059            SystemSnapshot::default(),
1060            KeySetProvider::new(1).get(),
1061        );
1062
1063        let (packet, _) = NtpPacket::poll_message(PollIntervalLimits::default().min);
1064        let mut serialized = serialize_packet_unencrypted(&packet);
1065
1066        let mut buf = [0; 1];
1067        let response = server.handle(
1068            "127.0.0.1".parse().unwrap(),
1069            NtpTimestamp::from_fixed_int(100),
1070            &serialized,
1071            &mut buf,
1072            &mut stats,
1073        );
1074        assert_eq!(
1075            stats.last_register.take(),
1076            Some((
1077                4,
1078                false,
1079                ServerReason::InternalError,
1080                ServerResponse::Ignore
1081            ))
1082        );
1083        assert!(matches!(response, ServerAction::Ignore));
1084
1085        serialized[0] = 42;
1086
1087        let mut buf = [0; 48];
1088        let response = server.handle(
1089            "127.0.0.1".parse().unwrap(),
1090            NtpTimestamp::from_fixed_int(100),
1091            &serialized,
1092            &mut buf,
1093            &mut stats,
1094        );
1095        assert_eq!(
1096            stats.last_register.take(),
1097            Some((5, false, ServerReason::ParseError, ServerResponse::Ignore))
1098        );
1099        assert!(matches!(response, ServerAction::Ignore));
1100
1101        let config = ServerConfig {
1102            denylist: FilterList {
1103                filter: vec![],
1104                action: FilterAction::Deny,
1105            },
1106            allowlist: FilterList {
1107                filter: vec!["128.0.0.0/24".parse().unwrap()],
1108                action: FilterAction::Deny,
1109            },
1110            rate_limiting_cutoff: Duration::from_millis(100),
1111            rate_limiting_cache_size: 0,
1112            require_nts: None,
1113            accepted_versions: vec![NtpVersion::V4],
1114        };
1115        server.update_config(config);
1116
1117        let mut buf = [0; 48];
1118        let response = server.handle(
1119            "127.0.0.1".parse().unwrap(),
1120            NtpTimestamp::from_fixed_int(100),
1121            &serialized,
1122            &mut buf,
1123            &mut stats,
1124        );
1125        assert_eq!(
1126            stats.last_register.take(),
1127            Some((5, false, ServerReason::ParseError, ServerResponse::Ignore))
1128        );
1129        assert!(matches!(response, ServerAction::Ignore));
1130
1131        let config = ServerConfig {
1132            denylist: FilterList {
1133                filter: vec![],
1134                action: FilterAction::Deny,
1135            },
1136            allowlist: FilterList {
1137                filter: vec!["128.0.0.0/24".parse().unwrap()],
1138                action: FilterAction::Ignore,
1139            },
1140            rate_limiting_cutoff: Duration::from_millis(100),
1141            rate_limiting_cache_size: 0,
1142            require_nts: None,
1143            accepted_versions: vec![NtpVersion::V4],
1144        };
1145        server.update_config(config);
1146
1147        let mut buf = [0; 48];
1148        let response = server.handle(
1149            "127.0.0.1".parse().unwrap(),
1150            NtpTimestamp::from_fixed_int(100),
1151            &serialized,
1152            &mut buf,
1153            &mut stats,
1154        );
1155        assert_eq!(
1156            stats.last_register.take(),
1157            Some((5, false, ServerReason::Policy, ServerResponse::Ignore))
1158        );
1159        assert!(matches!(response, ServerAction::Ignore));
1160
1161        let config = ServerConfig {
1162            denylist: FilterList {
1163                filter: vec!["127.0.0.0/24".parse().unwrap()],
1164                action: FilterAction::Deny,
1165            },
1166            allowlist: FilterList {
1167                filter: vec!["0.0.0.0/0".parse().unwrap()],
1168                action: FilterAction::Ignore,
1169            },
1170            rate_limiting_cutoff: Duration::from_millis(100),
1171            rate_limiting_cache_size: 0,
1172            require_nts: None,
1173            accepted_versions: vec![NtpVersion::V4],
1174        };
1175        server.update_config(config);
1176
1177        let mut buf = [0; 48];
1178        let response = server.handle(
1179            "127.0.0.1".parse().unwrap(),
1180            NtpTimestamp::from_fixed_int(100),
1181            &serialized,
1182            &mut buf,
1183            &mut stats,
1184        );
1185        assert_eq!(
1186            stats.last_register.take(),
1187            Some((5, false, ServerReason::ParseError, ServerResponse::Ignore))
1188        );
1189        assert!(matches!(response, ServerAction::Ignore));
1190
1191        let config = ServerConfig {
1192            denylist: FilterList {
1193                filter: vec!["127.0.0.0/24".parse().unwrap()],
1194                action: FilterAction::Ignore,
1195            },
1196            allowlist: FilterList {
1197                filter: vec!["0.0.0.0/0".parse().unwrap()],
1198                action: FilterAction::Ignore,
1199            },
1200            rate_limiting_cutoff: Duration::from_millis(100),
1201            rate_limiting_cache_size: 0,
1202            require_nts: None,
1203            accepted_versions: vec![NtpVersion::V4],
1204        };
1205        server.update_config(config);
1206
1207        let mut buf = [0; 48];
1208        let response = server.handle(
1209            "127.0.0.1".parse().unwrap(),
1210            NtpTimestamp::from_fixed_int(100),
1211            &serialized,
1212            &mut buf,
1213            &mut stats,
1214        );
1215        assert_eq!(
1216            stats.last_register.take(),
1217            Some((5, false, ServerReason::Policy, ServerResponse::Ignore))
1218        );
1219        assert!(matches!(response, ServerAction::Ignore));
1220    }
1221
1222    #[test]
1223    fn test_server_nts() {
1224        let config = ServerConfig {
1225            denylist: FilterList {
1226                filter: vec![],
1227                action: FilterAction::Deny,
1228            },
1229            allowlist: FilterList {
1230                filter: vec!["0.0.0.0/0".parse().unwrap()],
1231                action: FilterAction::Ignore,
1232            },
1233            rate_limiting_cutoff: Duration::from_millis(100),
1234            rate_limiting_cache_size: 0,
1235            require_nts: Some(FilterAction::Ignore),
1236            accepted_versions: vec![NtpVersion::V4],
1237        };
1238        let clock = TestClock {
1239            cur: NtpTimestamp::from_fixed_int(200),
1240        };
1241        let mut stats = TestStatHandler::default();
1242        let keyset = KeySetProvider::new(1).get();
1243
1244        let mut server = Server::new(config, clock, SystemSnapshot::default(), keyset.clone());
1245
1246        let decodedcookie = DecodedServerCookie {
1247            algorithm: AeadAlgorithm::AeadAesSivCmac256,
1248            s2c: Box::new(AesSivCmac256::new([0; 32].into())),
1249            c2s: Box::new(AesSivCmac256::new([0; 32].into())),
1250        };
1251        let cookie = keyset.encode_cookie(&decodedcookie);
1252        let (packet, id) =
1253            NtpPacket::nts_poll_message(&cookie, 0, PollIntervalLimits::default().min);
1254        let serialized = serialize_packet_encrypted(&packet, decodedcookie.c2s.as_ref());
1255
1256        let mut buf = [0; 1024];
1257        let response = server.handle(
1258            "127.0.0.1".parse().unwrap(),
1259            NtpTimestamp::from_fixed_int(100),
1260            &serialized,
1261            &mut buf,
1262            &mut stats,
1263        );
1264        assert_eq!(
1265            stats.last_register.take(),
1266            Some((4, true, ServerReason::Policy, ServerResponse::ProvideTime))
1267        );
1268        let data = match response {
1269            ServerAction::Ignore => panic!("Server ignored packet"),
1270            ServerAction::Respond { message } => message,
1271        };
1272        let packet = NtpPacket::deserialize(data, decodedcookie.s2c.as_ref())
1273            .unwrap()
1274            .0;
1275        assert_ne!(packet.stratum(), 0);
1276        assert!(packet.valid_server_response(id, true));
1277        assert_eq!(
1278            packet.receive_timestamp(),
1279            NtpTimestamp::from_fixed_int(100)
1280        );
1281        assert_eq!(
1282            packet.transmit_timestamp(),
1283            NtpTimestamp::from_fixed_int(200)
1284        );
1285
1286        let cookie_invalid = KeySetProvider::new(1).get().encode_cookie(&decodedcookie);
1287        let (packet_invalid, _) =
1288            NtpPacket::nts_poll_message(&cookie_invalid, 0, PollIntervalLimits::default().min);
1289        let serialized = serialize_packet_encrypted(&packet_invalid, decodedcookie.c2s.as_ref());
1290
1291        let mut buf = [0; 1024];
1292        let response = server.handle(
1293            "127.0.0.1".parse().unwrap(),
1294            NtpTimestamp::from_fixed_int(100),
1295            &serialized,
1296            &mut buf,
1297            &mut stats,
1298        );
1299        assert_eq!(
1300            stats.last_register.take(),
1301            Some((4, true, ServerReason::InvalidCrypto, ServerResponse::NTSNak))
1302        );
1303        let data = match response {
1304            ServerAction::Ignore => panic!("Server ignored packet"),
1305            ServerAction::Respond { message } => message,
1306        };
1307        let packet = NtpPacket::deserialize(data, decodedcookie.s2c.as_ref())
1308            .unwrap()
1309            .0;
1310        assert!(packet.is_kiss_ntsn());
1311    }
1312
1313    #[test]
1314    fn test_server_require_nts() {
1315        let mut config = ServerConfig {
1316            denylist: FilterList {
1317                filter: vec![],
1318                action: FilterAction::Deny,
1319            },
1320            allowlist: FilterList {
1321                filter: vec!["0.0.0.0/0".parse().unwrap()],
1322                action: FilterAction::Ignore,
1323            },
1324            rate_limiting_cutoff: Duration::from_secs(1),
1325            rate_limiting_cache_size: 0,
1326            require_nts: Some(FilterAction::Ignore),
1327            accepted_versions: vec![NtpVersion::V4],
1328        };
1329        let clock = TestClock {
1330            cur: NtpTimestamp::from_fixed_int(200),
1331        };
1332        let mut stats = TestStatHandler::default();
1333
1334        let mut server = Server::new(
1335            config.clone(),
1336            clock,
1337            SystemSnapshot::default(),
1338            KeySetProvider::new(1).get(),
1339        );
1340
1341        let (packet, _) = NtpPacket::poll_message(PollIntervalLimits::default().min);
1342        let serialized = serialize_packet_unencrypted(&packet);
1343
1344        let mut buf = [0; 1024];
1345        let response = server.handle(
1346            "127.0.0.1".parse().unwrap(),
1347            NtpTimestamp::from_fixed_int(100),
1348            &serialized,
1349            &mut buf,
1350            &mut stats,
1351        );
1352        assert_eq!(
1353            stats.last_register.take(),
1354            Some((4, false, ServerReason::Policy, ServerResponse::Ignore))
1355        );
1356        assert!(matches!(response, ServerAction::Ignore));
1357
1358        let decodedcookie = DecodedServerCookie {
1359            algorithm: AeadAlgorithm::AeadAesSivCmac256,
1360            s2c: Box::new(AesSivCmac256::new([0; 32].into())),
1361            c2s: Box::new(AesSivCmac256::new([0; 32].into())),
1362        };
1363        let cookie_invalid = KeySetProvider::new(1).get().encode_cookie(&decodedcookie);
1364        let (packet_invalid, _) =
1365            NtpPacket::nts_poll_message(&cookie_invalid, 0, PollIntervalLimits::default().min);
1366        let serialized = serialize_packet_encrypted(&packet_invalid, decodedcookie.c2s.as_ref());
1367        let response = server.handle(
1368            "127.0.0.1".parse().unwrap(),
1369            NtpTimestamp::from_fixed_int(100),
1370            &serialized,
1371            &mut buf,
1372            &mut stats,
1373        );
1374        assert_eq!(
1375            stats.last_register.take(),
1376            Some((4, true, ServerReason::InvalidCrypto, ServerResponse::NTSNak))
1377        );
1378        let data = match response {
1379            ServerAction::Ignore => panic!("Server ignored packet"),
1380            ServerAction::Respond { message } => message,
1381        };
1382        let packet = NtpPacket::deserialize(data, decodedcookie.s2c.as_ref())
1383            .unwrap()
1384            .0;
1385        assert!(packet.is_kiss_ntsn());
1386
1387        config.require_nts = Some(FilterAction::Deny);
1388        server.update_config(config.clone());
1389
1390        let (packet, id) = NtpPacket::poll_message(PollIntervalLimits::default().min);
1391        let serialized = serialize_packet_unencrypted(&packet);
1392        let response = server.handle(
1393            "127.0.0.1".parse().unwrap(),
1394            NtpTimestamp::from_fixed_int(100),
1395            &serialized,
1396            &mut buf,
1397            &mut stats,
1398        );
1399        assert_eq!(
1400            stats.last_register.take(),
1401            Some((4, false, ServerReason::Policy, ServerResponse::Deny))
1402        );
1403        let ServerAction::Respond { message } = response else {
1404            panic!("Server ignored packet")
1405        };
1406
1407        let packet = NtpPacket::deserialize(message, &NoCipher).unwrap().0;
1408        assert!(packet.valid_server_response(id, false));
1409        assert!(packet.is_kiss_deny());
1410    }
1411
1412    #[test]
1413    fn test_server_v5() {
1414        let config = ServerConfig {
1415            denylist: FilterList {
1416                filter: vec![],
1417                action: FilterAction::Deny,
1418            },
1419            allowlist: FilterList {
1420                filter: vec!["127.0.0.0/24".parse().unwrap()],
1421                action: FilterAction::Deny,
1422            },
1423            rate_limiting_cutoff: Duration::from_millis(100),
1424            rate_limiting_cache_size: 0,
1425            require_nts: None,
1426            accepted_versions: vec![NtpVersion::V5],
1427        };
1428        let clock = TestClock {
1429            cur: NtpTimestamp::from_fixed_int(200),
1430        };
1431        let mut stats = TestStatHandler::default();
1432
1433        let mut server = Server::new(
1434            config,
1435            clock,
1436            SystemSnapshot::default(),
1437            KeySetProvider::new(1).get(),
1438        );
1439
1440        let (packet, id) = NtpPacket::poll_message_v5(PollIntervalLimits::default().min);
1441        let serialized = serialize_packet_unencrypted(&packet);
1442
1443        let mut buf = [0; 1024];
1444        let response = server.handle(
1445            "127.0.0.1".parse().unwrap(),
1446            NtpTimestamp::from_fixed_int(100),
1447            &serialized,
1448            &mut buf,
1449            &mut stats,
1450        );
1451        assert_eq!(
1452            stats.last_register.take(),
1453            Some((5, false, ServerReason::Policy, ServerResponse::ProvideTime))
1454        );
1455        let data = match response {
1456            ServerAction::Ignore => panic!("Server ignored packet"),
1457            ServerAction::Respond { message } => message,
1458        };
1459        let packet = NtpPacket::deserialize(data, &NoCipher).unwrap().0;
1460        assert_ne!(packet.stratum(), 0);
1461        assert!(packet.valid_server_response(id, false));
1462        assert_eq!(
1463            packet.receive_timestamp(),
1464            NtpTimestamp::from_fixed_int(100)
1465        );
1466        assert_eq!(
1467            packet.transmit_timestamp(),
1468            NtpTimestamp::from_fixed_int(200)
1469        );
1470
1471        let mut buf = [0; 1024];
1472        let response = server.handle(
1473            "128.0.0.1".parse().unwrap(),
1474            NtpTimestamp::from_fixed_int(100),
1475            &serialized,
1476            &mut buf,
1477            &mut stats,
1478        );
1479        assert_eq!(
1480            stats.last_register.take(),
1481            Some((5, false, ServerReason::Policy, ServerResponse::Deny))
1482        );
1483        let data = match response {
1484            ServerAction::Ignore => panic!("Server ignored packet"),
1485            ServerAction::Respond { message } => message,
1486        };
1487        let packet = NtpPacket::deserialize(data, &NoCipher).unwrap().0;
1488        assert!(packet.valid_server_response(id, false));
1489        assert!(packet.is_kiss_deny());
1490    }
1491
1492    #[test]
1493    fn test_server_ignore_version() {
1494        let config = ServerConfig {
1495            denylist: FilterList {
1496                filter: vec![],
1497                action: FilterAction::Deny,
1498            },
1499            allowlist: FilterList {
1500                filter: vec!["0.0.0.0/0".parse().unwrap()],
1501                action: FilterAction::Ignore,
1502            },
1503            rate_limiting_cutoff: Duration::from_millis(1000),
1504            rate_limiting_cache_size: 0,
1505            require_nts: None,
1506            accepted_versions: vec![NtpVersion::V3, NtpVersion::V4],
1507        };
1508        let clock = TestClock {
1509            cur: NtpTimestamp::from_fixed_int(200),
1510        };
1511        let mut stats = TestStatHandler::default();
1512
1513        let mut server = Server::new(
1514            config,
1515            clock,
1516            SystemSnapshot::default(),
1517            KeySetProvider::new(1).get(),
1518        );
1519
1520        let (packet, _) = NtpPacket::poll_message_v5(PollIntervalLimits::default().min);
1521        let serialized = serialize_packet_unencrypted(&packet);
1522
1523        let mut buf = [0; 1024];
1524        let response = server.handle(
1525            "128.0.0.1".parse().unwrap(),
1526            NtpTimestamp::from_fixed_int(100),
1527            &serialized,
1528            &mut buf,
1529            &mut stats,
1530        );
1531
1532        assert_eq!(
1533            stats.last_register.take(),
1534            Some((5, false, ServerReason::Policy, ServerResponse::Ignore))
1535        );
1536        assert!(matches!(response, ServerAction::Ignore));
1537
1538        server.update_config(ServerConfig {
1539            denylist: FilterList {
1540                filter: vec![],
1541                action: FilterAction::Deny,
1542            },
1543            allowlist: FilterList {
1544                filter: vec!["0.0.0.0/0".parse().unwrap()],
1545                action: FilterAction::Ignore,
1546            },
1547            rate_limiting_cutoff: Duration::from_millis(100),
1548            rate_limiting_cache_size: 0,
1549            require_nts: None,
1550            accepted_versions: vec![NtpVersion::V5],
1551        });
1552
1553        let (packet, _) = NtpPacket::poll_message(PollIntervalLimits::default().min);
1554        let serialized = serialize_packet_unencrypted(&packet);
1555
1556        let mut buf = [0; 1024];
1557        let response = server.handle(
1558            "128.0.0.1".parse().unwrap(),
1559            NtpTimestamp::from_fixed_int(100),
1560            &serialized,
1561            &mut buf,
1562            &mut stats,
1563        );
1564
1565        assert_eq!(
1566            stats.last_register.take(),
1567            Some((4, false, ServerReason::Policy, ServerResponse::Ignore))
1568        );
1569        assert!(matches!(response, ServerAction::Ignore));
1570    }
1571
1572    // TimestampedCache tests
1573    #[test]
1574    fn timestamped_cache() {
1575        let length = 8u8;
1576        let mut cache: TimestampedCache<u8> = TimestampedCache::new(length as usize);
1577
1578        let second = Duration::from_secs(1);
1579        let instant = Instant::now();
1580
1581        assert!(cache.is_allowed(0, instant, second));
1582
1583        assert!(!cache.is_allowed(0, instant, second));
1584
1585        let later = instant + 2 * second;
1586        assert!(cache.is_allowed(0, later, second));
1587
1588        // simulate a hash collision
1589        let even_later = later + 2 * second;
1590        assert!(cache.is_allowed(length, even_later, second));
1591    }
1592
1593    #[test]
1594    fn timestamped_cache_size_0() {
1595        let mut cache = TimestampedCache::new(0);
1596
1597        let second = Duration::from_secs(1);
1598        let instant = Instant::now();
1599
1600        assert!(cache.is_allowed(0, instant, second));
1601    }
1602
1603    // IpSubnet parsing tests
1604    #[test]
1605    fn test_ipv4_subnet_parse() {
1606        use std::str::FromStr;
1607
1608        assert!(matches!(
1609            IpSubnet::from_str("bla/5"),
1610            Err(SubnetParseError::Ip(_))
1611        ));
1612        assert_eq!(IpSubnet::from_str("0.0.0.0"), Err(SubnetParseError::Subnet));
1613        assert_eq!(
1614            IpSubnet::from_str("0.0.0.0/33"),
1615            Err(SubnetParseError::Mask)
1616        );
1617
1618        assert_eq!(
1619            IpSubnet::from_str("0.0.0.0/0"),
1620            Ok(IpSubnet {
1621                addr: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
1622                mask: 0
1623            })
1624        );
1625        assert_eq!(
1626            IpSubnet::from_str("127.0.0.1/32"),
1627            Ok(IpSubnet {
1628                addr: IpAddr::V4(Ipv4Addr::LOCALHOST),
1629                mask: 32
1630            })
1631        );
1632
1633        assert_eq!(
1634            serde_json::from_str::<IpSubnet>(r#""0.0.0.0/0""#).unwrap(),
1635            IpSubnet {
1636                addr: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
1637                mask: 0,
1638            }
1639        );
1640
1641        assert_eq!(
1642            serde_json::from_str::<IpSubnet>(r#""127.0.0.1/32""#).unwrap(),
1643            IpSubnet {
1644                addr: IpAddr::V4(Ipv4Addr::LOCALHOST),
1645                mask: 32,
1646            }
1647        );
1648    }
1649
1650    #[test]
1651    fn test_ipv6_subnet_parse() {
1652        use std::str::FromStr;
1653
1654        assert!(matches!(
1655            IpSubnet::from_str("bla/5"),
1656            Err(SubnetParseError::Ip(_))
1657        ));
1658        assert_eq!(IpSubnet::from_str("::"), Err(SubnetParseError::Subnet));
1659        assert_eq!(IpSubnet::from_str("::/129"), Err(SubnetParseError::Mask));
1660
1661        assert_eq!(
1662            IpSubnet::from_str("::/0"),
1663            Ok(IpSubnet {
1664                addr: IpAddr::V6(Ipv6Addr::UNSPECIFIED),
1665                mask: 0
1666            })
1667        );
1668        assert_eq!(
1669            IpSubnet::from_str("::1/128"),
1670            Ok(IpSubnet {
1671                addr: IpAddr::V6(Ipv6Addr::LOCALHOST),
1672                mask: 128
1673            })
1674        );
1675
1676        assert_eq!(
1677            serde_json::from_str::<IpSubnet>(r#""::/0""#).unwrap(),
1678            IpSubnet {
1679                addr: IpAddr::V6(Ipv6Addr::UNSPECIFIED),
1680                mask: 0,
1681            }
1682        );
1683
1684        assert_eq!(
1685            serde_json::from_str::<IpSubnet>(r#""::1/128""#).unwrap(),
1686            IpSubnet {
1687                addr: IpAddr::V6(Ipv6Addr::LOCALHOST),
1688                mask: 128,
1689            }
1690        );
1691    }
1692}