1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
//! Resource record data.
//!
//! Each resource record type has it’s own definition of the content and
//! formatting of its data. This module provides the basics for implementing
//! specific types for this record data. The concrete implementations for
//! well-known record types live in the top-level [domain::rdata] module.
//!
//! There are three traits herein: Any type that represents record data
//! implements [`RecordData`]. Such a type can be added to a message. If
//! the data can also be parsed from an existing message, the type in addition
//! implements [`ParseRecordData`]. Because most types are implementations
//! for exactly one record type, the [`RtypeRecordData`] trait simplifies
//! implementations for such types.
//!
//! The module also provides a type, [`UnknownRecordData`], that can be used
//! to deal with record types whose specification is not known (or has not
//! been implemented yet).
//!
//! [`RecordData`]: trait.RecordData.html
//! [`ParseRecordData`]: trait.ParseRecordData.html
//! [`RtypeRecordData`]: trait.RtypeRecordData.html
//! [`UnknownRecorddata`]: struct.UnknownRecordData.html
//! [domain::rdata]: ../../rdata/index.html
use super::cmp::CanonicalOrd;
use super::iana::Rtype;
use super::octets::{
Compose, OctetsBuilder, OctetsFrom, OctetsRef, Parse, ParseError, Parser,
ShortBuf,
};
#[cfg(feature = "master")]
use crate::master::scan::{
CharSource, Scan, ScanError, Scanner, SyntaxError,
};
#[cfg(feature = "master")]
use bytes::{BufMut, Bytes, BytesMut};
use core::cmp::Ordering;
use core::fmt;
//----------- RecordData -----------------------------------------------------
/// A type that represents record data.
///
/// The type needs to be able to encode the record data into a DNS message
/// via the [`Compose`] trait. In addition, it needs to be
/// able to provide the record type of a record with a value’s data via the
/// [`rtype`] method.
///
/// [`Compose`]: ../compose/trait.Compose.html
/// [`rtype`]: #method.rtype
pub trait RecordData: Compose + Sized {
/// Returns the record type associated with this record data instance.
///
/// This is a method rather than an associated function to allow one
/// type to be used for several real record types.
fn rtype(&self) -> Rtype;
}
//------------ ParseRecordData -----------------------------------------------
/// A record data type that can be parsed from a message.
///
/// When record data types are generic – typically over a domain name type –,
/// they may not in all cases be parseable. They may still represent record
/// data to be used when constructing the message.
///
/// To reflect this asymmetry, parsing of record data has its own trait.
pub trait ParseRecordData<Ref>: RecordData {
/// Parses the record data.
///
/// The record data is for a record of type `rtype`. The function may
/// decide whether it wants to parse data for that type. It should return
/// `Ok(None)` if it doesn’t.
///
/// The `parser` is positioned at the beginning of the record data and is
/// is limited to the length of the data. The method only needs to parse
/// as much data as it needs. The caller has to make sure to deal with
/// data remaining in the parser.
///
/// If the function doesn’t want to process the data, it must not touch
/// the parser. In particual, it must not advance it.
fn parse_data(
rtype: Rtype,
parser: &mut Parser<Ref>,
) -> Result<Option<Self>, ParseError>;
}
//------------ RtypeRecordData -----------------------------------------------
/// A type for record data for a single specific record type.
///
/// If a record data type only ever processes one single record type, things
/// can be a lot simpler. The type can be given as an associated constant
/// which can be used to implement [`RecordData`]. In addition, parsing can
/// be done atop an implementation of the [`Parse`] trait.
///
/// This trait provides such a simplification by providing [`RecordData`]
/// for all types implementing it and the other requirements for
/// [`RecordData`]. If the type additionally implements [`Parse`], it will
/// also receive a [`ParseRecordData`] implementation.
///
/// [`RecordData`]: trait.RecordData.html
/// [`ParseRecordData`]: trait.ParseRecordData.html
/// [`Parse`]: ../parse/trait.Parse.html
pub trait RtypeRecordData {
/// The record type of a value of this type.
const RTYPE: Rtype;
}
impl<T: RtypeRecordData + Compose + Sized> RecordData for T {
fn rtype(&self) -> Rtype {
Self::RTYPE
}
}
impl<Octets, T> ParseRecordData<Octets> for T
where
T: RtypeRecordData + Parse<Octets> + Compose + Sized,
{
fn parse_data(
rtype: Rtype,
parser: &mut Parser<Octets>,
) -> Result<Option<Self>, ParseError> {
if rtype == Self::RTYPE {
Self::parse(parser).map(Some)
} else {
Ok(None)
}
}
}
//------------ UnknownRecordData ---------------------------------------------
/// A type for parsing any type of record data.
///
/// This type accepts any record type and stores the plain, unparsed record
/// data as an octets sequence.
///
/// Because some record types allow compressed domain names in their record
/// data, this type cannot be used safely with these record types. For these
/// record types, the structure of the content needs to be known.
///
/// [RFC 3597] limits the types for which compressed names are allowed in the
/// record data to those defined in [RFC 1035] itself. Specific types for all
/// these record types exist in
/// [`domain::rdata::rfc1035`][crate::rdata::rfc1035].
///
/// Ultimately, you should only use this type for record types for which there
/// is no implementation available in this crate. The two types
/// [`AllRecordData`] and [`MasterRecordData`] provide a convenient way to
/// always use the correct record data type.
///
/// [`AllRecordData`]: ../../rdata/enum.AllRecordData.html
/// [`MasterRecordData`]: ../../rdata/enum.MasterRecordData.html
/// [RFC 1035]: https://tools.ietf.org/html/rfc1035
/// [RFC 3597]: https://tools.ietf.org/html/rfc3597
/// [`domain::rdata::rfc1035]: ../../rdata/rfc1035/index.html
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct UnknownRecordData<Octets> {
/// The record type of this data.
rtype: Rtype,
/// The record data.
#[cfg_attr(
feature = "serde",
serde(
serialize_with = "crate::base::octets::SerializeOctets::serialize_octets",
deserialize_with = "crate::base::octets::DeserializeOctets::deserialize_octets",
bound(
serialize = "Octets: crate::base::octets::SerializeOctets",
deserialize = "Octets: crate::base::octets::DeserializeOctets<'de>",
)
)
)]
data: Octets,
}
impl<Octets> UnknownRecordData<Octets> {
/// Creates generic record data from a bytes value contain the data.
pub fn from_octets(rtype: Rtype, data: Octets) -> Self {
UnknownRecordData { rtype, data }
}
/// Returns the record type this data is for.
pub fn rtype(&self) -> Rtype {
self.rtype
}
/// Returns a reference to the record data.
pub fn data(&self) -> &Octets {
&self.data
}
}
#[cfg(feature = "master")]
impl UnknownRecordData<Bytes> {
/// Scans the record data.
///
/// This isn’t implemented via `Scan`, because we need the record type.
pub fn scan<C: CharSource>(
rtype: Rtype,
scanner: &mut Scanner<C>,
) -> Result<Self, ScanError> {
scanner.skip_literal("\\#")?;
let mut len = u16::scan(scanner)? as usize;
let mut res = BytesMut::with_capacity(len);
while len > 0 {
len = scanner.scan_word(
(&mut res, len, None), // buffer and optional first char
|&mut (ref mut res, ref mut len, ref mut first), symbol| {
if *len == 0 {
return Err(SyntaxError::LongGenericData);
}
let ch = symbol.into_digit(16)? as u8;
if let Some(ch1) = *first {
res.put_u8(ch1 << 4 | ch);
*len -= 1;
} else {
*first = Some(ch)
}
Ok(())
},
|(_, len, first)| {
if first.is_some() {
Err(SyntaxError::UnevenHexString)
} else {
Ok(len)
}
},
)?
}
Ok(UnknownRecordData::from_octets(rtype, res.freeze()))
}
}
//--- OctetsFrom
impl<Octets, SrcOctets> OctetsFrom<UnknownRecordData<SrcOctets>>
for UnknownRecordData<Octets>
where
Octets: OctetsFrom<SrcOctets>,
{
fn octets_from(
source: UnknownRecordData<SrcOctets>,
) -> Result<Self, ShortBuf> {
Ok(UnknownRecordData {
rtype: source.rtype,
data: Octets::octets_from(source.data)?,
})
}
}
//--- PartialEq and Eq
impl<Octets, Other> PartialEq<UnknownRecordData<Other>>
for UnknownRecordData<Octets>
where
Octets: AsRef<[u8]>,
Other: AsRef<[u8]>,
{
fn eq(&self, other: &UnknownRecordData<Other>) -> bool {
self.data.as_ref().eq(other.data.as_ref())
}
}
impl<Octets: AsRef<[u8]>> Eq for UnknownRecordData<Octets> {}
//--- PartialOrd, CanonicalOrd, and Ord
impl<Octets, Other> PartialOrd<UnknownRecordData<Other>>
for UnknownRecordData<Octets>
where
Octets: AsRef<[u8]>,
Other: AsRef<[u8]>,
{
fn partial_cmp(
&self,
other: &UnknownRecordData<Other>,
) -> Option<Ordering> {
self.data.as_ref().partial_cmp(other.data.as_ref())
}
}
impl<Octets, Other> CanonicalOrd<UnknownRecordData<Other>>
for UnknownRecordData<Octets>
where
Octets: AsRef<[u8]>,
Other: AsRef<[u8]>,
{
fn canonical_cmp(&self, other: &UnknownRecordData<Other>) -> Ordering {
self.data.as_ref().cmp(other.data.as_ref())
}
}
impl<Octets: AsRef<[u8]>> Ord for UnknownRecordData<Octets> {
fn cmp(&self, other: &Self) -> Ordering {
self.data.as_ref().cmp(other.data.as_ref())
}
}
//--- Compose, and Compress
impl<Octets: AsRef<[u8]>> Compose for UnknownRecordData<Octets> {
fn compose<T: OctetsBuilder>(
&self,
target: &mut T,
) -> Result<(), ShortBuf> {
target.append_slice(self.data.as_ref())
}
}
//--- RecordData and ParseRecordData
impl<Octets: AsRef<[u8]>> RecordData for UnknownRecordData<Octets> {
fn rtype(&self) -> Rtype {
self.rtype
}
}
impl<Octets, Ref> ParseRecordData<Ref> for UnknownRecordData<Octets>
where
Octets: AsRef<[u8]>,
Ref: OctetsRef<Range = Octets>,
{
fn parse_data(
rtype: Rtype,
parser: &mut Parser<Ref>,
) -> Result<Option<Self>, ParseError> {
let rdlen = parser.remaining();
parser
.parse_octets(rdlen)
.map(|data| Some(Self::from_octets(rtype, data)))
}
}
//--- Display
impl<Octets: AsRef<[u8]>> fmt::Display for UnknownRecordData<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\\# {}", self.data.as_ref().len())?;
for ch in self.data.as_ref() {
write!(f, " {:02x}", *ch)?
}
Ok(())
}
}
//--- Debug
impl<Octets: AsRef<[u8]>> fmt::Debug for UnknownRecordData<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("UnknownRecordData(")?;
fmt::Display::fmt(self, f)?;
f.write_str(")")
}
}