Skip to main content

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