3 Commits

Author SHA1 Message Date
6527dbe6c5 Merge remote-tracking branch 'origin/master' 2022-06-05 15:07:31 +02:00
b32531866a (refactor) according to new structure, have proto module with de- and encorders 2022-06-05 14:59:22 +02:00
d491ea12a5 (clippy) some small clippy fixes (#28)
Reviewed-on: #28
Co-authored-by: ddidderr <ddidderr@paul.network>
Co-committed-by: ddidderr <ddidderr@paul.network>
2022-06-05 14:58:37 +02:00
2 changed files with 182 additions and 209 deletions

View File

@ -1,204 +1,5 @@
use std::convert::TryInto; 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,
// 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 enum DNSClass {
Internet = 1,
Any = 255,
}
#[derive(Debug, Clone)]
pub enum DNSType {
HostAddress = 1,
NameServer = 2,
CanonicalName = 5,
StartOfZoneAuthority = 6,
WellKnownServiceDescription = 11,
DomainNamePointer = 12,
HostInformation = 13,
MailListInformation = 14,
MailExchange = 15,
TextStrings = 16,
Any = 255,
}
#[derive(Debug, Clone)]
pub struct DNSQuestion {
pub name: String,
pub r#type: DNSType,
pub class: DNSClass,
}
pub struct DNSResourceRecord {
pub name: String,
pub r#type: DNSType,
pub class: DNSClass,
pub ttl: u32,
pub data: String,
}
pub struct DNSMessage {
pub header: DNSHeader,
pub questions: Vec<DNSQuestion>,
pub answers: Vec<DNSResourceRecord>,
pub authorities: Vec<DNSResourceRecord>,
pub additionals: Vec<DNSResourceRecord>,
}
impl DNSHeader { impl DNSHeader {
const QR_MASK: u8 = 0b10000000; const QR_MASK: u8 = 0b10000000;
const OPCODE_MASK: u8 = 0b01111000; const OPCODE_MASK: u8 = 0b01111000;
@ -368,7 +169,7 @@ mod tests {
let invalid_rcodes = [11, 12, 13, 14, 15]; let invalid_rcodes = [11, 12, 13, 14, 15];
for rcode in invalid_rcodes { for rcode in invalid_rcodes {
dns_query[3] = (rcode as u8) << 0; dns_query[3] = rcode;
let parse_result = DNSHeader::from_udp_datagram(&dns_query); let parse_result = DNSHeader::from_udp_datagram(&dns_query);
@ -404,7 +205,7 @@ mod tests {
]; ];
for (rcode, parsed_rcode) in valid_rcodes { for (rcode, parsed_rcode) in valid_rcodes {
dns_query[3] = rcode << 0; 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?.response_code, parsed_rcode, parse_result?.response_code, parsed_rcode,
@ -561,7 +362,7 @@ mod tests {
0xff, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 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?.authorative_answer, true); assert!(parse_result?.authorative_answer);
Ok(()) Ok(())
} }
@ -571,7 +372,7 @@ mod tests {
0xff, 0x00, 0x00, 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?.authorative_answer, false); assert!(!parse_result?.authorative_answer);
Ok(()) Ok(())
} }
} }
@ -585,7 +386,7 @@ mod tests {
0xff, 0x00, 0x02, 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?.truncated, true); assert!(parse_result?.truncated);
Ok(()) Ok(())
} }
@ -595,7 +396,7 @@ mod tests {
0xff, 0x00, 0x00, 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?.truncated, false); assert!(!parse_result?.truncated);
Ok(()) Ok(())
} }
} }
@ -609,7 +410,7 @@ mod tests {
0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x01, 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?.recursion_desired, true); assert!(parse_result?.recursion_desired);
Ok(()) Ok(())
} }
@ -619,7 +420,7 @@ mod tests {
0xff, 0x00, 0x00, 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?.recursion_desired, false); assert!(!parse_result?.recursion_desired);
Ok(()) Ok(())
} }
} }
@ -633,7 +434,7 @@ mod tests {
0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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?.recursion_available, true); assert!(parse_result?.recursion_available);
Ok(()) Ok(())
} }
@ -643,7 +444,7 @@ mod tests {
0xff, 0x00, 0x00, 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?.recursion_available, false); assert!(!parse_result?.recursion_available);
Ok(()) Ok(())
} }
} }

172
src/proto/models.rs Normal file
View File

@ -0,0 +1,172 @@
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,
}
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;
// 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;
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[3] & Self::RA_MASK) != 0;
// 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;
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, // 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,
})
}
}