Compare commits
1 Commits
master
...
data_drive
Author | SHA1 | Date | |
---|---|---|---|
60316e5593 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1 @@
|
|||||||
/target
|
/target
|
||||||
.DS_Store
|
|
||||||
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -12,4 +12,4 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "hexhex"
|
name = "hexhex"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = "git+https://git.comff.net/rustics/hexhex.git?tag=v1.1#c92e07853136c8371b6034d93a9d0f1be9e665c5"
|
source = "git+https://git.comff.net/rustics/hexhex.git#fa738dd19563d7cea4b2383dcbd8a64c94ab91b7"
|
||||||
|
@ -6,4 +6,4 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
hexhex = {tag = "v1.1", git = "https://git.comff.net/rustics/hexhex.git"}
|
hexhex = {version = "1.0", git = "https://git.comff.net/rustics/hexhex.git"}
|
||||||
|
10
src/main.rs
10
src/main.rs
@ -1,11 +1,11 @@
|
|||||||
|
#![feature(concat_idents)]
|
||||||
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;
|
||||||
mod models;
|
use hexhex::print_hex;
|
||||||
|
use proto::DNSHeader;
|
||||||
|
|
||||||
fn listen() -> (
|
fn listen() -> (
|
||||||
JoinHandle<()>,
|
JoinHandle<()>,
|
||||||
@ -39,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 query = UdpCoder::decode(&msg).unwrap();
|
let hdr_struct = DNSHeader::from_udp_datagram(&msg).unwrap();
|
||||||
dbg!(query);
|
dbg!(hdr_struct);
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = thread_udp.join();
|
let _ = thread_udp.join();
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
#[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,
|
|
||||||
}
|
|
390
src/proto.rs
Normal file
390
src/proto.rs
Normal file
@ -0,0 +1,390 @@
|
|||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for DNSOpCode {
|
||||||
|
type Error = DNSParseError;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
0 => Ok(DNSOpCode::Query),
|
||||||
|
1 => Ok(DNSOpCode::IQuery),
|
||||||
|
2 => Ok(DNSOpCode::Status),
|
||||||
|
4 => Ok(DNSOpCode::Notify),
|
||||||
|
5 => Ok(DNSOpCode::Update),
|
||||||
|
_ => Err(DNSParseError::DNSOpCodeInvalid),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for DNSRCode {
|
||||||
|
type Error = DNSParseError;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
0 => Ok(DNSRCode::NoError),
|
||||||
|
1 => Ok(DNSRCode::FormErr),
|
||||||
|
2 => Ok(DNSRCode::ServFail),
|
||||||
|
3 => Ok(DNSRCode::NXDomain),
|
||||||
|
4 => Ok(DNSRCode::NotImp),
|
||||||
|
5 => Ok(DNSRCode::Refused),
|
||||||
|
6 => Ok(DNSRCode::YXDomain),
|
||||||
|
7 => Ok(DNSRCode::YXRRSet),
|
||||||
|
8 => Ok(DNSRCode::NXRRSet),
|
||||||
|
9 => Ok(DNSRCode::NotAuth),
|
||||||
|
10 => Ok(DNSRCode::NotZone),
|
||||||
|
_ => Err(DNSParseError::DNSRCodeInvalid),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
|
pub enum DNSMessageType {
|
||||||
|
Query,
|
||||||
|
Response,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for DNSMessageType {
|
||||||
|
fn from(value: bool) -> DNSMessageType {
|
||||||
|
match value {
|
||||||
|
false => Self::Query,
|
||||||
|
true => Self::Response,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
/// TODO: add documuentation about this flag
|
||||||
|
pub authentic_data: bool,
|
||||||
|
/// TODO: add documuentation about this flag
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
const RA_MASK: u8 = 0b10000000;
|
||||||
|
const AD_MASK: u8 = 0b00100000;
|
||||||
|
const CD_MASK: u8 = 0b00010000;
|
||||||
|
const RCODE_MASK: u8 = 0b00001111;
|
||||||
|
|
||||||
|
const OPCODE_OFFSET: u8 = 3;
|
||||||
|
|
||||||
|
pub fn from_udp_datagram(datagram: &[u8]) -> Result<Self, DNSParseError> {
|
||||||
|
if datagram.len() < 12 {
|
||||||
|
return Err(DNSParseError::DatagramTooShort);
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = u16::from_be_bytes((&datagram[..2]).try_into().unwrap());
|
||||||
|
|
||||||
|
let message_type = DNSMessageType::from(datagram[2] & Self::QR_MASK != 0);
|
||||||
|
let opcode = DNSOpCode::try_from((datagram[2] & Self::OPCODE_MASK) >> Self::OPCODE_OFFSET)?;
|
||||||
|
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[2] & Self::RA_MASK) != 0;
|
||||||
|
let authentic_data = (datagram[2] & Self::AD_MASK) != 0;
|
||||||
|
let checking_disabled = (datagram[2] & Self::CD_MASK) != 0;
|
||||||
|
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());
|
||||||
|
|
||||||
|
Ok(DNSHeader {
|
||||||
|
id,
|
||||||
|
message_type,
|
||||||
|
opcode,
|
||||||
|
authorative_answer,
|
||||||
|
truncated,
|
||||||
|
recursion_desired,
|
||||||
|
recursion_available,
|
||||||
|
authentic_data,
|
||||||
|
checking_disabled,
|
||||||
|
response_code,
|
||||||
|
query_count,
|
||||||
|
answer_count,
|
||||||
|
name_server_count,
|
||||||
|
additional_count,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum DNSParseError {
|
||||||
|
DatagramTooShort,
|
||||||
|
DNSOpCodeInvalid,
|
||||||
|
DNSRCodeInvalid,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
macro_rules! data_driven_test {
|
||||||
|
($name:expr, $func:expr, $input:literal, $output:literal) => {
|
||||||
|
#[test]
|
||||||
|
fn concat_idents!($name, _test) {
|
||||||
|
assert_eq!($input, $output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod from_udp_datagram {
|
||||||
|
|
||||||
|
data_driven_test!("my_macro_test", somefunc, 5, 5);
|
||||||
|
|
||||||
|
mod header_length {
|
||||||
|
use super::super::super::*;
|
||||||
|
|
||||||
|
#[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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod opcode {
|
||||||
|
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_opcodes = [3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||||
|
|
||||||
|
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,
|
||||||
|
];
|
||||||
|
let valid_opcodes = [
|
||||||
|
(0, DNSOpCode::Query),
|
||||||
|
(1, DNSOpCode::IQuery),
|
||||||
|
(2, DNSOpCode::Status),
|
||||||
|
(4, DNSOpCode::Notify),
|
||||||
|
(5, DNSOpCode::Update),
|
||||||
|
];
|
||||||
|
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod message_type {
|
||||||
|
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 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 response_code {
|
||||||
|
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];
|
||||||
|
|
||||||
|
for rcode in invalid_rcodes {
|
||||||
|
dns_query[3] = (rcode as u8) << 0;
|
||||||
|
|
||||||
|
let parse_result = DNSHeader::from_udp_datagram(&dns_query);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
parse_result,
|
||||||
|
Err(DNSParseError::DNSRCodeInvalid),
|
||||||
|
"query: {:02x?}, rcode: {}",
|
||||||
|
dns_query,
|
||||||
|
rcode,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid() -> Result<(), DNSParseError> {
|
||||||
|
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)
|
||||||
|
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 (rcode, parsed_rcode) in valid_rcodes {
|
||||||
|
dns_query[3] = rcode << 0;
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,387 +0,0 @@
|
|||||||
// use crate::models::dns_query::DNSQuery;
|
|
||||||
// use crate::models::dns_response::DNSResponse;
|
|
||||||
|
|
||||||
// #[cfg(test)]
|
|
||||||
// mod tests {
|
|
||||||
|
|
||||||
// mod from_udp_datagram {
|
|
||||||
|
|
||||||
// mod header_length {
|
|
||||||
// use super::super::super::*;
|
|
||||||
|
|
||||||
// #[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);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// mod opcode {
|
|
||||||
// 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_opcodes = [3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
// ];
|
|
||||||
// let valid_opcodes = [
|
|
||||||
// (0, DNSOpCode::Query),
|
|
||||||
// (1, DNSOpCode::IQuery),
|
|
||||||
// (2, DNSOpCode::Status),
|
|
||||||
// (4, DNSOpCode::Notify),
|
|
||||||
// (5, DNSOpCode::Update),
|
|
||||||
// ];
|
|
||||||
|
|
||||||
// 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(())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// mod message_type {
|
|
||||||
// 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 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 response_code {
|
|
||||||
// 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];
|
|
||||||
|
|
||||||
// for rcode in invalid_rcodes {
|
|
||||||
// dns_query[3] = rcode;
|
|
||||||
|
|
||||||
// let parse_result = DNSHeader::from_udp_datagram(&dns_query);
|
|
||||||
|
|
||||||
// assert_eq!(
|
|
||||||
// parse_result,
|
|
||||||
// Err(DNSParseError::DNSRCodeInvalid),
|
|
||||||
// "query: {:02x?}, rcode: {}",
|
|
||||||
// dns_query,
|
|
||||||
// rcode,
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn valid() -> Result<(), DNSParseError> {
|
|
||||||
// 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)
|
|
||||||
// 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 (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 query_count {
|
|
||||||
// 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?.query_count, 0);
|
|
||||||
// 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(())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[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(())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// mod answer_count {
|
|
||||||
// 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?.answer_count, 0);
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[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 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(())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// mod name_server_count {
|
|
||||||
// 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 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 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 additional_count {
|
|
||||||
// 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?.additional_count, 0);
|
|
||||||
// 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(())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[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(())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 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(())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
@ -1,13 +0,0 @@
|
|||||||
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
165
src/proto/udp.rs
@ -1,165 +0,0 @@
|
|||||||
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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user