1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10 #include <utility>
11
12 #include "base/bind.h"
13 #include "base/logging.h"
14 #include "base/task/post_task.h"
15 #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
16 #include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
17 #include "content/public/browser/browser_context.h"
18 #include "content/public/browser/browser_task_traits.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/render_frame_host.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/storage_partition.h"
23 #include "content/public/common/socket_permission_request.h"
24 #include "net/base/address_list.h"
25 #include "net/base/network_isolation_key.h"
26 #include "net/dns/public/dns_query_type.h"
27 #include "net/dns/public/resolve_error_info.h"
28 #include "ppapi/c/pp_errors.h"
29 #include "ppapi/c/private/ppb_host_resolver_private.h"
30 #include "ppapi/c/private/ppb_net_address_private.h"
31 #include "ppapi/host/dispatch_host_message.h"
32 #include "ppapi/host/error_conversion.h"
33 #include "ppapi/host/host_message_context.h"
34 #include "ppapi/proxy/ppapi_messages.h"
35 #include "ppapi/shared_impl/private/net_address_private_impl.h"
36 #include "services/network/public/mojom/network_context.mojom.h"
37
38 using ppapi::host::NetErrorToPepperError;
39 using ppapi::host::ReplyMessageContext;
40
41 namespace content {
42
43 namespace {
44
PrepareRequestInfo(const PP_HostResolver_Private_Hint & hint,network::mojom::ResolveHostParameters * params)45 void PrepareRequestInfo(const PP_HostResolver_Private_Hint& hint,
46 network::mojom::ResolveHostParameters* params) {
47 switch (hint.family) {
48 case PP_NETADDRESSFAMILY_PRIVATE_IPV4:
49 params->dns_query_type = net::DnsQueryType::A;
50 break;
51 case PP_NETADDRESSFAMILY_PRIVATE_IPV6:
52 params->dns_query_type = net::DnsQueryType::AAAA;
53 break;
54 default:
55 params->dns_query_type = net::DnsQueryType::UNSPECIFIED;
56 }
57
58 if (hint.flags & PP_HOST_RESOLVER_PRIVATE_FLAGS_CANONNAME)
59 params->include_canonical_name = true;
60 if (hint.flags & PP_HOST_RESOLVER_PRIVATE_FLAGS_LOOPBACK_ONLY)
61 params->loopback_only = true;
62 }
63
CreateNetAddressListFromAddressList(const net::AddressList & list,std::vector<PP_NetAddress_Private> * net_address_list)64 void CreateNetAddressListFromAddressList(
65 const net::AddressList& list,
66 std::vector<PP_NetAddress_Private>* net_address_list) {
67 DCHECK(net_address_list);
68
69 net_address_list->clear();
70 net_address_list->reserve(list.size());
71
72 PP_NetAddress_Private address;
73 for (size_t i = 0; i < list.size(); ++i) {
74 if (!ppapi::NetAddressPrivateImpl::IPEndPointToNetAddress(
75 list[i].address().bytes(), list[i].port(), &address)) {
76 net_address_list->clear();
77 return;
78 }
79 net_address_list->push_back(address);
80 }
81 }
82
83 } // namespace
84
PepperHostResolverMessageFilter(BrowserPpapiHostImpl * host,PP_Instance instance,bool private_api)85 PepperHostResolverMessageFilter::PepperHostResolverMessageFilter(
86 BrowserPpapiHostImpl* host,
87 PP_Instance instance,
88 bool private_api)
89 : external_plugin_(host->external_plugin()),
90 private_api_(private_api),
91 render_process_id_(0),
92 render_frame_id_(0) {
93 DCHECK(host);
94
95 if (!host->GetRenderFrameIDsForInstance(
96 instance, &render_process_id_, &render_frame_id_)) {
97 NOTREACHED();
98 }
99 }
100
~PepperHostResolverMessageFilter()101 PepperHostResolverMessageFilter::~PepperHostResolverMessageFilter() {}
102
103 scoped_refptr<base::SequencedTaskRunner>
OverrideTaskRunnerForMessage(const IPC::Message & message)104 PepperHostResolverMessageFilter::OverrideTaskRunnerForMessage(
105 const IPC::Message& message) {
106 if (message.type() == PpapiHostMsg_HostResolver_Resolve::ID)
107 return base::CreateSingleThreadTaskRunner({BrowserThread::UI});
108 return nullptr;
109 }
110
OnResourceMessageReceived(const IPC::Message & msg,ppapi::host::HostMessageContext * context)111 int32_t PepperHostResolverMessageFilter::OnResourceMessageReceived(
112 const IPC::Message& msg,
113 ppapi::host::HostMessageContext* context) {
114 PPAPI_BEGIN_MESSAGE_MAP(PepperHostResolverMessageFilter, msg)
115 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_HostResolver_Resolve,
116 OnMsgResolve)
117 PPAPI_END_MESSAGE_MAP()
118 return PP_ERROR_FAILED;
119 }
120
OnMsgResolve(const ppapi::host::HostMessageContext * context,const ppapi::HostPortPair & host_port,const PP_HostResolver_Private_Hint & hint)121 int32_t PepperHostResolverMessageFilter::OnMsgResolve(
122 const ppapi::host::HostMessageContext* context,
123 const ppapi::HostPortPair& host_port,
124 const PP_HostResolver_Private_Hint& hint) {
125 DCHECK_CURRENTLY_ON(BrowserThread::UI);
126
127 // Check plugin permissions.
128 SocketPermissionRequest request(
129 SocketPermissionRequest::RESOLVE_HOST, host_port.host, host_port.port);
130 if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_,
131 private_api_,
132 &request,
133 render_process_id_,
134 render_frame_id_)) {
135 return PP_ERROR_NOACCESS;
136 }
137
138 RenderFrameHost* render_frame_host =
139 RenderFrameHost::FromID(render_process_id_, render_frame_id_);
140 if (!render_frame_host)
141 return PP_ERROR_FAILED;
142 auto* storage_partition =
143 render_frame_host->GetProcess()->GetStoragePartition();
144
145 // Grab a reference to this class to ensure that it's fully alive if a
146 // connection error occurs (i.e. ref count is higher than 0 and there's no
147 // task from ResourceMessageFilterDeleteTraits to delete this object on the IO
148 // thread pending). Balanced in OnComplete();
149 AddRef();
150
151 network::mojom::ResolveHostParametersPtr parameters =
152 network::mojom::ResolveHostParameters::New();
153 PrepareRequestInfo(hint, parameters.get());
154
155 storage_partition->GetNetworkContext()->ResolveHost(
156 net::HostPortPair(host_port.host, host_port.port),
157 render_frame_host->GetNetworkIsolationKey(), std::move(parameters),
158 receiver_.BindNewPipeAndPassRemote());
159 receiver_.set_disconnect_handler(
160 base::BindOnce(&PepperHostResolverMessageFilter::OnComplete,
161 base::Unretained(this), net::ERR_NAME_NOT_RESOLVED,
162 net::ResolveErrorInfo(net::ERR_FAILED), base::nullopt));
163 host_resolve_context_ = context->MakeReplyMessageContext();
164
165 return PP_OK_COMPLETIONPENDING;
166 }
167
OnComplete(int result,const net::ResolveErrorInfo & resolve_error_info,const base::Optional<net::AddressList> & resolved_addresses)168 void PepperHostResolverMessageFilter::OnComplete(
169 int result,
170 const net::ResolveErrorInfo& resolve_error_info,
171 const base::Optional<net::AddressList>& resolved_addresses) {
172 DCHECK_CURRENTLY_ON(BrowserThread::UI);
173 receiver_.reset();
174
175 base::PostTask(
176 FROM_HERE, {BrowserThread::IO},
177 base::BindOnce(&PepperHostResolverMessageFilter::OnLookupFinished, this,
178 resolve_error_info.error, std::move(resolved_addresses),
179 host_resolve_context_));
180 host_resolve_context_ = ppapi::host::ReplyMessageContext();
181
182 Release(); // Balances AddRef in OnMsgResolve.
183 }
184
OnLookupFinished(int net_result,const base::Optional<net::AddressList> & addresses,const ReplyMessageContext & context)185 void PepperHostResolverMessageFilter::OnLookupFinished(
186 int net_result,
187 const base::Optional<net::AddressList>& addresses,
188 const ReplyMessageContext& context) {
189 if (net_result != net::OK) {
190 SendResolveError(NetErrorToPepperError(net_result), context);
191 } else {
192 const std::string& canonical_name = addresses.value().canonical_name();
193 NetAddressList net_address_list;
194 CreateNetAddressListFromAddressList(addresses.value(), &net_address_list);
195 if (net_address_list.empty())
196 SendResolveError(PP_ERROR_FAILED, context);
197 else
198 SendResolveReply(PP_OK, canonical_name, net_address_list, context);
199 }
200 }
201
SendResolveReply(int32_t result,const std::string & canonical_name,const NetAddressList & net_address_list,const ReplyMessageContext & context)202 void PepperHostResolverMessageFilter::SendResolveReply(
203 int32_t result,
204 const std::string& canonical_name,
205 const NetAddressList& net_address_list,
206 const ReplyMessageContext& context) {
207 ReplyMessageContext reply_context = context;
208 reply_context.params.set_result(result);
209 SendReply(reply_context,
210 PpapiPluginMsg_HostResolver_ResolveReply(canonical_name,
211 net_address_list));
212 }
213
SendResolveError(int32_t error,const ReplyMessageContext & context)214 void PepperHostResolverMessageFilter::SendResolveError(
215 int32_t error,
216 const ReplyMessageContext& context) {
217 SendResolveReply(error, std::string(), NetAddressList(), context);
218 }
219
220 } // namespace content
221