1use crate::{
3 Addr, AnonymizedDnsCryptRelay, DnsCrypt, DnsOverHttps, DnsOverTls, DnsPlain, DnsStamp,
4 DnsStampType, EncodeError, EncodeResult, ObliviousDoHTarget, Props,
5};
6use base64::{prelude::BASE64_URL_SAFE_NO_PAD, Engine};
7use std::net::{IpAddr, SocketAddr};
8
9fn encode_type(buffer: &mut Vec<u8>, dns_stamp_type: DnsStampType) {
11 buffer.push(dns_stamp_type as u8);
12}
13
14fn encode_props(buffer: &mut Vec<u8>, props: &Props) {
16 let bytes = props.bits().to_le_bytes();
17 buffer.extend(bytes.iter());
18}
19
20fn encode_bytes(buffer: &mut Vec<u8>, bytes: impl AsRef<[u8]>) -> EncodeResult<()> {
22 let bytes = bytes.as_ref();
23 let len = bytes.len();
24 if len <= u8::MAX as usize {
25 buffer.push(len as u8);
26 buffer.extend(bytes);
27 Ok(())
28 } else {
29 Err(EncodeError::TooManyBytes)
30 }
31}
32
33fn ip_addr_to_string(ip_addr: IpAddr) -> String {
35 let mut string = ip_addr.to_string();
36 if ip_addr.is_ipv6() {
37 string = format!("[{}]", string);
38 }
39 string
40}
41
42fn socket_addr_to_string(socket_addr: SocketAddr, default_port: u16) -> String {
44 match socket_addr {
45 SocketAddr::V6(socket_addr_v6) => {
46 if socket_addr_v6.scope_id() == 0 && socket_addr.port() == default_port {
47 ip_addr_to_string(socket_addr.ip())
48 } else {
49 socket_addr.to_string()
50 }
51 }
52 SocketAddr::V4(socket_addr_v4) => {
53 if socket_addr_v4.port() == default_port {
54 ip_addr_to_string(socket_addr.ip())
55 } else {
56 socket_addr_v4.to_string()
57 }
58 }
59 }
60}
61
62fn encode_socket_addr(
66 buffer: &mut Vec<u8>,
67 socket_addr: SocketAddr,
68 default_port: u16,
69) -> EncodeResult<()> {
70 let string = socket_addr_to_string(socket_addr, default_port);
71 encode_bytes(buffer, &string)
72}
73
74fn addr_to_string(addr: Addr, default_port: u16) -> String {
76 match addr {
77 Addr::SocketAddr(socket_addr) => socket_addr_to_string(socket_addr, default_port),
78 Addr::Port(port) => format!(":{}", port),
79 }
80}
81
82fn option_addr_to_string(addr: Option<Addr>, default_port: u16) -> String {
84 match addr {
85 Some(addr) => addr_to_string(addr, default_port),
86 None => "".to_string(),
87 }
88}
89
90fn encode_option_addr(
93 buffer: &mut Vec<u8>,
94 addr: Option<Addr>,
95 default_port: u16,
96) -> EncodeResult<()> {
97 let string = option_addr_to_string(addr, default_port);
98 encode_bytes(buffer, string)
99}
100
101fn encode_ip_addr(buffer: &mut Vec<u8>, ip_addr: IpAddr) -> EncodeResult<()> {
103 let string = ip_addr_to_string(ip_addr);
104 encode_bytes(buffer, &string)
105}
106
107fn encode_pk(buffer: &mut Vec<u8>, pk: &[u8; 32]) -> EncodeResult<()> {
109 encode_bytes(buffer, &pk[..])
110}
111
112fn encode_vlp<T: AsRef<[u8]>>(buffer: &mut Vec<u8>, vlp: &[T]) -> EncodeResult<()> {
117 if vlp.is_empty() {
118 encode_bytes(buffer, [])
119 } else {
120 let len = vlp.len();
121 if let Some(array) = vlp.get(..(len - 1)) {
122 for bytes in array {
123 let bytes = bytes.as_ref();
124 let len = bytes.len();
125 if len <= 0x80 {
126 buffer.push((len ^ 0x80) as u8);
127 buffer.extend(bytes);
128 } else {
129 return Err(EncodeError::TooManyBytes);
130 }
131 }
132 }
133 if let Some(bytes) = vlp.get(len - 1) {
134 encode_bytes(buffer, bytes)
135 } else {
136 Err(EncodeError::EmptyArray)
137 }
138 }
139}
140
141fn encode_hashi(buffer: &mut Vec<u8>, hashi: &[[u8; 32]]) -> EncodeResult<()> {
143 encode_vlp(buffer, hashi)
144}
145
146fn encode_bootstrap_ipi(buffer: &mut Vec<u8>, bootstrap_ipi: &[IpAddr]) -> EncodeResult<()> {
148 encode_vlp(
149 buffer,
150 &bootstrap_ipi
151 .iter()
152 .cloned()
153 .map(ip_addr_to_string)
154 .collect::<Vec<_>>(),
155 )
156}
157
158fn encode_base64(buffer: &[u8]) -> String {
160 format!("sdns://{}", BASE64_URL_SAFE_NO_PAD.encode(buffer))
161}
162
163fn encode_dns_plain(buffer: &mut Vec<u8>, dns_plain: &DnsPlain) -> EncodeResult<()> {
165 encode_type(buffer, DnsStampType::Plain);
166 encode_props(buffer, &dns_plain.props);
167 encode_ip_addr(buffer, dns_plain.addr)?;
168 Ok(())
169}
170
171fn encode_dns_crypt(buffer: &mut Vec<u8>, dns_crypt: &DnsCrypt) -> EncodeResult<()> {
173 encode_type(buffer, DnsStampType::DnsCrypt);
174 encode_props(buffer, &dns_crypt.props);
175 encode_socket_addr(buffer, dns_crypt.addr, 443)?;
176 encode_pk(buffer, &dns_crypt.pk)?;
177 encode_bytes(buffer, &dns_crypt.provider_name)?;
178 Ok(())
179}
180
181fn encode_dns_over_https_data(
183 buffer: &mut Vec<u8>,
184 dns_over_https: &DnsOverHttps,
185) -> EncodeResult<()> {
186 encode_props(buffer, &dns_over_https.props);
187 encode_option_addr(buffer, dns_over_https.addr, 443)?;
188 encode_hashi(buffer, &dns_over_https.hashi)?;
189 encode_bytes(buffer, &dns_over_https.hostname)?;
190 encode_bytes(buffer, &dns_over_https.path)?;
191 if !dns_over_https.bootstrap_ipi.is_empty() {
192 encode_bootstrap_ipi(buffer, &dns_over_https.bootstrap_ipi)?;
193 }
194 Ok(())
195}
196
197fn encode_dns_over_https(buffer: &mut Vec<u8>, dns_over_https: &DnsOverHttps) -> EncodeResult<()> {
200 encode_type(buffer, DnsStampType::DnsOverHttps);
201 encode_dns_over_https_data(buffer, dns_over_https)
202}
203
204fn encode_oblivious_doh_relay(
207 buffer: &mut Vec<u8>,
208 dns_over_https: &DnsOverHttps,
209) -> EncodeResult<()> {
210 encode_type(buffer, DnsStampType::ObliviousDoHRelay);
211 encode_dns_over_https_data(buffer, dns_over_https)
212}
213
214fn encode_dns_over_tls_data(buffer: &mut Vec<u8>, dns_over_tls: &DnsOverTls) -> EncodeResult<()> {
216 encode_props(buffer, &dns_over_tls.props);
217 encode_option_addr(buffer, dns_over_tls.addr, 443)?;
218 encode_hashi(buffer, &dns_over_tls.hashi)?;
219 encode_bytes(buffer, &dns_over_tls.hostname)?;
220 if !dns_over_tls.bootstrap_ipi.is_empty() {
221 encode_bootstrap_ipi(buffer, &dns_over_tls.bootstrap_ipi)?;
222 }
223 Ok(())
224}
225
226fn encode_dns_over_tls(buffer: &mut Vec<u8>, dns_over_tls: &DnsOverTls) -> EncodeResult<()> {
228 encode_type(buffer, DnsStampType::DnsOverTls);
229 encode_dns_over_tls_data(buffer, dns_over_tls)?;
230 Ok(())
231}
232
233fn encode_dns_over_quic(buffer: &mut Vec<u8>, dns_over_tls: &DnsOverTls) -> EncodeResult<()> {
235 encode_type(buffer, DnsStampType::DnsOverQuic);
236 encode_dns_over_tls_data(buffer, dns_over_tls)?;
237 Ok(())
238}
239
240fn encode_oblivious_doh_target(
243 buffer: &mut Vec<u8>,
244 oblivious_doh_target: &ObliviousDoHTarget,
245) -> EncodeResult<()> {
246 encode_type(buffer, DnsStampType::ObliviousDoHTarget);
247 encode_props(buffer, &oblivious_doh_target.props);
248 encode_bytes(buffer, &oblivious_doh_target.hostname)?;
249 encode_bytes(buffer, &oblivious_doh_target.path)?;
250 Ok(())
251}
252
253fn encode_anonymized_dns_crypt_relay(
256 buffer: &mut Vec<u8>,
257 anonymized_dns_crypt_relay: &AnonymizedDnsCryptRelay,
258) -> EncodeResult<()> {
259 encode_type(buffer, DnsStampType::AnonymizedDnsCryptRelay);
260 encode_socket_addr(buffer, anonymized_dns_crypt_relay.addr, 443)?;
261 Ok(())
262}
263
264impl DnsStamp {
265 pub fn encode(&self) -> EncodeResult<String> {
267 let mut buffer = Vec::new();
268 match self {
269 DnsStamp::DnsPlain(dns_plain) => encode_dns_plain(&mut buffer, dns_plain)?,
270 DnsStamp::DnsCrypt(dns_crypt) => encode_dns_crypt(&mut buffer, dns_crypt)?,
271 DnsStamp::DnsOverHttps(dns_over_https) => {
272 encode_dns_over_https(&mut buffer, dns_over_https)?
273 }
274 DnsStamp::DnsOverTls(dns_over_tls) => encode_dns_over_tls(&mut buffer, dns_over_tls)?,
275 DnsStamp::DnsOverQuic(dns_over_quic) => {
276 encode_dns_over_quic(&mut buffer, dns_over_quic)?
277 }
278 DnsStamp::ObliviousDoHTarget(oblivious_doh_target) => {
279 encode_oblivious_doh_target(&mut buffer, oblivious_doh_target)?
280 }
281 DnsStamp::AnonymizedDnsCryptRelay(anonymized_dns_crypt_relay) => {
282 encode_anonymized_dns_crypt_relay(&mut buffer, anonymized_dns_crypt_relay)?;
283 }
284 DnsStamp::ObliviousDoHRelay(oblivious_doh_relay) => {
285 encode_oblivious_doh_relay(&mut buffer, oblivious_doh_relay)?;
286 }
287 }
288
289 Ok(encode_base64(&buffer))
290 }
291}