simple_dns/dns/rdata/
aaaa.rs

1use crate::dns::WireFormat;
2use std::{convert::TryInto, net::Ipv6Addr};
3
4use super::RR;
5
6/// Represents a Resource Address (IPv6) [rfc3596](https://tools.ietf.org/html/rfc3596)
7#[derive(Debug, PartialEq, Eq, Hash, Clone)]
8pub struct AAAA {
9    /// a 128 bit ip address
10    pub address: u128,
11}
12
13impl RR for AAAA {
14    const TYPE_CODE: u16 = 28;
15}
16
17impl<'a> WireFormat<'a> for AAAA {
18    fn parse(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
19    where
20        Self: Sized,
21    {
22        let address = u128::from_be_bytes(data[*position..*position + 16].try_into()?);
23        *position += 16;
24        Ok(Self { address })
25    }
26
27    fn len(&self) -> usize {
28        16
29    }
30
31    fn write_to<T: std::io::Write>(&self, out: &mut T) -> crate::Result<()> {
32        out.write_all(&self.address.to_be_bytes())
33            .map_err(crate::SimpleDnsError::from)
34    }
35}
36
37impl AAAA {
38    /// Transforms the inner data into its owned type
39    pub fn into_owned(self) -> Self {
40        self
41    }
42}
43
44impl From<Ipv6Addr> for AAAA {
45    fn from(ip: Ipv6Addr) -> Self {
46        Self { address: ip.into() }
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use std::{net::Ipv6Addr, str::FromStr};
53
54    use crate::{rdata::RData, ResourceRecord};
55
56    use super::*;
57
58    #[test]
59    fn parse_and_write_a() {
60        let address = std::net::Ipv6Addr::from_str("FF02::FB").unwrap();
61        let aaaa = AAAA {
62            address: address.into(),
63        };
64
65        let mut bytes = Vec::new();
66        assert!(aaaa.write_to(&mut bytes).is_ok());
67
68        let aaaa = AAAA::parse(&bytes, &mut 0);
69        assert!(aaaa.is_ok());
70        let aaaa = aaaa.unwrap();
71
72        assert_eq!(address, Ipv6Addr::from(aaaa.address));
73        assert_eq!(bytes.len(), aaaa.len());
74    }
75
76    #[test]
77    fn parse_sample() -> Result<(), Box<dyn std::error::Error>> {
78        let sample_file = std::fs::read("samples/zonefile/AAAA.sample")?;
79        let sample_ip: u128 = "fd92:7065:b8e:ffff::5".parse::<Ipv6Addr>()?.into();
80
81        let sample_rdata = match ResourceRecord::parse(&sample_file, &mut 0)?.rdata {
82            RData::AAAA(rdata) => rdata,
83            _ => unreachable!(),
84        };
85
86        assert_eq!(sample_rdata.address, sample_ip);
87        Ok(())
88    }
89}