Repo of no-std crates for my personal embedded projects
at main 5.8 kB view raw
1use winnow::binary::{be_u16, be_u32}; 2use winnow::{ModalResult, Parser}; 3 4use super::label::Label; 5use super::records::Record; 6use crate::encoder::Encoder; 7use crate::{ 8 dns::{ 9 records::QType, 10 traits::{DnsParse, DnsParseKind, DnsSerialize}, 11 }, 12 encoder::DnsError, 13}; 14 15#[derive(Debug, PartialEq, Eq)] 16pub struct Query<'a> { 17 pub name: Label<'a>, 18 pub qtype: QType, 19 pub qclass: QClass, 20} 21 22#[derive(Debug, Clone, Copy, PartialEq, Eq)] 23#[repr(u16)] 24pub enum QClass { 25 IN = 1, 26 Multicast = 32769, // (IN + Cache flush bit) 27 Unknown(u16), 28} 29 30impl<'a> DnsParse<'a> for Query<'a> { 31 fn parse(input: &mut &'a [u8], context: &'a [u8]) -> ModalResult<Self> { 32 let name = Label::parse(input, context)?; 33 let qtype = QType::parse(input, context)?; 34 let qclass = be_u16.map(QClass::from_u16).parse_next(input)?; 35 36 Ok(Query { 37 name, 38 qtype, 39 qclass, 40 }) 41 } 42} 43 44impl<'a> DnsSerialize<'a> for Query<'a> { 45 type Error = DnsError; 46 47 fn serialize<'b>(&self, encoder: &mut Encoder<'a, 'b>) -> Result<(), Self::Error> { 48 self.name.serialize(encoder)?; 49 self.qtype.serialize(encoder).ok(); 50 encoder.write(&self.qclass.to_u16().to_be_bytes()); 51 Ok(()) 52 } 53 54 fn size(&self) -> usize { 55 self.name.size() + self.qtype.size() + core::mem::size_of::<QClass>() 56 } 57} 58 59#[derive(Debug, PartialEq, Eq)] 60pub struct Answer<'a> { 61 pub name: Label<'a>, 62 pub atype: QType, 63 pub aclass: QClass, 64 pub ttl: u32, 65 pub record: Record<'a>, 66} 67 68impl QClass { 69 fn from_u16(value: u16) -> Self { 70 match value { 71 1 => QClass::IN, 72 32769 => QClass::Multicast, 73 _ => QClass::Unknown(value), 74 } 75 } 76 77 fn to_u16(self) -> u16 { 78 match self { 79 QClass::IN => 1, 80 QClass::Multicast => 32769, 81 QClass::Unknown(value) => value, 82 } 83 } 84} 85 86impl<'a> DnsParse<'a> for Answer<'a> { 87 fn parse(input: &mut &'a [u8], context: &'a [u8]) -> ModalResult<Self> { 88 let name = Label::parse(input, context)?; 89 let atype = QType::parse(input, context)?; 90 let aclass = be_u16.map(QClass::from_u16).parse_next(input)?; 91 92 let ttl = be_u32.parse_next(input)?; 93 let record = atype.parse_kind(input, context)?; 94 95 Ok(Answer { 96 name, 97 atype, 98 aclass, 99 ttl, 100 record, 101 }) 102 } 103} 104 105impl<'a> DnsSerialize<'a> for Answer<'a> { 106 type Error = DnsError; 107 108 fn serialize<'b>(&self, encoder: &mut Encoder<'a, 'b>) -> Result<(), Self::Error> { 109 self.name.serialize(encoder)?; 110 self.atype.serialize(encoder).ok(); 111 encoder.write(&self.aclass.to_u16().to_be_bytes()); 112 encoder.write(&self.ttl.to_be_bytes()); 113 self.record.serialize(encoder) 114 } 115 116 fn size(&self) -> usize { 117 self.name.size() 118 + self.atype.size() 119 + core::mem::size_of::<QClass>() 120 + core::mem::size_of::<u32>() 121 + self.record.size() 122 } 123} 124 125#[cfg(feature = "defmt")] 126impl<'a> defmt::Format for Query<'a> { 127 fn format(&self, fmt: defmt::Formatter) { 128 defmt::write!( 129 fmt, 130 "Query {{ name: {:?}, qtype: {:?}, qclass: {:?} }}", 131 self.name, 132 self.qtype, 133 self.qclass 134 ); 135 } 136} 137 138#[cfg(feature = "defmt")] 139impl defmt::Format for QType { 140 fn format(&self, fmt: defmt::Formatter) { 141 let qtype_str = match self { 142 QType::A => "A", 143 QType::AAAA => "AAAA", 144 QType::PTR => "PTR", 145 QType::TXT => "TXT", 146 QType::SRV => "SRV", 147 QType::Any => "Any", 148 QType::Unknown(_) => "Unknown", 149 }; 150 defmt::write!(fmt, "QType({=str})", qtype_str); 151 } 152} 153 154#[cfg(feature = "defmt")] 155impl defmt::Format for QClass { 156 fn format(&self, fmt: defmt::Formatter) { 157 let qclass_str = match self { 158 QClass::IN => "IN", 159 QClass::Multicast => "Multicast", 160 QClass::Unknown(_) => "Unknown", 161 }; 162 defmt::write!(fmt, "QClass({=str})", qclass_str); 163 } 164} 165 166#[cfg(feature = "defmt")] 167impl<'a> defmt::Format for Answer<'a> { 168 fn format(&self, fmt: defmt::Formatter) { 169 defmt::write!( 170 fmt, 171 "Answer {{ name: {:?}, atype: {:?}, aclass: {:?}, ttl: {}, record: {:?} }}", 172 self.name, 173 self.atype, 174 self.aclass, 175 self.ttl, 176 self.record 177 ); 178 } 179} 180 181#[cfg(test)] 182mod tests { 183 use super::*; 184 use crate::dns::records::A; 185 use core::net::Ipv4Addr; 186 187 #[test] 188 fn roundtrip_query() { 189 let name = Label::from("example.local"); 190 191 let query = Query { 192 name, 193 qtype: QType::A, 194 qclass: QClass::IN, 195 }; 196 197 let mut buffer = [0u8; 256]; 198 let mut buffer = Encoder::new(&mut buffer); 199 query.serialize(&mut buffer).unwrap(); 200 let buffer = buffer.finish(); 201 let parsed_query = Query::parse(&mut &buffer[..], buffer).unwrap(); 202 203 assert_eq!(query, parsed_query); 204 } 205 206 #[test] 207 fn roundtrip_answer() { 208 let name = Label::from("example.local"); 209 210 let answer: Answer = Answer { 211 name, 212 atype: QType::A, 213 aclass: QClass::IN, 214 ttl: 120, 215 record: Record::A(A { 216 address: Ipv4Addr::new(192, 168, 1, 1), 217 }), 218 }; 219 220 let mut buffer = [0u8; 256]; 221 let mut buffer = Encoder::new(&mut buffer); 222 answer.serialize(&mut buffer).unwrap(); 223 let buffer = buffer.finish(); 224 let parsed_answer = Answer::parse(&mut &buffer[..], buffer).unwrap(); 225 226 assert_eq!(answer, parsed_answer); 227 } 228}