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
26pub use std::net::Ipv6Addr;
27use std::{fmt, net::AddrParseError, ops::Deref, str};
28
29#[cfg(feature = "serde-config")]
30use serde::{Deserialize, Serialize};
31
32use crate::{
33    error::ProtoResult,
34    rr::{RData, RecordData, RecordType},
35    serialize::binary::{BinDecodable, BinDecoder, BinEncodable, BinEncoder},
36};
37
38/// The DNS AAAA record type, an IPv6 address
39#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
40#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
41pub struct AAAA(pub Ipv6Addr);
42
43impl AAAA {
44    /// Construct a new AAAA record with the 128 bits of IPv6 address
45    #[allow(clippy::too_many_arguments)]
46    pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Self {
47        Self(Ipv6Addr::new(a, b, c, d, e, f, g, h))
48    }
49}
50
51impl RecordData for AAAA {
52    fn try_from_rdata(data: RData) -> Result<Self, crate::rr::RData> {
53        match data {
54            RData::AAAA(ipv4) => Ok(ipv4),
55            _ => Err(data),
56        }
57    }
58
59    fn try_borrow(data: &RData) -> Option<&Self> {
60        match data {
61            RData::AAAA(ipv6) => Some(ipv6),
62            _ => None,
63        }
64    }
65
66    fn record_type(&self) -> RecordType {
67        RecordType::A
68    }
69
70    fn into_rdata(self) -> RData {
71        RData::AAAA(self)
72    }
73}
74
75impl BinEncodable for AAAA {
76    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
77        let segments = self.segments();
78
79        // TODO: this might be more efficient as a single write of the array
80        encoder.emit_u16(segments[0])?;
81        encoder.emit_u16(segments[1])?;
82        encoder.emit_u16(segments[2])?;
83        encoder.emit_u16(segments[3])?;
84        encoder.emit_u16(segments[4])?;
85        encoder.emit_u16(segments[5])?;
86        encoder.emit_u16(segments[6])?;
87        encoder.emit_u16(segments[7])?;
88        Ok(())
89    }
90}
91
92impl<'r> BinDecodable<'r> for AAAA {
93    fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self> {
94        // TODO: would this be more efficient as two u64 reads?
95        let a: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
96        let b: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
97        let c: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
98        let d: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
99        let e: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
100        let f: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
101        let g: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
102        let h: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
103
104        Ok(Ipv6Addr::new(a, b, c, d, e, f, g, h).into())
105    }
106}
107
108/// Read the RData from the given Decoder
109#[allow(clippy::many_single_char_names)]
110#[deprecated(note = "use the BinDecodable::read method instead")]
111pub fn read(decoder: &mut BinDecoder<'_>) -> ProtoResult<AAAA> {
112    <AAAA as BinDecodable>::read(decoder)
113}
114
115/// Write the RData from the given Decoder
116#[deprecated(note = "use the BinEncodable::emit method instead")]
117pub fn emit(encoder: &mut BinEncoder<'_>, address: &Ipv6Addr) -> ProtoResult<()> {
118    BinEncodable::emit(&AAAA::from(*address), encoder)
119}
120
121impl From<Ipv6Addr> for AAAA {
122    fn from(aaaa: Ipv6Addr) -> Self {
123        Self(aaaa)
124    }
125}
126
127impl From<AAAA> for Ipv6Addr {
128    fn from(aaaa: AAAA) -> Self {
129        aaaa.0
130    }
131}
132
133impl Deref for AAAA {
134    type Target = Ipv6Addr;
135
136    fn deref(&self) -> &Self::Target {
137        &self.0
138    }
139}
140
141impl fmt::Display for AAAA {
142    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
143        write!(f, "{}", self.0)
144    }
145}
146
147impl str::FromStr for AAAA {
148    type Err = AddrParseError;
149    fn from_str(s: &str) -> Result<Self, AddrParseError> {
150        Ipv6Addr::from_str(s).map(From::from)
151    }
152}
153
154#[cfg(test)]
155mod tests {
156    use std::str::FromStr;
157
158    use super::*;
159    use crate::serialize::binary::bin_tests::{test_emit_data_set, test_read_data_set};
160
161    fn get_data() -> Vec<(AAAA, Vec<u8>)> {
162        vec![
163            (
164                AAAA::from_str("::").unwrap(),
165                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
166            ), // base case
167            (
168                AAAA::from_str("1::").unwrap(),
169                vec![0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
170            ),
171            (
172                AAAA::from_str("0:1::").unwrap(),
173                vec![0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
174            ),
175            (
176                AAAA::from_str("0:0:1::").unwrap(),
177                vec![0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
178            ),
179            (
180                AAAA::from_str("0:0:0:1::").unwrap(),
181                vec![0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
182            ),
183            (
184                AAAA::from_str("::1:0:0:0").unwrap(),
185                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
186            ),
187            (
188                AAAA::from_str("::1:0:0").unwrap(),
189                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
190            ),
191            (
192                AAAA::from_str("::1:0").unwrap(),
193                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
194            ),
195            (
196                AAAA::from_str("::1").unwrap(),
197                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
198            ),
199            (
200                AAAA::from_str("::127.0.0.1").unwrap(),
201                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1],
202            ),
203            (
204                AAAA::from_str("FF00::192.168.64.32").unwrap(),
205                vec![255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 64, 32],
206            ),
207        ]
208    }
209
210    #[test]
211    fn test_read() {
212        test_read_data_set(get_data(), |ref mut d| AAAA::read(d));
213    }
214
215    #[test]
216    fn test_emit() {
217        test_emit_data_set(get_data(), |e, d| d.emit(e));
218    }
219}