From b9ff4c9a51e39ccd57c61ca6b0fd5b80dde17148 Mon Sep 17 00:00:00 2001 From: Tobias Ottenweller Date: Tue, 15 Mar 2022 17:01:17 +0100 Subject: [PATCH] Move parsing of udp datagram for dns header into model --- src/main.rs | 59 +---------------------------- src/proto.rs | 102 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 97 insertions(+), 64 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1917d5d..8efa564 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,9 @@ use flume::{Receiver, Sender}; use std::net::UdpSocket; use std::thread::{self, JoinHandle}; -use std::convert::TryInto; mod proto; -use proto::{DNSHeader, DNSOpCode, DNSRCode}; - +use proto::DNSHeader; fn listen() -> (JoinHandle<()>, Sender>, Receiver>) { let (tx, rx) = flume::unbounded(); @@ -31,65 +29,12 @@ fn listen() -> (JoinHandle<()>, Sender>, Receiver>) { ) } - -const QR_MASK:u16 = 0x0001; -const OPCODE_MASK:u16 = 0x000e; -const AA_MASK:u16 = 0x0020; -const TC_MASK:u16 = 0x0040; -const RD_MASK:u16 = 0x0080; -const RA_MASK:u16 = 0x0100; -const AD_MASK:u16 = 0x0400; -const CD_MASK:u16 = 0x0800; -const RCODE_MASK:u16 = 0xf000; - -const OPCODE_OFFSET:u16 = 1; -const RCODE_OFFSET:u16 = 11; - fn main() { let (thread_udp, _thread_udp_tx, thread_udp_rx) = listen(); for msg in thread_udp_rx.iter() { - println!("{:?}", msg); - - // TODO: check for enough data in msg - - let id = u16::from_be_bytes((&msg[..2]).try_into().unwrap()); - - let flags = u16::from_be_bytes((&msg[2..4]).try_into().unwrap()); - let qr = (flags & QR_MASK) != 0; - let opcode:DNSOpCode = DNSOpCode::from((flags & OPCODE_MASK) >> OPCODE_OFFSET); - let authoritative_answer = (flags & AA_MASK) != 0; - let truncated = (flags & TC_MASK) != 0; - let recursion_desired= (flags & RD_MASK) != 0; - let recursion_available = (flags & RA_MASK) != 0; - let authentic_data = (flags & AD_MASK) != 0; - let checking_disabled = (flags & CD_MASK) != 0; - let response_code: DNSRCode = DNSRCode::from((flags & RCODE_MASK) >> RCODE_OFFSET); - - let qd_zo_count = u16::from_be_bytes((&msg[4..6]).try_into().unwrap()); - let an_pr_count = u16::from_be_bytes((&msg[6..8]).try_into().unwrap()); - let ns_up_count = u16::from_be_bytes((&msg[8..10]).try_into().unwrap()); - let ar_count = u16::from_be_bytes((&msg[10..12]).try_into().unwrap()); - - let hdr_struct = DNSHeader { - id, - qr, - opcode, - authoritative_answer, - truncated, - recursion_desired, - recursion_available, - authentic_data, - checking_disabled, - response_code, - qd_zo_count, - an_pr_count, - ns_up_count, - ar_count, - }; - + let hdr_struct = DNSHeader::from_udp_datagram(&msg).unwrap(); dbg!(hdr_struct); - } let _ = thread_udp.join(); diff --git a/src/proto.rs b/src/proto.rs index 177e557..6565a40 100644 --- a/src/proto.rs +++ b/src/proto.rs @@ -1,3 +1,5 @@ +use std::convert::TryInto; + #[derive(Debug)] pub enum DNSOpCode { QUERY = 0, @@ -62,16 +64,26 @@ pub struct DNSHeader { /// specifies whether this message is a query (false), or a response (true) pub qr: bool, pub opcode: DNSOpCode, - pub authoritative_answer: bool, - pub truncated: bool, - pub recursion_desired: bool, - pub recursion_available: bool, - pub authentic_data: bool, - pub checking_disabled: bool, - pub response_code: DNSRCode, + /// specifies that the responding name server is an authority for the domain name in question section + pub aa: bool, + /// specifies that this message was truncated due to length greater than that permitted on the transmission channel + pub tc: bool, + /// it directs the name server to pursue the query recursively + pub rd: bool, + /// denotes whether recursive query support is available in the name server + pub ra: bool, + /// TODO: add documuentation about this flag + pub ad: bool, + /// TODO: add documuentation about this flag + pub cd: bool, + pub rcode: DNSRCode, + /// TODO: add documuentation about this count pub qd_zo_count: u16, + /// TODO: add documuentation about this count pub an_pr_count: u16, + /// TODO: add documuentation about this count pub ns_up_count: u16, + /// TODO: add documuentation about this count pub ar_count: u16, } @@ -82,3 +94,79 @@ pub struct DNSQuery { pub qclass: u16, pub qtype: u16, } + +impl DNSHeader { + const QR_MASK: u16 = 0x0001; + const OPCODE_MASK: u16 = 0x000e; + const AA_MASK: u16 = 0x0020; + const TC_MASK: u16 = 0x0040; + const RD_MASK: u16 = 0x0080; + const RA_MASK: u16 = 0x0100; + const AD_MASK: u16 = 0x0400; + const CD_MASK: u16 = 0x0800; + const RCODE_MASK: u16 = 0xf000; + + const OPCODE_OFFSET: u16 = 1; + const RCODE_OFFSET: u16 = 11; + + pub fn from_udp_datagram(datagram: &[u8]) -> Result { + if datagram.len() < 11 { + return Err("Not enough data"); + } + + let id = u16::from_be_bytes((&datagram[..2]).try_into().map_err(|_err| "Invalid id")?); + + let flags = u16::from_be_bytes( + (&datagram[2..4]) + .try_into() + .map_err(|_err| "Invalid flags")?, + ); + let qr = (flags & DNSHeader::QR_MASK) != 0; + let opcode = DNSOpCode::from((flags & DNSHeader::OPCODE_MASK) >> DNSHeader::OPCODE_OFFSET); + let aa = (flags & DNSHeader::AA_MASK) != 0; + let tc = (flags & DNSHeader::TC_MASK) != 0; + let rd = (flags & DNSHeader::RD_MASK) != 0; + let ra = (flags & DNSHeader::RA_MASK) != 0; + let ad = (flags & DNSHeader::AD_MASK) != 0; + let cd = (flags & DNSHeader::CD_MASK) != 0; + let rcode = DNSRCode::from((flags & DNSHeader::RCODE_MASK) >> DNSHeader::RCODE_OFFSET); + + let qd_zo_count = u16::from_be_bytes( + (&datagram[4..6]) + .try_into() + .map_err(|_err| "Invalid qd_zo_count")?, + ); + let an_pr_count = u16::from_be_bytes( + (&datagram[6..8]) + .try_into() + .map_err(|_err| "Invalid an_pr_count")?, + ); + let ns_up_count = u16::from_be_bytes( + (&datagram[8..10]) + .try_into() + .map_err(|_err| "Invalid ns_up_count")?, + ); + let ar_count = u16::from_be_bytes( + (&datagram[10..12]) + .try_into() + .map_err(|_err| "Invalid ar_count")?, + ); + + Ok(DNSHeader { + id, + qr, + opcode, + aa, + tc, + rd, + ra, + ad, + cd, + rcode, + qd_zo_count, + an_pr_count, + ns_up_count, + ar_count, + }) + } +} -- 2.47.1