1use std::fmt;
2use std::fmt::Write;
3use std::str::from_utf8;
4
5use byteorder::{BigEndian, ByteOrder};
6
7use {Error};
8
9#[derive(Debug, Clone, Copy)]
14pub struct Name<'a>{
15 labels: &'a [u8],
16 original: &'a [u8],
19}
20
21impl<'a> Name<'a> {
22 pub fn scan(data: &'a[u8], original: &'a[u8]) -> Result<Name<'a>, Error> {
23 let mut parse_data = data;
24 let mut return_pos = None;
25 let mut pos = 0;
26 if parse_data.len() <= pos {
27 return Err(Error::UnexpectedEOF);
28 }
29 let mut largest_pos = original.len();
32 let mut byte = parse_data[pos];
33 while byte != 0 {
34 if parse_data.len() <= pos {
35 return Err(Error::UnexpectedEOF);
36 }
37 if byte & 0b1100_0000 == 0b1100_0000 {
38 if parse_data.len() < pos+2 {
39 return Err(Error::UnexpectedEOF);
40 }
41 let off = (BigEndian::read_u16(&parse_data[pos..pos+2])
42 & !0b1100_0000_0000_0000) as usize;
43 if off >= original.len() {
44 return Err(Error::UnexpectedEOF);
45 }
46 if let None = return_pos {
50 return_pos = Some(pos);
51 }
52
53 if off >= largest_pos {
56 return Err(Error::BadPointer);
57 }
58 largest_pos = off;
59 pos = 0;
60 parse_data = &original[off..];
61 } else if byte & 0b1100_0000 == 0 {
62 let end = pos + byte as usize + 1;
63 if parse_data.len() < end {
64 return Err(Error::UnexpectedEOF);
65 }
66 pos = end;
67 if parse_data.len() <= pos {
68 return Err(Error::UnexpectedEOF);
69 }
70 } else {
71 return Err(Error::UnknownLabelFormat);
72 }
73 byte = parse_data[pos];
74 }
75 if let Some(return_pos) = return_pos {
76 return Ok(Name {labels: &data[..return_pos+2], original: original});
77 } else {
78 return Ok(Name {labels: &data[..pos+1], original: original });
79 }
80 }
81 pub fn byte_len(&self) -> usize {
82 self.labels.len()
83 }
84}
85
86impl<'a> fmt::Display for Name<'a> {
87 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
88 let data = self.labels;
89 let original = self.original;
90 let mut pos = 0;
91 loop {
92 let byte = data[pos];
93 if byte == 0 {
94 return Ok(());
95 } else if byte & 0b1100_0000 == 0b1100_0000 {
96 let off = (BigEndian::read_u16(&data[pos..pos+2])
97 & !0b1100_0000_0000_0000) as usize;
98 if pos != 0 {
99 try!(fmt.write_char('.'));
100 }
101 return fmt::Display::fmt(
102 &Name::scan(&original[off..], original).unwrap(), fmt)
103 } else if byte & 0b1100_0000 == 0 {
104 if pos != 0 {
105 try!(fmt.write_char('.'));
106 }
107 let end = pos + byte as usize + 1;
108 try!(fmt.write_str(from_utf8(&data[pos+1..end]).unwrap()));
109 pos = end;
110 continue;
111 } else {
112 unreachable!();
113 }
114 }
115 }
116}
117
118#[cfg(test)]
119mod test {
120 use Error;
121 use Name;
122
123 #[test]
124 fn parse_badpointer_same_offset() {
125 let same_offset = vec![192, 2, 192, 2];
128 let is_match = matches!(Name::scan(&same_offset, &same_offset),
129 Err(Error::BadPointer));
130
131 assert!(is_match);
132 }
133
134 #[test]
135 fn parse_badpointer_forward_offset() {
136 let forwards_offset = vec![192, 2, 192, 4, 192, 2];
139 let is_match = matches!(Name::scan(&forwards_offset, &forwards_offset),
140 Err(Error::BadPointer));
141
142 assert!(is_match);
143 }
144
145 #[test]
146 fn nested_names() {
147 let buf = b"\x02xx\x00\x02yy\xc0\x00\x02zz\xc0\x04";
149
150 assert_eq!(Name::scan(&buf[..], buf).unwrap().to_string(),
151 "xx");
152 assert_eq!(Name::scan(&buf[..], buf).unwrap().labels,
153 b"\x02xx\x00");
154 assert_eq!(Name::scan(&buf[4..], buf).unwrap().to_string(),
155 "yy.xx");
156 assert_eq!(Name::scan(&buf[4..], buf).unwrap().labels,
157 b"\x02yy\xc0\x00");
158 assert_eq!(Name::scan(&buf[9..], buf).unwrap().to_string(),
159 "zz.yy.xx");
160 assert_eq!(Name::scan(&buf[9..], buf).unwrap().labels,
161 b"\x02zz\xc0\x04");
162 }
163}