// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! DNS Server watcher.

mod stream;
#[cfg(test)]
mod test_util;

use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};

use fidl_fuchsia_net::SocketAddress;
use fidl_fuchsia_net_name::{
    DhcpDnsServerSource, Dhcpv6DnsServerSource, DnsServerSource, DnsServer_, NdpDnsServerSource,
    StaticDnsServerSource,
};

pub use self::stream::*;

/// The default DNS server port.
pub const DEFAULT_DNS_PORT: u16 = 53;

/// The DNS servers learned from all sources.
#[derive(Default)]
pub struct DnsServers {
    /// DNS servers obtained from some default configurations.
    ///
    /// These servers will have the lowest priority of all servers.
    default: Vec<DnsServer_>,

    /// DNS servers obtained from the netstack.
    netstack: Vec<DnsServer_>,

    /// DNS servers obtained from DHCPv4 clients.
    dhcpv4: HashMap<u64, Vec<DnsServer_>>,

    /// DNS servers obtained from DHCPv6 clients.
    dhcpv6: HashMap<u64, Vec<DnsServer_>>,
}

impl DnsServers {
    /// Sets the DNS servers discovered from `source`.
    // TODO(https://fxbug.dev/42133326): Make sure `servers` only contain servers that could be obtained
    // from `source`.
    pub fn set_servers_from_source(
        &mut self,
        source: DnsServersUpdateSource,
        servers: Vec<DnsServer_>,
    ) {
        let Self { default, netstack, dhcpv4, dhcpv6 } = self;

        match source {
            DnsServersUpdateSource::Default => *default = servers,
            DnsServersUpdateSource::Netstack => *netstack = servers,
            DnsServersUpdateSource::Dhcpv4 { interface_id } => {
                // We discard existing servers since they are being replaced with
                // `servers` - the old servers are useless to us now.
                let _: Option<Vec<DnsServer_>> = if servers.is_empty() {
                    dhcpv4.remove(&interface_id)
                } else {
                    dhcpv4.insert(interface_id, servers)
                };
            }
            DnsServersUpdateSource::Dhcpv6 { interface_id } => {
                // We discard existing servers since they are being replaced with
                // `servers` - the old servers are useless to us now.
                let _: Option<Vec<DnsServer_>> = if servers.is_empty() {
                    dhcpv6.remove(&interface_id)
                } else {
                    dhcpv6.insert(interface_id, servers)
                };
            }
        }
    }

    /// Returns a consolidated list of server addresses.
    ///
    /// The servers will be returned deduplicated by their address and sorted by the source
    /// that each server was learned from. The servers will be sorted in most to least
    /// preferred order, with the most preferred server first. The preference of the servers
    /// is NDP, DHCPv4, DHCPv6 then Static, where NDP is the most preferred. No ordering is
    /// guaranteed across servers from different sources of the same source-kind, but ordering
    /// within a source is maintained.
    ///
    /// Example, say we had servers SA1 and SA2 set for DHCPv6 interface A, and SB1 and SB2
    /// for DHCPv6 interface B. The consolidated list will be either one of [SA1, SA2, SB1, SB2]
    /// or [SB1, SB2, SA1, SA2]. Notice how the ordering across sources (DHCPv6 interface A vs
    /// DHCPv6 interface B) is not fixed, but the ordering within the source ([SA1, SA2] for DHCPv6
    /// interface A and [SB1, SB2] for DHCPv6 interface B) is maintained.
    ///
    /// Note, if multiple `DnsServer_`s have the same address but different sources, only
    /// the `DnsServer_` with the most preferred source will be present in the consolidated
    /// list of servers.
    // TODO(https://fxbug.dev/42133571): Consider ordering across sources of the same source-kind based on some
    // metric.
    pub fn consolidated(&self) -> Vec<SocketAddress> {
        self.consolidate_filter_map(|x| x.address)
    }

    /// Returns a consolidated list of servers, with the mapping function `f` applied.
    ///
    /// See `consolidated` for details on ordering.
    fn consolidate_filter_map<T, F: Fn(DnsServer_) -> Option<T>>(&self, f: F) -> Vec<T> {
        let Self { default, netstack, dhcpv4, dhcpv6 } = self;
        let mut servers = netstack
            .iter()
            .chain(dhcpv4.values().flatten())
            .chain(dhcpv6.values().flatten())
            .cloned()
            .collect::<Vec<_>>();
        // Sorting happens before deduplication to ensure that when multiple sources report the same
        // address, the highest priority source wins.
        //
        // `sort_by` maintains the order of equal elements. This is required to maintain ordering
        // within a source of DNS servers. `sort_unstable_by` may not preserve this ordering.
        let () = servers.sort_by(Self::ordering);
        // Default servers are considered to have the lowest priority so we append them to the end
        // of the list of sorted dynamically learned servers.
        let () = servers.extend(default.clone());
        let mut addresses = HashSet::new();
        let () = servers.retain(move |s| addresses.insert(s.address));
        servers.into_iter().filter_map(f).collect()
    }

    /// Returns the ordering of [`DnsServer_`]s.
    ///
    /// The ordering from most to least preferred is is DHCP, NDP, DHCPv6, then Static. Preference
    /// is currently informed by a goal of keeping servers discovered via the same internet
    /// protocol together and preferring network-supplied configurations over product-supplied
    /// ones.
    ///
    /// TODO(https://fxbug.dev/42125772): We currently prioritize IPv4 servers over IPv6 as our DHCPv6
    /// client does not yet support stateful address assignment. This can result in situations
    /// where we can discover v6 nameservers that can't be reached as we've not discovered a global
    /// address.
    ///
    /// An unspecified source will be treated as a static address.
    fn ordering(a: &DnsServer_, b: &DnsServer_) -> Ordering {
        let ordering = |source| match source {
            Some(&DnsServerSource::Dhcp(DhcpDnsServerSource { source_interface: _, .. })) => 0,
            Some(&DnsServerSource::Ndp(NdpDnsServerSource { source_interface: _, .. })) => 1,
            Some(&DnsServerSource::Dhcpv6(Dhcpv6DnsServerSource {
                source_interface: _, ..
            })) => 2,
            Some(&DnsServerSource::StaticSource(StaticDnsServerSource { .. })) | None => 3,
        };
        let a = ordering(a.source.as_ref());
        let b = ordering(b.source.as_ref());
        std::cmp::Ord::cmp(&a, &b)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::test_util::constants::*;

    #[test]
    fn deduplicate_within_source() {
        // Simple deduplication and sorting of repeated `DnsServer_`.
        let servers = DnsServers {
            default: vec![ndp_server(), ndp_server()],
            netstack: vec![ndp_server(), static_server(), ndp_server(), static_server()],
            // `DHCPV4/6_SERVER2` would normally only come from an interface with ID
            // `DHCPV4/6_SERVER2_INTERFACE_ID`, but we are just testing deduplication
            // logic here.
            dhcpv4: [
                (DHCPV4_SERVER1_INTERFACE_ID, vec![dhcpv4_server1(), dhcpv4_server2()]),
                (DHCPV4_SERVER2_INTERFACE_ID, vec![dhcpv4_server1(), dhcpv4_server2()]),
            ]
            .into_iter()
            .collect(),
            dhcpv6: [
                (DHCPV6_SERVER1_INTERFACE_ID, vec![dhcpv6_server1(), dhcpv6_server2()]),
                (DHCPV6_SERVER2_INTERFACE_ID, vec![dhcpv6_server1(), dhcpv6_server2()]),
            ]
            .into_iter()
            .collect(),
        };
        // Ordering across (the DHCPv6) sources is not guaranteed, but both DHCPv6 sources
        // have the same set of servers with the same order. With deduplication, we know
        // we will only see one of the sources' servers.
        assert_eq!(
            servers.consolidated(),
            vec![
                DHCPV4_SOURCE_SOCKADDR1,
                DHCPV4_SOURCE_SOCKADDR2,
                NDP_SOURCE_SOCKADDR,
                DHCPV6_SOURCE_SOCKADDR1,
                DHCPV6_SOURCE_SOCKADDR2,
                STATIC_SOURCE_SOCKADDR,
            ],
        );
    }

    #[test]
    fn default_low_prio() {
        // Default servers should always have low priority, but if the same server
        // is observed by a higher priority source, then use the higher source for
        // ordering.
        let servers = DnsServers {
            default: vec![static_server(), ndp_server(), dhcpv4_server1(), dhcpv6_server1()],
            netstack: vec![static_server()],
            dhcpv4: [
                (DHCPV4_SERVER1_INTERFACE_ID, vec![dhcpv4_server1()]),
                (DHCPV4_SERVER2_INTERFACE_ID, vec![dhcpv4_server1()]),
            ]
            .into_iter()
            .collect(),
            dhcpv6: [
                (DHCPV6_SERVER1_INTERFACE_ID, vec![dhcpv6_server1()]),
                (DHCPV6_SERVER2_INTERFACE_ID, vec![dhcpv6_server2()]),
            ]
            .into_iter()
            .collect(),
        };
        // No ordering is guaranteed across servers from different sources of the same
        // source-kind.
        let mut got = servers.consolidated();
        let mut got = got.drain(..);
        let want_dhcpv4 = [DHCPV4_SOURCE_SOCKADDR1];
        assert_eq!(
            HashSet::from_iter(got.by_ref().take(want_dhcpv4.len())),
            HashSet::from(want_dhcpv4),
        );

        let want_dhcpv6 = [DHCPV6_SOURCE_SOCKADDR1, DHCPV6_SOURCE_SOCKADDR2];
        assert_eq!(
            HashSet::from_iter(got.by_ref().take(want_dhcpv6.len())),
            HashSet::from(want_dhcpv6),
        );

        let want_rest = [STATIC_SOURCE_SOCKADDR, NDP_SOURCE_SOCKADDR];
        assert_eq!(got.as_slice(), want_rest);
    }

    #[test]
    fn deduplicate_across_sources() {
        // Deduplication and sorting of same address across different sources.

        // DHCPv6 is not as preferred as NDP so this should not be in the consolidated
        // servers list.
        let dhcpv6_with_ndp_address = || DnsServer_ {
            address: Some(NDP_SOURCE_SOCKADDR),
            source: Some(DnsServerSource::Dhcpv6(Dhcpv6DnsServerSource {
                source_interface: Some(DHCPV6_SERVER1_INTERFACE_ID),
                ..Default::default()
            })),
            ..Default::default()
        };
        let mut dhcpv6 = HashMap::new();
        assert_matches::assert_matches!(
            dhcpv6.insert(
                DHCPV6_SERVER1_INTERFACE_ID,
                vec![dhcpv6_with_ndp_address(), dhcpv6_server1()]
            ),
            None
        );
        let mut servers = DnsServers {
            default: vec![],
            netstack: vec![
                dhcpv6_with_ndp_address(),
                dhcpv4_server1(),
                ndp_server(),
                static_server(),
            ],
            dhcpv4: [(DHCPV4_SERVER1_INTERFACE_ID, vec![dhcpv4_server1()])].into_iter().collect(),
            dhcpv6: [(
                DHCPV6_SERVER1_INTERFACE_ID,
                vec![dhcpv6_with_ndp_address(), dhcpv6_server1()],
            )]
            .into_iter()
            .collect(),
        };
        let expected_servers =
            vec![dhcpv4_server1(), ndp_server(), dhcpv6_server1(), static_server()];
        assert_eq!(servers.consolidate_filter_map(Some), expected_servers);
        let expected_sockaddrs = vec![
            DHCPV4_SOURCE_SOCKADDR1,
            NDP_SOURCE_SOCKADDR,
            DHCPV6_SOURCE_SOCKADDR1,
            STATIC_SOURCE_SOCKADDR,
        ];
        assert_eq!(servers.consolidated(), expected_sockaddrs);
        servers.netstack =
            vec![dhcpv4_server1(), ndp_server(), static_server(), dhcpv6_with_ndp_address()];
        assert_eq!(servers.consolidate_filter_map(Some), expected_servers);
        assert_eq!(servers.consolidated(), expected_sockaddrs);

        // NDP is more preferred than DHCPv6 so `dhcpv6_server1()` should not be in the
        // consolidated list of servers.
        let ndp_with_dhcpv6_sockaddr1 = || DnsServer_ {
            address: Some(DHCPV6_SOURCE_SOCKADDR1),
            source: Some(DnsServerSource::Ndp(NdpDnsServerSource {
                source_interface: Some(NDP_SERVER_INTERFACE_ID),
                ..Default::default()
            })),
            ..Default::default()
        };

        let mut dhcpv6 = HashMap::new();
        assert_matches::assert_matches!(
            dhcpv6.insert(DHCPV6_SERVER1_INTERFACE_ID, vec![dhcpv6_server1()]),
            None
        );
        assert_matches::assert_matches!(
            dhcpv6.insert(DHCPV6_SERVER2_INTERFACE_ID, vec![dhcpv6_server2()]),
            None
        );
        let mut servers = DnsServers {
            default: vec![],
            netstack: vec![ndp_with_dhcpv6_sockaddr1(), static_server()],
            dhcpv4: Default::default(),
            dhcpv6,
        };
        let expected_servers = vec![ndp_with_dhcpv6_sockaddr1(), dhcpv6_server2(), static_server()];
        assert_eq!(servers.consolidate_filter_map(Some), expected_servers);
        let expected_sockaddrs =
            vec![DHCPV6_SOURCE_SOCKADDR1, DHCPV6_SOURCE_SOCKADDR2, STATIC_SOURCE_SOCKADDR];
        assert_eq!(servers.consolidated(), expected_sockaddrs);
        servers.netstack = vec![static_server(), ndp_with_dhcpv6_sockaddr1()];
        assert_eq!(servers.consolidate_filter_map(Some), expected_servers);
        assert_eq!(servers.consolidated(), expected_sockaddrs);
    }

    #[test]
    fn test_dns_servers_ordering() {
        assert_eq!(DnsServers::ordering(&ndp_server(), &ndp_server()), Ordering::Equal);
        assert_eq!(DnsServers::ordering(&dhcpv4_server1(), &dhcpv4_server1()), Ordering::Equal);
        assert_eq!(DnsServers::ordering(&dhcpv6_server1(), &dhcpv6_server1()), Ordering::Equal);
        assert_eq!(DnsServers::ordering(&static_server(), &static_server()), Ordering::Equal);
        assert_eq!(
            DnsServers::ordering(&unspecified_source_server(), &unspecified_source_server()),
            Ordering::Equal
        );
        assert_eq!(
            DnsServers::ordering(&static_server(), &unspecified_source_server()),
            Ordering::Equal
        );

        let servers = [
            dhcpv4_server1(),
            ndp_server(),
            dhcpv6_server1(),
            static_server(),
            unspecified_source_server(),
        ];
        // We don't compare the last two servers in the list because their ordering is equal
        // w.r.t. eachother.
        for (i, a) in servers[..servers.len() - 2].iter().enumerate() {
            for b in servers[i + 1..].iter() {
                assert_eq!(DnsServers::ordering(a, b), Ordering::Less);
            }
        }

        let mut servers = vec![dhcpv6_server1(), dhcpv4_server1(), static_server(), ndp_server()];
        servers.sort_by(DnsServers::ordering);
        assert_eq!(
            servers,
            vec![dhcpv4_server1(), ndp_server(), dhcpv6_server1(), static_server()]
        );
    }
}
