chromium/chrome/browser/lacros/net/network_settings_translation_crosapi.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/lacros/net/network_settings_translation.h"
#include "components/proxy_config/proxy_config_pref_names.h"
#include "components/proxy_config/proxy_prefs.h"
#include "net/base/host_port_pair.h"
#include "net/base/proxy_chain.h"
#include "net/base/proxy_server.h"
#include "net/proxy_resolution/proxy_config.h"
#include "net/proxy_resolution/proxy_list.h"
#include "net/traffic_annotation/network_traffic_annotation.h"

namespace {

constexpr net::NetworkTrafficAnnotationTag kAshProxyConfigTrafficAnnotation =
    net::DefineNetworkTrafficAnnotation("proxy_config_system", R"(
      semantics {
        sender: "Proxy Config"
        description:
          "Establishing a connection through a proxy server using system proxy "
          "settings."
        trigger:
          "Whenever a network request is made when the system proxy settings "
          "are used, and they indicate to use a proxy server."
        data:
          "Proxy configuration."
        destination: OTHER
        destination_other:
          "The proxy server specified in the configuration."
      }
      policy {
        cookies_allowed: NO
        setting:
          "User cannot override system proxy settings, but can change them "
          "through the Chrome OS Network Settings UI."
        policy_exception_justification:
          "Using either of 'ProxyMode', 'ProxyServer', or 'ProxyPacUrl' "
          "policies can set Chrome to use a specific proxy settings and avoid "
          "system proxy."
      })");

net::ProxyConfigWithAnnotation TranslatePacProxySettings(
    crosapi::mojom::ProxySettingsPacPtr proxy_settings) {
  if (!proxy_settings->pac_url.is_valid())
    return net::ProxyConfigWithAnnotation::CreateDirect();
  net::ProxyConfig proxy_config =
      net::ProxyConfig::CreateFromCustomPacURL(proxy_settings->pac_url);
  if (proxy_settings->pac_mandatory)
    proxy_config.set_pac_mandatory(proxy_settings->pac_mandatory);
  return net::ProxyConfigWithAnnotation(proxy_config,
                                        kAshProxyConfigTrafficAnnotation);
}

net::ProxyConfigWithAnnotation TranslateWpadProxySettings(
    crosapi::mojom::ProxySettingsWpadPtr proxy_settings) {
  // Ash-Chrome has it's own mechanisms for detecting the PAC URL when
  // configured via WPAD.
  net::ProxyConfig proxy_config = net::ProxyConfig::CreateAutoDetect();
  return net::ProxyConfigWithAnnotation(proxy_config,
                                        kAshProxyConfigTrafficAnnotation);
}

net::ProxyChain ProxyToProxyChain(crosapi::mojom::ProxyLocation::Scheme in,
                                  net::HostPortPair host_port_pair) {
  switch (in) {
    // We map kUnknown to HTTP because this will make the proxy setting work for
    // most deployments with older ASH browser versions which do not support
    // sending the ProxyLocation::Scheme yet, as HTTP is the most commonly used
    // scheme for communicating with a HTTP proxy server.
    case crosapi::mojom::ProxyLocation::Scheme::kUnknown:
      return net::ProxyChain(net::ProxyServer::Scheme::SCHEME_HTTP,
                             host_port_pair);
    case crosapi::mojom::ProxyLocation::Scheme::kInvalid:
      return net::ProxyChain();
    case crosapi::mojom::ProxyLocation::Scheme::kDirect:
      return net::ProxyChain::Direct();
    case crosapi::mojom::ProxyLocation::Scheme::kHttp:
      return net::ProxyChain(net::ProxyServer::Scheme::SCHEME_HTTP,
                             host_port_pair);
    case crosapi::mojom::ProxyLocation::Scheme::kSocks4:
      return net::ProxyChain(net::ProxyServer::Scheme::SCHEME_SOCKS4,
                             host_port_pair);
    case crosapi::mojom::ProxyLocation::Scheme::kSocks5:
      return net::ProxyChain(net::ProxyServer::Scheme::SCHEME_SOCKS5,
                             host_port_pair);
    case crosapi::mojom::ProxyLocation::Scheme::kHttps:
      return net::ProxyChain(net::ProxyServer::Scheme::SCHEME_HTTPS,
                             host_port_pair);
    case crosapi::mojom::ProxyLocation::Scheme::kQuic:
      return net::ProxyChain(net::ProxyServer::Scheme::SCHEME_QUIC,
                             host_port_pair);
  }

  return net::ProxyChain();
}

net::ProxyConfigWithAnnotation TranslateManualProxySettings(
    crosapi::mojom::ProxySettingsManualPtr proxy_settings) {
  net::ProxyConfig proxy_config = net::ProxyConfig();
  proxy_config.proxy_rules().type =
      net::ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME;

  for (auto const& proxy : proxy_settings->http_proxies) {
    proxy_config.proxy_rules().proxies_for_http.AddProxyChain(ProxyToProxyChain(
        proxy->scheme, net::HostPortPair(proxy->host, proxy->port)));
  }
  for (auto const& proxy : proxy_settings->secure_http_proxies) {
    proxy_config.proxy_rules().proxies_for_https.AddProxyChain(
        ProxyToProxyChain(proxy->scheme,
                          net::HostPortPair(proxy->host, proxy->port)));
  }
  for (auto const& proxy : proxy_settings->socks_proxies) {
    // See `net::ProxyServer::GetSchemeFromPacTypeInternal()`.
    proxy_config.proxy_rules().fallback_proxies.AddProxyChain(ProxyToProxyChain(
        proxy->scheme, net::HostPortPair(proxy->host, proxy->port)));
  }

  for (const auto& domains : proxy_settings->exclude_domains) {
    proxy_config.proxy_rules().bypass_rules.AddRuleFromString(domains);
  }
  return net::ProxyConfigWithAnnotation(proxy_config,
                                        kAshProxyConfigTrafficAnnotation);
}

}  // namespace

namespace chromeos {

net::ProxyConfigWithAnnotation CrosapiProxyToNetProxy(
    crosapi::mojom::ProxyConfigPtr crosapi_proxy) {
  if (!crosapi_proxy)
    return net::ProxyConfigWithAnnotation::CreateDirect();

  if (crosapi_proxy->proxy_settings->is_direct())
    return net::ProxyConfigWithAnnotation::CreateDirect();

  if (crosapi_proxy->proxy_settings->is_pac())
    return TranslatePacProxySettings(
        std::move(crosapi_proxy->proxy_settings->get_pac()));

  if (crosapi_proxy->proxy_settings->is_wpad())
    return TranslateWpadProxySettings(
        std::move(crosapi_proxy->proxy_settings->get_wpad()));

  if (crosapi_proxy->proxy_settings->is_manual())
    return TranslateManualProxySettings(
        std::move(crosapi_proxy->proxy_settings->get_manual()));

  return net::ProxyConfigWithAnnotation::CreateDirect();
}

}  // namespace chromeos