1 use nom::{Err, IResult};
2 use nom::error::ErrorKind;
3 use nom::number::streaming::{be_i8, be_u8, be_u16, be_u32, be_u64};
4
5 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
6 pub struct NtpMode(pub u8);
7
8 #[allow(non_upper_case_globals)]
9 impl NtpMode {
10 pub const Reserved : NtpMode = NtpMode(0);
11 pub const SymmetricActive : NtpMode = NtpMode(1);
12 pub const SymmetricPassive : NtpMode = NtpMode(2);
13 pub const Client : NtpMode = NtpMode(3);
14 pub const Server : NtpMode = NtpMode(4);
15 pub const Broadcast : NtpMode = NtpMode(5);
16 pub const NtpControlMessage : NtpMode = NtpMode(6);
17 pub const Private : NtpMode = NtpMode(7);
18 }
19
20 #[derive(Debug,PartialEq)]
21 pub struct NtpPacket<'a> {
22 pub li: u8,
23 pub version: u8,
24 pub mode: NtpMode,
25 pub stratum: u8,
26 pub poll: i8,
27 pub precision: i8,
28 pub root_delay: u32,
29 pub root_dispersion: u32,
30 pub ref_id:u32,
31 pub ts_ref:u64,
32 pub ts_orig:u64,
33 pub ts_recv:u64,
34 pub ts_xmit:u64,
35
36 pub extensions:Vec<NtpExtension<'a>>,
37 pub auth: Option<NtpMac<'a>>
38 }
39
40 impl<'a> NtpPacket<'a> {
get_precision(&self) -> f3241 pub fn get_precision(&self) -> f32 {
42 2.0_f32.powf(self.precision as f32)
43 }
44 }
45
46 #[derive(Debug,PartialEq)]
47 pub struct NtpExtension<'a> {
48 pub field_type: u16,
49 pub length: u16,
50 pub value: &'a[u8],
51 /*padding*/
52 }
53
54 #[derive(Debug,PartialEq)]
55 pub struct NtpMac<'a> {
56 pub key_id: u32,
57 pub mac: &'a[u8],
58 }
59
parse_ntp_extension(i: &[u8]) -> IResult<&[u8],NtpExtension>60 pub fn parse_ntp_extension(i: &[u8]) -> IResult<&[u8],NtpExtension> {
61 do_parse!(
62 i,
63 field_type: be_u16 >>
64 length: be_u16 >> // len includes the padding
65 value: take!(length) >>
66 (
67 NtpExtension{
68 field_type,
69 length,
70 value,
71 }
72 )
73 )
74 }
75
parse_ntp_mac(i: &[u8]) -> IResult<&[u8],NtpMac>76 fn parse_ntp_mac(i: &[u8]) -> IResult<&[u8],NtpMac> {
77 do_parse!(
78 i,
79 key_id: be_u32 >>
80 mac: take!(16) >>
81 ( NtpMac{ key_id, mac} )
82 )
83 }
84
85 // optional fields, See section 7.5 of [RFC5905] and [RFC7822]
86 // extensions, key ID and MAC
87 //
88 // check length: if == 20, only MAC
89 // if > 20, ext + MAC
90 // if == 0, nothing
91 // else error
parse_extensions_and_auth(i:&[u8]) -> IResult<&[u8],(Vec<NtpExtension>,Option<NtpMac>)>92 fn parse_extensions_and_auth(i:&[u8]) -> IResult<&[u8],(Vec<NtpExtension>,Option<NtpMac>)> {
93 if i.is_empty() { Ok((i,(Vec::new(),None))) }
94 else if i.len() == 20 {
95 parse_ntp_mac(i).map(|(rem,m)| (rem,(Vec::new(),Some(m))))
96 }
97 else if i.len() > 20 {
98 do_parse!(
99 i,
100 v: flat_map!(
101 take!(i.len() - 20),
102 many1!(complete!(parse_ntp_extension))
103 ) >>
104 m: parse_ntp_mac >>
105 // eof!() >>
106 ( (v,Some(m)) )
107 )
108 } else {
109 Err(Err::Error(error_position!(i, ErrorKind::Eof)))
110 }
111 }
112
113 named!(pub parse_ntp<NtpPacket>,
114 do_parse!(
115 b0: bits!(
116 tuple!(take_bits!(2u8),take_bits!(3u8),take_bits!(3u8))
117 ) >>
118 stratum: be_u8 >>
119 poll: be_i8 >>
120 precision: be_i8 >>
121 root_delay: be_u32 >>
122 root_dispersion: be_u32 >>
123 ref_id: be_u32 >>
124 ts_ref: be_u64 >>
125 ts_orig: be_u64 >>
126 ts_recv: be_u64 >>
127 ts_xmit: be_u64 >>
128 ext_and_auth: parse_extensions_and_auth >>
129 (
130 NtpPacket {
131 li:b0.0,
132 version:b0.1,
133 mode:NtpMode(b0.2),
134 stratum,
135 poll,
136 precision,
137 root_delay,
138 root_dispersion,
139 ref_id,
140 ts_ref,
141 ts_orig,
142 ts_recv,
143 ts_xmit,
144 extensions: ext_and_auth.0,
145 auth: ext_and_auth.1
146 }
147 ))
148 );
149
150 #[cfg(test)]
151 mod tests {
152 use crate::ntp::*;
153
154 static NTP_REQ1: &'static [u8] = &[
155 0xd9, 0x00, 0x0a, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x90,
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158 0x00, 0x00, 0x00, 0x00, 0xc5, 0x02, 0x04, 0xec, 0xec, 0x42, 0xee, 0x92
159 ];
160
161 #[test]
test_ntp_packet_simple()162 fn test_ntp_packet_simple() {
163 let empty = &b""[..];
164 let bytes = NTP_REQ1;
165 let expected = NtpPacket{
166 li:3,
167 version:3,
168 mode:NtpMode::SymmetricActive,
169 stratum:0,
170 poll:10,
171 precision:-6,
172 root_delay:0,
173 root_dispersion:0x010290,
174 ref_id:0,
175 ts_ref:0,
176 ts_orig:0,
177 ts_recv:0,
178 ts_xmit:14195914391047827090u64,
179 extensions:Vec::new(),
180 auth:None,
181 };
182 let res = parse_ntp(&bytes);
183 assert_eq!(res, Ok((empty,expected)));
184 }
185
186 static NTP_REQ2: &'static [u8] = &[
187 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
188 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
189 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190 0x00, 0x00, 0x00, 0x00, 0xcc, 0x25, 0xcc, 0x13, 0x2b, 0x02, 0x10, 0x00,
191 0x00, 0x00, 0x00, 0x01, 0x52, 0x80, 0x0c, 0x2b, 0x59, 0x00, 0x64, 0x66,
192 0x84, 0xf4, 0x4c, 0xa4, 0xee, 0xce, 0x12, 0xb8
193 ];
194
195 #[test]
test_ntp_packet_mac()196 fn test_ntp_packet_mac() {
197 let empty = &b""[..];
198 let bytes = NTP_REQ2;
199 let expected = NtpPacket{
200 li:0,
201 version:4,
202 mode:NtpMode::Client,
203 stratum:0,
204 poll:0,
205 precision:0,
206 root_delay:12,
207 root_dispersion:0,
208 ref_id:0,
209 ts_ref:0,
210 ts_orig:0,
211 ts_recv:0,
212 ts_xmit:14710388140573593600,
213 extensions:Vec::new(),
214 auth:Some(NtpMac{key_id:1,mac:&bytes[52..]}),
215 };
216 let res = parse_ntp(&bytes);
217 assert_eq!(res, Ok((empty,expected)));
218 }
219
220 static NTP_REQ2B: &'static [u8] = &[
221 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
224 0x00, 0x00, 0x00, 0x00, 0xcc, 0x25, 0xcc, 0x13, 0x2b, 0x02, 0x10, 0x00,
225 0x00, 0x00, 0x00, 0x00,
226 0x00, 0x00, 0x00, 0x01, 0x52, 0x80, 0x0c, 0x2b,
227 0x59, 0x00, 0x64, 0x66, 0x84, 0xf4, 0x4c, 0xa4, 0xee, 0xce, 0x12, 0xb8,
228 ];
229
230 #[test]
test_ntp_packet_extension()231 fn test_ntp_packet_extension() {
232 let empty = &b""[..];
233 let bytes = NTP_REQ2B;
234 let expected = NtpPacket{
235 li:0,
236 version:4,
237 mode:NtpMode::Client,
238 stratum:0,
239 poll:0,
240 precision:0,
241 root_delay:12,
242 root_dispersion:0,
243 ref_id:0,
244 ts_ref:0,
245 ts_orig:0,
246 ts_recv:0,
247 ts_xmit:14710388140573593600,
248 extensions:vec![NtpExtension{
249 field_type: 0,
250 length: 0,
251 value: empty
252 }],
253 auth:Some(NtpMac{key_id:1,mac:&bytes[56..]}),
254 };
255 let res = parse_ntp(&bytes);
256 assert_eq!(res, Ok((empty,expected)));
257 }
258
259 }
260