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
use crate::decode::error::DecodeError::ECHLengthMismatch;
use crate::decode::Decoder;
use crate::rr::{ServiceBinding, ServiceParameter};
use crate::DecodeResult;
use super::Header;
use std::collections::BTreeSet;
impl<'a, 'b: 'a> Decoder<'b, 'b> {
/// Decode a Service Binding (SVCB or HTTP) resource record
///
/// Preconditions
/// * The header and question sections should have already been decoded. Specifically, index of
/// any previously-identified domain names must already be captured.
///
/// Parameters
/// - `header` - the header that precedes the question section
/// - `https` - true for `HTTPS` resource records, false for `SVCB`
pub(super) fn rr_service_binding(
&'a mut self,
header: Header,
https: bool,
) -> DecodeResult<ServiceBinding> {
let priority = self.u16()?;
let target_name = self.domain_name()?;
let mut parameters = BTreeSet::new();
if priority != 0 {
while !self.is_finished()? {
let service_parameter_key = self.u16()?;
let value_length = self.u16()?;
let mut parameter_decoder = self.sub(value_length)?;
let service_parameter =
parameter_decoder.rr_service_parameter(service_parameter_key)?;
parameter_decoder.finished()?;
parameters.insert(service_parameter);
}
}
Ok(ServiceBinding {
name: header.domain_name,
ttl: header.ttl,
priority,
target_name,
parameters,
https,
})
}
}
impl<'a, 'b: 'a> Decoder<'a, 'b> {
/// Decode a single service parameter
///
/// Parameters:
/// - `service_parameter_key` - the IANA-controlled numeric identifier as defined in section 14.3 of the RFC
///
/// Returns:
/// - `Ok(ServiceParameter)` - if there were no issues decoding the value
/// - `Err` - if there was any decoding error
fn rr_service_parameter(
&mut self,
service_parameter_key: u16,
) -> DecodeResult<ServiceParameter> {
let service_parameter = match service_parameter_key {
0 => {
let mut key_ids = vec![];
while !self.is_finished()? {
key_ids.push(self.u16()?);
}
ServiceParameter::MANDATORY { key_ids }
}
1 => {
let mut alpn_ids = vec![];
while !self.is_finished()? {
alpn_ids.push(self.string_with_len()?);
}
ServiceParameter::ALPN { alpn_ids }
}
2 => ServiceParameter::NO_DEFAULT_ALPN,
3 => ServiceParameter::PORT { port: self.u16()? },
4 => {
let mut hints = vec![];
while !self.is_finished()? {
hints.push(self.ipv4_addr()?);
}
ServiceParameter::IPV4_HINT { hints }
}
5 => {
// Note the RFC does not explicitly state that the length is two octets
// "In wire format, the value of the parameter is an ECHConfigList [ECH],
// including the redundant length prefix." - RFC Section 9
let length = self.u16()? as usize;
let config_list = self.vec()?;
if config_list.len() != length {
return Err(ECHLengthMismatch(length, config_list.len()));
}
ServiceParameter::ECH { config_list }
}
6 => {
let mut hints = vec![];
while !self.is_finished()? {
hints.push(self.ipv6_addr()?);
}
ServiceParameter::IPV6_HINT { hints }
}
65535 => ServiceParameter::KEY_65535,
number => ServiceParameter::PRIVATE {
number,
wire_data: self.vec()?,
},
};
Ok(service_parameter)
}
}