dns/src/proto.rs

213 lines
6.8 KiB
Rust
Raw Normal View History

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
2022-03-13 21:56:17 +01:00
#[derive(Debug)]
pub enum DNSOpCode {
Query = 0,
IQuery = 1, // obsolete
Status = 2,
Notify = 4,
Update = 5,
2022-03-13 21:56:17 +01:00
}
impl TryFrom<u16> for DNSOpCode {
type Error = DNSParseError;
fn try_from(value: u16) -> 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),
2022-03-13 21:56:17 +01:00
}
}
}
/// 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.
2022-03-13 21:56:17 +01:00
#[derive(Debug)]
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,
2022-03-13 21:56:17 +01:00
}
impl TryFrom<u16> for DNSRCode {
type Error = DNSParseError;
fn try_from(value: u16) -> 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),
2022-03-13 21:56:17 +01:00
}
}
}
#[derive(Debug)]
pub struct DNSHeader {
/// used by the requester to match up replies to outstanding queries
pub id: u16,
/// specifies whether this message is a query (false), or a response (true)
pub qr: bool,
pub opcode: DNSOpCode,
/// 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
2022-03-13 21:56:17 +01:00
pub qd_zo_count: u16,
/// TODO: add documuentation about this count
2022-03-13 21:56:17 +01:00
pub an_pr_count: u16,
/// TODO: add documuentation about this count
2022-03-13 21:56:17 +01:00
pub ns_up_count: u16,
/// TODO: add documuentation about this count
2022-03-13 21:56:17 +01:00
pub ar_count: u16,
}
#[derive(Debug)]
pub struct DNSQuery {
pub hdr: DNSHeader,
pub name: String,
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;
2022-04-03 17:10:59 +02:00
pub fn from_udp_datagram(datagram: &[u8]) -> Result<Self, DNSParseError> {
if datagram.len() < 11 {
return Err(DNSParseError::DatagramTooShort);
}
let id = u16::from_be_bytes((&datagram[..2]).try_into().unwrap());
let flags = u16::from_be_bytes((&datagram[2..4]).try_into().unwrap());
let qr = (flags & Self::QR_MASK) != 0;
let opcode = DNSOpCode::try_from((flags & Self::OPCODE_MASK) >> Self::OPCODE_OFFSET)?;
let aa = (flags & Self::AA_MASK) != 0;
let tc = (flags & Self::TC_MASK) != 0;
let rd = (flags & Self::RD_MASK) != 0;
let ra = (flags & Self::RA_MASK) != 0;
let ad = (flags & Self::AD_MASK) != 0;
let cd = (flags & Self::CD_MASK) != 0;
let rcode = DNSRCode::try_from((flags & Self::RCODE_MASK) >> Self::RCODE_OFFSET)?;
let qd_zo_count = u16::from_be_bytes((&datagram[4..6]).try_into().unwrap());
let an_pr_count = u16::from_be_bytes((&datagram[6..8]).try_into().unwrap());
let ns_up_count = u16::from_be_bytes((&datagram[8..10]).try_into().unwrap());
let ar_count = u16::from_be_bytes((&datagram[10..12]).try_into().unwrap());
Ok(DNSHeader {
id,
qr,
opcode,
aa,
tc,
rd,
ra,
ad,
cd,
rcode,
qd_zo_count,
an_pr_count,
ns_up_count,
ar_count,
})
}
}
2022-04-03 17:01:07 +02:00
2022-04-03 17:10:59 +02:00
#[derive(Debug)]
pub enum DNSParseError {
DatagramTooShort,
DNSOpCodeInvalid,
DNSRCodeInvalid,
2022-04-03 17:01:07 +02:00
}