1 use crate::error::*; 2 3 use std::collections::HashMap; 4 use std::fmt; 5 6 const NAME_LEN: usize = 255; 7 8 // A Name is a non-encoded domain name. It is used instead of strings to avoid 9 // allocations. 10 #[derive(Default, PartialEq, Eq, Debug, Clone)] 11 pub struct Name { 12 pub data: String, 13 } 14 15 // String implements fmt.Stringer.String. 16 impl fmt::Display for Name { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result17 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 18 write!(f, "{}", self.data) 19 } 20 } 21 22 impl Name { new(data: &str) -> Result<Self>23 pub fn new(data: &str) -> Result<Self> { 24 if data.len() > NAME_LEN { 25 Err(Error::ErrCalcLen) 26 } else { 27 Ok(Name { 28 data: data.to_owned(), 29 }) 30 } 31 } 32 33 // pack appends the wire format of the Name to msg. 34 // 35 // Domain names are a sequence of counted strings split at the dots. They end 36 // with a zero-length string. Compression can be used to reuse domain suffixes. 37 // 38 // The compression map will be updated with new domain suffixes. If compression 39 // is nil, compression will not be used. pack( &self, mut msg: Vec<u8>, compression: &mut Option<HashMap<String, usize>>, compression_off: usize, ) -> Result<Vec<u8>>40 pub fn pack( 41 &self, 42 mut msg: Vec<u8>, 43 compression: &mut Option<HashMap<String, usize>>, 44 compression_off: usize, 45 ) -> Result<Vec<u8>> { 46 let data = self.data.as_bytes(); 47 48 // Add a trailing dot to canonicalize name. 49 if data.is_empty() || data[data.len() - 1] != b'.' { 50 return Err(Error::ErrNonCanonicalName); 51 } 52 53 // Allow root domain. 54 if data.len() == 1 && data[0] == b'.' { 55 msg.push(0); 56 return Ok(msg); 57 } 58 59 // Emit sequence of counted strings, chopping at dots. 60 let mut begin = 0; 61 for i in 0..data.len() { 62 // Check for the end of the segment. 63 if data[i] == b'.' { 64 // The two most significant bits have special meaning. 65 // It isn't allowed for segments to be long enough to 66 // need them. 67 if i - begin >= (1 << 6) { 68 return Err(Error::ErrSegTooLong); 69 } 70 71 // Segments must have a non-zero length. 72 if i - begin == 0 { 73 return Err(Error::ErrZeroSegLen); 74 } 75 76 msg.push((i - begin) as u8); 77 msg.extend_from_slice(&data[begin..i]); 78 79 begin = i + 1; 80 continue; 81 } 82 83 // We can only compress domain suffixes starting with a new 84 // segment. A pointer is two bytes with the two most significant 85 // bits set to 1 to indicate that it is a pointer. 86 if i == 0 || data[i - 1] == b'.' { 87 if let Some(compression) = compression { 88 let key: String = self.data.chars().skip(i).collect(); 89 if let Some(ptr) = compression.get(&key) { 90 // Hit. Emit a pointer instead of the rest of 91 // the domain. 92 msg.push(((ptr >> 8) | 0xC0) as u8); 93 msg.push((ptr & 0xFF) as u8); 94 return Ok(msg); 95 } 96 97 // Miss. Add the suffix to the compression table if the 98 // offset can be stored in the available 14 bytes. 99 if msg.len() <= 0x3FFF { 100 compression.insert(key, msg.len() - compression_off); 101 } 102 } 103 } 104 } 105 106 msg.push(0); 107 Ok(msg) 108 } 109 110 // unpack unpacks a domain name. unpack(&mut self, msg: &[u8], off: usize) -> Result<usize>111 pub fn unpack(&mut self, msg: &[u8], off: usize) -> Result<usize> { 112 self.unpack_compressed(msg, off, true /* allowCompression */) 113 } 114 unpack_compressed( &mut self, msg: &[u8], off: usize, allow_compression: bool, ) -> Result<usize>115 pub fn unpack_compressed( 116 &mut self, 117 msg: &[u8], 118 off: usize, 119 allow_compression: bool, 120 ) -> Result<usize> { 121 // curr_off is the current working offset. 122 let mut curr_off = off; 123 124 // new_off is the offset where the next record will start. Pointers lead 125 // to data that belongs to other names and thus doesn't count towards to 126 // the usage of this name. 127 let mut new_off = off; 128 129 // ptr is the number of pointers followed. 130 let mut ptr = 0; 131 132 // Name is a slice representation of the name data. 133 let mut name = String::new(); //n.Data[:0] 134 135 loop { 136 if curr_off >= msg.len() { 137 return Err(Error::ErrBaseLen); 138 } 139 let c = msg[curr_off]; 140 curr_off += 1; 141 match c & 0xC0 { 142 0x00 => { 143 // String segment 144 if c == 0x00 { 145 // A zero length signals the end of the name. 146 break; 147 } 148 let end_off = curr_off + c as usize; 149 if end_off > msg.len() { 150 return Err(Error::ErrCalcLen); 151 } 152 name.push_str(String::from_utf8(msg[curr_off..end_off].to_vec())?.as_str()); 153 name.push('.'); 154 curr_off = end_off; 155 } 156 0xC0 => { 157 // Pointer 158 if !allow_compression { 159 return Err(Error::ErrCompressedSrv); 160 } 161 if curr_off >= msg.len() { 162 return Err(Error::ErrInvalidPtr); 163 } 164 let c1 = msg[curr_off]; 165 curr_off += 1; 166 if ptr == 0 { 167 new_off = curr_off; 168 } 169 // Don't follow too many pointers, maybe there's a loop. 170 ptr += 1; 171 if ptr > 10 { 172 return Err(Error::ErrTooManyPtr); 173 } 174 curr_off = ((c ^ 0xC0) as usize) << 8 | (c1 as usize); 175 } 176 _ => { 177 // Prefixes 0x80 and 0x40 are reserved. 178 return Err(Error::ErrReserved); 179 } 180 } 181 } 182 if name.is_empty() { 183 name.push('.'); 184 } 185 if name.len() > NAME_LEN { 186 return Err(Error::ErrCalcLen); 187 } 188 self.data = name; 189 if ptr == 0 { 190 new_off = curr_off; 191 } 192 Ok(new_off) 193 } 194 skip(msg: &[u8], off: usize) -> Result<usize>195 pub(crate) fn skip(msg: &[u8], off: usize) -> Result<usize> { 196 // new_off is the offset where the next record will start. Pointers lead 197 // to data that belongs to other names and thus doesn't count towards to 198 // the usage of this name. 199 let mut new_off = off; 200 201 loop { 202 if new_off >= msg.len() { 203 return Err(Error::ErrBaseLen); 204 } 205 let c = msg[new_off]; 206 new_off += 1; 207 match c & 0xC0 { 208 0x00 => { 209 if c == 0x00 { 210 // A zero length signals the end of the name. 211 break; 212 } 213 // literal string 214 new_off += c as usize; 215 if new_off > msg.len() { 216 return Err(Error::ErrCalcLen); 217 } 218 } 219 0xC0 => { 220 // Pointer to somewhere else in msg. 221 222 // Pointers are two bytes. 223 new_off += 1; 224 225 // Don't follow the pointer as the data here has ended. 226 break; 227 } 228 _ => { 229 // Prefixes 0x80 and 0x40 are reserved. 230 return Err(Error::ErrReserved); 231 } 232 } 233 } 234 235 Ok(new_off) 236 } 237 } 238