use crate::models::DNSQuery; use crate::models::DNSResponse; use crate::proto::Coder; pub struct UdpCoder {} impl Coder for UdpCoder { fn decode(datagram: &[u8]) -> Result { let message = Message::try_from(datagram)?; Ok(DNSQuery { id: message.header.id, questions: vec![], }) } fn encode(respone: DNSResponse) -> Result, DNSParseError> { todo!(); } } #[derive(Debug, Clone, PartialEq)] pub enum DNSParseError { DatagramTooShort } #[derive(Debug, PartialEq, Clone, Copy)] enum MessageType { Query, Response, } impl From for MessageType { fn from(value: bool) -> MessageType { match value { false => Self::Query, true => Self::Response, } } } #[derive(Debug, Clone, PartialEq)] struct Header { /// used by the requester to match up replies to outstanding queries id: u16, /// specifies whether this message is a query or a response message_type: MessageType, opcode: u8, /// specifies that the responding name server is an authority for the domain name in question section authorative_answer: bool, /// specifies that this message was truncated due to length greater than that permitted on the transmission channel truncated: bool, /// it directs the name server to pursue the query recursively recursion_desired: bool, /// denotes whether recursive query support is available in the name server recursion_available: bool, // no support of rfc4035 at the moment //pub authentic_data: bool, // no support of rfc4035 at the moment //pub checking_disabled: bool, response_code: u8, /// TODO: add documuentation about this count query_count: u16, /// TODO: add documuentation about this count answer_count: u16, /// TODO: add documuentation about this count name_server_count: u16, /// TODO: add documuentation about this count additional_count: u16, } #[derive(Debug, Clone)] struct Question { name: String, r#type: u16, class: u16, } #[derive(Debug, Clone)] struct ResourceRecord { name: String, r#type: u16, class: u16, ttl: u32, data: String, } #[derive(Debug, Clone)] pub struct Message { header: Header, questions: Vec, answers: Vec, authorities: Vec, additionals: Vec, } impl TryFrom<&[u8]> for Message { type Error = DNSParseError; fn try_from(value: &[u8]) -> Result { todo!(); } } impl TryFrom<&[u8]> for Header { type Error = DNSParseError; fn try_from(value: &[u8]) -> Result { const QR_MASK: u8 = 0b10000000; const OPCODE_MASK: u8 = 0b01111000; const AA_MASK: u8 = 0b00000100; const TC_MASK: u8 = 0b00000010; const RD_MASK: u8 = 0b00000001; const RA_MASK: u8 = 0b10000000; // no support of rfc4035 at the moment //const AD_MASK: u8 = 0b00100000; //const CD_MASK: u8 = 0b00010000; const RCODE_MASK: u8 = 0b00001111; const OPCODE_OFFSET: u8 = 3; if value.len() < 12 { return Err(DNSParseError::DatagramTooShort); } let id = u16::from_be_bytes((&value[..2]).try_into().unwrap()); let message_type = MessageType::from(value[2] & QR_MASK != 0); let opcode =(value[2] & OPCODE_MASK) >> OPCODE_OFFSET; let authorative_answer = (value[2] & AA_MASK) != 0; let truncated = (value[2] & TC_MASK) != 0; let recursion_desired = (value[2] & RD_MASK) != 0; let recursion_available = (value[3] & RA_MASK) != 0; // no support for rfc4035 at the moment //let authentic_data = (datagram[2] & AD_MASK) != 0; //let checking_disabled = (datagram[2] & CD_MASK) != 0; let response_code = value[3] & RCODE_MASK; let query_count = u16::from_be_bytes((value[4..6]).try_into().unwrap()); let answer_count = u16::from_be_bytes((value[6..8]).try_into().unwrap()); let name_server_count = u16::from_be_bytes((value[8..10]).try_into().unwrap()); let additional_count = u16::from_be_bytes((value[10..12]).try_into().unwrap()); Ok(Header { id, message_type, opcode, authorative_answer, truncated, recursion_desired, recursion_available, //authentic_data, // no support of rfc4035 at the moment //checking_disabled, // no support of rfc4035 at the moment response_code, query_count, answer_count, name_server_count, additional_count, }) } }