File: chrome_direct_sockets_delegate.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (157 lines) | stat: -rw-r--r-- 6,651 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// 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/browser/profiles/profile.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;
using RequestDetails = content::DirectSocketsDelegate::RequestDetails;

bool ValidateAddressAndPortForChromeApp(const extensions::Extension* extension,
                                        const RequestDetails& request) {
  switch (request.protocol) {
    case ProtocolType::kTcp:
      return extensions::SocketsManifestData::CheckRequest(
          extension,
          /*request=*/{content::SocketPermissionRequest::TCP_CONNECT,
                       request.address, request.port});
    case ProtocolType::kConnectedUdp:
      return extensions::SocketsManifestData::CheckRequest(
          extension,
          /*request=*/{content::SocketPermissionRequest::UDP_SEND_TO,
                       request.address, request.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,
                              request.address, request.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,
                                  request.address, request.port});
  }
}

bool ValidateAddressAndPortForIwa(const RequestDetails& request) {
  switch (request.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 request.port == 0 || request.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 request.port == 0 || request.port >= 32768;
  }
}

bool IsContentSettingAllowedForUrl(content::BrowserContext* browser_context,
                                   const GURL& url,
                                   ContentSettingsType content_setting) {
  return HostContentSettingsMapFactory::GetForProfile(browser_context)
             ->GetContentSetting(url, url, content_setting) ==
         CONTENT_SETTING_ALLOW;
}

}  // namespace

bool ChromeDirectSocketsDelegate::ValidateRequest(
    content::RenderFrameHost& rfh,
    const RequestDetails& request) {
  // 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, request);
  }

  const GURL& url = rfh.GetMainFrame()->GetLastCommittedURL();
  if (!IsContentSettingAllowedForUrl(rfh.GetBrowserContext(), url,
                                     ContentSettingsType::DIRECT_SOCKETS)) {
    return false;
  }

  if (url.SchemeIs(chrome::kIsolatedAppScheme)) {
    return ValidateAddressAndPortForIwa(request);
  }

  return false;
}

bool ChromeDirectSocketsDelegate::ValidateRequestForSharedWorker(
    content::BrowserContext* browser_context,
    const GURL& shared_worker_url,
    const RequestDetails& request) {
  return IsContentSettingAllowedForUrl(browser_context, shared_worker_url,
                                       ContentSettingsType::DIRECT_SOCKETS) &&
         ValidateAddressAndPortForIwa(request);
}

bool ChromeDirectSocketsDelegate::ValidateRequestForServiceWorker(
    content::BrowserContext* browser_context,
    const url::Origin& origin,
    const RequestDetails& request) {
  return IsContentSettingAllowedForUrl(browser_context, origin.GetURL(),
                                       ContentSettingsType::DIRECT_SOCKETS) &&
         ValidateAddressAndPortForIwa(request);
}

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.
  std::move(callback).Run(IsContentSettingAllowedForUrl(
      rfh.GetBrowserContext(), rfh.GetMainFrame()->GetLastCommittedURL(),
      ContentSettingsType::DIRECT_SOCKETS_PRIVATE_NETWORK_ACCESS));
}

bool ChromeDirectSocketsDelegate::IsPrivateNetworkAccessAllowedForSharedWorker(
    content::BrowserContext* browser_context,
    const GURL& shared_worker_url) {
  return IsContentSettingAllowedForUrl(
      browser_context, shared_worker_url,
      ContentSettingsType::DIRECT_SOCKETS_PRIVATE_NETWORK_ACCESS);
}

bool ChromeDirectSocketsDelegate::IsPrivateNetworkAccessAllowedForServiceWorker(
    content::BrowserContext* browser_context,
    const url::Origin& origin) {
  const GURL& url = origin.GetURL();
  return IsContentSettingAllowedForUrl(
      browser_context, url,
      ContentSettingsType::DIRECT_SOCKETS_PRIVATE_NETWORK_ACCESS);
}