Skip to main content

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
26use alloc::string::ToString;
27pub use core::net::Ipv6Addr;
28use core::{
29    fmt,
30    net::AddrParseError,
31    ops::Deref,
32    str::{self, FromStr},
33};
34
35#[cfg(feature = "serde")]
36use serde::{Deserialize, Serialize};
37
38use crate::{
39    error::ProtoResult,
40    rr::{RData, RecordData, RecordType},
41    serialize::{
42        binary::{BinDecodable, BinDecoder, BinEncodable, BinEncoder, DecodeError},
43        txt::ParseError,
44    },
45};
46
47/// The DNS AAAA record type, an IPv6 address
48#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
49#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
50pub struct AAAA(pub Ipv6Addr);
51
52impl AAAA {
53    /// Construct a new AAAA record with the 128 bits of IPv6 address
54    #[allow(clippy::too_many_arguments)]
55    pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Self {
56        Self(Ipv6Addr::new(a, b, c, d, e, f, g, h))
57    }
58
59    /// Parse the RData from a set of Tokens
60    pub(crate) fn from_tokens<'i, I: Iterator<Item = &'i str>>(
61        mut tokens: I,
62    ) -> Result<Self, ParseError> {
63        let address: Ipv6Addr = tokens
64            .next()
65            .ok_or_else(|| ParseError::MissingToken("ipv6 address".to_string()))
66            .and_then(|s| Ipv6Addr::from_str(s).map_err(Into::into))?;
67        Ok(address.into())
68    }
69}
70
71impl RecordData for AAAA {
72    fn try_borrow(data: &RData) -> Option<&Self> {
73        match data {
74            RData::AAAA(ipv6) => Some(ipv6),
75            _ => None,
76        }
77    }
78
79    fn record_type(&self) -> RecordType {
80        RecordType::AAAA
81    }
82
83    fn into_rdata(self) -> RData {
84        RData::AAAA(self)
85    }
86}
87
88impl BinEncodable for AAAA {
89    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
90        let segments = self.segments();
91
92        // TODO: this might be more efficient as a single write of the array
93        encoder.emit_u16(segments[0])?;
94        encoder.emit_u16(segments[1])?;
95        encoder.emit_u16(segments[2])?;
96        encoder.emit_u16(segments[3])?;
97        encoder.emit_u16(segments[4])?;
98        encoder.emit_u16(segments[5])?;
99        encoder.emit_u16(segments[6])?;
100        encoder.emit_u16(segments[7])?;
101        Ok(())
102    }
103}
104
105impl<'r> BinDecodable<'r> for AAAA {
106    fn read(decoder: &mut BinDecoder<'r>) -> Result<Self, DecodeError> {
107        // TODO: would this be more efficient as two u64 reads?
108        let a: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
109        let b: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
110        let c: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
111        let d: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
112        let e: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
113        let f: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
114        let g: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
115        let h: u16 = decoder.read_u16()?.unverified(/*valid as any u16*/);
116
117        Ok(Ipv6Addr::new(a, b, c, d, e, f, g, h).into())
118    }
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 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 alloc::vec::Vec;
157    use core::str::FromStr;
158
159    use super::*;
160    use crate::serialize::binary::bin_tests::{test_emit_data_set, test_read_data_set};
161
162    fn get_data() -> Vec<(AAAA, Vec<u8>)> {
163        vec![
164            (
165                AAAA::from_str("::").unwrap(),
166                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
167            ), // base case
168            (
169                AAAA::from_str("1::").unwrap(),
170                vec![0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
171            ),
172            (
173                AAAA::from_str("0:1::").unwrap(),
174                vec![0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
175            ),
176            (
177                AAAA::from_str("0:0:1::").unwrap(),
178                vec![0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
179            ),
180            (
181                AAAA::from_str("0:0:0:1::").unwrap(),
182                vec![0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
183            ),
184            (
185                AAAA::from_str("::1:0:0:0").unwrap(),
186                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
187            ),
188            (
189                AAAA::from_str("::1:0:0").unwrap(),
190                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
191            ),
192            (
193                AAAA::from_str("::1:0").unwrap(),
194                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
195            ),
196            (
197                AAAA::from_str("::1").unwrap(),
198                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
199            ),
200            (
201                AAAA::from_str("::127.0.0.1").unwrap(),
202                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1],
203            ),
204            (
205                AAAA::from_str("FF00::192.168.64.32").unwrap(),
206                vec![255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 64, 32],
207            ),
208        ]
209    }
210
211    #[test]
212    fn test_read() {
213        test_read_data_set(get_data(), |mut d| AAAA::read(&mut d));
214    }
215
216    #[test]
217    fn test_emit() {
218        test_emit_data_set(get_data(), |e, d| d.emit(e));
219    }
220}