diff --git a/dnstp-client/src/main.rs b/dnstp-client/src/main.rs index c311adf..bf02c00 100644 --- a/dnstp-client/src/main.rs +++ b/dnstp-client/src/main.rs @@ -72,6 +72,7 @@ fn main() { qclass: QClass::Internet } ], + additional_records: vec![], peer: address }; diff --git a/dnstp/src/message/answer/ip_address.rs b/dnstp/src/message/answer/a_rdata.rs similarity index 68% rename from dnstp/src/message/answer/ip_address.rs rename to dnstp/src/message/answer/a_rdata.rs index 7510e2b..a38275f 100644 --- a/dnstp/src/message/answer/ip_address.rs +++ b/dnstp/src/message/answer/a_rdata.rs @@ -1,12 +1,12 @@ use std::fmt::{Debug, Formatter}; -use std::net::{IpAddr, Ipv4Addr}; +use std::net::Ipv4Addr; use crate::message::answer::RData; -pub struct IpRData { +pub struct ARdata { pub rdata: Ipv4Addr } -impl Debug for IpRData { +impl Debug for ARdata { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("IP") .field("data", &self.rdata) @@ -14,16 +14,16 @@ impl Debug for IpRData { } } -impl RData for IpRData { +impl RData for ARdata { fn to_bytes(&self) -> Vec { return self.rdata.octets().to_vec(); } } -impl IpRData { - pub fn from(rdata: Ipv4Addr) -> IpRData +impl ARdata { + pub fn from(rdata: Ipv4Addr) -> ARdata { - IpRData { + ARdata { rdata } } diff --git a/dnstp/src/message/answer/mod.rs b/dnstp/src/message/answer/mod.rs index aa3123a..d318042 100644 --- a/dnstp/src/message/answer/mod.rs +++ b/dnstp/src/message/answer/mod.rs @@ -1,17 +1,16 @@ mod raw_rdata; pub use raw_rdata::RawRData; -mod ip_address; -pub use ip_address::IpRData; +mod a_rdata; +pub use a_rdata::ARdata; #[cfg(test)] mod tests; -use std::fmt::{Debug, Display}; +use std::fmt::Debug; +use std::fmt::Display; use crate::byte::{four_byte_split, two_byte_split}; -use crate::message::question::{DNSQuestion, QClass, QType, QuestionParseError}; -use crate::string::encode_domain_name; - +use crate::message::question::{DNSQuestion, QClass, QType}; pub trait RData: Debug { fn to_bytes(&self) -> Vec; @@ -19,7 +18,7 @@ pub trait RData: Debug { #[derive(Debug)] pub struct DNSAnswer { - pub name: String, + pub name_offset: u16, pub answer_type: QType, pub class: QClass, pub ttl: u32, @@ -31,7 +30,8 @@ impl DNSAnswer { pub fn to_bytes(&self) -> Vec { - let mut ret = encode_domain_name(&self.name); + let (name_1, name_2) = two_byte_split(self.name_offset | (0b11 << 14)); + let mut ret = vec![name_1, name_2]; let type_split = two_byte_split(self.answer_type as u16); ret.push(type_split.0); @@ -56,10 +56,10 @@ impl DNSAnswer { return ret } - pub fn from_query(query: &DNSQuestion, data: Box, ttl: Option) -> DNSAnswer + pub fn from_query(query: &DNSQuestion, name_offset: u16, data: Box, ttl: Option) -> DNSAnswer { DNSAnswer { - name: query.qname.clone(), + name_offset, answer_type: query.qtype, class: query.qclass, ttl: ttl.unwrap_or(0), diff --git a/dnstp/src/message/answer/tests.rs b/dnstp/src/message/answer/tests.rs index 564e8ff..ee702cf 100644 --- a/dnstp/src/message/answer/tests.rs +++ b/dnstp/src/message/answer/tests.rs @@ -6,7 +6,8 @@ use super::*; #[ignore] fn one_answer_back_and_forth() { let q = DNSAnswer { - name: "google.com".to_string(), + // name_offset: "google.com".to_string(), + name_offset: 12, answer_type: QType::A, class: QClass::Internet, ttl: 0, @@ -19,7 +20,7 @@ fn one_answer_back_and_forth() { let (q_read, q_reconstructed) = answers_from_bytes(q_bytes, 0).unwrap(); - assert_eq!(q.name, q_reconstructed[0].name); + assert_eq!(q.name_offset, q_reconstructed[0].name_offset); assert_eq!(q.answer_type, q_reconstructed[0].answer_type); assert_eq!(q.class, q_reconstructed[0].class); assert_eq!(q.ttl, q_reconstructed[0].ttl); diff --git a/dnstp/src/message/question/mod.rs b/dnstp/src/message/question/mod.rs index a261295..d5d01a3 100644 --- a/dnstp/src/message/question/mod.rs +++ b/dnstp/src/message/question/mod.rs @@ -2,8 +2,10 @@ mod tests; use urlencoding::decode; +use crate::byte::{two_byte_extraction, two_byte_split}; use crate::string::encode_domain_name; +#[repr(u16)] #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Copy, Clone)] pub enum QType { A = 1, @@ -21,29 +23,30 @@ pub enum QType { SRV = 33 } -impl TryFrom for QType { - type Error = u8; +impl TryFrom for QType { + type Error = u16; - fn try_from(v: u8) -> Result { + fn try_from(v: u16) -> Result { match v { - x if x == QType::A as u8 => Ok(QType::A), - x if x == QType::NS as u8 => Ok(QType::NS), - x if x == QType::CNAME as u8 => Ok(QType::CNAME), - x if x == QType::SOA as u8 => Ok(QType::SOA), - x if x == QType::WKS as u8 => Ok(QType::WKS), - x if x == QType::PTR as u8 => Ok(QType::PTR), - x if x == QType::HINFO as u8 => Ok(QType::HINFO), - x if x == QType::MINFO as u8 => Ok(QType::MINFO), - x if x == QType::MX as u8 => Ok(QType::MX), - x if x == QType::TXT as u8 => Ok(QType::TXT), - x if x == QType::RP as u8 => Ok(QType::RP), - x if x == QType::AAAA as u8 => Ok(QType::AAAA), - x if x == QType::SRV as u8 => Ok(QType::SRV), + x if x == QType::A as u16 => Ok(QType::A), + x if x == QType::NS as u16 => Ok(QType::NS), + x if x == QType::CNAME as u16 => Ok(QType::CNAME), + x if x == QType::SOA as u16 => Ok(QType::SOA), + x if x == QType::WKS as u16 => Ok(QType::WKS), + x if x == QType::PTR as u16 => Ok(QType::PTR), + x if x == QType::HINFO as u16 => Ok(QType::HINFO), + x if x == QType::MINFO as u16 => Ok(QType::MINFO), + x if x == QType::MX as u16 => Ok(QType::MX), + x if x == QType::TXT as u16 => Ok(QType::TXT), + x if x == QType::RP as u16 => Ok(QType::RP), + x if x == QType::AAAA as u16 => Ok(QType::AAAA), + x if x == QType::SRV as u16 => Ok(QType::SRV), _ => Err(v), } } } +#[repr(u16)] #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Copy, Clone)] pub enum QClass { Internet = 1, @@ -51,14 +54,14 @@ pub enum QClass { Hesiod = 4, } -impl TryFrom for QClass { - type Error = u8; +impl TryFrom for QClass { + type Error = u16; - fn try_from(v: u8) -> Result { + fn try_from(v: u16) -> Result { match v { - x if x == QClass::Internet as u8 => Ok(QClass::Internet), - x if x == QClass::Chaos as u8 => Ok(QClass::Chaos), - x if x == QClass::Hesiod as u8 => Ok(QClass::Hesiod), + x if x == QClass::Internet as u16 => Ok(QClass::Internet), + x if x == QClass::Chaos as u16 => Ok(QClass::Chaos), + x if x == QClass::Hesiod as u16 => Ok(QClass::Hesiod), _ => Err(v), } } @@ -85,8 +88,15 @@ impl DNSQuestion { { let mut ret = encode_domain_name(&self.qname); - ret.push(self.qtype as u8); - ret.push(self.qclass as u8); + let (qtype_1, qtype_2) = two_byte_split(self.qtype as u16); + + ret.push(qtype_1); + ret.push(qtype_2); + + let (qclass_1, qclass_2) = two_byte_split(self.qclass as u16); + + ret.push(qclass_1); + ret.push(qclass_2); ret } @@ -107,8 +117,8 @@ pub fn questions_to_bytes(questions: &Vec) -> Vec #[derive(Ord, PartialOrd, Eq, PartialEq, Debug)] pub enum QuestionParseError { ShortLength(usize), - QTypeParse(u8), - QClassParse(u8) + QTypeParse(u16), + QClassParse(u16) } pub fn questions_from_bytes(bytes: Vec, total_questions: u16) -> Result<(i32, Vec), QuestionParseError> @@ -123,7 +133,8 @@ pub fn questions_from_bytes(bytes: Vec, total_questions: u16) -> Result<(i32 let mut current_length: Option = None; let mut remaining_length: u8 = 0; - let mut current_qtype: Option = None; + let mut current_qtype: (Option, Option) = (None, None); + let mut current_qclass: (Option, Option) = (None, None); let mut trailers_reached = false; let mut byte_counter = 0; @@ -137,7 +148,7 @@ pub fn questions_from_bytes(bytes: Vec, total_questions: u16) -> Result<(i32 current_query.clear(); } Some(_) => { - if byte == 0 { + if byte == 0 && !trailers_reached { trailers_reached = true; continue } @@ -148,12 +159,19 @@ pub fn questions_from_bytes(bytes: Vec, total_questions: u16) -> Result<(i32 remaining_length = byte; } else if trailers_reached { // trailer fields - match current_qtype { - None => { - current_qtype = Some(byte); + match (current_qtype, current_qclass) { + ((None, _), (_, _)) => { + current_qtype.0 = Some(byte); + }, + ((_, None), (_, _)) => { + current_qtype.1 = Some(byte); + }, + ((_, _), (None, _)) => { + current_qclass.0 = Some(byte); } - Some(qtype_b) => { - match (qtype_b.try_into(), byte.try_into()) { + ((Some(qtype_1), Some(qtype_2)), (Some(qclass_1), None)) => { + match (two_byte_extraction(&[qtype_1, qtype_2], 0).try_into(), + two_byte_extraction(&[qclass_1, byte], 0).try_into()) { (Ok(qtype), Ok(qclass)) => { questions.push(DNSQuestion { qname: decode(String::from_utf8(current_query.clone()).unwrap().as_str()).unwrap().to_string(), @@ -168,7 +186,8 @@ pub fn questions_from_bytes(bytes: Vec, total_questions: u16) -> Result<(i32 current_length = None; remaining_length = byte; current_query.clear(); - current_qtype = None; + current_qtype = (None, None); + current_qclass = (None, None); trailers_reached = false; } (Err(qtype_e), _) => { @@ -179,6 +198,7 @@ pub fn questions_from_bytes(bytes: Vec, total_questions: u16) -> Result<(i32 } } } + _ => {} } } else { diff --git a/dnstp/src/message/request.rs b/dnstp/src/message/request.rs index 128ccbf..d14d3ea 100644 --- a/dnstp/src/message/request.rs +++ b/dnstp/src/message/request.rs @@ -6,6 +6,7 @@ use crate::message::question::{DNSQuestion, questions_to_bytes}; pub struct DNSRequest { pub header: DNSHeader, pub questions: Vec, + pub additional_records: Vec, pub peer: SocketAddr } diff --git a/dnstp/src/processor/request.rs b/dnstp/src/processor/request.rs index f7a1ae1..6ee45b8 100644 --- a/dnstp/src/processor/request.rs +++ b/dnstp/src/processor/request.rs @@ -1,9 +1,9 @@ -use std::net::{IpAddr, Ipv4Addr}; +use std::net::Ipv4Addr; use std::sync::mpsc; use std::sync::mpsc::{Receiver, Sender}; use std::thread; use log::{error, info}; -use crate::message::answer::{DNSAnswer, IpRData, RawRData}; +use crate::message::answer::{DNSAnswer, ARdata}; use crate::message::header::{Direction, ResponseCode}; use crate::message::question::QuestionParseError; use crate::message::response::DNSResponse; @@ -43,11 +43,18 @@ impl RequestProcesor { peer: r.peer }; - // response.answers = r.questions.iter().map(|x| DNSAnswer::from_query(x, Box::from(IpRData::from(Ipv4Addr::from([127, 0, 0, 1]))), None)).collect(); + response.answers = r.questions + .iter() + .map(|x| + DNSAnswer::from_query(x, + 12, + Box::from(ARdata::from(Ipv4Addr::from([127, 0, 0, 1]))), + None)) + .collect(); response.header.direction = Direction::Response; - response.header.response = ResponseCode::NameError; - response.header.answer_record_count = 0; + response.header.response = ResponseCode::NoError; + response.header.answer_record_count = 1; response.header.authority_record_count = 0; response.header.additional_record_count = 0; diff --git a/dnstp/src/processor/response.rs b/dnstp/src/processor/response.rs index 991b18e..6e0f701 100644 --- a/dnstp/src/processor/response.rs +++ b/dnstp/src/processor/response.rs @@ -27,8 +27,6 @@ impl ResponseProcesor { { info!("processing: {}", str::from_utf8(&(*(*m).buffer)).unwrap()); - // (*(*m).buffer).reverse(); - // match sending_channel.send(m) { // Ok(_) => {} // Err(_) => {} diff --git a/dnstp/src/request_parser.rs b/dnstp/src/request_parser.rs index 0b4609c..0bc1aa1 100644 --- a/dnstp/src/request_parser.rs +++ b/dnstp/src/request_parser.rs @@ -90,14 +90,27 @@ pub fn parse_request(msg: NetworkMessage) -> Result { let mut trimmed = msg.buffer.to_vec(); trimmed.drain(0 .. 12); + let buffer_size = trimmed.len(); match questions_from_bytes(trimmed, header.question_count) { Ok((bytes_read, questions)) => { - Ok(DNSRequest { - header, - questions, - peer: msg.peer - }) + + if buffer_size > bytes_read as usize { + Ok(DNSRequest { + header, + questions, + peer: msg.peer, + additional_records: vec![] + }) + } + else { + Ok(DNSRequest { + header, + questions, + peer: msg.peer, + additional_records: vec![] + }) + } } Err(e) => Err(QuesionsParse(e)) }