use crate::dissect::{Dissect, DissectResult};
use crate::format::pcap::mask::{DNS_OPCODE, DNS_QR, DNS_RCODE};
use crate::Error;
#[derive(Debug, Clone)]
pub struct Dns<'a> {
data: &'a [u8],
}
impl<'a> Dns<'a> {
pub fn new(data: &'a [u8]) -> Result<Self, Error> {
if data.len() < 12 {
return Err(Error::truncated(12, data.len()));
}
Ok(Self { data })
}
pub fn id(&self) -> u16 {
u16::from_be_bytes([self.data[0], self.data[1]])
}
pub fn flags(&self) -> u16 {
u16::from_be_bytes([self.data[2], self.data[3]])
}
pub fn is_response(&self) -> bool {
(self.flags() & DNS_QR) != 0
}
pub fn opcode(&self) -> u8 {
((self.flags() & DNS_OPCODE) >> 11) as u8
}
pub fn rcode(&self) -> u8 {
(self.flags() & DNS_RCODE) as u8
}
pub fn qd_count(&self) -> u16 {
u16::from_be_bytes([self.data[4], self.data[5]])
}
pub fn an_count(&self) -> u16 {
u16::from_be_bytes([self.data[6], self.data[7]])
}
pub fn ns_count(&self) -> u16 {
u16::from_be_bytes([self.data[8], self.data[9]])
}
pub fn ar_count(&self) -> u16 {
u16::from_be_bytes([self.data[10], self.data[11]])
}
pub fn payload(&self) -> &'a [u8] {
if self.data.len() <= 12 {
&[]
} else {
&self.data[12..]
}
}
}
impl<'a> Dissect<'a> for Dns<'a> {
type Output = &'a [u8];
fn dissect(&self) -> DissectResult<Self::Output> {
Ok(self.payload())
}
fn data(&self) -> &'a [u8] {
self.data
}
fn header_len(&self) -> usize {
12
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dns_new_valid() {
let data = vec![
0x12, 0x34, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
let dns = Dns::new(&data).unwrap();
assert_eq!(dns.id(), 0x1234);
assert!(!dns.is_response());
}
#[test]
fn test_dns_new_truncated() {
let data = vec![0u8; 8];
let result = Dns::new(&data);
assert!(result.is_err());
}
#[test]
fn test_dns_flags() {
let data = vec![
0x12, 0x34, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, ];
let dns = Dns::new(&data).unwrap();
assert!(dns.is_response());
assert_eq!(dns.rcode(), 0); }
#[test]
fn test_dns_counts() {
let data = vec![
0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, ];
let dns = Dns::new(&data).unwrap();
assert_eq!(dns.qd_count(), 2);
assert_eq!(dns.an_count(), 3);
assert_eq!(dns.ns_count(), 4);
assert_eq!(dns.ar_count(), 5);
}
#[test]
fn test_dns_payload() {
let mut data = vec![
0x12, 0x34, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
data.extend_from_slice(&[0xde, 0xad, 0xbe, 0xef]); let dns = Dns::new(&data).unwrap();
assert_eq!(dns.payload(), &[0xde, 0xad, 0xbe, 0xef]);
}
}