1 use std::fmt;
2 use std::fmt::Write;
3 use std::str::from_utf8;
4 
5 // Deprecated since rustc 1.23
6 #[allow(unused_imports, deprecated)]
7 use std::ascii::AsciiExt;
8 
9 use byteorder::{BigEndian, ByteOrder};
10 
11 use {Error};
12 
13 /// The DNS name as stored in the original packet
14 ///
15 /// This contains just a reference to a slice that contains the data.
16 /// You may turn this into a string using `.to_string()`
17 #[derive(Clone, Copy)]
18 pub struct Name<'a>{
19     labels: &'a [u8],
20     /// This is the original buffer size. The compressed names in original
21     /// are calculated in this buffer
22     original: &'a [u8],
23 }
24 
25 impl<'a> Name<'a> {
26     /// Scan the data to get Name object
27     ///
28     /// The `data` should be a part of `original` where name should start.
29     /// The `original` is the data starting a the start of a packet, so
30     /// that offsets in compressed name starts from the `original`.
scan(data: &'a[u8], original: &'a[u8]) -> Result<Name<'a>, Error>31     pub fn scan(data: &'a[u8], original: &'a[u8]) -> Result<Name<'a>, Error> {
32         let mut parse_data = data;
33         let mut return_pos = None;
34         let mut pos = 0;
35         if parse_data.len() <= pos {
36             return Err(Error::UnexpectedEOF);
37         }
38         // By setting the largest_pos to be the original len, a side effect
39         // is that the pos variable can move forwards in the buffer once.
40         let mut largest_pos = original.len();
41         let mut byte = parse_data[pos];
42         while byte != 0 {
43             if parse_data.len() <= pos {
44                 return Err(Error::UnexpectedEOF);
45             }
46             if byte & 0b1100_0000 == 0b1100_0000 {
47                 if parse_data.len() < pos+2 {
48                     return Err(Error::UnexpectedEOF);
49                 }
50                 let off = (BigEndian::read_u16(&parse_data[pos..pos+2])
51                            & !0b1100_0000_0000_0000) as usize;
52                 if off >= original.len() {
53                     return Err(Error::UnexpectedEOF);
54                 }
55                 // Set value for return_pos which is the pos in the original
56                 // data buffer that should be used to return after validating
57                 // the offsetted labels.
58                 if let None = return_pos {
59                     return_pos = Some(pos);
60                 }
61 
62                 // Check then set largest_pos to ensure we never go backwards
63                 // in the buffer.
64                 if off >= largest_pos {
65                     return Err(Error::BadPointer);
66                 }
67                 largest_pos = off;
68                 pos = 0;
69                 parse_data = &original[off..];
70             } else if byte & 0b1100_0000 == 0 {
71                 let end = pos + byte as usize + 1;
72                 if parse_data.len() < end {
73                     return Err(Error::UnexpectedEOF);
74                 }
75                 if !parse_data[pos+1..end].is_ascii() {
76                     return Err(Error::LabelIsNotAscii);
77                 }
78                 pos = end;
79                 if parse_data.len() <= pos {
80                     return Err(Error::UnexpectedEOF);
81                 }
82             } else {
83                 return Err(Error::UnknownLabelFormat);
84             }
85             byte = parse_data[pos];
86         }
87         if let Some(return_pos) = return_pos {
88             return Ok(Name {labels: &data[..return_pos+2], original: original});
89         } else {
90             return Ok(Name {labels: &data[..pos+1], original: original });
91         }
92     }
93     /// Number of bytes serialized name occupies
byte_len(&self) -> usize94     pub fn byte_len(&self) -> usize {
95         self.labels.len()
96     }
97 }
98 
99 impl<'a> fmt::Display for Name<'a> {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result100     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
101         let data = self.labels;
102         let original = self.original;
103         let mut pos = 0;
104         loop {
105             let byte = data[pos];
106             if byte == 0 {
107                 return Ok(());
108             } else if byte & 0b1100_0000 == 0b1100_0000 {
109                 let off = (BigEndian::read_u16(&data[pos..pos+2])
110                            & !0b1100_0000_0000_0000) as usize;
111                 if pos != 0 {
112                     try!(fmt.write_char('.'));
113                 }
114                 return fmt::Display::fmt(
115                     &Name::scan(&original[off..], original).unwrap(), fmt)
116             } else if byte & 0b1100_0000 == 0 {
117                 if pos != 0 {
118                     try!(fmt.write_char('.'));
119                 }
120                 let end = pos + byte as usize + 1;
121                 try!(fmt.write_str(from_utf8(&data[pos+1..end]).unwrap()));
122                 pos = end;
123                 continue;
124             } else {
125                 unreachable!();
126             }
127         }
128     }
129 }
130 impl<'a> fmt::Debug for Name<'a> {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result131     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
132         fmt.debug_tuple("Name")
133         .field(&format!("{}", self))
134         .finish()
135     }
136 }
137 
138 #[cfg(test)]
139 mod test {
140     use Error;
141     use Name;
142 
143     #[test]
parse_badpointer_same_offset()144     fn parse_badpointer_same_offset() {
145         // A buffer where an offset points to itself,
146         // which is a bad compression pointer.
147         let same_offset = vec![192, 2, 192, 2];
148         let is_match = matches!(Name::scan(&same_offset, &same_offset),
149                                 Err(Error::BadPointer));
150 
151         assert!(is_match);
152     }
153 
154     #[test]
parse_badpointer_forward_offset()155     fn parse_badpointer_forward_offset() {
156         // A buffer where the offsets points back to each other which causes
157         // infinite recursion if never checked, a bad compression pointer.
158         let forwards_offset = vec![192, 2, 192, 4, 192, 2];
159         let is_match = matches!(Name::scan(&forwards_offset, &forwards_offset),
160                                 Err(Error::BadPointer));
161 
162         assert!(is_match);
163     }
164 
165     #[test]
nested_names()166     fn nested_names() {
167         // A buffer where an offset points to itself, a bad compression pointer.
168         let buf = b"\x02xx\x00\x02yy\xc0\x00\x02zz\xc0\x04";
169 
170         assert_eq!(Name::scan(&buf[..], buf).unwrap().to_string(),
171             "xx");
172         assert_eq!(Name::scan(&buf[..], buf).unwrap().labels,
173             b"\x02xx\x00");
174         assert_eq!(Name::scan(&buf[4..], buf).unwrap().to_string(),
175             "yy.xx");
176         assert_eq!(Name::scan(&buf[4..], buf).unwrap().labels,
177             b"\x02yy\xc0\x00");
178         assert_eq!(Name::scan(&buf[9..], buf).unwrap().to_string(),
179             "zz.yy.xx");
180         assert_eq!(Name::scan(&buf[9..], buf).unwrap().labels,
181             b"\x02zz\xc0\x04");
182     }
183 }
184