1mod stream;
8#[cfg(test)]
9mod test_util;
10
11use std::cmp::Ordering;
12use std::collections::{HashMap, HashSet};
13
14use fidl_fuchsia_net::SocketAddress;
15use fidl_fuchsia_net_name::{
16 DhcpDnsServerSource, Dhcpv6DnsServerSource, DnsServer_, DnsServerSource, NdpDnsServerSource,
17 SocketProxyDnsServerSource, StaticDnsServerSource,
18};
19
20pub use self::stream::*;
21
22pub const DEFAULT_DNS_PORT: u16 = 53;
24
25#[derive(Debug, Default)]
27pub struct DnsServers {
28 default: Vec<DnsServer_>,
32
33 dhcpv4: HashMap<u64, Vec<DnsServer_>>,
35
36 dhcpv6: HashMap<u64, Vec<DnsServer_>>,
38
39 ndp: HashMap<u64, Vec<DnsServer_>>,
41
42 socketproxy: Vec<DnsServer_>,
44}
45
46impl DnsServers {
47 pub fn set_servers_from_source(
51 &mut self,
52 source: DnsServersUpdateSource,
53 servers: Vec<DnsServer_>,
54 ) {
55 let Self { default, dhcpv4, dhcpv6, ndp, socketproxy } = self;
56
57 match source {
58 DnsServersUpdateSource::Default => *default = servers,
59 DnsServersUpdateSource::Dhcpv4 { interface_id } => {
60 let _: Option<Vec<DnsServer_>> = if servers.is_empty() {
63 dhcpv4.remove(&interface_id)
64 } else {
65 dhcpv4.insert(interface_id, servers)
66 };
67 }
68 DnsServersUpdateSource::Dhcpv6 { interface_id } => {
69 let _: Option<Vec<DnsServer_>> = if servers.is_empty() {
72 dhcpv6.remove(&interface_id)
73 } else {
74 dhcpv6.insert(interface_id, servers)
75 };
76 }
77 DnsServersUpdateSource::Ndp { interface_id } => {
78 let _: Option<Vec<DnsServer_>> = if servers.is_empty() {
81 ndp.remove(&interface_id)
82 } else {
83 ndp.insert(interface_id, servers)
84 };
85 }
86 DnsServersUpdateSource::SocketProxy => *socketproxy = servers,
87 }
88 }
89
90 pub fn consolidated(&self) -> Vec<SocketAddress> {
111 self.consolidate_filter_map(|x| x.address)
112 }
113
114 pub fn consolidated_dns_servers(&self) -> Vec<DnsServer_> {
133 self.consolidate_filter_map(|x| Some(x))
134 }
135
136 fn consolidate_filter_map<T, F: Fn(DnsServer_) -> Option<T>>(&self, f: F) -> Vec<T> {
140 let Self { default, dhcpv4, dhcpv6, ndp, socketproxy } = self;
141 let mut servers = socketproxy
142 .iter()
143 .chain(dhcpv4.values().flatten())
144 .chain(ndp.values().flatten())
145 .chain(dhcpv6.values().flatten())
146 .cloned()
147 .collect::<Vec<_>>();
148 servers.sort_by(Self::ordering);
154 servers.extend(default.clone());
157 let mut addresses = HashSet::new();
158 servers.retain(move |s| addresses.insert(s.address));
159 servers.into_iter().filter_map(f).collect()
160 }
161
162 fn ordering(a: &DnsServer_, b: &DnsServer_) -> Ordering {
178 let ordering = |source| match source {
179 Some(&DnsServerSource::SocketProxy(SocketProxyDnsServerSource {
180 source_interface: _,
181 ..
182 })) => 0,
183 Some(&DnsServerSource::Dhcp(DhcpDnsServerSource { source_interface: _, .. })) => 1,
184 Some(&DnsServerSource::Ndp(NdpDnsServerSource { source_interface: _, .. })) => 2,
185 Some(&DnsServerSource::Dhcpv6(Dhcpv6DnsServerSource {
186 source_interface: _, ..
187 })) => 3,
188 Some(&DnsServerSource::StaticSource(StaticDnsServerSource { .. })) => 4,
189 Some(&DnsServerSource::__SourceBreaking { .. }) | None => 5,
190 };
191 let a = ordering(a.source.as_ref());
192 let b = ordering(b.source.as_ref());
193 std::cmp::Ord::cmp(&a, &b)
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200 use crate::test_util::constants::*;
201
202 #[test]
203 fn deduplicate_within_source() {
204 let servers = DnsServers {
206 default: vec![ndp_server(), static_server(), ndp_server(), static_server()],
207 dhcpv4: [
211 (DHCPV4_SERVER1_INTERFACE_ID, vec![dhcpv4_server1(), dhcpv4_server2()]),
212 (DHCPV4_SERVER2_INTERFACE_ID, vec![dhcpv4_server1(), dhcpv4_server2()]),
213 ]
214 .into_iter()
215 .collect(),
216 dhcpv6: [
217 (DHCPV6_SERVER1_INTERFACE_ID, vec![dhcpv6_server1(), dhcpv6_server2()]),
218 (DHCPV6_SERVER2_INTERFACE_ID, vec![dhcpv6_server1(), dhcpv6_server2()]),
219 ]
220 .into_iter()
221 .collect(),
222 ndp: [(NDP_SERVER_INTERFACE_ID, vec![ndp_server(), ndp_server()])]
223 .into_iter()
224 .collect(),
225 socketproxy: vec![socketproxy_server1(), socketproxy_server2(), socketproxy_server1()],
226 };
227 assert_eq!(
231 servers.consolidated(),
232 vec![
233 SOCKETPROXY_SOURCE_SOCKADDR1,
234 SOCKETPROXY_SOURCE_SOCKADDR2,
235 DHCPV4_SOURCE_SOCKADDR1,
236 DHCPV4_SOURCE_SOCKADDR2,
237 NDP_SOURCE_SOCKADDR,
238 DHCPV6_SOURCE_SOCKADDR1,
239 DHCPV6_SOURCE_SOCKADDR2,
240 STATIC_SOURCE_SOCKADDR,
241 ],
242 );
243 }
244
245 #[test]
246 fn default_low_prio() {
247 let servers = DnsServers {
251 default: vec![
252 static_server(),
253 dhcpv4_server1(),
254 dhcpv6_server1(),
255 socketproxy_server1(),
256 ],
257 dhcpv4: [
258 (DHCPV4_SERVER1_INTERFACE_ID, vec![dhcpv4_server1()]),
259 (DHCPV4_SERVER2_INTERFACE_ID, vec![dhcpv4_server1()]),
260 ]
261 .into_iter()
262 .collect(),
263 dhcpv6: [
264 (DHCPV6_SERVER1_INTERFACE_ID, vec![dhcpv6_server1()]),
265 (DHCPV6_SERVER2_INTERFACE_ID, vec![dhcpv6_server2()]),
266 ]
267 .into_iter()
268 .collect(),
269 ndp: [(NDP_SERVER_INTERFACE_ID, vec![ndp_server()])].into_iter().collect(),
270 socketproxy: vec![socketproxy_server1()],
271 };
272 let mut got = servers.consolidated();
275 let mut got = got.drain(..);
276 let want_socketproxy = [SOCKETPROXY_SOURCE_SOCKADDR1];
277 assert_eq!(
278 HashSet::from_iter(got.by_ref().take(want_socketproxy.len())),
279 HashSet::from(want_socketproxy),
280 );
281
282 let want_dhcpv4 = [DHCPV4_SOURCE_SOCKADDR1];
283 assert_eq!(
284 HashSet::from_iter(got.by_ref().take(want_dhcpv4.len())),
285 HashSet::from(want_dhcpv4),
286 );
287
288 let want_ndp = [NDP_SOURCE_SOCKADDR];
289 assert_eq!(HashSet::from_iter(got.by_ref().take(want_ndp.len())), HashSet::from(want_ndp));
290
291 let want_dhcpv6 = [DHCPV6_SOURCE_SOCKADDR1, DHCPV6_SOURCE_SOCKADDR2];
292 assert_eq!(
293 HashSet::from_iter(got.by_ref().take(want_dhcpv6.len())),
294 HashSet::from(want_dhcpv6),
295 );
296
297 let want_rest = [STATIC_SOURCE_SOCKADDR];
298 assert_eq!(got.as_slice(), want_rest);
299 }
300
301 #[test]
302 fn deduplicate_across_sources() {
303 let dhcpv6_with_ndp_address = || DnsServer_ {
308 address: Some(NDP_SOURCE_SOCKADDR),
309 source: Some(DnsServerSource::Dhcpv6(Dhcpv6DnsServerSource {
310 source_interface: Some(DHCPV6_SERVER1_INTERFACE_ID),
311 ..Default::default()
312 })),
313 ..Default::default()
314 };
315 let mut dhcpv6 = HashMap::new();
316 assert_matches::assert_matches!(
317 dhcpv6.insert(
318 DHCPV6_SERVER1_INTERFACE_ID,
319 vec![dhcpv6_with_ndp_address(), dhcpv6_server1()]
320 ),
321 None
322 );
323 let servers = DnsServers {
324 default: vec![static_server()],
325 dhcpv4: [(DHCPV4_SERVER1_INTERFACE_ID, vec![dhcpv4_server1()])].into_iter().collect(),
326 dhcpv6: [(
327 DHCPV6_SERVER1_INTERFACE_ID,
328 vec![dhcpv6_with_ndp_address(), dhcpv6_server1()],
329 )]
330 .into_iter()
331 .collect(),
332 ndp: [(NDP_SERVER_INTERFACE_ID, vec![ndp_server(), dhcpv6_with_ndp_address()])]
333 .into_iter()
334 .collect(),
335 socketproxy: vec![],
336 };
337 let expected_servers =
338 vec![dhcpv4_server1(), ndp_server(), dhcpv6_server1(), static_server()];
339 assert_eq!(servers.consolidate_filter_map(Some), expected_servers);
340 let expected_sockaddrs = vec![
341 DHCPV4_SOURCE_SOCKADDR1,
342 NDP_SOURCE_SOCKADDR,
343 DHCPV6_SOURCE_SOCKADDR1,
344 STATIC_SOURCE_SOCKADDR,
345 ];
346 assert_eq!(servers.consolidated(), expected_sockaddrs);
347
348 let ndp_with_dhcpv6_sockaddr1 = || DnsServer_ {
351 address: Some(DHCPV6_SOURCE_SOCKADDR1),
352 source: Some(DnsServerSource::Ndp(NdpDnsServerSource {
353 source_interface: Some(NDP_SERVER_INTERFACE_ID),
354 ..Default::default()
355 })),
356 ..Default::default()
357 };
358
359 let mut dhcpv6 = HashMap::new();
360 assert_matches::assert_matches!(
361 dhcpv6.insert(DHCPV6_SERVER1_INTERFACE_ID, vec![dhcpv6_server1()]),
362 None
363 );
364 assert_matches::assert_matches!(
365 dhcpv6.insert(DHCPV6_SERVER2_INTERFACE_ID, vec![dhcpv6_server2()]),
366 None
367 );
368 let servers = DnsServers {
369 default: vec![static_server()],
370 dhcpv4: Default::default(),
371 dhcpv6,
372 ndp: [(NDP_SERVER_INTERFACE_ID, vec![ndp_with_dhcpv6_sockaddr1()])]
373 .into_iter()
374 .collect(),
375 socketproxy: vec![],
376 };
377 let expected_servers = vec![ndp_with_dhcpv6_sockaddr1(), dhcpv6_server2(), static_server()];
378 assert_eq!(servers.consolidate_filter_map(Some), expected_servers);
379 let expected_sockaddrs =
380 vec![DHCPV6_SOURCE_SOCKADDR1, DHCPV6_SOURCE_SOCKADDR2, STATIC_SOURCE_SOCKADDR];
381 assert_eq!(servers.consolidated(), expected_sockaddrs);
382 }
383
384 #[test]
385 fn test_dns_servers_ordering() {
386 assert_eq!(
387 DnsServers::ordering(&socketproxy_server1(), &socketproxy_server1()),
388 Ordering::Equal
389 );
390 assert_eq!(DnsServers::ordering(&ndp_server(), &ndp_server()), Ordering::Equal);
391 assert_eq!(DnsServers::ordering(&dhcpv4_server1(), &dhcpv4_server1()), Ordering::Equal);
392 assert_eq!(DnsServers::ordering(&dhcpv6_server1(), &dhcpv6_server1()), Ordering::Equal);
393 assert_eq!(DnsServers::ordering(&static_server(), &static_server()), Ordering::Equal);
394 assert_eq!(
395 DnsServers::ordering(&unspecified_source_server(), &unspecified_source_server()),
396 Ordering::Equal
397 );
398
399 let mut servers = vec![
400 unspecified_source_server(),
401 dhcpv6_server1(),
402 dhcpv4_server1(),
403 static_server(),
404 ndp_server(),
405 socketproxy_server1(),
406 ];
407 servers.sort_by(DnsServers::ordering);
408 assert_eq!(
409 servers,
410 vec![
411 socketproxy_server1(),
412 dhcpv4_server1(),
413 ndp_server(),
414 dhcpv6_server1(),
415 static_server(),
416 unspecified_source_server(),
417 ]
418 );
419 }
420}