blob: 6157921f83129f76250add94b444e734968d5261 [file] [log] [blame]
// Copyright 2022 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/direct_sockets/chrome_direct_sockets_delegate.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/common/url_constants.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/socket_permission_request.h"
#include "extensions/browser/process_map.h"
#include "extensions/common/api/sockets/sockets_manifest_data.h"
namespace {
using ProtocolType = content::DirectSocketsDelegate::ProtocolType;
bool ValidateAddressAndPortForChromeApp(const extensions::Extension* extension,
const std::string& address,
uint16_t port,
ProtocolType protocol) {
switch (protocol) {
case ProtocolType::kTcp:
return extensions::SocketsManifestData::CheckRequest(
extension,
/*request=*/{content::SocketPermissionRequest::TCP_CONNECT, address,
port});
case ProtocolType::kConnectedUdp:
return extensions::SocketsManifestData::CheckRequest(
extension,
/*request=*/{content::SocketPermissionRequest::UDP_SEND_TO, address,
port});
case ProtocolType::kBoundUdp:
// For kBoundUdp we check both UDP_BIND for the given |address| and
// |port| as well as ensure that UDP_SEND_TO allows routing packets
// anywhere. '*' is the wildcard address, 0 is the wildcard port.
return extensions::SocketsManifestData::CheckRequest(
extension,
/*request=*/{content::SocketPermissionRequest::UDP_BIND,
address, port}) &&
extensions::SocketsManifestData::CheckRequest(
extension,
/*request=*/{content::SocketPermissionRequest::UDP_SEND_TO,
/*host=*/"*", /*port=*/0});
case ProtocolType::kTcpServer:
return extensions::SocketsManifestData::CheckRequest(
extension, /*request=*/{content::SocketPermissionRequest::TCP_LISTEN,
address, port});
}
}
bool ValidateAddressAndPortForIwa(const std::string& address,
uint16_t port,
ProtocolType protocol) {
switch (protocol) {
case ProtocolType::kTcp:
case ProtocolType::kConnectedUdp:
return true;
case ProtocolType::kBoundUdp:
// Port 0 indicates automatic port allocation.
// Ports below 1024 are usually system ports and should not be exposed.
return port == 0 || port >= 1024;
case ProtocolType::kTcpServer:
// Port 0 indicates automatic port allocation.
// Ports below 1024 are usually system ports and should not be exposed.
// Port numbers between 1024 and 32767 are usually specific to selected
// apps (which predominantly communicate over TCP).
return port == 0 || port >= 32768;
}
}
} // namespace
bool ChromeDirectSocketsDelegate::IsAPIAccessAllowed(
content::RenderFrameHost& rfh) {
// No additional rules for Chrome Apps.
if (extensions::ProcessMap::Get(rfh.GetBrowserContext())
->Contains(rfh.GetProcess()->GetDeprecatedID())) {
return true;
}
const GURL& url = rfh.GetMainFrame()->GetLastCommittedURL();
return HostContentSettingsMapFactory::GetForProfile(rfh.GetBrowserContext())
->GetContentSetting(url, url,
ContentSettingsType::DIRECT_SOCKETS) ==
CONTENT_SETTING_ALLOW;
}
bool ChromeDirectSocketsDelegate::ValidateAddressAndPort(
content::RenderFrameHost& rfh,
const std::string& address,
uint16_t port,
ProtocolType protocol) {
// If we're running an extension, follow the chrome.sockets.* permission
// model.
if (const extensions::Extension* extension =
extensions::ProcessMap::Get(rfh.GetBrowserContext())
->GetEnabledExtensionByProcessID(
rfh.GetProcess()->GetDeprecatedID())) {
return ValidateAddressAndPortForChromeApp(extension, address, port,
protocol);
}
if (rfh.GetMainFrame()->GetLastCommittedURL().SchemeIs(
chrome::kIsolatedAppScheme)) {
return ValidateAddressAndPortForIwa(address, port, protocol);
}
return false;
}
void ChromeDirectSocketsDelegate::RequestPrivateNetworkAccess(
content::RenderFrameHost& rfh,
base::OnceCallback<void(bool)> callback) {
// No additional rules for Chrome Apps.
if (extensions::ProcessMap::Get(rfh.GetBrowserContext())
->Contains(rfh.GetProcess()->GetDeprecatedID())) {
std::move(callback).Run(/*allow_access=*/true);
return;
}
// TODO(crbug.com/368266657): Show a permission prompt for DS-PNA & ponder
// whether this requires transient activation.
const GURL& url = rfh.GetMainFrame()->GetLastCommittedURL();
std::move(callback).Run(
HostContentSettingsMapFactory::GetForProfile(rfh.GetBrowserContext())
->GetContentSetting(
url, url,
ContentSettingsType::DIRECT_SOCKETS_PRIVATE_NETWORK_ACCESS) ==
CONTENT_SETTING_ALLOW);
}