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