blob: a8e8546b3fbf9a8db317bbfa32fc77573b158544 [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef DNS_PROXY_PROXY_H_
#define DNS_PROXY_PROXY_H_
#include <iostream>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include <base/memory/weak_ptr.h>
#include <base/files/scoped_file.h>
#include <brillo/daemons/dbus_daemon.h>
#include <chromeos/patchpanel/dbus/client.h>
#include <gtest/gtest_prod.h> // for FRIEND_TEST
#include <shill/dbus/client/client.h>
#include "dns-proxy/resolver.h"
namespace dns_proxy {
// The process that runs the actual proxying code.
class Proxy : public brillo::DBusDaemon {
public:
enum class Type { kSystem, kDefault, kARC };
struct Options {
Type type;
// Required for ARC proxies as it specifies which physical interface
// should (always) be tracked. This field is ignored (but should be empty)
// for the system and default network proxies.
std::string ifname;
};
explicit Proxy(const Options& opts);
// For testing.
Proxy(const Options& opts,
std::unique_ptr<patchpanel::Client> patchpanel,
std::unique_ptr<shill::Client> shill);
Proxy(const Proxy&) = delete;
Proxy& operator=(const Proxy&) = delete;
~Proxy();
static const char* TypeToString(Type t);
static std::optional<Type> StringToType(const std::string& s);
protected:
int OnInit() override;
void OnShutdown(int*) override;
// Added for testing.
virtual std::unique_ptr<Resolver> NewResolver(base::TimeDelta timeout,
base::TimeDelta retry_delay,
int max_num_retries);
private:
static const uint8_t kMaxShillPropertyRetries = 10;
// Helper for parsing and applying shill's DNSProxyDOHProviders property.
class DoHConfig {
public:
DoHConfig() = default;
DoHConfig(const DoHConfig&) = delete;
DoHConfig& operator=(const DoHConfig&) = delete;
~DoHConfig() = default;
// Stores the resolver to configure whenever settings are updated.
void set_resolver(Resolver* resolver);
// |nameservers| is the list of name servers for the network the proxy is
// tracking.
void set_nameservers(const std::vector<std::string>& nameservers);
// |settings| is the DoH providers property we get from shill. It keys, as
// applicable, secure DNS provider endpoints to standard DNS name servers.
void set_providers(const brillo::VariantDictionary& providers);
void clear();
private:
void update();
Resolver* resolver_{nullptr};
std::vector<std::string> nameservers_;
// If non-empty, the secure providers to use for always-on DoH.
std::set<std::string> secure_providers_;
// If non-empty, maps name servers to secure DNS providers, for automatic
// update.
std::map<std::string, std::string> auto_providers_;
};
void Setup();
void OnPatchpanelReady(bool success);
void OnPatchpanelReset(bool reset);
void OnShillReady(bool success);
void OnShillReset(bool reset);
// Triggered whenever the device attached to the default network changes.
// |device| can be null and indicates the default service is disconnected.
void OnDefaultDeviceChanged(const shill::Client::Device* const device);
void OnDeviceChanged(const shill::Client::Device* const device);
void UpdateNameServers(const shill::Client::IPConfig& ipconfig);
void OnDoHProvidersChanged(const brillo::Any& value);
// Helper func for setting the dns-proxy address in shill.
// Only valid for the system proxy.
// Will retry on failure up to |num_retries| before possibly crashing the
// proxy.
void SetShillProperty(const std::string& addr,
bool die_on_failure = false,
uint8_t num_retries = kMaxShillPropertyRetries);
// Return the property accessor, creating it if needed.
shill::Client::ManagerPropertyAccessor* shill_props();
FRIEND_TEST(ProxyTest, SystemProxy_OnShutdownClearsAddressPropertyOnShill);
FRIEND_TEST(ProxyTest, NonSystemProxy_OnShutdownDoesNotCallShill);
FRIEND_TEST(ProxyTest, SystemProxy_SetShillPropertyWithNoRetriesCrashes);
FRIEND_TEST(ProxyTest, SystemProxy_SetShillPropertyDoesntCrashIfDieFalse);
FRIEND_TEST(ProxyTest, ShillInitializedWhenReady);
FRIEND_TEST(ProxyTest, SystemProxy_ConnectedNamedspace);
FRIEND_TEST(ProxyTest, DefaultProxy_ConnectedNamedspace);
FRIEND_TEST(ProxyTest, ArcProxy_ConnectedNamedspace);
FRIEND_TEST(ProxyTest, CrashOnConnectNamespaceFailure);
FRIEND_TEST(ProxyTest, CrashOnPatchpanelNotReady);
FRIEND_TEST(ProxyTest, ShillResetRestoresAddressProperty);
FRIEND_TEST(ProxyTest, StateClearedIfDefaultServiceDrops);
FRIEND_TEST(ProxyTest, ArcProxy_IgnoredIfDefaultServiceDrops);
FRIEND_TEST(ProxyTest, StateClearedIfDefaultServiceIsNotOnline);
FRIEND_TEST(ProxyTest, NewResolverStartsListeningOnDefaultServiceComesOnline);
FRIEND_TEST(ProxyTest, CrashOnListenFailure);
FRIEND_TEST(ProxyTest, NameServersUpdatedOnDefaultServiceComesOnline);
FRIEND_TEST(ProxyTest,
SystemProxy_ShillPropertyUpdatedOnDefaultServiceComesOnline);
FRIEND_TEST(ProxyTest, SystemProxy_IgnoresVPN);
FRIEND_TEST(ProxyTest, SystemProxy_GetsPhysicalDeviceOnInitialVPN);
FRIEND_TEST(ProxyTest, DefaultProxy_UsesVPN);
FRIEND_TEST(ProxyTest, NameServersUpdatedOnDeviceChangeEvent);
FRIEND_TEST(ProxyTest, DeviceChangeEventIgnored);
FRIEND_TEST(ProxyTest, BasicDoHDisable);
FRIEND_TEST(ProxyTest, BasicDoHAlwaysOn);
FRIEND_TEST(ProxyTest, BasicDoHAutomatic);
FRIEND_TEST(ProxyTest, NewResolverConfiguredWhenSet);
FRIEND_TEST(ProxyTest, DoHModeChangingFixedNameServers);
FRIEND_TEST(ProxyTest, MultipleDoHProvidersForAlwaysOnMode);
FRIEND_TEST(ProxyTest, MultipleDoHProvidersForAutomaticMode);
FRIEND_TEST(ProxyTest, DoHBadAlwaysOnConfigSetsAutomaticMode);
const Options opts_;
std::unique_ptr<patchpanel::Client> patchpanel_;
std::unique_ptr<shill::Client> shill_;
std::unique_ptr<shill::Client::ManagerPropertyAccessor> shill_props_;
base::ScopedFD ns_fd_;
patchpanel::ConnectNamespaceResponse ns_;
std::unique_ptr<Resolver> resolver_;
DoHConfig doh_config_;
std::unique_ptr<shill::Client::Device> device_;
base::WeakPtrFactory<Proxy> weak_factory_{this};
};
std::ostream& operator<<(std::ostream& stream, Proxy::Type type);
std::ostream& operator<<(std::ostream& stream, Proxy::Options opt);
} // namespace dns_proxy
#endif // DNS_PROXY_PROXY_H_