simple_dns/dns/rdata/
nsap.rs

1use crate::{dns::WireFormat, SimpleDnsError};
2
3use super::RR;
4
5#[derive(Debug, PartialEq, Eq, Hash, Clone)]
6/// NSAP structure [RFC 1706](https://datatracker.ietf.org/doc/html/rfc1706)  
7///  ATTENTION: this code doesn't validade the content of the NSAP RR, it just split the bytes in the correct order
8pub struct NSAP {
9    /// Authority and Format Identifier
10    pub afi: u8,
11    /// Initial Domain Identifier
12    pub idi: u16,
13    /// DSP Format Identifier
14    pub dfi: u8,
15    /// Administrative Authority
16    pub aa: u32,
17    /// Reserved
18    pub rsvd: u16,
19    /// Routing Domain Identifier
20    pub rd: u16,
21    /// Area Identifier
22    pub area: u16,
23    /// System Identifier
24    pub id: u64,
25    /// NSAP Selector
26    pub sel: u8,
27}
28
29impl RR for NSAP {
30    const TYPE_CODE: u16 = 22;
31}
32
33impl NSAP {
34    /// Transforms the inner data into its owned type
35    pub fn into_owned(self) -> Self {
36        self
37    }
38}
39
40impl<'a> WireFormat<'a> for NSAP {
41    fn parse(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
42    where
43        Self: Sized,
44    {
45        if data.len() < *position + 20 {
46            return Err(SimpleDnsError::InsufficientData);
47        }
48
49        let data = &data[*position..*position + 20];
50        *position += 20;
51
52        let afi = u8::from_be(data[0]);
53        let idi = u16::from_be_bytes([data[1], data[2]]);
54        let dfi = u8::from_be(data[3]);
55        let aa = u32::from_be_bytes([0, data[4], data[5], data[6]]);
56        let rsvd = u16::from_be_bytes([data[7], data[8]]);
57        let rd = u16::from_be_bytes([data[9], data[10]]);
58        let area = u16::from_be_bytes([data[11], data[12]]);
59
60        let id = u64::from_be_bytes([
61            0, 0, data[13], data[14], data[15], data[16], data[17], data[18],
62        ]);
63        let sel = u8::from_be(data[19]);
64
65        Ok(Self {
66            afi,
67            idi,
68            dfi,
69            aa,
70            rsvd,
71            rd,
72            area,
73            id,
74            sel,
75        })
76    }
77
78    fn write_to<T: std::io::Write>(&self, out: &mut T) -> crate::Result<()> {
79        out.write_all(&[self.afi.to_be()])?;
80        out.write_all(&self.idi.to_be_bytes())?;
81        out.write_all(&[self.dfi.to_be()])?;
82        out.write_all(&self.aa.to_be_bytes()[1..4])?;
83        out.write_all(&self.rsvd.to_be_bytes())?;
84        out.write_all(&self.rd.to_be_bytes())?;
85        out.write_all(&self.area.to_be_bytes())?;
86        out.write_all(&self.id.to_be_bytes()[2..8])?;
87        out.write_all(&[self.sel.to_be()])?;
88
89        Ok(())
90    }
91
92    fn len(&self) -> usize {
93        20
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use crate::{rdata::RData, ResourceRecord};
100
101    use super::*;
102
103    #[test]
104    pub fn parse_and_write_nsap() {
105        let nsap = NSAP {
106            afi: 47,
107            idi: 5,
108            dfi: 0x80,
109            aa: 0x005a00,
110            rsvd: 0x10,
111            rd: 0x1000,
112            area: 0x0020,
113            id: 0x00800a123456,
114            sel: 0x10,
115        };
116
117        let mut data = Vec::new();
118        assert!(nsap.write_to(&mut data).is_ok());
119
120        let nsap = NSAP::parse(&data, &mut 0);
121        assert!(nsap.is_ok());
122        let nsap = nsap.unwrap();
123
124        assert_eq!(data.len(), nsap.len());
125        assert_eq!(47, nsap.afi);
126        assert_eq!(5, nsap.idi);
127        assert_eq!(0x80, nsap.dfi);
128        assert_eq!(0x005a00, nsap.aa);
129        assert_eq!(0x10, nsap.rsvd);
130        assert_eq!(0x1000, nsap.rd);
131        assert_eq!(0x0020, nsap.area);
132        assert_eq!(0x00800a123456, nsap.id);
133        assert_eq!(0x10, nsap.sel);
134    }
135
136    #[test]
137    fn parse_sample() -> Result<(), Box<dyn std::error::Error>> {
138        let sample_file = std::fs::read("samples/zonefile/NSAP.sample")?;
139
140        let sample_rdata = match ResourceRecord::parse(&sample_file, &mut 0)?.rdata {
141            RData::NSAP(rdata) => rdata,
142            _ => unreachable!(),
143        };
144
145        //  0x47.0005.80.005a00.0000.0001.e133.ffffff000164.00
146        assert_eq!(0x47, sample_rdata.afi);
147        assert_eq!(0x0005, sample_rdata.idi);
148        assert_eq!(0x80, sample_rdata.dfi);
149        assert_eq!(0x005a00, sample_rdata.aa);
150        assert_eq!(0x00, sample_rdata.rsvd);
151        assert_eq!(0x0001, sample_rdata.rd);
152        assert_eq!(0xe133, sample_rdata.area);
153        assert_eq!(0xffffff000164, sample_rdata.id);
154        assert_eq!(0x00, sample_rdata.sel);
155
156        Ok(())
157    }
158}