From 0ae64f674cd8ba55fa20993f807690cd32192dd9 Mon Sep 17 00:00:00 2001 From: Andy Pack Date: Fri, 2 Feb 2024 20:21:57 +0000 Subject: [PATCH] adding rdata trait, tightening question parsing --- dnstp/src/message/answer/ip_address.rs | 30 ++ .../src/message/{answer.rs => answer/mod.rs} | 47 ++- dnstp/src/message/answer/raw_rdata.rs | 29 ++ dnstp/src/message/answer/tests.rs | 27 ++ dnstp/src/message/header.rs | 2 +- dnstp/src/message/question.rs | 291 ------------------ dnstp/src/message/question/mod.rs | 193 ++++++++++++ dnstp/src/message/question/tests.rs | 91 ++++++ dnstp/src/message/request.rs | 2 +- dnstp/src/message/response.rs | 2 +- dnstp/src/processor/request.rs | 37 ++- dnstp/src/request_parser.rs | 2 +- 12 files changed, 448 insertions(+), 305 deletions(-) create mode 100644 dnstp/src/message/answer/ip_address.rs rename dnstp/src/message/{answer.rs => answer/mod.rs} (54%) create mode 100644 dnstp/src/message/answer/raw_rdata.rs create mode 100644 dnstp/src/message/answer/tests.rs delete mode 100644 dnstp/src/message/question.rs create mode 100644 dnstp/src/message/question/mod.rs create mode 100644 dnstp/src/message/question/tests.rs diff --git a/dnstp/src/message/answer/ip_address.rs b/dnstp/src/message/answer/ip_address.rs new file mode 100644 index 0000000..7510e2b --- /dev/null +++ b/dnstp/src/message/answer/ip_address.rs @@ -0,0 +1,30 @@ +use std::fmt::{Debug, Formatter}; +use std::net::{IpAddr, Ipv4Addr}; +use crate::message::answer::RData; + +pub struct IpRData { + pub rdata: Ipv4Addr +} + +impl Debug for IpRData { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("IP") + .field("data", &self.rdata) + .finish() + } +} + +impl RData for IpRData { + fn to_bytes(&self) -> Vec { + return self.rdata.octets().to_vec(); + } +} + +impl IpRData { + pub fn from(rdata: Ipv4Addr) -> IpRData + { + IpRData { + rdata + } + } +} \ No newline at end of file diff --git a/dnstp/src/message/answer.rs b/dnstp/src/message/answer/mod.rs similarity index 54% rename from dnstp/src/message/answer.rs rename to dnstp/src/message/answer/mod.rs index 2a852c7..aa3123a 100644 --- a/dnstp/src/message/answer.rs +++ b/dnstp/src/message/answer/mod.rs @@ -1,15 +1,30 @@ +mod raw_rdata; +pub use raw_rdata::RawRData; + +mod ip_address; +pub use ip_address::IpRData; + +#[cfg(test)] +mod tests; + +use std::fmt::{Debug, Display}; use crate::byte::{four_byte_split, two_byte_split}; -use crate::message::question::{DNSQuestion, QClass, QType}; +use crate::message::question::{DNSQuestion, QClass, QType, QuestionParseError}; use crate::string::encode_domain_name; -#[derive(Ord, PartialOrd, Eq, PartialEq, Debug)] + +pub trait RData: Debug { + fn to_bytes(&self) -> Vec; +} + +#[derive(Debug)] pub struct DNSAnswer { pub name: String, pub answer_type: QType, pub class: QClass, pub ttl: u32, pub rd_length: u16, - pub r_data: Vec + pub r_data: Box } impl DNSAnswer { @@ -36,10 +51,22 @@ impl DNSAnswer { ret.push(rd_length_split.0); ret.push(rd_length_split.1); - ret.append(&mut self.r_data.clone()); + ret.append(&mut self.r_data.to_bytes()); return ret } + + pub fn from_query(query: &DNSQuestion, data: Box, ttl: Option) -> DNSAnswer + { + DNSAnswer { + name: query.qname.clone(), + answer_type: query.qtype, + class: query.qclass, + ttl: ttl.unwrap_or(0), + rd_length: data.to_bytes().len() as u16, + r_data: data + } + } } pub fn answers_to_bytes(answers: &Vec) -> Vec @@ -52,4 +79,16 @@ pub fn answers_to_bytes(answers: &Vec) -> Vec } ret +} + +#[derive(Ord, PartialOrd, Eq, PartialEq, Debug)] +pub enum AnswerParseError { + ShortLength(usize), + QTypeParse(u8), + QClassParse(u8) +} + +pub fn answers_from_bytes(bytes: Vec, total_answers: u16) -> Result<(i32, Vec), AnswerParseError> +{ + Ok((0, vec![])) } \ No newline at end of file diff --git a/dnstp/src/message/answer/raw_rdata.rs b/dnstp/src/message/answer/raw_rdata.rs new file mode 100644 index 0000000..6018291 --- /dev/null +++ b/dnstp/src/message/answer/raw_rdata.rs @@ -0,0 +1,29 @@ +use std::fmt::{Debug, Formatter}; +use crate::message::answer::RData; + +pub struct RawRData { + pub rdata: Vec +} + +impl Debug for RawRData { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("RawRData") + .field("data", &self.rdata) + .finish() + } +} + +impl RData for RawRData { + fn to_bytes(&self) -> Vec { + return self.rdata.clone(); + } +} + +impl RawRData { + pub fn from(rdata: Vec) -> RawRData + { + RawRData { + rdata + } + } +} \ No newline at end of file diff --git a/dnstp/src/message/answer/tests.rs b/dnstp/src/message/answer/tests.rs new file mode 100644 index 0000000..564e8ff --- /dev/null +++ b/dnstp/src/message/answer/tests.rs @@ -0,0 +1,27 @@ +use crate::message::question::{DNSQuestion, QClass, QType, questions_from_bytes}; + +use super::*; + +#[test] +#[ignore] +fn one_answer_back_and_forth() { + let q = DNSAnswer { + name: "google.com".to_string(), + answer_type: QType::A, + class: QClass::Internet, + ttl: 0, + rd_length: 0, + r_data: Box::from(RawRData::from(vec![])) + }; + + let mut q_bytes = q.to_bytes(); + q_bytes.append(&mut vec![0, 0, 0, 0, 0, 0]); + + let (q_read, q_reconstructed) = answers_from_bytes(q_bytes, 0).unwrap(); + + assert_eq!(q.name, q_reconstructed[0].name); + 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); + assert_eq!(q.rd_length, q_reconstructed[0].rd_length); +} \ No newline at end of file diff --git a/dnstp/src/message/header.rs b/dnstp/src/message/header.rs index 85baa35..ac8d6c8 100644 --- a/dnstp/src/message/header.rs +++ b/dnstp/src/message/header.rs @@ -73,7 +73,7 @@ impl TryFrom for ResponseCode { } /// Represents a header including flag fields and record counts -#[derive(Ord, PartialOrd, Eq, PartialEq, Debug)] +#[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Clone)] pub struct DNSHeader { /// Random ID for associating responses with requests pub id: u16, diff --git a/dnstp/src/message/question.rs b/dnstp/src/message/question.rs deleted file mode 100644 index 85a0ccf..0000000 --- a/dnstp/src/message/question.rs +++ /dev/null @@ -1,291 +0,0 @@ -use std::ops::Sub; -use urlencoding::{encode, decode}; -use crate::string::encode_domain_name; - -#[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Copy, Clone)] -pub enum QType { - A = 1, - NS = 2, - CNAME = 5, - SOA = 6, - WKS = 11, - PTR = 12, - HINFO = 13, - MINFO = 14, - MX = 15, - TXT = 16, - RP = 17, - AAAA = 28, - SRV = 33 -} - -impl TryFrom for QType { - type Error = u8; - - fn try_from(v: u8) -> 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), - _ => Err(v), - } - } -} - -#[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Copy, Clone)] -pub enum QClass { - Internet = 1, - Chaos = 3, - Hesiod = 4, -} - -impl TryFrom for QClass { - type Error = u8; - - fn try_from(v: u8) -> 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), - _ => Err(v), - } - } -} - -#[derive(Ord, PartialOrd, Eq, PartialEq, Debug)] -pub struct DNSQuestion { - pub qname: String, - pub qtype: QType, - pub qclass: QClass -} - -impl DNSQuestion { - pub fn new(qname: String, qtype: QType, qclass: QClass) -> DNSQuestion - { - DNSQuestion { - qname, - qtype, - qclass - } - } - - pub fn to_bytes(&self) -> Vec - { - let mut ret = encode_domain_name(&self.qname); - - ret.push(self.qtype as u8); - ret.push(self.qclass as u8); - - ret - } -} - -pub fn questions_to_bytes(questions: &Vec) -> Vec -{ - let mut ret = Vec::with_capacity(20); - - for q in questions - { - ret.append(&mut q.to_bytes()); - } - - ret -} - -#[derive(Ord, PartialOrd, Eq, PartialEq, Debug)] -pub enum QuestionParseError { - ShortLength(usize), - QTypeParse(u8), - QClassParse(u8) -} - -pub fn questions_from_bytes(bytes: Vec, total_questions: u16) -> Result, QuestionParseError> -{ - if bytes.len() < 4 - { - return Err(QuestionParseError::ShortLength(bytes.len())); - } - - let mut questions: Vec = Vec::with_capacity(total_questions as usize); - let mut current_query: Option> = None; - - let mut current_length: Option = None; - let mut remaining_length: Box = Box::from(0); - let mut current_qtype: Option = None; - let mut current_qclass: Option = None; - let mut trailers_reached = false; - // let mut finished = false; - - for byte in bytes { - if questions.len() != total_questions as usize { - match current_length { - None => { // next question, init lengths - current_length = Some(byte); - remaining_length = Box::from(byte); - current_query = Some(Vec::with_capacity(10)); - } - Some(_) => { - if byte == 0 { - trailers_reached = true; - continue - } - - if *remaining_length == 0 && !trailers_reached { - current_query.as_mut().unwrap().push('.' as u8); - current_length = Some(byte); - remaining_length = Box::from(byte); - } - else if trailers_reached { // trailer fields - match current_qtype { - None => { - current_qtype = Some(byte); - } - Some(qtype_b) => { - match current_qclass { - None => { - // current_qclass = Some(byte); - match (qtype_b.try_into(), byte.try_into()) { - (Ok(qtype), Ok(qclass)) => { - questions.push(DNSQuestion { - qname: decode(String::from_utf8(current_query.unwrap()).unwrap().as_str()).unwrap().to_string(), - qtype, - qclass - }); - - current_length = None; - remaining_length = Box::from(byte); - current_query = None; - current_qtype = None; - current_qclass = None; - trailers_reached = false; - } - (Err(qtype_e), _) => { - return Err(QuestionParseError::QTypeParse(qtype_e)); - } - (_, Err(qclass_e)) => { - return Err(QuestionParseError::QClassParse(qclass_e)); - } - } - } - Some(_) => { - - } - } - } - } - } else { - current_query.as_mut().unwrap().push(byte); - *remaining_length = remaining_length.sub(1); - } - } - } - } - } - - Ok(questions) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn one_question_back_and_forth() { - let q = DNSQuestion { - qname: "google.com".to_string(), - qclass: QClass::Internet, - qtype: QType::A - }; - - let mut q_bytes = q.to_bytes(); - q_bytes.append(&mut vec![0, 0, 0, 0, 0, 0]); - - let q_reconstructed = questions_from_bytes(q_bytes, 1).unwrap(); - - assert_eq!(q.qname, q_reconstructed[0].qname); - assert_eq!(q.qclass, q_reconstructed[0].qclass); - assert_eq!(q.qtype, q_reconstructed[0].qtype); - } - - #[test] - fn two_questions_back_and_forth() { - let q = DNSQuestion { - qname: "google.com".to_string(), - qclass: QClass::Internet, - qtype: QType::A - }; - - let q2 = DNSQuestion { - qname: "duck.com".to_string(), - qclass: QClass::Internet, - qtype: QType::AAAA - }; - - let mut q_bytes = q.to_bytes(); - let mut q2_bytes = q2.to_bytes(); - - q_bytes.append(&mut q2_bytes); - - let q_reconstructed = questions_from_bytes(q_bytes, 2).unwrap(); - - assert_eq!(q.qname, q_reconstructed[0].qname); - assert_eq!(q.qclass, q_reconstructed[0].qclass); - assert_eq!(q.qtype, q_reconstructed[0].qtype); - - assert_eq!(q2.qname, q_reconstructed[1].qname); - assert_eq!(q2.qclass, q_reconstructed[1].qclass); - assert_eq!(q2.qtype, q_reconstructed[1].qtype); - } - - #[test] - fn three_questions_back_and_forth() { - let q = DNSQuestion { - qname: "google.com".to_string(), - qclass: QClass::Internet, - qtype: QType::A - }; - - let q2 = DNSQuestion { - qname: "duck.com".to_string(), - qclass: QClass::Internet, - qtype: QType::AAAA - }; - - let q3 = DNSQuestion { - qname: "facebook.com".to_string(), - qclass: QClass::Hesiod, - qtype: QType::CNAME - }; - - let mut q_bytes = q.to_bytes(); - let mut q2_bytes = q2.to_bytes(); - let mut q3_bytes = q3.to_bytes(); - - q_bytes.append(&mut q2_bytes); - q_bytes.append(&mut q3_bytes); - - let q_reconstructed = questions_from_bytes(q_bytes, 3).unwrap(); - - assert_eq!(q.qname, q_reconstructed[0].qname); - assert_eq!(q.qclass, q_reconstructed[0].qclass); - assert_eq!(q.qtype, q_reconstructed[0].qtype); - - assert_eq!(q2.qname, q_reconstructed[1].qname); - assert_eq!(q2.qclass, q_reconstructed[1].qclass); - assert_eq!(q2.qtype, q_reconstructed[1].qtype); - - assert_eq!(q3.qname, q_reconstructed[2].qname); - assert_eq!(q3.qclass, q_reconstructed[2].qclass); - assert_eq!(q3.qtype, q_reconstructed[2].qtype); - } -} \ No newline at end of file diff --git a/dnstp/src/message/question/mod.rs b/dnstp/src/message/question/mod.rs new file mode 100644 index 0000000..a261295 --- /dev/null +++ b/dnstp/src/message/question/mod.rs @@ -0,0 +1,193 @@ +#[cfg(test)] +mod tests; + +use urlencoding::decode; +use crate::string::encode_domain_name; + +#[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Copy, Clone)] +pub enum QType { + A = 1, + NS = 2, + CNAME = 5, + SOA = 6, + WKS = 11, + PTR = 12, + HINFO = 13, + MINFO = 14, + MX = 15, + TXT = 16, + RP = 17, + AAAA = 28, + SRV = 33 +} + +impl TryFrom for QType { + type Error = u8; + + fn try_from(v: u8) -> 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), + _ => Err(v), + } + } +} + +#[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Copy, Clone)] +pub enum QClass { + Internet = 1, + Chaos = 3, + Hesiod = 4, +} + +impl TryFrom for QClass { + type Error = u8; + + fn try_from(v: u8) -> 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), + _ => Err(v), + } + } +} + +#[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Clone)] +pub struct DNSQuestion { + pub qname: String, + pub qtype: QType, + pub qclass: QClass +} + +impl DNSQuestion { + pub fn new(qname: String, qtype: QType, qclass: QClass) -> DNSQuestion + { + DNSQuestion { + qname, + qtype, + qclass + } + } + + pub fn to_bytes(&self) -> Vec + { + let mut ret = encode_domain_name(&self.qname); + + ret.push(self.qtype as u8); + ret.push(self.qclass as u8); + + ret + } +} + +pub fn questions_to_bytes(questions: &Vec) -> Vec +{ + let mut ret = Vec::with_capacity(20); + + for q in questions + { + ret.append(&mut q.to_bytes()); + } + + ret +} + +#[derive(Ord, PartialOrd, Eq, PartialEq, Debug)] +pub enum QuestionParseError { + ShortLength(usize), + QTypeParse(u8), + QClassParse(u8) +} + +pub fn questions_from_bytes(bytes: Vec, total_questions: u16) -> Result<(i32, Vec), QuestionParseError> +{ + if bytes.len() < 4 + { + return Err(QuestionParseError::ShortLength(bytes.len())); + } + + let mut questions: Vec = Vec::with_capacity(total_questions as usize); + let mut current_query: Vec = Vec::with_capacity(10); + + let mut current_length: Option = None; + let mut remaining_length: u8 = 0; + let mut current_qtype: Option = None; + let mut trailers_reached = false; + + let mut byte_counter = 0; + + for byte in bytes { + byte_counter += 1; + match current_length { + None => { // next question, init lengths + current_length = Some(byte); + remaining_length = byte; + current_query.clear(); + } + Some(_) => { + if byte == 0 { + trailers_reached = true; + continue + } + + if remaining_length == 0 && !trailers_reached { + current_query.push('.' as u8); + current_length = Some(byte); + remaining_length = byte; + } + else if trailers_reached { // trailer fields + match current_qtype { + None => { + current_qtype = Some(byte); + } + Some(qtype_b) => { + match (qtype_b.try_into(), byte.try_into()) { + (Ok(qtype), Ok(qclass)) => { + questions.push(DNSQuestion { + qname: decode(String::from_utf8(current_query.clone()).unwrap().as_str()).unwrap().to_string(), + qtype, + qclass + }); + + if questions.len() == total_questions as usize { + break + } + + current_length = None; + remaining_length = byte; + current_query.clear(); + current_qtype = None; + trailers_reached = false; + } + (Err(qtype_e), _) => { + return Err(QuestionParseError::QTypeParse(qtype_e)); + } + (_, Err(qclass_e)) => { + return Err(QuestionParseError::QClassParse(qclass_e)); + } + } + } + } + } + else { + current_query.push(byte); + remaining_length -= 1; + } + } + } + } + + Ok((byte_counter, questions)) +} \ No newline at end of file diff --git a/dnstp/src/message/question/tests.rs b/dnstp/src/message/question/tests.rs new file mode 100644 index 0000000..424c46e --- /dev/null +++ b/dnstp/src/message/question/tests.rs @@ -0,0 +1,91 @@ +use super::*; + +#[test] +fn one_question_back_and_forth() { + let q = DNSQuestion { + qname: "google.com".to_string(), + qclass: QClass::Internet, + qtype: QType::A + }; + + let mut q_bytes = q.to_bytes(); + q_bytes.append(&mut vec![0, 0, 0, 0, 0, 0]); + + let (q_read, q_reconstructed) = questions_from_bytes(q_bytes, 1).unwrap(); + + assert_eq!(q.qname, q_reconstructed[0].qname); + assert_eq!(q.qclass, q_reconstructed[0].qclass); + assert_eq!(q.qtype, q_reconstructed[0].qtype); +} + +#[test] +fn two_questions_back_and_forth() { + let q = DNSQuestion { + qname: "google.com".to_string(), + qclass: QClass::Internet, + qtype: QType::A + }; + + let q2 = DNSQuestion { + qname: "duck.com".to_string(), + qclass: QClass::Internet, + qtype: QType::AAAA + }; + + let mut q_bytes = q.to_bytes(); + let mut q2_bytes = q2.to_bytes(); + + q_bytes.append(&mut q2_bytes); + + let (q_read, q_reconstructed) = questions_from_bytes(q_bytes, 2).unwrap(); + + assert_eq!(q.qname, q_reconstructed[0].qname); + assert_eq!(q.qclass, q_reconstructed[0].qclass); + assert_eq!(q.qtype, q_reconstructed[0].qtype); + + assert_eq!(q2.qname, q_reconstructed[1].qname); + assert_eq!(q2.qclass, q_reconstructed[1].qclass); + assert_eq!(q2.qtype, q_reconstructed[1].qtype); +} + +#[test] +fn three_questions_back_and_forth() { + let q = DNSQuestion { + qname: "google.com".to_string(), + qclass: QClass::Internet, + qtype: QType::A + }; + + let q2 = DNSQuestion { + qname: "duck.com".to_string(), + qclass: QClass::Internet, + qtype: QType::AAAA + }; + + let q3 = DNSQuestion { + qname: "facebook.com".to_string(), + qclass: QClass::Hesiod, + qtype: QType::CNAME + }; + + let mut q_bytes = q.to_bytes(); + let mut q2_bytes = q2.to_bytes(); + let mut q3_bytes = q3.to_bytes(); + + q_bytes.append(&mut q2_bytes); + q_bytes.append(&mut q3_bytes); + + let (q_read, q_reconstructed) = questions_from_bytes(q_bytes, 3).unwrap(); + + assert_eq!(q.qname, q_reconstructed[0].qname); + assert_eq!(q.qclass, q_reconstructed[0].qclass); + assert_eq!(q.qtype, q_reconstructed[0].qtype); + + assert_eq!(q2.qname, q_reconstructed[1].qname); + assert_eq!(q2.qclass, q_reconstructed[1].qclass); + assert_eq!(q2.qtype, q_reconstructed[1].qtype); + + assert_eq!(q3.qname, q_reconstructed[2].qname); + assert_eq!(q3.qclass, q_reconstructed[2].qclass); + assert_eq!(q3.qtype, q_reconstructed[2].qtype); +} \ No newline at end of file diff --git a/dnstp/src/message/request.rs b/dnstp/src/message/request.rs index cf89344..128ccbf 100644 --- a/dnstp/src/message/request.rs +++ b/dnstp/src/message/request.rs @@ -2,7 +2,7 @@ use std::net::SocketAddr; use crate::message::header::DNSHeader; use crate::message::question::{DNSQuestion, questions_to_bytes}; -#[derive(Ord, PartialOrd, Eq, PartialEq, Debug)] +#[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Clone)] pub struct DNSRequest { pub header: DNSHeader, pub questions: Vec, diff --git a/dnstp/src/message/response.rs b/dnstp/src/message/response.rs index 79c2454..734307e 100644 --- a/dnstp/src/message/response.rs +++ b/dnstp/src/message/response.rs @@ -3,7 +3,7 @@ use crate::message::answer::{answers_to_bytes, DNSAnswer}; use crate::message::header::DNSHeader; use crate::message::question::{DNSQuestion, questions_to_bytes}; -#[derive(Ord, PartialOrd, Eq, PartialEq, Debug)] +#[derive(Debug)] pub struct DNSResponse { pub header: DNSHeader, pub questions: Vec, diff --git a/dnstp/src/processor/request.rs b/dnstp/src/processor/request.rs index 2824b18..f7a1ae1 100644 --- a/dnstp/src/processor/request.rs +++ b/dnstp/src/processor/request.rs @@ -1,9 +1,13 @@ +use std::net::{IpAddr, 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::header::{Direction, ResponseCode}; use crate::message::question::QuestionParseError; -use crate::net::raw_request::NetworkMessagePtr; +use crate::message::response::DNSResponse; +use crate::net::raw_request::{NetworkMessage, NetworkMessagePtr}; use crate::request_parser::{HeaderParseError, parse_request, RequestParseError}; pub struct RequestProcesor { @@ -31,6 +35,32 @@ impl RequestProcesor { match parse_request(*m) { Ok(r) => { info!("received dns message: {:?}", r); + + let mut response = DNSResponse{ + header: r.header.clone(), + questions: r.questions.clone(), + answers: vec![], + 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.header.direction = Direction::Response; + response.header.response = ResponseCode::NameError; + response.header.answer_record_count = 0; + response.header.authority_record_count = 0; + response.header.additional_record_count = 0; + + if response.header.recursion_desired { + response.header.recursion_available = true; + } + + sending_channel.send(Box::from( + NetworkMessage { + buffer: Box::from(response.to_bytes()), + peer: response.peer + } + )); } Err(e) => { match e { @@ -60,11 +90,6 @@ impl RequestProcesor { } } } - - // match sending_channel.send(m) { - // Ok(_) => {} - // Err(_) => {} - // } } info!("message processing thread finishing") diff --git a/dnstp/src/request_parser.rs b/dnstp/src/request_parser.rs index bd4490f..0b4609c 100644 --- a/dnstp/src/request_parser.rs +++ b/dnstp/src/request_parser.rs @@ -92,7 +92,7 @@ pub fn parse_request(msg: NetworkMessage) -> Result { + Ok((bytes_read, questions)) => { Ok(DNSRequest { header, questions,