Create module structure #29

Merged
ddidderr merged 1 commits from proto-module into master 2022-06-05 19:05:49 +02:00
8 changed files with 560 additions and 634 deletions
Showing only changes of commit b3af9e9e08 - Show all commits

1
.gitignore vendored
View File

@ -1 +1,2 @@
/target /target
.DS_Store

View File

@ -1,10 +1,11 @@
use std::net::UdpSocket; use std::net::UdpSocket;
use std::sync::mpsc; use std::sync::mpsc;
use std::thread::{self, JoinHandle}; use std::thread::{self, JoinHandle};
use hexhex::print_hex;
use crate::proto::{UdpCoder, Coder};
mod proto; mod proto;
use hexhex::print_hex; mod models;
use proto::DNSHeader;
fn listen() -> ( fn listen() -> (
JoinHandle<()>, JoinHandle<()>,
@ -38,8 +39,8 @@ fn main() {
for msg in thread_udp_rx.iter() { for msg in thread_udp_rx.iter() {
print_hex(&msg); print_hex(&msg);
let hdr_struct = DNSHeader::from_udp_datagram(&msg).unwrap(); let query = UdpCoder::decode(&msg).unwrap();
dbg!(hdr_struct); dbg!(query);
} }
let _ = thread_udp.join(); let _ = thread_udp.join();

View File

@ -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,
}

View File

@ -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,
}

37
src/models/mod.rs Normal file
View File

@ -0,0 +1,37 @@
#[derive(Debug, Clone)]
pub struct DNSQuery {
pub id: u16,
pub questions: Vec<DNSQuestion>,
}
#[derive(Debug, Clone)]
pub struct DNSResponse {
pub id: u16,
pub questions: Vec<DNSQuestion>,
pub answers: Vec<DNSResourceRecord>,
}
#[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,
}

View File

@ -1,452 +1,387 @@
use std::convert::TryInto; // use crate::models::dns_query::DNSQuery;
// use crate::models::dns_response::DNSResponse;
impl DNSHeader { // #[cfg(test)]
const QR_MASK: u8 = 0b10000000; // mod tests {
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; // mod from_udp_datagram {
// 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; // mod header_length {
// use super::super::super::*;
pub fn from_udp_datagram(datagram: &[u8]) -> Result<Self, DNSParseError> { // #[test]
if datagram.len() < 12 { // fn too_short() {
return Err(DNSParseError::DatagramTooShort); // // 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); // #[test]
let opcode = DNSOpCode::try_from((datagram[2] & Self::OPCODE_MASK) >> Self::OPCODE_OFFSET)?; // 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; // for opcode in invalid_opcodes {
let truncated = (datagram[2] & Self::TC_MASK) != 0; // dns_query[2] = opcode << 3;
let recursion_desired = (datagram[2] & Self::RD_MASK) != 0; // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
let recursion_available = (datagram[3] & Self::RA_MASK) != 0; // assert_eq!(
// parse_result.err(),
// Some(DNSParseError::DNSOpCodeInvalid),
// "query: {:02x?}, opcode: {}",
// dns_query,
// opcode
// );
// }
// }
// no support for rfc4035 at the moment // #[test]
//let authentic_data = (datagram[2] & Self::AD_MASK) != 0; // fn valid() -> Result<(), DNSParseError> {
//let checking_disabled = (datagram[2] & Self::CD_MASK) != 0; // 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)?; // for (opcode, parsed_opcode) in valid_opcodes {
let query_count = u16::from_be_bytes((datagram[4..6]).try_into().unwrap()); // dns_query[2] = opcode << 3;
let answer_count = u16::from_be_bytes((datagram[6..8]).try_into().unwrap()); // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
let name_server_count = u16::from_be_bytes((datagram[8..10]).try_into().unwrap()); // assert_eq!(
let additional_count = u16::from_be_bytes((datagram[10..12]).try_into().unwrap()); // parse_result?.opcode, parsed_opcode,
// "query: {:02x?}, opcode: {}",
// dns_query, opcode
// );
// }
// Ok(())
// }
// }
Ok(DNSHeader { // mod message_type {
id, // use super::super::super::*;
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,
})
}
}
#[derive(Debug, Clone, PartialEq)] // #[test]
pub enum DNSParseError { // fn query() -> Result<(), DNSParseError> {
DatagramTooShort, // let dns_query = [
DNSOpCodeInvalid, // 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
DNSRCodeInvalid, // ];
} // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
// assert_eq!(parse_result?.message_type, DNSMessageType::Query);
// Ok(())
// }
#[cfg(test)] // #[test]
mod tests { // 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 { // #[test]
use super::super::super::*; // 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] // for rcode in invalid_rcodes {
fn too_short() { // dns_query[3] = rcode;
// 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);
}
}
mod opcode { // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
use super::super::super::*;
#[test] // assert_eq!(
fn invalid() { // parse_result,
let mut dns_query = [ // Err(DNSParseError::DNSRCodeInvalid),
0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "query: {:02x?}, rcode: {}",
]; // dns_query,
let invalid_opcodes = [3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; // rcode,
// );
// }
// }
for opcode in invalid_opcodes { // #[test]
dns_query[2] = opcode << 3; // fn valid() -> Result<(), DNSParseError> {
let parse_result = DNSHeader::from_udp_datagram(&dns_query); // let mut dns_query = [
assert_eq!( // 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
parse_result.err(), // ];
Some(DNSParseError::DNSOpCodeInvalid),
"query: {:02x?}, opcode: {}",
dns_query,
opcode
);
}
}
#[test] // // for now we only support RCodes 0 to 10 (inclusive)
fn valid() -> Result<(), DNSParseError> { // let valid_rcodes = [
let mut dns_query = [ // (0, DNSRCode::NoError),
0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // (1, DNSRCode::FormErr),
]; // (2, DNSRCode::ServFail),
let valid_opcodes = [ // (3, DNSRCode::NXDomain),
(0, DNSOpCode::Query), // (4, DNSRCode::NotImp),
(1, DNSOpCode::IQuery), // (5, DNSRCode::Refused),
(2, DNSOpCode::Status), // (6, DNSRCode::YXDomain),
(4, DNSOpCode::Notify), // (7, DNSRCode::YXRRSet),
(5, DNSOpCode::Update), // (8, DNSRCode::NXRRSet),
]; // (9, DNSRCode::NotAuth),
// (10, DNSRCode::NotZone),
// ];
for (opcode, parsed_opcode) in valid_opcodes { // for (rcode, parsed_rcode) in valid_rcodes {
dns_query[2] = opcode << 3; // dns_query[3] = rcode;
let parse_result = DNSHeader::from_udp_datagram(&dns_query); // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
assert_eq!( // assert_eq!(
parse_result?.opcode, parsed_opcode, // parse_result?.response_code, parsed_rcode,
"query: {:02x?}, opcode: {}", // "query: {:02x?}, rcode: {}, parsed_rcode: {:?}",
dns_query, opcode // dns_query, rcode, parsed_rcode
); // );
} // }
Ok(()) // Ok(())
} // }
} // }
mod message_type { // mod query_count {
use super::super::super::*; // use super::super::super::*;
#[test] // #[test]
fn query() -> Result<(), DNSParseError> { // fn zero() -> Result<(), DNSParseError> {
let dns_query = [ // let dns_query = [
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]; // ];
let parse_result = DNSHeader::from_udp_datagram(&dns_query); // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
assert_eq!(parse_result?.message_type, DNSMessageType::Query); // assert_eq!(parse_result?.query_count, 0);
Ok(()) // Ok(())
} // }
#[test] // #[test]
fn response() -> Result<(), DNSParseError> { // fn one() -> Result<(), DNSParseError> {
let dns_query = [ // let dns_query = [
0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xff, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]; // ];
let parse_result = DNSHeader::from_udp_datagram(&dns_query); // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
assert_eq!(parse_result?.message_type, DNSMessageType::Response); // assert_eq!(parse_result?.query_count, 1);
Ok(()) // Ok(())
} // }
}
mod response_code { // #[test]
use super::super::super::*; // 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] // mod answer_count {
fn invalid() { // use super::super::super::*;
let mut dns_query = [
0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
let invalid_rcodes = [11, 12, 13, 14, 15];
for rcode in invalid_rcodes { // #[test]
dns_query[3] = rcode; // 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!( // #[test]
parse_result, // fn max_value() -> Result<(), DNSParseError> {
Err(DNSParseError::DNSRCodeInvalid), // let dns_query = [
"query: {:02x?}, rcode: {}", // 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
dns_query, // ];
rcode, // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
); // assert_eq!(parse_result?.answer_count, 65535);
} // Ok(())
} // }
// }
#[test] // mod name_server_count {
fn valid() -> Result<(), DNSParseError> { // use super::super::super::*;
let mut dns_query = [
0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
// for now we only support RCodes 0 to 10 (inclusive) // #[test]
let valid_rcodes = [ // fn zero() -> Result<(), DNSParseError> {
(0, DNSRCode::NoError), // let dns_query = [
(1, DNSRCode::FormErr), // 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
(2, DNSRCode::ServFail), // ];
(3, DNSRCode::NXDomain), // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
(4, DNSRCode::NotImp), // assert_eq!(parse_result?.name_server_count, 0);
(5, DNSRCode::Refused), // Ok(())
(6, DNSRCode::YXDomain), // }
(7, DNSRCode::YXRRSet),
(8, DNSRCode::NXRRSet),
(9, DNSRCode::NotAuth),
(10, DNSRCode::NotZone),
];
for (rcode, parsed_rcode) in valid_rcodes { // #[test]
dns_query[3] = rcode; // fn one() -> Result<(), DNSParseError> {
let parse_result = DNSHeader::from_udp_datagram(&dns_query); // let dns_query = [
assert_eq!( // 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
parse_result?.response_code, parsed_rcode, // ];
"query: {:02x?}, rcode: {}, parsed_rcode: {:?}", // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
dns_query, rcode, parsed_rcode // assert_eq!(parse_result?.name_server_count, 1);
); // Ok(())
} // }
Ok(())
}
}
mod query_count { // #[test]
use super::super::super::*; // 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] // mod additional_count {
fn zero() -> Result<(), DNSParseError> { // use super::super::super::*;
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] // #[test]
fn one() -> Result<(), DNSParseError> { // fn zero() -> Result<(), DNSParseError> {
let dns_query = [ // let dns_query = [
0xff, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]; // ];
let parse_result = DNSHeader::from_udp_datagram(&dns_query); // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
assert_eq!(parse_result?.query_count, 1); // assert_eq!(parse_result?.additional_count, 0);
Ok(()) // Ok(())
} // }
#[test] // #[test]
fn max_value() -> Result<(), DNSParseError> { // fn one() -> Result<(), DNSParseError> {
let dns_query = [ // let dns_query = [
0xff, 0x00, 0x80, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
]; // ];
let parse_result = DNSHeader::from_udp_datagram(&dns_query); // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
assert_eq!(parse_result?.query_count, 65535); // assert_eq!(parse_result?.additional_count, 1);
Ok(()) // Ok(())
} // }
}
mod answer_count { // #[test]
use super::super::super::*; // 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] // mod authorative_answer {
fn zero() -> Result<(), DNSParseError> { // use super::super::super::*;
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(())
}
#[test] // #[test]
fn one() -> Result<(), DNSParseError> { // fn yes() -> Result<(), DNSParseError> {
let dns_query = [ // let dns_query = [
0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // 0xff, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]; // ];
let parse_result = DNSHeader::from_udp_datagram(&dns_query); // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
assert_eq!(parse_result?.answer_count, 1); // assert!(parse_result?.authorative_answer);
Ok(()) // Ok(())
} // }
#[test] // #[test]
fn max_value() -> Result<(), DNSParseError> { // fn no() -> Result<(), DNSParseError> {
let dns_query = [ // let dns_query = [
0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, // 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]; // ];
let parse_result = DNSHeader::from_udp_datagram(&dns_query); // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
assert_eq!(parse_result?.answer_count, 65535); // assert!(!parse_result?.authorative_answer);
Ok(()) // Ok(())
} // }
} // }
mod name_server_count { // mod truncated {
use super::super::super::*; // use super::super::super::*;
#[test] // #[test]
fn zero() -> Result<(), DNSParseError> { // fn yes() -> Result<(), DNSParseError> {
let dns_query = [ // let dns_query = [
0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xff, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]; // ];
let parse_result = DNSHeader::from_udp_datagram(&dns_query); // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
assert_eq!(parse_result?.name_server_count, 0); // assert!(parse_result?.truncated);
Ok(()) // Ok(())
} // }
#[test] // #[test]
fn one() -> Result<(), DNSParseError> { // fn no() -> Result<(), DNSParseError> {
let dns_query = [ // let dns_query = [
0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, // 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]; // ];
let parse_result = DNSHeader::from_udp_datagram(&dns_query); // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
assert_eq!(parse_result?.name_server_count, 1); // assert!(!parse_result?.truncated);
Ok(()) // Ok(())
} // }
// }
#[test] // mod recursion_desired {
fn max_value() -> Result<(), DNSParseError> { // use super::super::super::*;
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 additional_count { // #[test]
use super::super::super::*; // 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] // #[test]
fn zero() -> Result<(), DNSParseError> { // fn no() -> Result<(), DNSParseError> {
let dns_query = [ // let dns_query = [
0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]; // ];
let parse_result = DNSHeader::from_udp_datagram(&dns_query); // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
assert_eq!(parse_result?.additional_count, 0); // assert!(!parse_result?.recursion_desired);
Ok(()) // Ok(())
} // }
// }
#[test] // mod recursion_available {
fn one() -> Result<(), DNSParseError> { // use super::super::super::*;
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(())
}
#[test] // #[test]
fn max_value() -> Result<(), DNSParseError> { // fn yes() -> Result<(), DNSParseError> {
let dns_query = [ // let dns_query = [
0xff, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, // 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]; // ];
let parse_result = DNSHeader::from_udp_datagram(&dns_query); // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
assert_eq!(parse_result?.additional_count, 65535); // assert!(parse_result?.recursion_available);
Ok(()) // Ok(())
} // }
}
mod authorative_answer { // #[test]
use super::super::super::*; // fn no() -> Result<(), DNSParseError> {
// let dns_query = [
#[test] // 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
fn yes() -> Result<(), DNSParseError> { // ];
let dns_query = [ // let parse_result = DNSHeader::from_udp_datagram(&dns_query);
0xff, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // assert!(!parse_result?.recursion_available);
]; // Ok(())
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(())
}
}
}
}

13
src/proto/mod.rs Normal file
View File

@ -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<DNSQuery, DNSParseError>;
fn encode(respone: DNSResponse) -> Result<Vec<u8>, DNSParseError>;
}

165
src/proto/udp.rs Normal file
View File

@ -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<DNSQuery, DNSParseError> {
let message = Message::try_from(datagram)?;
Ok(DNSQuery {
id: message.header.id,
questions: vec![],
})
}
fn encode(respone: DNSResponse) -> Result<Vec<u8>, DNSParseError> {
todo!();
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum DNSParseError {
DatagramTooShort
}
#[derive(Debug, PartialEq, Clone, Copy)]
enum MessageType {
Query,
Response,
}
impl From<bool> 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<Question>,
answers: Vec<ResourceRecord>,
authorities: Vec<ResourceRecord>,
additionals: Vec<ResourceRecord>,
}
impl TryFrom<&[u8]> for Message {
type Error = DNSParseError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
todo!();
}
}
impl TryFrom<&[u8]> for Header {
type Error = DNSParseError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
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,
})
}
}