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 RateLimit,
26 ParseError,
28 InvalidCrypto,
30 InternalError,
32 Policy,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
37pub enum ServerResponse {
38 NTSNak,
40 Deny,
42 Ignore,
44 ProvideTime,
46}
47
48pub trait ServerStatHandler {
49 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
95fn fallback_message_version(message: &[u8]) -> u8 {
97 message.first().map_or(0, |v| (v & 0b0011_1000) >> 3)
98}
99
100impl<C> Server<C> {
101 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 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 pub fn update_system(&mut self, system: SystemSnapshot) {
138 self.system = system;
139 }
140
141 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 (self.config.denylist.action.into(), ServerReason::Policy)
150 } else if !self.allowfilter.is_in(&client_ip) {
151 (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 (ServerResponse::Ignore, ServerReason::RateLimit)
160 } else {
161 (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 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 #[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 stats_handler.register(fallback_message_version(message), false, reason, action);
239 return Err(ServerAction::Ignore);
240 }
241
242 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 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 let version = packet.version();
277
278 if !self.config.accepted_versions.contains(&version) {
279 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 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#[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 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 return true;
408 }
409
410 let index = self.index(&item);
411
412 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 timestamp.duration_since(old_timestamp) >= cutoff
423 } else {
424 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 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 #[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 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 #[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}