hickory_proto/rr/rdata/
aaaa.rs

1// Copyright 2015-2023 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// https://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! IPv6 address record data
9//!
10//! [RFC 3596, DNS Extensions to Support IPv6, October 2003](https://tools.ietf.org/html/rfc3596)
11//!
12//! ```text
13//! 2.1 AAAA record type
14//!
15//!   The AAAA resource record type is a record specific to the Internet
16//!   class that stores a single IPv6 address.
17//!
18//!   The IANA assigned value of the type is 28 (decimal).
19//!
20//! 2.2 AAAA data format
21//!
22//!   A 128 bit IPv6 address is encoded in the data portion of an AAAA
23//!   resource record in network byte order (high-order byte first).
24//! ```
25
26#[cfg(not(feature = "std"))]
27use core::net::AddrParseError;
28use core::{fmt, ops::Deref, str};
29#[cfg(feature = "std")]
30use std::net::AddrParseError;
31
32#[cfg(not(feature = "std"))]
33pub use core::net::Ipv6Addr;
34#[cfg(feature = "std")]
35pub use std::net::Ipv6Addr;
36
37#[cfg(feature = "serde")]
38use serde::{Deserialize, Serialize};
39
40use crate::{
41    error::ProtoResult,
42    rr::{RData, RecordData, RecordType},
43    serialize::binary::{BinDecodable, BinDecoder, BinEncodable, BinEncoder},
44};
45
46/// The DNS AAAA record type, an IPv6 address
47#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
48#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
49pub struct AAAA(pub Ipv6Addr);
50
51impl AAAA {
52    /// Construct a new AAAA record with the 128 bits of IPv6 address
53    #[allow(clippy::too_many_arguments)]
54    pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Self {
55        Self(Ipv6Addr::new(a, b, c, d, e, f, g, h))
56    }
57}
58
59impl RecordData for AAAA {
60    fn try_from_rdata(data: RData) -> Result<Self, crate::rr::RData> {
61        match data {
62            RData::AAAA(ipv4) => Ok(ipv4),
63            _ => Err(data),
64        }
65    }
66
67    fn try_borrow(data: &RData) -> Option<&Self> {
68        match data {
69            RData::AAAA(ipv6) => Some(ipv6),
70            _ => None,
71        }
72    }
73
74    fn record_type(&self) -> RecordType {
75        RecordType::AAAA
76    }
77
78    fn into_rdata(self) -> RData {
79        RData::AAAA(self)
80    }
81}
82
83impl BinEncodable for AAAA {
84    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
85        let segments = self.segments();
86
87        // TODO: this might be more efficient as a single write of the array
88        encoder.emit_u16(segments[0])?;
89        encoder.emit_u16(segments[1])?;
90        encoder.emit_u16(segments[2])?;
91        encoder.emit_u16(segments[3])?;
92        encoder.emit_u16(segments[4])?;
93        encoder.emit_u16(segments[5])?;
94        encoder.emit_u16(segments[6])?;
95        encoder.emit_u16(segments[7])?;
96        Ok(())
97    }
98}
99
100impl<'r> BinDecodable<'r> for AAAA {
101    fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self> {
102        // TODO: would this be more efficient as two u64 reads?
103        let a: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
104        let b: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
105        let c: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
106        let d: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
107        let e: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
108        let f: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
109        let g: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
110        let h: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
111
112        Ok(Ipv6Addr::new(a, b, c, d, e, f, g, h).into())
113    }
114}
115
116/// Read the RData from the given Decoder
117#[allow(clippy::many_single_char_names)]
118#[deprecated(note = "use the BinDecodable::read method instead")]
119pub fn read(decoder: &mut BinDecoder<'_>) -> ProtoResult<AAAA> {
120    <AAAA as BinDecodable>::read(decoder)
121}
122
123/// Write the RData from the given Decoder
124#[deprecated(note = "use the BinEncodable::emit method instead")]
125pub fn emit(encoder: &mut BinEncoder<'_>, address: &Ipv6Addr) -> ProtoResult<()> {
126    BinEncodable::emit(&AAAA::from(*address), encoder)
127}
128
129impl From<Ipv6Addr> for AAAA {
130    fn from(aaaa: Ipv6Addr) -> Self {
131        Self(aaaa)
132    }
133}
134
135impl From<AAAA> for Ipv6Addr {
136    fn from(aaaa: AAAA) -> Self {
137        aaaa.0
138    }
139}
140
141impl Deref for AAAA {
142    type Target = Ipv6Addr;
143
144    fn deref(&self) -> &Self::Target {
145        &self.0
146    }
147}
148
149impl fmt::Display for AAAA {
150    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
151        write!(f, "{}", self.0)
152    }
153}
154
155impl str::FromStr for AAAA {
156    type Err = AddrParseError;
157    fn from_str(s: &str) -> Result<Self, AddrParseError> {
158        Ipv6Addr::from_str(s).map(From::from)
159    }
160}
161
162#[cfg(test)]
163mod tests {
164    use alloc::vec::Vec;
165    use core::str::FromStr;
166
167    use super::*;
168    use crate::serialize::binary::bin_tests::{test_emit_data_set, test_read_data_set};
169
170    fn get_data() -> Vec<(AAAA, Vec<u8>)> {
171        vec![
172            (
173                AAAA::from_str("::").unwrap(),
174                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
175            ), // base case
176            (
177                AAAA::from_str("1::").unwrap(),
178                vec![0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
179            ),
180            (
181                AAAA::from_str("0:1::").unwrap(),
182                vec![0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
183            ),
184            (
185                AAAA::from_str("0:0:1::").unwrap(),
186                vec![0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
187            ),
188            (
189                AAAA::from_str("0:0:0:1::").unwrap(),
190                vec![0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
191            ),
192            (
193                AAAA::from_str("::1:0:0:0").unwrap(),
194                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
195            ),
196            (
197                AAAA::from_str("::1:0:0").unwrap(),
198                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
199            ),
200            (
201                AAAA::from_str("::1:0").unwrap(),
202                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
203            ),
204            (
205                AAAA::from_str("::1").unwrap(),
206                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
207            ),
208            (
209                AAAA::from_str("::127.0.0.1").unwrap(),
210                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1],
211            ),
212            (
213                AAAA::from_str("FF00::192.168.64.32").unwrap(),
214                vec![255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 64, 32],
215            ),
216        ]
217    }
218
219    #[test]
220    fn test_read() {
221        test_read_data_set(get_data(), |mut d| AAAA::read(&mut d));
222    }
223
224    #[test]
225    fn test_emit() {
226        test_emit_data_set(get_data(), |e, d| d.emit(e));
227    }
228}