1 use super::header::*; 2 use super::question::*; 3 use super::resource::*; 4 use super::*; 5 use crate::error::*; 6 7 use std::collections::HashMap; 8 9 // A Builder allows incrementally packing a DNS message. 10 // 11 // Example usage: 12 // b := NewBuilder(Header{...}) 13 // b.enable_compression() 14 // // Optionally start a section and add things to that section. 15 // // Repeat adding sections as necessary. 16 // buf, err := b.Finish() 17 // // If err is nil, buf[2:] will contain the built bytes. 18 #[derive(Default)] 19 pub struct Builder { 20 // msg is the storage for the message being built. 21 pub msg: Option<Vec<u8>>, 22 23 // section keeps track of the current section being built. 24 pub section: Section, 25 26 // header keeps track of what should go in the header when Finish is 27 // called. 28 pub header: HeaderInternal, 29 30 // start is the starting index of the bytes allocated in msg for header. 31 pub start: usize, 32 33 // compression is a mapping from name suffixes to their starting index 34 // in msg. 35 pub compression: Option<HashMap<String, usize>>, 36 } 37 38 impl Builder { 39 // NewBuilder creates a new builder with compression disabled. 40 // 41 // Note: Most users will want to immediately enable compression with the 42 // enable_compression method. See that method's comment for why you may or may 43 // not want to enable compression. 44 // 45 // The DNS message is appended to the provided initial buffer buf (which may be 46 // nil) as it is built. The final message is returned by the (*Builder).Finish 47 // method, which may return the same underlying array if there was sufficient 48 // capacity in the slice. new(h: &Header) -> Self49 pub fn new(h: &Header) -> Self { 50 let (id, bits) = h.pack(); 51 52 Builder { 53 msg: Some(vec![0; HEADER_LEN]), 54 start: 0, 55 section: Section::Header, 56 header: HeaderInternal { 57 id, 58 bits, 59 ..Default::default() 60 }, 61 compression: None, 62 } 63 64 //var hb [HEADER_LEN]byte 65 //b.msg = append(b.msg, hb[:]...) 66 //return b 67 } 68 69 // enable_compression enables compression in the Builder. 70 // 71 // Leaving compression disabled avoids compression related allocations, but can 72 // result in larger message sizes. Be careful with this mode as it can cause 73 // messages to exceed the UDP size limit. 74 // 75 // According to RFC 1035, section 4.1.4, the use of compression is optional, but 76 // all implementations must accept both compressed and uncompressed DNS 77 // messages. 78 // 79 // Compression should be enabled before any sections are added for best results. enable_compression(&mut self)80 pub fn enable_compression(&mut self) { 81 self.compression = Some(HashMap::new()); 82 } 83 start_check(&self, section: Section) -> Result<()>84 fn start_check(&self, section: Section) -> Result<()> { 85 if self.section <= Section::NotStarted { 86 return Err(Error::ErrNotStarted); 87 } 88 if self.section > section { 89 return Err(Error::ErrSectionDone); 90 } 91 92 Ok(()) 93 } 94 95 // start_questions prepares the builder for packing Questions. start_questions(&mut self) -> Result<()>96 pub fn start_questions(&mut self) -> Result<()> { 97 self.start_check(Section::Questions)?; 98 self.section = Section::Questions; 99 Ok(()) 100 } 101 102 // start_answers prepares the builder for packing Answers. start_answers(&mut self) -> Result<()>103 pub fn start_answers(&mut self) -> Result<()> { 104 self.start_check(Section::Answers)?; 105 self.section = Section::Answers; 106 Ok(()) 107 } 108 109 // start_authorities prepares the builder for packing Authorities. start_authorities(&mut self) -> Result<()>110 pub fn start_authorities(&mut self) -> Result<()> { 111 self.start_check(Section::Authorities)?; 112 self.section = Section::Authorities; 113 Ok(()) 114 } 115 116 // start_additionals prepares the builder for packing Additionals. start_additionals(&mut self) -> Result<()>117 pub fn start_additionals(&mut self) -> Result<()> { 118 self.start_check(Section::Additionals)?; 119 self.section = Section::Additionals; 120 Ok(()) 121 } 122 increment_section_count(&mut self) -> Result<()>123 fn increment_section_count(&mut self) -> Result<()> { 124 let section = self.section; 125 let (count, err) = match section { 126 Section::Questions => (&mut self.header.questions, Error::ErrTooManyQuestions), 127 Section::Answers => (&mut self.header.answers, Error::ErrTooManyAnswers), 128 Section::Authorities => (&mut self.header.authorities, Error::ErrTooManyAuthorities), 129 Section::Additionals => (&mut self.header.additionals, Error::ErrTooManyAdditionals), 130 Section::NotStarted => return Err(Error::ErrNotStarted), 131 Section::Done => return Err(Error::ErrSectionDone), 132 Section::Header => return Err(Error::ErrSectionHeader), 133 }; 134 135 if *count == u16::MAX { 136 Err(err) 137 } else { 138 *count += 1; 139 Ok(()) 140 } 141 } 142 143 // question adds a single question. add_question(&mut self, q: &Question) -> Result<()>144 pub fn add_question(&mut self, q: &Question) -> Result<()> { 145 if self.section < Section::Questions { 146 return Err(Error::ErrNotStarted); 147 } 148 if self.section > Section::Questions { 149 return Err(Error::ErrSectionDone); 150 } 151 let msg = self.msg.take(); 152 if let Some(mut msg) = msg { 153 msg = q.pack(msg, &mut self.compression, self.start)?; 154 self.increment_section_count()?; 155 self.msg = Some(msg); 156 } 157 158 Ok(()) 159 } 160 check_resource_section(&self) -> Result<()>161 fn check_resource_section(&self) -> Result<()> { 162 if self.section < Section::Answers { 163 return Err(Error::ErrNotStarted); 164 } 165 if self.section > Section::Additionals { 166 return Err(Error::ErrSectionDone); 167 } 168 Ok(()) 169 } 170 171 // Resource adds a single resource. add_resource(&mut self, r: &mut Resource) -> Result<()>172 pub fn add_resource(&mut self, r: &mut Resource) -> Result<()> { 173 self.check_resource_section()?; 174 175 if let Some(body) = &r.body { 176 r.header.typ = body.real_type(); 177 } else { 178 return Err(Error::ErrNilResourceBody); 179 } 180 181 if let Some(msg) = self.msg.take() { 182 let (mut msg, len_off) = r.header.pack(msg, &mut self.compression, self.start)?; 183 let pre_len = msg.len(); 184 if let Some(body) = &r.body { 185 msg = body.pack(msg, &mut self.compression, self.start)?; 186 r.header.fix_len(&mut msg, len_off, pre_len)?; 187 self.increment_section_count()?; 188 } 189 self.msg = Some(msg); 190 } 191 192 Ok(()) 193 } 194 195 // Finish ends message building and generates a binary message. finish(&mut self) -> Result<Vec<u8>>196 pub fn finish(&mut self) -> Result<Vec<u8>> { 197 if self.section < Section::Header { 198 return Err(Error::ErrNotStarted); 199 } 200 self.section = Section::Done; 201 202 // Space for the header was allocated in NewBuilder. 203 let buf = self.header.pack(vec![]); 204 assert_eq!(buf.len(), HEADER_LEN); 205 if let Some(mut msg) = self.msg.take() { 206 msg[..HEADER_LEN].copy_from_slice(&buf[..HEADER_LEN]); 207 Ok(msg) 208 } else { 209 Err(Error::ErrEmptyBuilderMsg) 210 } 211 } 212 } 213