1//! EDNS Options for signalling zone expire times.
2//!
3//! The option in this module, [`Expire`], allows a authoritative server to
4//! signal when a zone expires independently of the SOA’s expire field. This
5//! allows to determine the expire time when a secondary server is updating
6//! a zone from another secondary server rather than directly from the
7//! primary.
8//!
9//! This option is defined in [RFC 7314](https://tools.ietf.org/html/rfc7314).
1011use core::fmt;
12use super::super::iana::OptionCode;
13use super::super::message_builder::OptBuilder;
14use super::super::wire::{Compose, Composer, Parse, ParseError};
15use super::{Opt, OptData, ComposeOptData, ParseOptData};
16use octseq::builder::OctetsBuilder;
17use octseq::octets::Octets;
18use octseq::parse::Parser;
192021//------------ Expire --------------------------------------------------------
2223/// Option data for the Expire EDNS option.
24///
25/// The option’s data consists of an optional `u32`. The value is omitted if
26/// the option is added to a query to request it being included by the server
27/// in an answer. In this answer the value should be present and indicates the
28/// expire time of the zone on the server.
29///
30/// See [RFC 7314](https://tools.ietf.org/html/rfc7314) for details.
31#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
32pub struct Expire(Option<u32>);
3334impl Expire {
35/// Creates a new expire option with the given optional expire value.
36#[must_use]
37pub fn new(expire: Option<u32>) -> Self {
38 Expire(expire)
39 }
4041/// Returns the content of the optional expire value.
42#[must_use]
43pub fn expire(self) -> Option<u32> {
44self.0
45}
4647/// Parses a value from its wire format.
48pub fn parse<Octs: AsRef<[u8]>>(
49 parser: &mut Parser<Octs>
50 ) -> Result<Self, ParseError> {
51if parser.remaining() == 0 {
52Ok(Expire::new(None))
53 }
54else {
55 u32::parse(parser).map(|res| Expire::new(Some(res)))
56 }
57 }
58}
5960//--- OptData
6162impl OptData for Expire {
63fn code(&self) -> OptionCode {
64 OptionCode::Expire
65 }
66}
6768impl<'a, Octs: AsRef<[u8]>> ParseOptData<'a, Octs> for Expire {
69fn parse_option(
70 code: OptionCode,
71 parser: &mut Parser<'a, Octs>,
72 ) -> Result<Option<Self>, ParseError> {
73if code == OptionCode::Expire {
74Self::parse(parser).map(Some)
75 }
76else {
77Ok(None)
78 }
79 }
80}
8182impl ComposeOptData for Expire {
83fn compose_len(&self) -> u16 {
84match self.0 {
85Some(_) => u32::COMPOSE_LEN,
86None => 0,
87 }
88 }
8990fn compose_option<Target: OctetsBuilder + ?Sized>(
91&self, target: &mut Target
92 ) -> Result<(), Target::AppendError> {
93if let Some(value) = self.0 {
94 value.compose(target)?;
95 }
96Ok(())
97 }
98}
99100//--- Display
101102impl fmt::Display for Expire {
103fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104match self.0 {
105Some(expire) => expire.fmt(f),
106None => Ok(())
107 }
108 }
109}
110111//--- Extended Opt and OptBuilder
112113impl<Octs: Octets> Opt<Octs> {
114/// Returns the content of the Expire option if present.
115 ///
116 /// The Expire option allows an authoritative server to signal its own
117 /// expiry time of a zone.
118pub fn expire(&self) -> Option<Expire> {
119self.first()
120 }
121}
122123impl<'a, Target: Composer> OptBuilder<'a, Target> {
124/// Appends the Expire option.
125 ///
126 /// The Expire option allows an authoritative server to signal its own
127 /// expiry time of a zone.
128pub fn expire(
129&mut self, expire: Option<u32>
130 ) -> Result<(), Target::AppendError> {
131self.push(&Expire::new(expire))
132 }
133}
134135136//============ Testing ======================================================
137138#[cfg(test)]
139#[cfg(all(feature = "std", feature = "bytes"))]
140mod test {
141use super::*;
142use super::super::test::test_option_compose_parse;
143144#[test]
145 #[allow(clippy::redundant_closure)] // lifetimes ...
146fn expire_compose_parse() {
147 test_option_compose_parse(
148&Expire::new(None),
149 |parser| Expire::parse(parser)
150 );
151 test_option_compose_parse(
152&Expire::new(Some(12)),
153 |parser| Expire::parse(parser)
154 );
155 }
156}
157