simple_dns/dns/rdata/
ipseckey.rs

1use super::RR;
2use crate::{
3    bytes_buffer::BytesBuffer,
4    dns::WireFormat,
5    lib::{Cow, Ipv4Addr, Ipv6Addr},
6    lib::Write,
7    Name,
8};
9
10/// IPSECKEY record type stores information about IPsec key material
11#[derive(Debug, PartialEq, Eq, Hash, Clone)]
12pub struct IPSECKEY<'a> {
13    /// Precedence for this record, lower values are preferred
14    pub precedence: u8,
15    /// Public key algorithm (1=DSA, 2=RSA)
16    pub algorithm: u8,
17    /// Domain name of the gateway
18    pub gateway: Gateway<'a>,
19    /// The public key material
20    pub public_key: Cow<'a, [u8]>,
21}
22
23/// Gateway type for IPSECKEY records
24#[derive(Debug, PartialEq, Eq, Hash, Clone)]
25pub enum Gateway<'a> {
26    /// No gateway
27    None,
28    /// IPv4 gateway
29    IPv4(Ipv4Addr),
30    /// IPv6 gateway
31    IPv6(Ipv6Addr),
32    /// Domain gateway
33    Domain(Name<'a>),
34}
35
36impl Gateway<'_> {
37    /// Transforms the inner data into its owned type
38    pub fn into_owned<'b>(self) -> Gateway<'b> {
39        match self {
40            Gateway::None => Gateway::None,
41            Gateway::IPv4(x) => Gateway::IPv4(x),
42            Gateway::IPv6(x) => Gateway::IPv6(x),
43            Gateway::Domain(x) => Gateway::Domain(x.into_owned()),
44        }
45    }
46}
47
48impl RR for IPSECKEY<'_> {
49    const TYPE_CODE: u16 = 45;
50}
51
52impl<'a> WireFormat<'a> for IPSECKEY<'a> {
53    const MINIMUM_LEN: usize = 5;
54
55    fn parse(data: &mut BytesBuffer<'a>) -> crate::Result<Self>
56    where
57        Self: Sized,
58    {
59        let precedence = data.get_u8()?;
60        let gateway_type = data.get_u8()?;
61        let algorithm = data.get_u8()?;
62        let gateway = match gateway_type {
63            0 => Gateway::None,
64            1 => Gateway::IPv4(data.get_u32()?.into()),
65            2 => Gateway::IPv6(data.get_u128()?.into()),
66            3 => Gateway::Domain(Name::parse(data)?),
67            _ => return Err(crate::SimpleDnsError::AttemptedInvalidOperation),
68        };
69        let public_key = data.get_remaining();
70        Ok(Self {
71            precedence,
72            algorithm,
73            gateway,
74            public_key: Cow::Borrowed(public_key),
75        })
76    }
77
78    fn write_to<T: Write>(&self, out: &mut T) -> crate::Result<()> {
79        match &self.gateway {
80            Gateway::None => {
81                out.write_all(&[self.precedence, 0, self.algorithm])?;
82            }
83            Gateway::IPv4(ipv4_addr) => {
84                out.write_all(&[self.precedence, 1, self.algorithm])?;
85                out.write_all(&ipv4_addr.octets())?
86            }
87            Gateway::IPv6(ipv6_addr) => {
88                out.write_all(&[self.precedence, 2, self.algorithm])?;
89                out.write_all(&ipv6_addr.octets())?
90            }
91            Gateway::Domain(name) => {
92                out.write_all(&[self.precedence, 3, self.algorithm])?;
93                name.write_to(out)?
94            }
95        };
96        out.write_all(&self.public_key)?;
97        Ok(())
98    }
99
100    fn len(&self) -> usize {
101        (match &self.gateway {
102            Gateway::None => 0,
103            Gateway::IPv4(_) => 4,
104            Gateway::IPv6(_) => 16,
105            Gateway::Domain(name) => name.len(),
106        }) + self.public_key.len()
107            + Self::MINIMUM_LEN
108    }
109}
110
111impl IPSECKEY<'_> {
112    /// Transforms the inner data into its owned type
113    pub fn into_owned<'b>(self) -> IPSECKEY<'b> {
114        IPSECKEY {
115            precedence: self.precedence,
116            algorithm: self.algorithm,
117            gateway: self.gateway.into_owned(),
118            public_key: self.public_key.into_owned().into(),
119        }
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126    use crate::lib::Vec;
127
128    #[test]
129    fn parse_and_write_ipseckey() {
130        let ipseckey = IPSECKEY {
131            precedence: 10,
132            algorithm: 2,
133            gateway: Gateway::IPv4(Ipv4Addr::new(192,0,2,38)),
134            public_key: Cow::Borrowed(b"\x01\x03\x51\x53\x79\x86\xed\x35\x53\x3b\x60\x64\x47\x8e\xee\xb2\x7b\x5b\xd7\x4d\xae\x14\x9b\x6e\x81\xba\x3a\x05\x21\xaf\x82\xab\x78\x01"),
135        };
136
137        let mut data = Vec::new();
138        ipseckey.write_to(&mut data).unwrap();
139
140        let ipseckey = IPSECKEY::parse(&mut (&data[..]).into()).unwrap();
141        assert_eq!(ipseckey.precedence, 10);
142        assert_eq!(ipseckey.algorithm, 2);
143        assert_eq!(
144            ipseckey.gateway,
145            Gateway::IPv4(Ipv4Addr::new(192, 0, 2, 38))
146        );
147        assert_eq!(*ipseckey.public_key, *b"\x01\x03\x51\x53\x79\x86\xed\x35\x53\x3b\x60\x64\x47\x8e\xee\xb2\x7b\x5b\xd7\x4d\xae\x14\x9b\x6e\x81\xba\x3a\x05\x21\xaf\x82\xab\x78\x01");
148    }
149
150    #[test]
151    #[cfg(feature = "std")]
152    fn parse_sample() -> Result<(), Box<dyn std::error::Error>> {
153        use crate::{rdata::RData, ResourceRecord};
154        let sample_file = std::fs::read("samples/zonefile/IPSECKEY.sample")?;
155
156        let sample_rdata = match ResourceRecord::parse(&mut (&sample_file[..]).into())?.rdata {
157            RData::IPSECKEY(rdata) => rdata,
158            _ => unreachable!(),
159        };
160
161        assert_eq!(sample_rdata.precedence, 10);
162        assert_eq!(sample_rdata.algorithm, 2);
163        assert_eq!(
164            sample_rdata.gateway,
165            Gateway::IPv4(Ipv4Addr::new(192, 0, 2, 38))
166        );
167        assert_eq!(*sample_rdata.public_key, *b"\x01\x03\x51\x53\x79\x86\xed\x35\x53\x3b\x60\x64\x47\x8e\xee\xb2\x7b\x5b\xd7\x4d\xae\x14\x9b\x6e\x81\xba\x3a\x05\x21\xaf\x82\xab\x78\x01");
168
169        Ok(())
170    }
171}