dns/
config.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use fuchsia_sync::Mutex;
6use std::collections::HashSet;
7use {fidl_fuchsia_net as net, fidl_fuchsia_net_ext as net_ext};
8
9/// Alias for a list of [`net::SocketAddress`].
10///
11/// The servers in the list are in priority order.
12pub type ServerList = Vec<net::SocketAddress>;
13
14/// Holds current [`ServerConfigSink`] state.
15#[derive(Debug)]
16struct ServerConfigInner {
17    servers: ServerList,
18}
19
20/// Provides shared access to a [`ServerList`].
21#[derive(Debug)]
22pub struct ServerConfigState(Mutex<ServerConfigInner>);
23
24/// The result of updating a [`ServerConfigState`].
25#[derive(Debug, PartialEq, Eq)]
26pub enum UpdateServersResult {
27    /// Server list was updated to the provided value.
28    Updated(ServerList),
29    /// No change was applied to the server list.
30    NoChange,
31    /// Invalid servers provided.
32    InvalidsServers,
33}
34
35impl ServerConfigState {
36    /// Creates a new empty `ServerConfigState`.
37    pub fn new() -> Self {
38        Self(Mutex::new(ServerConfigInner { servers: Vec::new() }))
39    }
40
41    /// Returns the servers.
42    pub fn servers(&self) -> ServerList {
43        let Self(current) = self;
44        let inner = current.lock();
45        inner.servers.clone()
46    }
47
48    /// Updates the server list after deduplication.
49    pub fn update_servers(&self, mut servers: ServerList) -> UpdateServersResult {
50        let Self(current) = self;
51
52        if servers.iter().any(|s| {
53            // Addresses must not contain an unspecified or multicast address.
54            let net_ext::SocketAddress(sockaddr) = From::from(*s);
55            let ip = sockaddr.ip();
56            ip.is_multicast() || ip.is_unspecified()
57        }) {
58            return UpdateServersResult::InvalidsServers;
59        }
60
61        let mut set = HashSet::new();
62        let () = servers.retain(|s| set.insert(*s));
63        let mut inner = current.lock();
64        if inner.servers == servers {
65            return UpdateServersResult::NoChange;
66        }
67        inner.servers = servers.clone();
68        UpdateServersResult::Updated(servers)
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75    use crate::test_util::*;
76    use net_declare::fidl_socket_addr;
77
78    #[test]
79    fn test_config_state() {
80        let state = ServerConfigState::new();
81        assert_eq!(state.servers(), []);
82
83        // Ordering is respected.
84        let values = [DHCP_SERVER, NDP_SERVER];
85        assert_eq!(
86            state.update_servers(values.to_vec()),
87            UpdateServersResult::Updated(values.to_vec())
88        );
89        assert_eq!(state.servers(), values);
90
91        // Duplicates are removed.
92        assert_eq!(
93            state.update_servers(vec![DHCP_SERVER, DHCP_SERVER, NDP_SERVER]),
94            UpdateServersResult::NoChange
95        );
96        assert_eq!(state.servers(), values);
97
98        // Bad addresses are rejected.
99        for addr in [
100            fidl_socket_addr!("0.0.0.0:1111"),
101            fidl_socket_addr!("[::]:2222"),
102            fidl_socket_addr!("224.0.0.1:3333"),
103            fidl_socket_addr!("[ff02::1]:4444"),
104        ] {
105            assert_eq!(state.update_servers(vec![addr]), UpdateServersResult::InvalidsServers);
106        }
107        assert_eq!(state.servers(), values);
108
109        // Empty inputs become empty output.
110        assert_eq!(state.update_servers(vec![]), UpdateServersResult::Updated(vec![]));
111        assert_eq!(state.servers(), []);
112    }
113}