1use nom::bytes::streaming::take;
2use nom::combinator::{complete, map, map_parser, opt};
3use nom::error::{make_error, ErrorKind};
4use nom::multi::many1;
5use nom::number::streaming::be_u8;
6pub use nom::{Err, IResult};
7use nom_derive::*;
8
9#[derive(Debug, PartialEq)]
10pub enum NtpPacket<'a> {
11 V3(NtpV3Packet<'a>),
12 V4(NtpV4Packet<'a>),
13}
14
15#[derive(Clone, Copy, Debug, Eq, PartialEq, NomBE)]
16pub struct NtpMode(pub u8);
17
18#[allow(non_upper_case_globals)]
19impl NtpMode {
20 pub const Reserved: NtpMode = NtpMode(0);
21 pub const SymmetricActive: NtpMode = NtpMode(1);
22 pub const SymmetricPassive: NtpMode = NtpMode(2);
23 pub const Client: NtpMode = NtpMode(3);
24 pub const Server: NtpMode = NtpMode(4);
25 pub const Broadcast: NtpMode = NtpMode(5);
26 pub const NtpControlMessage: NtpMode = NtpMode(6);
27 pub const Private: NtpMode = NtpMode(7);
28}
29
30#[derive(Debug, PartialEq, NomBE)]
32pub struct NtpV3Packet<'a> {
33 #[nom(PreExec = "let (i, b0) = be_u8(i)?;")]
34 #[nom(Value(b0 >> 6))]
35 pub li: u8,
36 #[nom(Value((b0 >> 3) & 0b111))]
37 pub version: u8,
38 #[nom(Value(NtpMode(b0 & 0b111)))]
39 pub mode: NtpMode,
40 pub stratum: u8,
41 pub poll: i8,
42 pub precision: i8,
43 pub root_delay: u32,
44 pub root_dispersion: u32,
45 pub ref_id: u32,
46 pub ts_ref: u64,
47 pub ts_orig: u64,
48 pub ts_recv: u64,
49 pub ts_xmit: u64,
50
51 #[nom(Parse = "opt(complete(take(12usize)))")]
52 pub authenticator: Option<&'a [u8]>,
53}
54
55#[derive(Debug, PartialEq, NomBE)]
57pub struct NtpV4Packet<'a> {
58 #[nom(PreExec = "let (i, b0) = be_u8(i)?;")]
59 #[nom(Value(b0 >> 6))]
60 pub li: u8,
61 #[nom(Value((b0 >> 3) & 0b111))]
62 pub version: u8,
63 #[nom(Value(NtpMode(b0 & 0b111)))]
64 pub mode: NtpMode,
65 pub stratum: u8,
66 pub poll: i8,
67 pub precision: i8,
68 pub root_delay: u32,
69 pub root_dispersion: u32,
70 pub ref_id: u32,
71 pub ts_ref: u64,
72 pub ts_orig: u64,
73 pub ts_recv: u64,
74 pub ts_xmit: u64,
75
76 #[nom(Parse = "try_parse_extensions")]
77 pub extensions: Vec<NtpExtension<'a>>,
78 #[nom(Cond(!i.is_empty()))]
79 pub auth: Option<NtpMac<'a>>,
80}
81
82impl<'a> NtpV4Packet<'a> {
83 pub fn get_precision(&self) -> f32 {
84 2.0_f32.powf(self.precision as f32)
85 }
86}
87
88#[derive(Debug, PartialEq, NomBE)]
89pub struct NtpExtension<'a> {
90 pub field_type: u16,
91 pub length: u16,
92 #[nom(Parse = "take(length)")]
93 pub value: &'a [u8],
94 }
96
97#[derive(Debug, PartialEq, NomBE)]
98pub struct NtpMac<'a> {
99 pub key_id: u32,
100 #[nom(Parse = "take(16usize)")]
101 pub mac: &'a [u8],
102}
103
104#[inline]
105pub fn parse_ntp_extension(i: &[u8]) -> IResult<&[u8], NtpExtension> {
106 NtpExtension::parse(i)
107}
108
109fn try_parse_extensions(i: &[u8]) -> IResult<&[u8], Vec<NtpExtension>> {
122 if i.is_empty() || i.len() == 20 {
123 return Ok((i, Vec::new()));
126 }
127 if i.len() < 20 {
128 return Err(Err::Error(make_error(i, ErrorKind::Eof)));
129 }
130 map_parser(take(i.len() - 20), many1(complete(parse_ntp_extension)))(i)
131}
132
133#[inline]
135pub fn parse_ntpv3(i: &[u8]) -> IResult<&[u8], NtpV3Packet> {
136 NtpV3Packet::parse(i)
137}
138
139#[inline]
141pub fn parse_ntpv4(i: &[u8]) -> IResult<&[u8], NtpV4Packet> {
142 NtpV4Packet::parse(i)
143}
144
145#[inline]
147pub fn parse_ntp(i: &[u8]) -> IResult<&[u8], NtpPacket> {
148 let (_, b0) = be_u8(i)?;
149 match (b0 >> 3) & 0b111 {
150 3 => map(NtpV3Packet::parse, NtpPacket::V3)(i),
151 4 => map(NtpV4Packet::parse, NtpPacket::V4)(i),
152 _ => Err(Err::Error(make_error(i, ErrorKind::Tag))),
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use crate::ntp::*;
159
160 static NTP_REQ1: &[u8] = &[
161 0xd9, 0x00, 0x0a, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x90, 0x00, 0x00, 0x00,
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x02, 0x04, 0xec, 0xec,
164 0x42, 0xee, 0x92,
165 ];
166
167 #[test]
168 fn test_ntp_packet_simple() {
169 let empty = &b""[..];
170 let bytes = NTP_REQ1;
171 let expected = NtpV4Packet {
172 li: 3,
173 version: 3,
174 mode: NtpMode::SymmetricActive,
175 stratum: 0,
176 poll: 10,
177 precision: -6,
178 root_delay: 0,
179 root_dispersion: 0x010290,
180 ref_id: 0,
181 ts_ref: 0,
182 ts_orig: 0,
183 ts_recv: 0,
184 ts_xmit: 14195914391047827090u64,
185 extensions: Vec::new(),
186 auth: None,
187 };
188 let res = parse_ntpv4(&bytes);
189 assert_eq!(res, Ok((empty, expected)));
190 }
191
192 static NTP_REQ2: &[u8] = &[
193 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
194 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x25, 0xcc, 0x13, 0x2b,
196 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x52, 0x80, 0x0c, 0x2b, 0x59, 0x00, 0x64, 0x66,
197 0x84, 0xf4, 0x4c, 0xa4, 0xee, 0xce, 0x12, 0xb8,
198 ];
199
200 #[test]
201 fn test_ntp_packet_mac() {
202 let empty = &b""[..];
203 let bytes = NTP_REQ2;
204 let expected = NtpV4Packet {
205 li: 0,
206 version: 4,
207 mode: NtpMode::Client,
208 stratum: 0,
209 poll: 0,
210 precision: 0,
211 root_delay: 12,
212 root_dispersion: 0,
213 ref_id: 0,
214 ts_ref: 0,
215 ts_orig: 0,
216 ts_recv: 0,
217 ts_xmit: 14710388140573593600,
218 extensions: Vec::new(),
219 auth: Some(NtpMac {
220 key_id: 1,
221 mac: &bytes[52..],
222 }),
223 };
224 let res = parse_ntpv4(&bytes);
225 assert_eq!(res, Ok((empty, expected)));
226 }
227
228 static NTP_REQ2B: &[u8] = &[
229 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x25, 0xcc, 0x13, 0x2b,
232 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x52, 0x80, 0x0c, 0x2b,
233 0x59, 0x00, 0x64, 0x66, 0x84, 0xf4, 0x4c, 0xa4, 0xee, 0xce, 0x12, 0xb8,
234 ];
235
236 #[test]
237 fn test_ntp_packet_extension() {
238 let empty = &b""[..];
239 let bytes = NTP_REQ2B;
240 let expected = NtpV4Packet {
241 li: 0,
242 version: 4,
243 mode: NtpMode::Client,
244 stratum: 0,
245 poll: 0,
246 precision: 0,
247 root_delay: 12,
248 root_dispersion: 0,
249 ref_id: 0,
250 ts_ref: 0,
251 ts_orig: 0,
252 ts_recv: 0,
253 ts_xmit: 14710388140573593600,
254 extensions: vec![NtpExtension {
255 field_type: 0,
256 length: 0,
257 value: empty,
258 }],
259 auth: Some(NtpMac {
260 key_id: 1,
261 mac: &bytes[56..],
262 }),
263 };
264 let res = parse_ntpv4(&bytes);
265 assert_eq!(res, Ok((empty, expected)));
266 }
267
268 static NTPV3_REQ: &[u8] = &[
270 0x1b, 0x04, 0x06, 0xf5, 0x00, 0x00, 0x10, 0x0d, 0x00, 0x00, 0x05, 0x57, 0x82, 0xdc, 0x18,
271 0x18, 0xba, 0x29, 0x66, 0x36, 0x7d, 0xd0, 0x00, 0x00, 0xba, 0x29, 0x66, 0x36, 0x7d, 0x58,
272 0x40, 0x00, 0xba, 0x29, 0x66, 0x36, 0x7d, 0xd0, 0x00, 0x00, 0xba, 0x29, 0x66, 0x76, 0x7d,
273 0x50, 0x50, 0x00,
274 ];
275
276 #[test]
277 fn test_ntp_packet_v3() {
278 let empty = &b""[..];
279 let bytes = NTPV3_REQ;
280 let expected = NtpV3Packet {
281 li: 0,
282 version: 3,
283 mode: NtpMode::Client,
284 stratum: 4,
285 poll: 6,
286 precision: -11,
287 root_delay: 4109,
288 root_dispersion: 0x0557,
289 ref_id: 0x82dc1818,
290 ts_ref: 0xba296636_7dd00000,
291 ts_orig: 0xba296636_7d584000,
292 ts_recv: 0xba296636_7dd00000,
293 ts_xmit: 0xba296676_7d505000,
294 authenticator: None,
295 };
296 let res = NtpV3Packet::parse(&bytes);
297 assert_eq!(res, Ok((empty, expected)));
298 }
299}