use crate::dns::parser::{DnsPacket, DnsQuestionIter, DnsRecordIter};
#[derive(Debug, Clone)]
pub struct MdnsPacket<'a> {
dns: DnsPacket<'a>,
}
impl<'a> MdnsPacket<'a> {
pub fn new(buf: &'a [u8]) -> Option<Self> {
DnsPacket::new(buf).map(|dns| Self { dns })
}
pub fn is_query(&self) -> bool { !self.dns.qr() }
pub fn is_response(&self) -> bool { self.dns.qr() }
pub fn unicast_response_requested(&self) -> bool {
self.dns.questions().next()
.map(|q| u16::from(q.qclass) & 0x8000 != 0)
.unwrap_or(false)
}
pub fn questions(&self) -> DnsQuestionIter<'a> { self.dns.questions() }
pub fn answers(&self) -> DnsRecordIter<'a> { self.dns.answers() }
pub fn authorities(&self) -> DnsRecordIter<'a> { self.dns.authorities() }
pub fn additionals(&self) -> DnsRecordIter<'a> { self.dns.additionals() }
}
#[inline]
pub fn is_cache_flush(class: u16) -> bool {
class & 0x8000 != 0
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dns::builder::DnsPacketBuilder;
use crate::dns::types::{DnsClass, DnsType};
#[test]
fn parse_mdns_query() {
let q = DnsPacketBuilder::query()
.add_question("_http._tcp.local", DnsType::PTR, DnsClass::IN)
.build();
let p = MdnsPacket::new(&q).unwrap();
assert!(p.is_query());
assert!(!p.unicast_response_requested());
let qs: Vec<_> = p.questions().collect();
assert_eq!(qs.len(), 1);
}
#[test]
fn parse_mdns_response() {
let r = DnsPacketBuilder::response()
.add_question("printer.local", DnsType::A, DnsClass::IN)
.add_raw_answer("printer.local", DnsType::A, 120, &[192, 168, 1, 100])
.build();
let p = MdnsPacket::new(&r).unwrap();
assert!(p.is_response());
}
#[test]
fn unicast_response_bit() {
let qu_class = DnsClass::Unknown(0x8001); let q = DnsPacketBuilder::query()
.add_question("test.local", DnsType::A, qu_class)
.build();
let p = MdnsPacket::new(&q).unwrap();
assert!(p.unicast_response_requested());
}
}