diff --git a/.gitignore b/.gitignore index ea8c4bf..0592392 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +.DS_Store diff --git a/src/main.rs b/src/main.rs index abb751a..3f1896c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,11 @@ use std::net::UdpSocket; use std::sync::mpsc; use std::thread::{self, JoinHandle}; +use hexhex::print_hex; +use crate::proto::{UdpCoder, Coder}; mod proto; -use hexhex::print_hex; -use proto::DNSHeader; +mod models; fn listen() -> ( JoinHandle<()>, @@ -38,8 +39,8 @@ fn main() { for msg in thread_udp_rx.iter() { print_hex(&msg); - let hdr_struct = DNSHeader::from_udp_datagram(&msg).unwrap(); - dbg!(hdr_struct); + let query = UdpCoder::decode(&msg).unwrap(); + dbg!(query); } let _ = thread_udp.join(); diff --git a/src/models/dns_query.rs b/src/models/dns_query.rs deleted file mode 100644 index bdc6390..0000000 --- a/src/models/dns_query.rs +++ /dev/null @@ -1,113 +0,0 @@ -use std::convert::TryInto; - -/// Taken from RFC 6895, 2.2. OpCode Assignment -/// Currently, DNS OpCodes are assigned as follows: -/// OpCode Name Reference -/// -/// 0 Query [RFC1035] -/// 1 IQuery (Inverse Query, OBSOLETE) [RFC3425] -/// 2 Status [RFC1035] -/// 3 Unassigned -/// 4 Notify [RFC1996] -/// 5 Update [RFC2136] -/// 6-15 Unassigned -#[derive(Debug, PartialEq, Copy, Clone)] -pub enum DNSOpCode { - Query = 0, - IQuery = 1, // obsolete - Status = 2, - Notify = 4, - Update = 5, -} - -/// Taken from RFC 6895, 2.3. RCODE Assignment -/// -/// RCODE Name Description Reference -/// -/// 0 NoError No Error [RFC1035] -/// 1 FormErr Format Error [RFC1035] -/// 2 ServFail Server Failure [RFC1035] -/// 3 NXDomain Non-Existent Domain [RFC1035] -/// 4 NotImp Not Implemented [RFC1035] -/// 5 Refused Query Refused [RFC1035] -/// 6 YXDomain Name Exists when it should not [RFC2136] -/// 7 YXRRSet RR Set Exists when it should not [RFC2136] -/// 8 NXRRSet RR Set that should exist does not [RFC2136] -/// 9 NotAuth Server Not Authoritative for zone [RFC2136] -/// 9 NotAuth Not Authorized [RFC2845] -/// 10 NotZone Name not contained in zone [RFC2136] -/// -/// 11 - 15 Unassigned -/// -/// 16 BADVERS Bad OPT Version [RFC6891] -/// 16 BADSIG TSIG Signature Failure [RFC2845] -/// 17 BADKEY Key not recognized [RFC2845] -/// 18 BADTIME Signature out of time window [RFC2845] -/// 19 BADMODE Bad TKEY Mode [RFC2930] -/// 20 BADNAME Duplicate key name [RFC2930] -/// 21 BADALG Algorithm not supported [RFC2930] -/// 22 BADTRUNC Bad Truncation [RFC4635] -/// -/// 23 - 3,840 -/// 0x0017 - 0x0F00 Unassigned -/// -/// 3,841 - 4,095 -/// 0x0F01 - 0x0FFF Reserved for Private Use -/// -/// 4,096 - 65,534 -/// 0x1000 - 0xFFFE Unassigned -/// -/// 65,535 -/// 0xFFFF Reserved; can only be allocated by Standards Action. -#[derive(Debug, PartialEq, Copy, Clone)] -pub enum DNSRCode { - NoError = 0, - FormErr = 1, - ServFail = 2, - NXDomain = 3, - NotImp = 4, - Refused = 5, - YXDomain = 6, - YXRRSet = 7, - NXRRSet = 8, - NotAuth = 9, - NotZone = 10, -} - -#[derive(Debug, Clone, PartialEq)] -pub struct DNSHeader { - /// used by the requester to match up replies to outstanding queries - pub id: u16, - /// specifies whether this message is a query or a response - pub message_type: DNSMessageType, - pub opcode: DNSOpCode, - /// specifies that the responding name server is an authority for the domain name in question section - pub authorative_answer: bool, - /// specifies that this message was truncated due to length greater than that permitted on the transmission channel - pub truncated: bool, - /// it directs the name server to pursue the query recursively - pub recursion_desired: bool, - /// denotes whether recursive query support is available in the name server - pub 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, - pub response_code: DNSRCode, - /// TODO: add documuentation about this count - pub query_count: u16, - /// TODO: add documuentation about this count - pub answer_count: u16, - /// TODO: add documuentation about this count - pub name_server_count: u16, - /// TODO: add documuentation about this count - pub additional_count: u16, -} - -#[derive(Debug, Clone)] -pub struct DNSQuery { - pub hdr: DNSHeader, - pub name: String, - pub qclass: u16, - pub qtype: u16, -} diff --git a/src/models/dns_response.rs b/src/models/dns_response.rs deleted file mode 100644 index bdc6390..0000000 --- a/src/models/dns_response.rs +++ /dev/null @@ -1,113 +0,0 @@ -use std::convert::TryInto; - -/// Taken from RFC 6895, 2.2. OpCode Assignment -/// Currently, DNS OpCodes are assigned as follows: -/// OpCode Name Reference -/// -/// 0 Query [RFC1035] -/// 1 IQuery (Inverse Query, OBSOLETE) [RFC3425] -/// 2 Status [RFC1035] -/// 3 Unassigned -/// 4 Notify [RFC1996] -/// 5 Update [RFC2136] -/// 6-15 Unassigned -#[derive(Debug, PartialEq, Copy, Clone)] -pub enum DNSOpCode { - Query = 0, - IQuery = 1, // obsolete - Status = 2, - Notify = 4, - Update = 5, -} - -/// Taken from RFC 6895, 2.3. RCODE Assignment -/// -/// RCODE Name Description Reference -/// -/// 0 NoError No Error [RFC1035] -/// 1 FormErr Format Error [RFC1035] -/// 2 ServFail Server Failure [RFC1035] -/// 3 NXDomain Non-Existent Domain [RFC1035] -/// 4 NotImp Not Implemented [RFC1035] -/// 5 Refused Query Refused [RFC1035] -/// 6 YXDomain Name Exists when it should not [RFC2136] -/// 7 YXRRSet RR Set Exists when it should not [RFC2136] -/// 8 NXRRSet RR Set that should exist does not [RFC2136] -/// 9 NotAuth Server Not Authoritative for zone [RFC2136] -/// 9 NotAuth Not Authorized [RFC2845] -/// 10 NotZone Name not contained in zone [RFC2136] -/// -/// 11 - 15 Unassigned -/// -/// 16 BADVERS Bad OPT Version [RFC6891] -/// 16 BADSIG TSIG Signature Failure [RFC2845] -/// 17 BADKEY Key not recognized [RFC2845] -/// 18 BADTIME Signature out of time window [RFC2845] -/// 19 BADMODE Bad TKEY Mode [RFC2930] -/// 20 BADNAME Duplicate key name [RFC2930] -/// 21 BADALG Algorithm not supported [RFC2930] -/// 22 BADTRUNC Bad Truncation [RFC4635] -/// -/// 23 - 3,840 -/// 0x0017 - 0x0F00 Unassigned -/// -/// 3,841 - 4,095 -/// 0x0F01 - 0x0FFF Reserved for Private Use -/// -/// 4,096 - 65,534 -/// 0x1000 - 0xFFFE Unassigned -/// -/// 65,535 -/// 0xFFFF Reserved; can only be allocated by Standards Action. -#[derive(Debug, PartialEq, Copy, Clone)] -pub enum DNSRCode { - NoError = 0, - FormErr = 1, - ServFail = 2, - NXDomain = 3, - NotImp = 4, - Refused = 5, - YXDomain = 6, - YXRRSet = 7, - NXRRSet = 8, - NotAuth = 9, - NotZone = 10, -} - -#[derive(Debug, Clone, PartialEq)] -pub struct DNSHeader { - /// used by the requester to match up replies to outstanding queries - pub id: u16, - /// specifies whether this message is a query or a response - pub message_type: DNSMessageType, - pub opcode: DNSOpCode, - /// specifies that the responding name server is an authority for the domain name in question section - pub authorative_answer: bool, - /// specifies that this message was truncated due to length greater than that permitted on the transmission channel - pub truncated: bool, - /// it directs the name server to pursue the query recursively - pub recursion_desired: bool, - /// denotes whether recursive query support is available in the name server - pub 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, - pub response_code: DNSRCode, - /// TODO: add documuentation about this count - pub query_count: u16, - /// TODO: add documuentation about this count - pub answer_count: u16, - /// TODO: add documuentation about this count - pub name_server_count: u16, - /// TODO: add documuentation about this count - pub additional_count: u16, -} - -#[derive(Debug, Clone)] -pub struct DNSQuery { - pub hdr: DNSHeader, - pub name: String, - pub qclass: u16, - pub qtype: u16, -} diff --git a/src/models/mod.rs b/src/models/mod.rs new file mode 100644 index 0000000..b3d4954 --- /dev/null +++ b/src/models/mod.rs @@ -0,0 +1,37 @@ +#[derive(Debug, Clone)] +pub struct DNSQuery { + pub id: u16, + pub questions: Vec, +} + +#[derive(Debug, Clone)] +pub struct DNSResponse { + pub id: u16, + pub questions: Vec, + pub answers: Vec, +} + +#[derive(Debug, Clone)] +pub struct DNSQuestion { + pub name: String, + pub r#type: DNSType, +} + +#[derive(Debug, Clone)] +pub enum DNSType { + HostAddress, + NameServer, + CanonicalName, + StartOfZoneAuthority, + DomainNamePointer, + MailExchange, + TextStrings, +} + +#[derive(Debug, Clone)] +pub struct DNSResourceRecord { + pub name: String, + pub r#type: DNSType, + pub ttl: u32, + pub data: String, +} diff --git a/src/proto/decoder.rs b/src/proto/decoder.rs index dfb7185..ec61bc5 100644 --- a/src/proto/decoder.rs +++ b/src/proto/decoder.rs @@ -1,452 +1,387 @@ -use std::convert::TryInto; +// use crate::models::dns_query::DNSQuery; +// use crate::models::dns_response::DNSResponse; -impl DNSHeader { - 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; +// #[cfg(test)] +// mod tests { - 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; +// mod from_udp_datagram { - const OPCODE_OFFSET: u8 = 3; +// mod header_length { +// use super::super::super::*; - pub fn from_udp_datagram(datagram: &[u8]) -> Result { - if datagram.len() < 12 { - return Err(DNSParseError::DatagramTooShort); - } +// #[test] +// fn too_short() { +// // minimal header with 1 byte missing +// let dns_query = [ +// 0x13, 0x37, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!(parse_result.err().unwrap(), DNSParseError::DatagramTooShort); +// } +// } - let id = u16::from_be_bytes((&datagram[..2]).try_into().unwrap()); +// mod opcode { +// use super::super::super::*; - let message_type = DNSMessageType::from(datagram[2] & Self::QR_MASK != 0); - let opcode = DNSOpCode::try_from((datagram[2] & Self::OPCODE_MASK) >> Self::OPCODE_OFFSET)?; +// #[test] +// fn invalid() { +// let mut dns_query = [ +// 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let invalid_opcodes = [3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; - let authorative_answer = (datagram[2] & Self::AA_MASK) != 0; - let truncated = (datagram[2] & Self::TC_MASK) != 0; - let recursion_desired = (datagram[2] & Self::RD_MASK) != 0; - let recursion_available = (datagram[3] & Self::RA_MASK) != 0; +// for opcode in invalid_opcodes { +// dns_query[2] = opcode << 3; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!( +// parse_result.err(), +// Some(DNSParseError::DNSOpCodeInvalid), +// "query: {:02x?}, opcode: {}", +// dns_query, +// opcode +// ); +// } +// } - // no support for rfc4035 at the moment - //let authentic_data = (datagram[2] & Self::AD_MASK) != 0; - //let checking_disabled = (datagram[2] & Self::CD_MASK) != 0; +// #[test] +// fn valid() -> Result<(), DNSParseError> { +// let mut dns_query = [ +// 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let valid_opcodes = [ +// (0, DNSOpCode::Query), +// (1, DNSOpCode::IQuery), +// (2, DNSOpCode::Status), +// (4, DNSOpCode::Notify), +// (5, DNSOpCode::Update), +// ]; - let response_code = DNSRCode::try_from(datagram[3] & Self::RCODE_MASK)?; - let query_count = u16::from_be_bytes((datagram[4..6]).try_into().unwrap()); - let answer_count = u16::from_be_bytes((datagram[6..8]).try_into().unwrap()); - let name_server_count = u16::from_be_bytes((datagram[8..10]).try_into().unwrap()); - let additional_count = u16::from_be_bytes((datagram[10..12]).try_into().unwrap()); +// for (opcode, parsed_opcode) in valid_opcodes { +// dns_query[2] = opcode << 3; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!( +// parse_result?.opcode, parsed_opcode, +// "query: {:02x?}, opcode: {}", +// dns_query, opcode +// ); +// } +// Ok(()) +// } +// } - Ok(DNSHeader { - 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, - }) - } -} +// mod message_type { +// use super::super::super::*; -#[derive(Debug, Clone, PartialEq)] -pub enum DNSParseError { - DatagramTooShort, - DNSOpCodeInvalid, - DNSRCodeInvalid, -} +// #[test] +// fn query() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!(parse_result?.message_type, DNSMessageType::Query); +// Ok(()) +// } -#[cfg(test)] -mod tests { +// #[test] +// fn response() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!(parse_result?.message_type, DNSMessageType::Response); +// Ok(()) +// } +// } - mod from_udp_datagram { +// mod response_code { +// use super::super::super::*; - mod header_length { - use super::super::super::*; +// #[test] +// fn invalid() { +// let mut dns_query = [ +// 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let invalid_rcodes = [11, 12, 13, 14, 15]; - #[test] - fn too_short() { - // minimal header with 1 byte missing - let dns_query = [ - 0x13, 0x37, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!(parse_result.err().unwrap(), DNSParseError::DatagramTooShort); - } - } +// for rcode in invalid_rcodes { +// dns_query[3] = rcode; - mod opcode { - use super::super::super::*; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); - #[test] - fn invalid() { - let mut dns_query = [ - 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let invalid_opcodes = [3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; +// assert_eq!( +// parse_result, +// Err(DNSParseError::DNSRCodeInvalid), +// "query: {:02x?}, rcode: {}", +// dns_query, +// rcode, +// ); +// } +// } - for opcode in invalid_opcodes { - dns_query[2] = opcode << 3; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!( - parse_result.err(), - Some(DNSParseError::DNSOpCodeInvalid), - "query: {:02x?}, opcode: {}", - dns_query, - opcode - ); - } - } +// #[test] +// fn valid() -> Result<(), DNSParseError> { +// let mut dns_query = [ +// 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; - #[test] - fn valid() -> Result<(), DNSParseError> { - let mut dns_query = [ - 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let valid_opcodes = [ - (0, DNSOpCode::Query), - (1, DNSOpCode::IQuery), - (2, DNSOpCode::Status), - (4, DNSOpCode::Notify), - (5, DNSOpCode::Update), - ]; +// // for now we only support RCodes 0 to 10 (inclusive) +// let valid_rcodes = [ +// (0, DNSRCode::NoError), +// (1, DNSRCode::FormErr), +// (2, DNSRCode::ServFail), +// (3, DNSRCode::NXDomain), +// (4, DNSRCode::NotImp), +// (5, DNSRCode::Refused), +// (6, DNSRCode::YXDomain), +// (7, DNSRCode::YXRRSet), +// (8, DNSRCode::NXRRSet), +// (9, DNSRCode::NotAuth), +// (10, DNSRCode::NotZone), +// ]; - for (opcode, parsed_opcode) in valid_opcodes { - dns_query[2] = opcode << 3; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!( - parse_result?.opcode, parsed_opcode, - "query: {:02x?}, opcode: {}", - dns_query, opcode - ); - } - Ok(()) - } - } +// for (rcode, parsed_rcode) in valid_rcodes { +// dns_query[3] = rcode; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!( +// parse_result?.response_code, parsed_rcode, +// "query: {:02x?}, rcode: {}, parsed_rcode: {:?}", +// dns_query, rcode, parsed_rcode +// ); +// } +// Ok(()) +// } +// } - mod message_type { - use super::super::super::*; +// mod query_count { +// use super::super::super::*; - #[test] - fn query() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!(parse_result?.message_type, DNSMessageType::Query); - Ok(()) - } +// #[test] +// fn zero() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!(parse_result?.query_count, 0); +// Ok(()) +// } - #[test] - fn response() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!(parse_result?.message_type, DNSMessageType::Response); - Ok(()) - } - } +// #[test] +// fn one() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!(parse_result?.query_count, 1); +// Ok(()) +// } - mod response_code { - use super::super::super::*; +// #[test] +// fn max_value() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x80, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!(parse_result?.query_count, 65535); +// Ok(()) +// } +// } - #[test] - fn invalid() { - let mut dns_query = [ - 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let invalid_rcodes = [11, 12, 13, 14, 15]; +// mod answer_count { +// use super::super::super::*; - for rcode in invalid_rcodes { - dns_query[3] = rcode; +// #[test] +// fn zero() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!(parse_result?.answer_count, 0); +// Ok(()) +// } - let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// #[test] +// fn one() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!(parse_result?.answer_count, 1); +// Ok(()) +// } - assert_eq!( - parse_result, - Err(DNSParseError::DNSRCodeInvalid), - "query: {:02x?}, rcode: {}", - dns_query, - rcode, - ); - } - } +// #[test] +// fn max_value() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!(parse_result?.answer_count, 65535); +// Ok(()) +// } +// } - #[test] - fn valid() -> Result<(), DNSParseError> { - let mut dns_query = [ - 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; +// mod name_server_count { +// use super::super::super::*; - // for now we only support RCodes 0 to 10 (inclusive) - let valid_rcodes = [ - (0, DNSRCode::NoError), - (1, DNSRCode::FormErr), - (2, DNSRCode::ServFail), - (3, DNSRCode::NXDomain), - (4, DNSRCode::NotImp), - (5, DNSRCode::Refused), - (6, DNSRCode::YXDomain), - (7, DNSRCode::YXRRSet), - (8, DNSRCode::NXRRSet), - (9, DNSRCode::NotAuth), - (10, DNSRCode::NotZone), - ]; +// #[test] +// fn zero() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!(parse_result?.name_server_count, 0); +// Ok(()) +// } - for (rcode, parsed_rcode) in valid_rcodes { - dns_query[3] = rcode; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!( - parse_result?.response_code, parsed_rcode, - "query: {:02x?}, rcode: {}, parsed_rcode: {:?}", - dns_query, rcode, parsed_rcode - ); - } - Ok(()) - } - } +// #[test] +// fn one() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!(parse_result?.name_server_count, 1); +// Ok(()) +// } - mod query_count { - use super::super::super::*; +// #[test] +// fn max_value() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!(parse_result?.name_server_count, 65535); +// Ok(()) +// } +// } - #[test] - fn zero() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!(parse_result?.query_count, 0); - Ok(()) - } +// mod additional_count { +// use super::super::super::*; - #[test] - fn one() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!(parse_result?.query_count, 1); - Ok(()) - } +// #[test] +// fn zero() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!(parse_result?.additional_count, 0); +// Ok(()) +// } - #[test] - fn max_value() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x80, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!(parse_result?.query_count, 65535); - Ok(()) - } - } +// #[test] +// fn one() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!(parse_result?.additional_count, 1); +// Ok(()) +// } - mod answer_count { - use super::super::super::*; +// #[test] +// fn max_value() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert_eq!(parse_result?.additional_count, 65535); +// Ok(()) +// } +// } - #[test] - fn zero() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!(parse_result?.answer_count, 0); - Ok(()) - } +// mod authorative_answer { +// use super::super::super::*; - #[test] - fn one() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!(parse_result?.answer_count, 1); - Ok(()) - } +// #[test] +// fn yes() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert!(parse_result?.authorative_answer); +// Ok(()) +// } - #[test] - fn max_value() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!(parse_result?.answer_count, 65535); - Ok(()) - } - } +// #[test] +// fn no() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert!(!parse_result?.authorative_answer); +// Ok(()) +// } +// } - mod name_server_count { - use super::super::super::*; +// mod truncated { +// use super::super::super::*; - #[test] - fn zero() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!(parse_result?.name_server_count, 0); - Ok(()) - } +// #[test] +// fn yes() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert!(parse_result?.truncated); +// Ok(()) +// } - #[test] - fn one() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!(parse_result?.name_server_count, 1); - Ok(()) - } +// #[test] +// fn no() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert!(!parse_result?.truncated); +// Ok(()) +// } +// } - #[test] - fn max_value() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!(parse_result?.name_server_count, 65535); - Ok(()) - } - } +// mod recursion_desired { +// use super::super::super::*; - mod additional_count { - use super::super::super::*; +// #[test] +// fn yes() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert!(parse_result?.recursion_desired); +// Ok(()) +// } - #[test] - fn zero() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!(parse_result?.additional_count, 0); - Ok(()) - } +// #[test] +// fn no() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert!(!parse_result?.recursion_desired); +// Ok(()) +// } +// } - #[test] - fn one() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!(parse_result?.additional_count, 1); - Ok(()) - } +// mod recursion_available { +// use super::super::super::*; - #[test] - fn max_value() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert_eq!(parse_result?.additional_count, 65535); - Ok(()) - } - } +// #[test] +// fn yes() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert!(parse_result?.recursion_available); +// Ok(()) +// } - mod authorative_answer { - use super::super::super::*; - - #[test] - fn yes() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert!(parse_result?.authorative_answer); - Ok(()) - } - - #[test] - fn no() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert!(!parse_result?.authorative_answer); - Ok(()) - } - } - - mod truncated { - use super::super::super::*; - - #[test] - fn yes() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert!(parse_result?.truncated); - Ok(()) - } - - #[test] - fn no() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert!(!parse_result?.truncated); - Ok(()) - } - } - - mod recursion_desired { - use super::super::super::*; - - #[test] - fn yes() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert!(parse_result?.recursion_desired); - Ok(()) - } - - #[test] - fn no() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert!(!parse_result?.recursion_desired); - Ok(()) - } - } - - mod recursion_available { - use super::super::super::*; - - #[test] - fn yes() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert!(parse_result?.recursion_available); - Ok(()) - } - - #[test] - fn no() -> Result<(), DNSParseError> { - let dns_query = [ - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - let parse_result = DNSHeader::from_udp_datagram(&dns_query); - assert!(!parse_result?.recursion_available); - Ok(()) - } - } - } -} +// #[test] +// fn no() -> Result<(), DNSParseError> { +// let dns_query = [ +// 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// ]; +// let parse_result = DNSHeader::from_udp_datagram(&dns_query); +// assert!(!parse_result?.recursion_available); +// Ok(()) +// } +// } +// } +// } diff --git a/src/proto/mod.rs b/src/proto/mod.rs new file mode 100644 index 0000000..55b84b5 --- /dev/null +++ b/src/proto/mod.rs @@ -0,0 +1,13 @@ +pub mod udp; +pub mod decoder; + +use crate::models::DNSQuery; +use crate::models::DNSResponse; +use crate::proto::udp::DNSParseError; + +pub use crate::proto::udp::UdpCoder; + +pub trait Coder { + fn decode(datagram: &[u8]) -> Result; + fn encode(respone: DNSResponse) -> Result, DNSParseError>; +} \ No newline at end of file diff --git a/src/proto/udp.rs b/src/proto/udp.rs new file mode 100644 index 0000000..57938a0 --- /dev/null +++ b/src/proto/udp.rs @@ -0,0 +1,165 @@ +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, + }) + } +}