simple_dns/dns/rdata/
nsap.rs1use crate::{dns::WireFormat, SimpleDnsError};
2
3use super::RR;
4
5#[derive(Debug, PartialEq, Eq, Hash, Clone)]
6pub struct NSAP {
9 pub afi: u8,
11 pub idi: u16,
13 pub dfi: u8,
15 pub aa: u32,
17 pub rsvd: u16,
19 pub rd: u16,
21 pub area: u16,
23 pub id: u64,
25 pub sel: u8,
27}
28
29impl RR for NSAP {
30 const TYPE_CODE: u16 = 22;
31}
32
33impl NSAP {
34 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 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}