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