1 // Copyright 2015-2021 Benjamin Fry <benjaminfry@me.com>
2 //
3 // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4 // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5 // http://opensource.org/licenses/MIT>, at your option. This file may not be
6 // copied, modified, or distributed except according to those terms.
7 
8 //! SVCB records, see [draft-ietf-dnsop-svcb-https-03 SVCB and HTTPS RRs for DNS, February 2021](https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-03)
9 
10 use std::{
11     cmp::{Ord, Ordering, PartialOrd},
12     convert::TryFrom,
13     fmt,
14     net::Ipv4Addr,
15     net::Ipv6Addr,
16 };
17 
18 use enum_as_inner::EnumAsInner;
19 
20 use crate::error::*;
21 use crate::rr::Name;
22 use crate::serialize::binary::*;
23 
24 ///  [draft-ietf-dnsop-svcb-https-03 SVCB and HTTPS RRs for DNS, February 2021](https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-03#section-2.2)
25 ///
26 /// ```text
27 /// 2.2.  RDATA wire format
28 ///
29 ///   The RDATA for the SVCB RR consists of:
30 ///
31 ///   *  a 2 octet field for SvcPriority as an integer in network byte
32 ///      order.
33 ///   *  the uncompressed, fully-qualified TargetName, represented as a
34 ///      sequence of length-prefixed labels as in Section 3.1 of [RFC1035].
35 ///   *  the SvcParams, consuming the remainder of the record (so smaller
36 ///      than 65535 octets and constrained by the RDATA and DNS message
37 ///      sizes).
38 ///
39 ///   When the list of SvcParams is non-empty (ServiceMode), it contains a
40 ///   series of SvcParamKey=SvcParamValue pairs, represented as:
41 ///
42 ///   *  a 2 octet field containing the SvcParamKey as an integer in
43 ///      network byte order.  (See Section 14.3.2 for the defined values.)
44 ///   *  a 2 octet field containing the length of the SvcParamValue as an
45 ///      integer between 0 and 65535 in network byte order (but constrained
46 ///      by the RDATA and DNS message sizes).
47 ///   *  an octet string of this length whose contents are in a format
48 ///      determined by the SvcParamKey.
49 ///
50 ///   SvcParamKeys SHALL appear in increasing numeric order.
51 ///
52 ///   Clients MUST consider an RR malformed if:
53 ///
54 ///   *  the end of the RDATA occurs within a SvcParam.
55 ///   *  SvcParamKeys are not in strictly increasing numeric order.
56 ///   *  the SvcParamValue for an SvcParamKey does not have the expected
57 ///      format.
58 ///
59 ///   Note that the second condition implies that there are no duplicate
60 ///   SvcParamKeys.
61 ///
62 ///   If any RRs are malformed, the client MUST reject the entire RRSet and
63 ///   fall back to non-SVCB connection establishment.
64 /// ```
65 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
66 pub struct SVCB {
67     svc_priority: u16,
68     target_name: Name,
69     svc_params: Vec<(SvcParamKey, SvcParamValue)>,
70 }
71 
72 impl SVCB {
73     /// Create a new SVCB record from parts
74     ///
75     /// It is up to the caller to validate the data going into the record
new( svc_priority: u16, target_name: Name, svc_params: Vec<(SvcParamKey, SvcParamValue)>, ) -> Self76     pub fn new(
77         svc_priority: u16,
78         target_name: Name,
79         svc_params: Vec<(SvcParamKey, SvcParamValue)>,
80     ) -> Self {
81         Self {
82             svc_priority,
83             target_name,
84             svc_params,
85         }
86     }
87 
88     ///  [draft-ietf-dnsop-svcb-https-03 SVCB and HTTPS RRs for DNS, February 2021](https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-03#section-2.4.1)
89     /// ```text
90     /// 2.4.1.  SvcPriority
91     ///
92     ///   When SvcPriority is 0 the SVCB record is in AliasMode
93     ///   (Section 2.4.2).  Otherwise, it is in ServiceMode (Section 2.4.3).
94     ///
95     ///   Within a SVCB RRSet, all RRs SHOULD have the same Mode.  If an RRSet
96     ///   contains a record in AliasMode, the recipient MUST ignore any
97     ///   ServiceMode records in the set.
98     ///
99     ///   RRSets are explicitly unordered collections, so the SvcPriority field
100     ///   is used to impose an ordering on SVCB RRs.  SVCB RRs with a smaller
101     ///   SvcPriority value SHOULD be given preference over RRs with a larger
102     ///   SvcPriority value.
103     ///
104     ///   When receiving an RRSet containing multiple SVCB records with the
105     ///   same SvcPriority value, clients SHOULD apply a random shuffle within
106     ///   a priority level to the records before using them, to ensure uniform
107     ///   load-balancing.
108     /// ```
svc_priority(&self) -> u16109     pub fn svc_priority(&self) -> u16 {
110         self.svc_priority
111     }
112 
113     ///  [draft-ietf-dnsop-svcb-https-03 SVCB and HTTPS RRs for DNS, February 2021](https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-03#section-2.5)
114     /// ```text
115     /// 2.5.  Special handling of "." in TargetName
116     ///
117     ///   If TargetName has the value "." (represented in the wire format as a
118     ///    zero-length label), special rules apply.
119     ///
120     /// 2.5.1.  AliasMode
121     ///
122     ///    For AliasMode SVCB RRs, a TargetName of "." indicates that the
123     ///    service is not available or does not exist.  This indication is
124     ///    advisory: clients encountering this indication MAY ignore it and
125     ///    attempt to connect without the use of SVCB.
126     ///
127     /// 2.5.2.  ServiceMode
128     ///
129     ///    For ServiceMode SVCB RRs, if TargetName has the value ".", then the
130     ///    owner name of this record MUST be used as the effective TargetName.
131     ///
132     ///    For example, in the following example "svc2.example.net" is the
133     ///    effective TargetName:
134     ///
135     ///    example.com.      7200  IN HTTPS 0 svc.example.net.
136     ///    svc.example.net.  7200  IN CNAME svc2.example.net.
137     ///    svc2.example.net. 7200  IN HTTPS 1 . port=8002 echconfig="..."
138     ///    svc2.example.net. 300   IN A     192.0.2.2
139     ///    svc2.example.net. 300   IN AAAA  2001:db8::2
140     /// ```
target_name(&self) -> &Name141     pub fn target_name(&self) -> &Name {
142         &self.target_name
143     }
144 
145     /// See [`SvcParamKey`] for details on each parameter
svc_params(&self) -> &[(SvcParamKey, SvcParamValue)]146     pub fn svc_params(&self) -> &[(SvcParamKey, SvcParamValue)] {
147         &self.svc_params
148     }
149 }
150 
151 /// ```text
152 /// 14.3.2.  Initial contents
153 ///
154 ///   The "Service Binding (SVCB) Parameter Registry" shall initially be
155 ///   populated with the registrations below:
156 ///
157 ///   +=============+=================+======================+===========+
158 ///   | Number      | Name            | Meaning              | Reference |
159 ///   +=============+=================+======================+===========+
160 ///   | 0           | mandatory       | Mandatory keys in    | (This     |
161 ///   |             |                 | this RR              | document) |
162 ///   +-------------+-----------------+----------------------+-----------+
163 ///   | 1           | alpn            | Additional supported | (This     |
164 ///   |             |                 | protocols            | document) |
165 ///   +-------------+-----------------+----------------------+-----------+
166 ///   | 2           | no-default-alpn | No support for       | (This     |
167 ///   |             |                 | default protocol     | document) |
168 ///   +-------------+-----------------+----------------------+-----------+
169 ///   | 3           | port            | Port for alternative | (This     |
170 ///   |             |                 | endpoint             | document) |
171 ///   +-------------+-----------------+----------------------+-----------+
172 ///   | 4           | ipv4hint        | IPv4 address hints   | (This     |
173 ///   |             |                 |                      | document) |
174 ///   +-------------+-----------------+----------------------+-----------+
175 ///   | 5           | echconfig       | Encrypted            | (This     |
176 ///   |             |                 | ClientHello info     | document) |
177 ///   +-------------+-----------------+----------------------+-----------+
178 ///   | 6           | ipv6hint        | IPv6 address hints   | (This     |
179 ///   |             |                 |                      | document) |
180 ///   +-------------+-----------------+----------------------+-----------+
181 ///   | 65280-65534 | keyNNNNN        | Private Use          | (This     |
182 ///   |             |                 |                      | document) |
183 ///   +-------------+-----------------+----------------------+-----------+
184 ///   | 65535       | key65535        | Reserved ("Invalid   | (This     |
185 ///   |             |                 | key")                | document) |
186 ///   +-------------+-----------------+----------------------+-----------+
187 ///
188 /// parsing done via:
189 ///   *  a 2 octet field containing the SvcParamKey as an integer in
190 ///      network byte order.  (See Section 14.3.2 for the defined values.)
191 /// ```
192 #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
193 pub enum SvcParamKey {
194     /// Mandatory keys in this RR
195     Mandatory,
196     /// Additional supported protocols
197     Alpn,
198     /// No support for default protocol
199     NoDefaultAlpn,
200     /// Port for alternative endpoint
201     Port,
202     /// IPv4 address hints
203     Ipv4Hint,
204     /// Encrypted ClientHello info
205     EchConfig,
206     /// IPv6 address hints
207     Ipv6Hint,
208     /// Private Use
209     Key(u16),
210     /// Reserved ("Invalid key")
211     Key65535,
212     /// Unknown
213     Unknown(u16),
214 }
215 
216 impl From<u16> for SvcParamKey {
from(val: u16) -> Self217     fn from(val: u16) -> Self {
218         match val {
219             0 => SvcParamKey::Mandatory,
220             1 => SvcParamKey::Alpn,
221             2 => SvcParamKey::NoDefaultAlpn,
222             3 => SvcParamKey::Port,
223             4 => SvcParamKey::Ipv4Hint,
224             5 => SvcParamKey::EchConfig,
225             6 => SvcParamKey::Ipv6Hint,
226             65280..=65534 => SvcParamKey::Key(val),
227             65535 => SvcParamKey::Key65535,
228             _ => SvcParamKey::Unknown(val),
229         }
230     }
231 }
232 
233 impl From<SvcParamKey> for u16 {
from(val: SvcParamKey) -> Self234     fn from(val: SvcParamKey) -> Self {
235         match val {
236             SvcParamKey::Mandatory => 0,
237             SvcParamKey::Alpn => 1,
238             SvcParamKey::NoDefaultAlpn => 2,
239             SvcParamKey::Port => 3,
240             SvcParamKey::Ipv4Hint => 4,
241             SvcParamKey::EchConfig => 5,
242             SvcParamKey::Ipv6Hint => 6,
243             SvcParamKey::Key(val) => val,
244             SvcParamKey::Key65535 => 65535,
245             SvcParamKey::Unknown(val) => val,
246         }
247     }
248 }
249 
250 impl<'r> BinDecodable<'r> for SvcParamKey {
251     // a 2 octet field containing the SvcParamKey as an integer in
252     //      network byte order.  (See Section 14.3.2 for the defined values.)
read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self>253     fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self> {
254         Ok(decoder.read_u16()?.unverified(/*any u16 is valid*/).into())
255     }
256 }
257 
258 impl BinEncodable for SvcParamKey {
259     // a 2 octet field containing the SvcParamKey as an integer in
260     //      network byte order.  (See Section 14.3.2 for the defined values.)
emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()>261     fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
262         encoder.emit_u16((*self).into())
263     }
264 }
265 
266 impl fmt::Display for SvcParamKey {
fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error>267     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
268         let mut write_key = |name| write!(f, "{}", name);
269 
270         match *self {
271             SvcParamKey::Mandatory => write_key("mandatory")?,
272             SvcParamKey::Alpn => write_key("alpn")?,
273             SvcParamKey::NoDefaultAlpn => write_key("no-default-alpn")?,
274             SvcParamKey::Port => write_key("port")?,
275             SvcParamKey::Ipv4Hint => write_key("ipv4hint")?,
276             SvcParamKey::EchConfig => write_key("echconfig")?,
277             SvcParamKey::Ipv6Hint => write_key("ipv6hint")?,
278             SvcParamKey::Key(val) => write!(f, "key{}", val)?,
279             SvcParamKey::Key65535 => write_key("key65535")?,
280             SvcParamKey::Unknown(val) => write!(f, "unknown{}", val)?,
281         }
282 
283         Ok(())
284     }
285 }
286 
287 impl std::str::FromStr for SvcParamKey {
288     type Err = ProtoError;
289 
from_str(s: &str) -> Result<Self, Self::Err>290     fn from_str(s: &str) -> Result<Self, Self::Err> {
291         /// keys are in the format of key#, e.g. key12344, with a max value of u16
292         fn parse_unknown_key(key: &str) -> Result<SvcParamKey, ProtoError> {
293             let key_value = key.strip_prefix("key").ok_or_else(|| {
294                 ProtoError::from(ProtoErrorKind::Msg(format!(
295                     "bad formatted key ({}), expected key1234",
296                     key
297                 )))
298             })?;
299 
300             let key_value = u16::from_str(key_value)?;
301             let key = SvcParamKey::from(key_value);
302             Ok(key)
303         }
304 
305         let key = match s {
306             "mandatory" => SvcParamKey::Mandatory,
307             "alpn" => SvcParamKey::Alpn,
308             "no-default-alpn" => SvcParamKey::NoDefaultAlpn,
309             "port" => SvcParamKey::Port,
310             "ipv4hint" => SvcParamKey::Ipv4Hint,
311             "echconfig" => SvcParamKey::EchConfig,
312             "ipv6hint" => SvcParamKey::Ipv6Hint,
313             "key65535" => SvcParamKey::Key65535,
314             _ => parse_unknown_key(s)?,
315         };
316 
317         Ok(key)
318     }
319 }
320 
321 impl Ord for SvcParamKey {
cmp(&self, other: &Self) -> Ordering322     fn cmp(&self, other: &Self) -> Ordering {
323         u16::from(*self).cmp(&u16::from(*other))
324     }
325 }
326 
327 impl PartialOrd for SvcParamKey {
partial_cmp(&self, other: &Self) -> Option<Ordering>328     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
329         Some(self.cmp(other))
330     }
331 }
332 
333 /// Warning, it is currently up to users of this type to validate the data against that expected by the key
334 ///
335 /// ```text
336 ///   *  a 2 octet field containing the length of the SvcParamValue as an
337 ///      integer between 0 and 65535 in network byte order (but constrained
338 ///      by the RDATA and DNS message sizes).
339 ///   *  an octet string of this length whose contents are in a format
340 ///      determined by the SvcParamKey.
341 /// ```
342 #[derive(Debug, PartialEq, Eq, Hash, Clone, EnumAsInner)]
343 pub enum SvcParamValue {
344     ///    In a ServiceMode RR, a SvcParamKey is considered "mandatory" if the
345     ///    RR will not function correctly for clients that ignore this
346     ///    SvcParamKey.  Each SVCB protocol mapping SHOULD specify a set of keys
347     ///    that are "automatically mandatory", i.e. mandatory if they are
348     ///    present in an RR.  The SvcParamKey "mandatory" is used to indicate
349     ///    any mandatory keys for this RR, in addition to any automatically
350     ///    mandatory keys that are present.
351     ///
352     /// see `Mandatory`
353     Mandatory(Mandatory),
354     /// The "alpn" and "no-default-alpn" SvcParamKeys together indicate the
355     ///    set of Application Layer Protocol Negotiation (ALPN) protocol
356     ///    identifiers [ALPN] and associated transport protocols supported by
357     ///    this service endpoint.
358     Alpn(Alpn),
359     /// For "no-default-alpn", the presentation and wire format values MUST
360     ///    be empty.
361     /// See also `Alpn`
362     NoDefaultAlpn,
363     /// ```text
364     ///    6.2.  "port"
365     ///
366     ///   The "port" SvcParamKey defines the TCP or UDP port that should be
367     ///   used to reach this alternative endpoint.  If this key is not present,
368     ///   clients SHALL use the authority endpoint's port number.
369     ///
370     ///   The presentation "value" of the SvcParamValue is a single decimal
371     ///   integer between 0 and 65535 in ASCII.  Any other "value" (e.g. an
372     ///   empty value) is a syntax error.  To enable simpler parsing, this
373     ///   SvcParam MUST NOT contain escape sequences.
374     ///
375     ///   The wire format of the SvcParamValue is the corresponding 2 octet
376     ///   numeric value in network byte order.
377     ///
378     ///   If a port-restricting firewall is in place between some client and
379     ///   the service endpoint, changing the port number might cause that
380     ///   client to lose access to the service, so operators should exercise
381     ///   caution when using this SvcParamKey to specify a non-default port.
382     /// ```
383     Port(u16),
384     ///   The "ipv4hint" and "ipv6hint" keys convey IP addresses that clients
385     ///   MAY use to reach the service.  If A and AAAA records for TargetName
386     ///   are locally available, the client SHOULD ignore these hints.
387     ///   Otherwise, clients SHOULD perform A and/or AAAA queries for
388     ///   TargetName as in Section 3, and clients SHOULD use the IP address in
389     ///   those responses for future connections.  Clients MAY opt to terminate
390     ///   any connections using the addresses in hints and instead switch to
391     ///   the addresses in response to the TargetName query.  Failure to use A
392     ///   and/or AAAA response addresses could negatively impact load balancing
393     ///   or other geo-aware features and thereby degrade client performance.
394     ///
395     /// see `IpHint`
396     Ipv4Hint(IpHint<Ipv4Addr>),
397     /// ```text
398     /// 6.3.  "echconfig"
399     ///
400     ///   The SvcParamKey to enable Encrypted ClientHello (ECH) is "echconfig".
401     ///   Its value is defined in Section 9.  It is applicable to most TLS-
402     ///   based protocols.
403     ///
404     ///   When publishing a record containing an "echconfig" parameter, the
405     ///   publisher MUST ensure that all IP addresses of TargetName correspond
406     ///   to servers that have access to the corresponding private key or are
407     ///   authoritative for the public name.  (See Section 7.2.2 of [ECH] for
408     ///   more details about the public name.)  This yields an anonymity set of
409     ///   cardinality equal to the number of ECH-enabled server domains
410     ///   supported by a given client-facing server.  Thus, even with an
411     ///   encrypted ClientHello, an attacker who can enumerate the set of ECH-
412     ///   enabled domains supported by a client-facing server can guess the
413     ///   correct SNI with probability at least 1/K, where K is the size of
414     ///   this ECH-enabled server anonymity set.  This probability may be
415     ///   increased via traffic analysis or other mechanisms.
416     /// ```
417     EchConfig(EchConfig),
418     /// See `IpHint`
419     Ipv6Hint(IpHint<Ipv6Addr>),
420     /// Unparsed network data. Refer to documents on the associated key value
421     ///
422     /// This will be left as is when read off the wire, and encoded in bas64
423     ///    for presentation.
424     Unknown(Unknown),
425 }
426 
427 impl SvcParamValue {
428     // a 2 octet field containing the length of the SvcParamValue as an
429     //      integer between 0 and 65535 in network byte order (but constrained
430     //      by the RDATA and DNS message sizes).
read(key: SvcParamKey, decoder: &mut BinDecoder<'_>) -> ProtoResult<Self>431     fn read(key: SvcParamKey, decoder: &mut BinDecoder<'_>) -> ProtoResult<Self> {
432         let len: usize = decoder
433             .read_u16()?
434             .verify_unwrap(|len| *len as usize <= decoder.len())
435             .map(|len| len as usize)
436             .map_err(|u| {
437                 ProtoError::from(format!(
438                     "length of SvcParamValue ({}) exceeds remainder in RDATA ({})",
439                     u,
440                     decoder.len()
441                 ))
442             })?;
443 
444         let param_data = decoder.read_slice(len)?.unverified(/*verification to be done by individual param types*/);
445         let mut decoder = BinDecoder::new(param_data);
446 
447         let value = match key {
448             SvcParamKey::Mandatory => Self::Mandatory(Mandatory::read(&mut decoder)?),
449             SvcParamKey::Alpn => Self::Alpn(Alpn::read(&mut decoder)?),
450             // should always be empty
451             SvcParamKey::NoDefaultAlpn => {
452                 if len > 0 {
453                     return Err(ProtoError::from("Alpn expects at least one value"));
454                 }
455 
456                 Self::NoDefaultAlpn
457             }
458             // The wire format of the SvcParamValue is the corresponding 2 octet
459             // numeric value in network byte order.
460             SvcParamKey::Port => {
461                 let port = decoder.read_u16()?.unverified(/*all values are legal ports*/);
462                 Self::Port(port)
463             }
464             SvcParamKey::Ipv4Hint => Self::Ipv4Hint(IpHint::<Ipv4Addr>::read(&mut decoder)?),
465             SvcParamKey::EchConfig => Self::EchConfig(EchConfig::read(&mut decoder)?),
466             SvcParamKey::Ipv6Hint => Self::Ipv6Hint(IpHint::<Ipv6Addr>::read(&mut decoder)?),
467             SvcParamKey::Key(_) | SvcParamKey::Key65535 | SvcParamKey::Unknown(_) => {
468                 Self::Unknown(Unknown::read(&mut decoder)?)
469             }
470         };
471 
472         Ok(value)
473     }
474 }
475 
476 impl BinEncodable for SvcParamValue {
477     // a 2 octet field containing the length of the SvcParamValue as an
478     //      integer between 0 and 65535 in network byte order (but constrained
479     //      by the RDATA and DNS message sizes).
emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()>480     fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
481         // set the place for the length...
482         let place = encoder.place::<u16>()?;
483 
484         match self {
485             SvcParamValue::Mandatory(mandatory) => mandatory.emit(encoder)?,
486             SvcParamValue::Alpn(alpn) => alpn.emit(encoder)?,
487             SvcParamValue::NoDefaultAlpn => (),
488             SvcParamValue::Port(port) => encoder.emit_u16(*port)?,
489             SvcParamValue::Ipv4Hint(ip_hint) => ip_hint.emit(encoder)?,
490             SvcParamValue::EchConfig(ech_config) => ech_config.emit(encoder)?,
491             SvcParamValue::Ipv6Hint(ip_hint) => ip_hint.emit(encoder)?,
492             SvcParamValue::Unknown(unknown) => unknown.emit(encoder)?,
493         }
494 
495         // go back and set the length
496         let len = u16::try_from(encoder.len_since_place(&place))
497             .map_err(|_| ProtoError::from("Total length of SvcParamValue exceeds u16::MAX"))?;
498         place.replace(encoder, len)?;
499 
500         Ok(())
501     }
502 }
503 
504 impl fmt::Display for SvcParamValue {
fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error>505     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
506         match self {
507             SvcParamValue::Mandatory(mandatory) => write!(f, "{}", mandatory)?,
508             SvcParamValue::Alpn(alpn) => write!(f, "{}", alpn)?,
509             SvcParamValue::NoDefaultAlpn => (),
510             SvcParamValue::Port(port) => write!(f, "{}", port)?,
511             SvcParamValue::Ipv4Hint(ip_hint) => write!(f, "{}", ip_hint)?,
512             SvcParamValue::EchConfig(ech_config) => write!(f, "{}", ech_config)?,
513             SvcParamValue::Ipv6Hint(ip_hint) => write!(f, "{}", ip_hint)?,
514             SvcParamValue::Unknown(unknown) => write!(f, "{}", unknown)?,
515         }
516 
517         Ok(())
518     }
519 }
520 
521 /// ```text
522 /// 7.  ServiceMode RR compatibility and mandatory keys
523 ///
524 ///    In a ServiceMode RR, a SvcParamKey is considered "mandatory" if the
525 ///    RR will not function correctly for clients that ignore this
526 ///    SvcParamKey.  Each SVCB protocol mapping SHOULD specify a set of keys
527 ///    that are "automatically mandatory", i.e. mandatory if they are
528 ///    present in an RR.  The SvcParamKey "mandatory" is used to indicate
529 ///    any mandatory keys for this RR, in addition to any automatically
530 ///    mandatory keys that are present.
531 ///
532 ///    A ServiceMode RR is considered "compatible" with a client if the
533 ///    client recognizes all the mandatory keys, and their values indicate
534 ///    that successful connection establishment is possible.  If the SVCB
535 ///    RRSet contains no compatible RRs, the client will generally act as if
536 ///    the RRSet is empty.
537 ///
538 ///    The presentation "value" SHALL be a comma-separated list
539 ///    (Appendix A.1) of one or more valid SvcParamKeys, either by their
540 ///    registered name or in the unknown-key format (Section 2.1).  Keys MAY
541 ///    appear in any order, but MUST NOT appear more than once.  For self-
542 ///    consistency (Section 2.4.3), listed keys MUST also appear in the
543 ///    SvcParams.
544 ///
545 ///    To enable simpler parsing, this SvcParamValue MUST NOT contain escape
546 ///    sequences.
547 ///
548 ///    For example, the following is a valid list of SvcParams:
549 ///
550 ///    echconfig=... key65333=ex1 key65444=ex2 mandatory=key65444,echconfig
551 ///
552 ///    In wire format, the keys are represented by their numeric values in
553 ///    network byte order, concatenated in ascending order.
554 ///
555 ///    This SvcParamKey is always automatically mandatory, and MUST NOT
556 ///    appear in its own value-list.  Other automatically mandatory keys
557 ///    SHOULD NOT appear in the list either.  (Including them wastes space
558 ///    and otherwise has no effect.)
559 /// ```
560 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
561 #[repr(transparent)]
562 pub struct Mandatory(pub Vec<SvcParamKey>);
563 
564 impl<'r> BinDecodable<'r> for Mandatory {
565     /// This expects the decoder to be limited to only this field, i.e. the end of input for the decoder
566     ///   is the end of input for the fields
567     ///
568     /// ```text
569     ///    In wire format, the keys are represented by their numeric values in
570     ///    network byte order, concatenated in ascending order.
571     /// ```
read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self>572     fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self> {
573         let mut keys = Vec::with_capacity(1);
574 
575         while decoder.peek().is_some() {
576             keys.push(SvcParamKey::read(decoder)?);
577         }
578 
579         if keys.is_empty() {
580             return Err(ProtoError::from("Mandatory expects at least one value"));
581         }
582 
583         Ok(Mandatory(keys))
584     }
585 }
586 
587 impl BinEncodable for Mandatory {
588     /// This expects the decoder to be limited to only this field, i.e. the end of input for the decoder
589     ///   is the end of input for the fields
590     ///
591     /// ```text
592     ///    In wire format, the keys are represented by their numeric values in
593     ///    network byte order, concatenated in ascending order.
594     /// ```
emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()>595     fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
596         if self.0.is_empty() {
597             return Err(ProtoError::from("Alpn expects at least one value"));
598         }
599 
600         // TODO: order by key value
601         for key in self.0.iter() {
602             key.emit(encoder)?
603         }
604 
605         Ok(())
606     }
607 }
608 
609 impl fmt::Display for Mandatory {
610     ///    The presentation "value" SHALL be a comma-separated list
611     ///    (Appendix A.1) of one or more valid SvcParamKeys, either by their
612     ///    registered name or in the unknown-key format (Section 2.1).  Keys MAY
613     ///    appear in any order, but MUST NOT appear more than once.  For self-
614     ///    consistency (Section 2.4.3), listed keys MUST also appear in the
615     ///    SvcParams.
616     ///
617     ///    To enable simpler parsing, this SvcParamValue MUST NOT contain escape
618     ///    sequences.
619     ///
620     ///    For example, the following is a valid list of SvcParams:
621     ///
622     ///    echconfig=... key65333=ex1 key65444=ex2 mandatory=key65444,echconfig
fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error>623     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
624         for key in self.0.iter() {
625             // TODO: confirm in the RFC that trailing commas are ok
626             write!(f, "{},", key)?;
627         }
628 
629         Ok(())
630     }
631 }
632 
633 ///  [draft-ietf-dnsop-svcb-https-03 SVCB and HTTPS RRs for DNS, February 2021](https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-03#section-6.1)
634 ///
635 /// ```text
636 /// 6.1.  "alpn" and "no-default-alpn"
637 ///
638 ///   The "alpn" and "no-default-alpn" SvcParamKeys together indicate the
639 ///   set of Application Layer Protocol Negotiation (ALPN) protocol
640 ///   identifiers [ALPN] and associated transport protocols supported by
641 ///   this service endpoint.
642 ///
643 ///   As with Alt-Svc [AltSvc], the ALPN protocol identifier is used to
644 ///   identify the application protocol and associated suite of protocols
645 ///   supported by the endpoint (the "protocol suite").  Clients filter the
646 ///   set of ALPN identifiers to match the protocol suites they support,
647 ///   and this informs the underlying transport protocol used (such as
648 ///   QUIC-over-UDP or TLS-over-TCP).
649 ///
650 ///   ALPNs are identified by their registered "Identification Sequence"
651 ///   ("alpn-id"), which is a sequence of 1-255 octets.
652 ///
653 ///   alpn-id = 1*255OCTET
654 ///
655 ///   The presentation "value" SHALL be a comma-separated list
656 ///   (Appendix A.1) of one or more "alpn-id"s.
657 ///
658 ///   The wire format value for "alpn" consists of at least one "alpn-id"
659 ///   prefixed by its length as a single octet, and these length-value
660 ///   pairs are concatenated to form the SvcParamValue.  These pairs MUST
661 ///   exactly fill the SvcParamValue; otherwise, the SvcParamValue is
662 ///   malformed.
663 ///
664 ///   For "no-default-alpn", the presentation and wire format values MUST
665 ///   be empty.  When "no-default-alpn" is specified in an RR, "alpn" must
666 ///   also be specified in order for the RR to be "self-consistent"
667 ///   (Section 2.4.3).
668 ///
669 ///   Each scheme that uses this SvcParamKey defines a "default set" of
670 ///   supported ALPNs, which SHOULD NOT be empty.  To determine the set of
671 ///   protocol suites supported by an endpoint (the "SVCB ALPN set"), the
672 ///   client adds the default set to the list of "alpn-id"s unless the "no-
673 ///   default-alpn" SvcParamKey is present.  The presence of an ALPN
674 ///   protocol in the SVCB ALPN set indicates that this service endpoint,
675 ///   described by TargetName and the other parameters (e.g. "port") offers
676 ///   service with the protocol suite associated with this ALPN protocol.
677 ///
678 ///   ALPN protocol names that do not uniquely identify a protocol suite
679 ///   (e.g. an Identification Sequence that can be used with both TLS and
680 ///   DTLS) are not compatible with this SvcParamKey and MUST NOT be
681 ///   included in the SVCB ALPN set.
682 ///
683 ///   To establish a connection to the endpoint, clients MUST
684 ///
685 ///   1.  Let SVCB-ALPN-Intersection be the set of protocols in the SVCB
686 ///       ALPN set that the client supports.
687 ///
688 ///   2.  Let Intersection-Transports be the set of transports (e.g.  TLS,
689 ///       DTLS, QUIC) implied by the protocols in SVCB-ALPN-Intersection.
690 ///
691 ///   3.  For each transport in Intersection-Transports, construct a
692 ///       ProtocolNameList containing the Identification Sequences of all
693 ///       the client's supported ALPN protocols for that transport, without
694 ///       regard to the SVCB ALPN set.
695 ///
696 ///   For example, if the SVCB ALPN set is ["http/1.1", "h3"], and the
697 ///   client supports HTTP/1.1, HTTP/2, and HTTP/3, the client could
698 ///   attempt to connect using TLS over TCP with a ProtocolNameList of
699 ///   ["http/1.1", "h2"], and could also attempt a connection using QUIC,
700 ///   with a ProtocolNameList of ["h3"].
701 ///
702 ///   Once the client has constructed a ClientHello, protocol negotiation
703 ///   in that handshake proceeds as specified in [ALPN], without regard to
704 ///   the SVCB ALPN set.
705 ///
706 ///   With this procedure in place, an attacker who can modify DNS and
707 ///   network traffic can prevent a successful transport connection, but
708 ///   cannot otherwise interfere with ALPN protocol selection.  This
709 ///   procedure also ensures that each ProtocolNameList includes at least
710 ///   one protocol from the SVCB ALPN set.
711 ///
712 ///   Clients SHOULD NOT attempt connection to a service endpoint whose
713 ///   SVCB ALPN set does not contain any supported protocols.  To ensure
714 ///   consistency of behavior, clients MAY reject the entire SVCB RRSet and
715 ///   fall back to basic connection establishment if all of the RRs
716 ///   indicate "no-default-alpn", even if connection could have succeeded
717 ///   using a non-default alpn.
718 ///
719 ///   For compatibility with clients that require default transports, zone
720 ///   operators SHOULD ensure that at least one RR in each RRSet supports
721 ///   the default transports.
722 /// ```
723 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
724 #[repr(transparent)]
725 pub struct Alpn(pub Vec<String>);
726 
727 impl<'r> BinDecodable<'r> for Alpn {
728     /// This expects the decoder to be limited to only this field, i.e. the end of input for the decoder
729     ///   is the end of input for the fields
730     ///
731     /// ```text
732     ///   The wire format value for "alpn" consists of at least one "alpn-id"
733     ///   prefixed by its length as a single octet, and these length-value
734     ///   pairs are concatenated to form the SvcParamValue.  These pairs MUST
735     ///   exactly fill the SvcParamValue; otherwise, the SvcParamValue is
736     ///   malformed.
737     /// ```
read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self>738     fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self> {
739         let mut alpns = Vec::with_capacity(1);
740 
741         while decoder.peek().is_some() {
742             let alpn = decoder.read_character_data()?.unverified(/*will rely on string parser*/);
743             let alpn = String::from_utf8(alpn.to_vec())?;
744             alpns.push(alpn);
745         }
746 
747         if alpns.is_empty() {
748             return Err(ProtoError::from("Alpn expects at least one value"));
749         }
750 
751         Ok(Alpn(alpns))
752     }
753 }
754 
755 impl BinEncodable for Alpn {
756     ///   The wire format value for "alpn" consists of at least one "alpn-id"
757     ///   prefixed by its length as a single octet, and these length-value
758     ///   pairs are concatenated to form the SvcParamValue.  These pairs MUST
759     ///   exactly fill the SvcParamValue; otherwise, the SvcParamValue is
760     ///   malformed.
emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()>761     fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
762         if self.0.is_empty() {
763             return Err(ProtoError::from("Alpn expects at least one value"));
764         }
765 
766         for alpn in self.0.iter() {
767             encoder.emit_character_data(alpn)?
768         }
769 
770         Ok(())
771     }
772 }
773 
774 impl fmt::Display for Alpn {
775     ///   The presentation "value" SHALL be a comma-separated list
776     ///   (Appendix A.1) of one or more "alpn-id"s.
fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error>777     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
778         for alpn in self.0.iter() {
779             // TODO: confirm in the RFC that trailing commas are ok
780             write!(f, "{},", alpn)?;
781         }
782 
783         Ok(())
784     }
785 }
786 
787 /// ```text
788 /// 9.  SVCB/HTTPS RR parameter for ECH configuration
789 ///
790 ///   The SVCB "echconfig" parameter is defined for conveying the ECH
791 ///   configuration of an alternative endpoint.  In wire format, the value
792 ///   of the parameter is an ECHConfigs vector [ECH], including the
793 ///   redundant length prefix.  In presentation format, the value is a
794 ///   single ECHConfigs encoded in Base64 [base64].  Base64 is used here to
795 ///   simplify integration with TLS server software.  To enable simpler
796 ///   parsing, this SvcParam MUST NOT contain escape sequences.
797 ///
798 ///   When ECH is in use, the TLS ClientHello is divided into an
799 ///   unencrypted "outer" and an encrypted "inner" ClientHello.  The outer
800 ///   ClientHello is an implementation detail of ECH, and its contents are
801 ///   controlled by the ECHConfig in accordance with [ECH].  The inner
802 ///   ClientHello is used for establishing a connection to the service, so
803 ///   its contents may be influenced by other SVCB parameters.  For
804 ///   example, the requirements on the ProtocolNameList in Section 6.1
805 ///   apply only to the inner ClientHello.  Similarly, it is the inner
806 ///   ClientHello whose Server Name Indication identifies the desired
807 /// ```
808 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
809 #[repr(transparent)]
810 pub struct EchConfig(pub Vec<u8>);
811 
812 impl<'r> BinDecodable<'r> for EchConfig {
813     /// In wire format, the value
814     ///   of the parameter is an ECHConfigs vector [ECH], including the
815     ///   redundant length prefix (a 2 octet field containing the length of the SvcParamValue
816     ///   as an integer between 0 and 65535 in network byte order).
read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self>817     fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self> {
818         let redundant_len = decoder
819             .read_u16()?
820             .map(|len| len as usize)
821             .verify_unwrap(|len| *len <= decoder.len())
822             .map_err(|_| ProtoError::from("ECH value length exceeds max size of u16::MAX"))?;
823 
824         let data =
825             decoder.read_vec(redundant_len)?.unverified(/*up to consumer to validate this data*/);
826 
827         Ok(EchConfig(data))
828     }
829 }
830 
831 impl BinEncodable for EchConfig {
832     /// In wire format, the value
833     ///   of the parameter is an ECHConfigs vector [ECH], including the
834     ///   redundant length prefix (a 2 octet field containing the length of the SvcParamValue
835     ///   as an integer between 0 and 65535 in network byte order).
emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()>836     fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
837         let len = u16::try_from(self.0.len())
838             .map_err(|_| ProtoError::from("ECH value length exceeds max size of u16::MAX"))?;
839 
840         // redundant length...
841         encoder.emit_u16(len)?;
842         encoder.emit_vec(&self.0)?;
843 
844         Ok(())
845     }
846 }
847 
848 impl fmt::Display for EchConfig {
849     /// In presentation format, the value is a
850     ///   single ECHConfigs encoded in Base64 [base64].  Base64 is used here to
851     ///   simplify integration with TLS server software.  To enable simpler
852     ///   parsing, this SvcParam MUST NOT contain escape sequences.
853     ///
854     /// *note* while the on the wire the EchConfig has a redundant length,
855     ///   the RFC is not explicit about including it in the base64
fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error>856     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
857         write!(f, "\"{}\"", data_encoding::BASE64.encode(&self.0))
858     }
859 }
860 
861 /// ```text
862 ///    6.4.  "ipv4hint" and "ipv6hint"
863 ///
864 ///   The "ipv4hint" and "ipv6hint" keys convey IP addresses that clients
865 ///   MAY use to reach the service.  If A and AAAA records for TargetName
866 ///   are locally available, the client SHOULD ignore these hints.
867 ///   Otherwise, clients SHOULD perform A and/or AAAA queries for
868 ///   TargetName as in Section 3, and clients SHOULD use the IP address in
869 ///   those responses for future connections.  Clients MAY opt to terminate
870 ///   any connections using the addresses in hints and instead switch to
871 ///   the addresses in response to the TargetName query.  Failure to use A
872 ///   and/or AAAA response addresses could negatively impact load balancing
873 ///   or other geo-aware features and thereby degrade client performance.
874 ///
875 ///   The presentation "value" SHALL be a comma-separated list
876 ///   (Appendix A.1) of one or more IP addresses of the appropriate family
877 ///   in standard textual format [RFC5952].  To enable simpler parsing,
878 ///   this SvcParamValue MUST NOT contain escape sequences.
879 ///
880 ///   The wire format for each parameter is a sequence of IP addresses in
881 ///   network byte order.  Like an A or AAAA RRSet, the list of addresses
882 ///   represents an unordered collection, and clients SHOULD pick addresses
883 ///   to use in a random order.  An empty list of addresses is invalid.
884 ///
885 ///   When selecting between IPv4 and IPv6 addresses to use, clients may
886 ///   use an approach such as Happy Eyeballs [HappyEyeballsV2].  When only
887 ///   "ipv4hint" is present, IPv6-only clients may synthesize IPv6
888 ///   addresses as specified in [RFC7050] or ignore the "ipv4hint" key and
889 ///   wait for AAAA resolution (Section 3).  Recursive resolvers MUST NOT
890 ///   perform DNS64 ([RFC6147]) on parameters within a SVCB record.  For
891 ///   best performance, server operators SHOULD include an "ipv6hint"
892 ///   parameter whenever they include an "ipv4hint" parameter.
893 ///
894 ///   These parameters are intended to minimize additional connection
895 ///   latency when a recursive resolver is not compliant with the
896 ///   requirements in Section 4, and SHOULD NOT be included if most clients
897 ///   are using compliant recursive resolvers.  When TargetName is the
898 ///   origin hostname or the owner name (which can be written as "."),
899 ///   server operators SHOULD NOT include these hints, because they are
900 ///   unlikely to convey any performance benefit.
901 /// ```
902 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
903 #[repr(transparent)]
904 pub struct IpHint<T>(pub Vec<T>);
905 
906 impl<'r, T> BinDecodable<'r> for IpHint<T>
907 where
908     T: BinDecodable<'r>,
909 {
910     ///   The wire format for each parameter is a sequence of IP addresses in
911     ///   network byte order.  Like an A or AAAA RRSet, the list of addresses
912     ///   represents an unordered collection, and clients SHOULD pick addresses
913     ///   to use in a random order.  An empty list of addresses is invalid.
read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self>914     fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self> {
915         let mut ips = Vec::new();
916 
917         while decoder.peek().is_some() {
918             ips.push(T::read(decoder)?)
919         }
920 
921         Ok(IpHint(ips))
922     }
923 }
924 
925 impl<T> BinEncodable for IpHint<T>
926 where
927     T: BinEncodable,
928 {
929     ///   The wire format for each parameter is a sequence of IP addresses in
930     ///   network byte order.  Like an A or AAAA RRSet, the list of addresses
931     ///   represents an unordered collection, and clients SHOULD pick addresses
932     ///   to use in a random order.  An empty list of addresses is invalid.
emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()>933     fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
934         for ip in self.0.iter() {
935             ip.emit(encoder)?;
936         }
937 
938         Ok(())
939     }
940 }
941 
942 impl<T> fmt::Display for IpHint<T>
943 where
944     T: fmt::Display,
945 {
946     ///   The presentation "value" SHALL be a comma-separated list
947     ///   (Appendix A.1) of one or more IP addresses of the appropriate family
948     ///   in standard textual format [RFC5952].  To enable simpler parsing,
949     ///   this SvcParamValue MUST NOT contain escape sequences.
fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error>950     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
951         for ip in self.0.iter() {
952             write!(f, "{},", ip)?;
953         }
954 
955         Ok(())
956     }
957 }
958 
959 /// [draft-ietf-dnsop-svcb-https-03 SVCB and HTTPS RRs for DNS, February 2021](https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-03#section-2.1)
960 /// ```text
961 /// Unrecognized keys are represented in presentation format as
962 ///   "keyNNNNN" where NNNNN is the numeric value of the key type without
963 ///   leading zeros.  A SvcParam in this form SHALL be parsed as specified
964 ///   above, and the decoded "value" SHALL be used as its wire format
965 ///   encoding.
966 ///
967 ///   For some SvcParamKeys, the "value" corresponds to a list or set of
968 ///   items.  Presentation formats for such keys SHOULD use a comma-
969 ///   separated list (Appendix A.1).
970 ///
971 ///   SvcParams in presentation format MAY appear in any order, but keys
972 ///   MUST NOT be repeated.
973 /// ```
974 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
975 #[repr(transparent)]
976 pub struct Unknown(pub Vec<Vec<u8>>);
977 
978 impl<'r> BinDecodable<'r> for Unknown {
read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self>979     fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self> {
980         let mut unknowns = Vec::new();
981 
982         while decoder.peek().is_some() {
983             let data = decoder.read_character_data()?;
984             let data = data.unverified(/*any data is valid here*/).to_vec();
985             unknowns.push(data)
986         }
987 
988         Ok(Unknown(unknowns))
989     }
990 }
991 
992 impl BinEncodable for Unknown {
emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()>993     fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
994         for unknown in self.0.iter() {
995             encoder.emit_character_data(unknown)?;
996         }
997 
998         Ok(())
999     }
1000 }
1001 
1002 impl fmt::Display for Unknown {
fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error>1003     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1004         for unknown in self.0.iter() {
1005             // TODO: this needs to be properly encoded
1006             write!(f, "\"{}\",", String::from_utf8_lossy(unknown))?;
1007         }
1008 
1009         Ok(())
1010     }
1011 }
1012 
1013 /// Reads the SVCB record from the decoder.
1014 ///
1015 /// ```text
1016 ///   Clients MUST consider an RR malformed if:
1017 ///
1018 ///   *  the end of the RDATA occurs within a SvcParam.
1019 ///   *  SvcParamKeys are not in strictly increasing numeric order.
1020 ///   *  the SvcParamValue for an SvcParamKey does not have the expected
1021 ///      format.
1022 ///
1023 ///   Note that the second condition implies that there are no duplicate
1024 ///   SvcParamKeys.
1025 ///
1026 ///   If any RRs are malformed, the client MUST reject the entire RRSet and
1027 ///   fall back to non-SVCB connection establishment.
1028 /// ```
read(decoder: &mut BinDecoder<'_>, rdata_length: Restrict<u16>) -> ProtoResult<SVCB>1029 pub fn read(decoder: &mut BinDecoder<'_>, rdata_length: Restrict<u16>) -> ProtoResult<SVCB> {
1030     let start_index = decoder.index();
1031 
1032     let svc_priority = decoder.read_u16()?.unverified(/*any u16 is valid*/);
1033     let target_name = Name::read(decoder)?;
1034 
1035     let mut remainder_len = rdata_length.map(|len| len as usize).checked_sub(decoder.index() - start_index).map_err(|len| format!("Bad length for RDATA of SVCB: {}", len))?.unverified(/*valid len*/);
1036     let mut svc_params: Vec<(SvcParamKey, SvcParamValue)> = Vec::new();
1037 
1038     // must have at least 4 bytes left for the key and the length
1039     while remainder_len >= 4 {
1040         // a 2 octet field containing the SvcParamKey as an integer in
1041         //      network byte order.  (See Section 14.3.2 for the defined values.)
1042         let key = SvcParamKey::read(decoder)?;
1043 
1044         // a 2 octet field containing the length of the SvcParamValue as an
1045         //      integer between 0 and 65535 in network byte order (but constrained
1046         //      by the RDATA and DNS message sizes).
1047         let value = SvcParamValue::read(key, decoder)?;
1048 
1049         if let Some(last_key) = svc_params.last().map(|(key, _)| key) {
1050             if last_key >= &key {
1051                 return Err(ProtoError::from("SvcParams out of order"));
1052             }
1053         }
1054 
1055         svc_params.push((key, value));
1056         remainder_len = rdata_length.map(|len| len as usize).checked_sub(decoder.index() - start_index).map_err(|len| format!("Bad length for RDATA of SVCB: {}", len))?.unverified(/*valid len*/);
1057     }
1058 
1059     Ok(SVCB {
1060         svc_priority,
1061         target_name,
1062         svc_params,
1063     })
1064 }
1065 
1066 /// Write the RData from the given Decoder
emit(encoder: &mut BinEncoder<'_>, svcb: &SVCB) -> ProtoResult<()>1067 pub fn emit(encoder: &mut BinEncoder<'_>, svcb: &SVCB) -> ProtoResult<()> {
1068     svcb.svc_priority.emit(encoder)?;
1069     svcb.target_name.emit(encoder)?;
1070 
1071     let mut last_key: Option<SvcParamKey> = None;
1072     for (key, param) in svcb.svc_params.iter() {
1073         if let Some(last_key) = last_key {
1074             if key <= &last_key {
1075                 return Err(ProtoError::from("SvcParams out of order"));
1076             }
1077         }
1078 
1079         key.emit(encoder)?;
1080         param.emit(encoder)?;
1081 
1082         last_key = Some(*key);
1083     }
1084 
1085     Ok(())
1086 }
1087 
1088 /// [draft-ietf-dnsop-svcb-https-03 SVCB and HTTPS RRs for DNS, February 2021](https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-03#section-10.3)
1089 ///
1090 /// ```text
1091 /// simple.example. 7200 IN HTTPS 1 . alpn=h3
1092 /// pool  7200 IN HTTPS 1 h3pool alpn=h2,h3 echconfig="123..."
1093 ///               HTTPS 2 .      alpn=h2 echconfig="abc..."
1094 /// @     7200 IN HTTPS 0 www
1095 /// _8765._baz.api.example.com. 7200 IN SVCB 0 svc4-baz.example.net.
1096 /// ```
1097 impl fmt::Display for SVCB {
fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error>1098     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1099         write!(
1100             f,
1101             "{svc_priority} {target_name}",
1102             svc_priority = self.svc_priority,
1103             target_name = self.target_name,
1104         )?;
1105 
1106         for (key, param) in self.svc_params.iter() {
1107             write!(f, " {key}={param}", key = key, param = param)?
1108         }
1109 
1110         Ok(())
1111     }
1112 }
1113 
1114 #[cfg(test)]
1115 mod tests {
1116     use super::*;
1117 
1118     #[test]
read_svcb_key()1119     fn read_svcb_key() {
1120         assert_eq!(SvcParamKey::Mandatory, 0.into());
1121         assert_eq!(SvcParamKey::Alpn, 1.into());
1122         assert_eq!(SvcParamKey::NoDefaultAlpn, 2.into());
1123         assert_eq!(SvcParamKey::Port, 3.into());
1124         assert_eq!(SvcParamKey::Ipv4Hint, 4.into());
1125         assert_eq!(SvcParamKey::EchConfig, 5.into());
1126         assert_eq!(SvcParamKey::Ipv6Hint, 6.into());
1127         assert_eq!(SvcParamKey::Key(65280), 65280.into());
1128         assert_eq!(SvcParamKey::Key(65534), 65534.into());
1129         assert_eq!(SvcParamKey::Key65535, 65535.into());
1130         assert_eq!(SvcParamKey::Unknown(65279), 65279.into());
1131     }
1132 
1133     #[test]
read_svcb_key_to_u16()1134     fn read_svcb_key_to_u16() {
1135         assert_eq!(u16::from(SvcParamKey::Mandatory), 0);
1136         assert_eq!(u16::from(SvcParamKey::Alpn), 1);
1137         assert_eq!(u16::from(SvcParamKey::NoDefaultAlpn), 2);
1138         assert_eq!(u16::from(SvcParamKey::Port), 3);
1139         assert_eq!(u16::from(SvcParamKey::Ipv4Hint), 4);
1140         assert_eq!(u16::from(SvcParamKey::EchConfig), 5);
1141         assert_eq!(u16::from(SvcParamKey::Ipv6Hint), 6);
1142         assert_eq!(u16::from(SvcParamKey::Key(65280)), 65280);
1143         assert_eq!(u16::from(SvcParamKey::Key(65534)), 65534);
1144         assert_eq!(u16::from(SvcParamKey::Key65535), 65535);
1145         assert_eq!(u16::from(SvcParamKey::Unknown(65279)), 65279);
1146     }
1147 
1148     // TODO: add this back after upgrading rustc version to 1.46
1149     // #[track_caller]
test_encode_decode(rdata: SVCB)1150     fn test_encode_decode(rdata: SVCB) {
1151         let mut bytes = Vec::new();
1152         let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
1153         emit(&mut encoder, &rdata).expect("failed to emit SVCB");
1154         let bytes = encoder.into_bytes();
1155 
1156         println!("svcb: {}", rdata);
1157         println!("bytes: {:?}", bytes);
1158 
1159         let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
1160         let read_rdata =
1161             read(&mut decoder, Restrict::new(bytes.len() as u16)).expect("failed to read back");
1162         assert_eq!(rdata, read_rdata);
1163     }
1164 
1165     #[test]
test_encode_decode_svcb()1166     fn test_encode_decode_svcb() {
1167         test_encode_decode(SVCB::new(
1168             0,
1169             Name::from_utf8("www.example.com.").unwrap(),
1170             vec![],
1171         ));
1172         test_encode_decode(SVCB::new(
1173             0,
1174             Name::from_utf8(".").unwrap(),
1175             vec![(
1176                 SvcParamKey::Alpn,
1177                 SvcParamValue::Alpn(Alpn(vec!["h2".to_string()])),
1178             )],
1179         ));
1180         test_encode_decode(SVCB::new(
1181             0,
1182             Name::from_utf8("example.com.").unwrap(),
1183             vec![
1184                 (
1185                     SvcParamKey::Mandatory,
1186                     SvcParamValue::Mandatory(Mandatory(vec![SvcParamKey::Alpn])),
1187                 ),
1188                 (
1189                     SvcParamKey::Alpn,
1190                     SvcParamValue::Alpn(Alpn(vec!["h2".to_string()])),
1191                 ),
1192             ],
1193         ));
1194     }
1195 
1196     #[test]
1197     #[should_panic]
test_encode_decode_svcb_bad_order()1198     fn test_encode_decode_svcb_bad_order() {
1199         test_encode_decode(SVCB::new(
1200             0,
1201             Name::from_utf8(".").unwrap(),
1202             vec![
1203                 (
1204                     SvcParamKey::Alpn,
1205                     SvcParamValue::Alpn(Alpn(vec!["h2".to_string()])),
1206                 ),
1207                 (
1208                     SvcParamKey::Mandatory,
1209                     SvcParamValue::Mandatory(Mandatory(vec![SvcParamKey::Alpn])),
1210                 ),
1211             ],
1212         ));
1213     }
1214 
1215     #[test]
test_no_panic()1216     fn test_no_panic() {
1217         const BUF: &[u8] = &[
1218             255, 121, 0, 0, 0, 0, 40, 255, 255, 160, 160, 0, 0, 0, 64, 0, 1, 255, 158, 0, 0, 0, 8,
1219             0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0,
1220         ];
1221         assert!(crate::op::Message::from_vec(&BUF).is_err());
1222     }
1223 }
1224