use crate::{dns::packet_part::PacketPart, SimpleDnsError};
use super::RR;
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct NSAP {
pub afi: u8,
pub idi: u16,
pub dfi: u8,
pub aa: u32,
pub rsvd: u16,
pub rd: u16,
pub area: u16,
pub id: u64,
pub sel: u8,
}
impl RR for NSAP {
const TYPE_CODE: u16 = 22;
}
impl NSAP {
pub fn into_owned(self) -> Self {
self
}
}
impl<'a> PacketPart<'a> for NSAP {
fn parse(data: &'a [u8], position: usize) -> crate::Result<Self>
where
Self: Sized,
{
if data.len() < position + 20 {
return Err(SimpleDnsError::InsufficientData);
}
let data = &data[position..position + 20];
let afi = u8::from_be(data[0]);
let idi = u16::from_be_bytes([data[1], data[2]]);
let dfi = u8::from_be(data[3]);
let aa = u32::from_be_bytes([0, data[4], data[5], data[6]]);
let rsvd = u16::from_be_bytes([data[7], data[8]]);
let rd = u16::from_be_bytes([data[9], data[10]]);
let area = u16::from_be_bytes([data[11], data[12]]);
let id = u64::from_be_bytes([
0, 0, data[13], data[14], data[15], data[16], data[17], data[18],
]);
let sel = u8::from_be(data[19]);
Ok(Self {
afi,
idi,
dfi,
aa,
rsvd,
rd,
area,
id,
sel,
})
}
fn write_to<T: std::io::Write>(&self, out: &mut T) -> crate::Result<()> {
out.write_all(&[self.afi.to_be()])?;
out.write_all(&self.idi.to_be_bytes())?;
out.write_all(&[self.dfi.to_be()])?;
out.write_all(&self.aa.to_be_bytes()[1..4])?;
out.write_all(&self.rsvd.to_be_bytes())?;
out.write_all(&self.rd.to_be_bytes())?;
out.write_all(&self.area.to_be_bytes())?;
out.write_all(&self.id.to_be_bytes()[2..8])?;
out.write_all(&[self.sel.to_be()])?;
Ok(())
}
fn len(&self) -> usize {
20
}
}
#[cfg(test)]
mod tests {
use crate::{rdata::RData, ResourceRecord};
use super::*;
#[test]
pub fn parse_and_write_nsap() {
let nsap = NSAP {
afi: 47,
idi: 5,
dfi: 0x80,
aa: 0x005a00,
rsvd: 0x10,
rd: 0x1000,
area: 0x0020,
id: 0x00800a123456,
sel: 0x10,
};
let mut data = Vec::new();
assert!(nsap.write_to(&mut data).is_ok());
let nsap = NSAP::parse(&data, 0);
assert!(nsap.is_ok());
let nsap = nsap.unwrap();
assert_eq!(data.len(), nsap.len());
assert_eq!(47, nsap.afi);
assert_eq!(5, nsap.idi);
assert_eq!(0x80, nsap.dfi);
assert_eq!(0x005a00, nsap.aa);
assert_eq!(0x10, nsap.rsvd);
assert_eq!(0x1000, nsap.rd);
assert_eq!(0x0020, nsap.area);
assert_eq!(0x00800a123456, nsap.id);
assert_eq!(0x10, nsap.sel);
}
#[test]
fn parse_sample() -> Result<(), Box<dyn std::error::Error>> {
let sample_file = std::fs::read("samples/zonefile/NSAP.sample")?;
let sample_rdata = match ResourceRecord::parse(&sample_file, 0)?.rdata {
RData::NSAP(rdata) => rdata,
_ => unreachable!(),
};
assert_eq!(0x47, sample_rdata.afi);
assert_eq!(0x0005, sample_rdata.idi);
assert_eq!(0x80, sample_rdata.dfi);
assert_eq!(0x005a00, sample_rdata.aa);
assert_eq!(0x00, sample_rdata.rsvd);
assert_eq!(0x0001, sample_rdata.rd);
assert_eq!(0xe133, sample_rdata.area);
assert_eq!(0xffffff000164, sample_rdata.id);
assert_eq!(0x00, sample_rdata.sel);
Ok(())
}
}