1 // Copyright 2014 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.
5 #include "extensions/browser/api/vpn_provider/vpn_provider_api.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/string_util.h"
13 #include "base/values.h"
14 #include "extensions/browser/api/vpn_provider/vpn_service.h"
15 #include "extensions/browser/api/vpn_provider/vpn_service_factory.h"
16 #include "extensions/common/api/vpn_provider.h"
17 #include "third_party/cros_system_api/dbus/service_constants.h"
19 namespace extensions
{
23 namespace api_vpn
= extensions::core_api::vpn_provider
;
25 const char kCIDRSeperator
[] = "/";
27 bool CheckIPCIDRSanity(const std::string
& value
, bool cidr
, bool ipv6
) {
28 int dots
= ipv6
? 0 : 3;
29 int sep
= cidr
? 1 : 0;
30 int colon
= ipv6
? 7 : 0;
31 bool hex_allowed
= ipv6
;
34 for (const auto& elem
: value
) {
35 if (IsAsciiDigit(elem
)) {
43 } else if (elem
== kCIDRSeperator
[0]) {
44 if (!sep
|| dots
|| colon
== 7 || !counter
)
46 // Separator observed, no more dots and colons, only digits are allowed
47 // after observing separator. So setting hex_allowed to false.
52 } else if (elem
== ':') {
56 } else if (!hex_allowed
|| !IsHexDigit(elem
)) {
62 return !sep
&& !dots
&& (colon
< 7) && counter
;
65 bool CheckIPCIDRSanityList(const std::vector
<std::string
>& list
,
68 for (const auto& address
: list
) {
69 if (!CheckIPCIDRSanity(address
, cidr
, ipv6
)) {
76 void ConvertParameters(const api_vpn::Parameters
& parameters
,
77 base::DictionaryValue
* parameter_value
,
79 if (!CheckIPCIDRSanity(parameters
.address
, true /* CIDR */,
81 *error
= "Address CIDR sanity check failed.";
85 if (!CheckIPCIDRSanityList(parameters
.exclusion_list
, true /* CIDR */,
87 *error
= "Exclusion list CIDR sanity check failed.";
91 if (!CheckIPCIDRSanityList(parameters
.inclusion_list
, true /* CIDR */,
93 *error
= "Inclusion list CIDR sanity check failed.";
97 if (!CheckIPCIDRSanityList(parameters
.dns_servers
, false /* Not CIDR */,
99 *error
= "DNS server IP sanity check failed.";
103 std::vector
<std::string
> cidr_parts
;
104 CHECK(Tokenize(parameters
.address
, kCIDRSeperator
, &cidr_parts
) == 2);
106 parameter_value
->SetStringWithoutPathExpansion(
107 shill::kAddressParameterThirdPartyVpn
, cidr_parts
[0]);
109 parameter_value
->SetStringWithoutPathExpansion(
110 shill::kSubnetPrefixParameterThirdPartyVpn
, cidr_parts
[1]);
112 parameter_value
->SetStringWithoutPathExpansion(
113 shill::kExclusionListParameterThirdPartyVpn
,
114 JoinString(parameters
.exclusion_list
, shill::kIPDelimiter
));
116 parameter_value
->SetStringWithoutPathExpansion(
117 shill::kInclusionListParameterThirdPartyVpn
,
118 JoinString(parameters
.inclusion_list
, shill::kIPDelimiter
));
120 if (parameters
.mtu
) {
121 parameter_value
->SetStringWithoutPathExpansion(
122 shill::kMtuParameterThirdPartyVpn
, *parameters
.mtu
);
125 if (parameters
.broadcast_address
) {
126 parameter_value
->SetStringWithoutPathExpansion(
127 shill::kBroadcastAddressParameterThirdPartyVpn
,
128 *parameters
.broadcast_address
);
131 if (parameters
.domain_search
) {
132 parameter_value
->SetStringWithoutPathExpansion(
133 shill::kDomainSearchParameterThirdPartyVpn
,
134 JoinString(*parameters
.domain_search
, shill::kNonIPDelimiter
));
137 parameter_value
->SetStringWithoutPathExpansion(
138 shill::kDnsServersParameterThirdPartyVpn
,
139 JoinString(parameters
.dns_servers
, shill::kIPDelimiter
));
146 VpnThreadExtensionFunction::~VpnThreadExtensionFunction() {
149 void VpnThreadExtensionFunction::SignalCallCompletionSuccess() {
150 Respond(NoArguments());
153 void VpnThreadExtensionFunction::SignalCallCompletionSuccessWithId(
154 const std::string
& configuration_id
) {
155 Respond(OneArgument(new base::StringValue(configuration_id
)));
158 void VpnThreadExtensionFunction::SignalCallCompletionSuccessWithWarning(
159 const std::string
& warning
) {
160 if (!warning
.empty()) {
161 WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_WARNING
, warning
);
163 Respond(NoArguments());
166 void VpnThreadExtensionFunction::SignalCallCompletionFailure(
167 const std::string
& error_name
,
168 const std::string
& error_message
) {
169 if (!error_name
.empty() && !error_message
.empty()) {
170 Respond(Error(error_name
+ ": " + error_message
));
171 } else if (!error_name
.empty()) {
172 Respond(Error(error_name
));
174 Respond(Error(error_message
));
178 VpnProviderCreateConfigFunction::~VpnProviderCreateConfigFunction() {
181 ExtensionFunction::ResponseAction
VpnProviderCreateConfigFunction::Run() {
182 scoped_ptr
<api_vpn::CreateConfig::Params
> params(
183 api_vpn::CreateConfig::Params::Create(*args_
));
185 return RespondNow(Error("Invalid arguments."));
188 chromeos::VpnService
* service
=
189 chromeos::VpnServiceFactory::GetForBrowserContext(browser_context());
191 return RespondNow(Error("Invalid profile."));
194 // Use the configuration name as ID. In the future, a different ID scheme may
195 // be used, requiring a mapping between the two.
196 service
->CreateConfiguration(
197 extension_id(), extension()->name(), params
->name
,
199 &VpnProviderCreateConfigFunction::SignalCallCompletionSuccessWithId
,
201 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
202 SignalCallCompletionFailure
,
205 return RespondLater();
208 VpnProviderDestroyConfigFunction::~VpnProviderDestroyConfigFunction() {
211 ExtensionFunction::ResponseAction
VpnProviderDestroyConfigFunction::Run() {
212 scoped_ptr
<api_vpn::DestroyConfig::Params
> params(
213 api_vpn::DestroyConfig::Params::Create(*args_
));
215 return RespondNow(Error("Invalid arguments."));
218 chromeos::VpnService
* service
=
219 chromeos::VpnServiceFactory::GetForBrowserContext(browser_context());
221 return RespondNow(Error("Invalid profile."));
224 service
->DestroyConfiguration(
225 extension_id(), params
->id
,
226 base::Bind(&VpnProviderDestroyConfigFunction::SignalCallCompletionSuccess
,
228 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
229 SignalCallCompletionFailure
,
232 return RespondLater();
235 VpnProviderSetParametersFunction::~VpnProviderSetParametersFunction() {
238 ExtensionFunction::ResponseAction
VpnProviderSetParametersFunction::Run() {
239 scoped_ptr
<api_vpn::SetParameters::Params
> params(
240 api_vpn::SetParameters::Params::Create(*args_
));
242 return RespondNow(Error("Invalid arguments."));
245 chromeos::VpnService
* service
=
246 chromeos::VpnServiceFactory::GetForBrowserContext(browser_context());
248 return RespondNow(Error("Invalid profile."));
251 base::DictionaryValue parameter_value
;
253 ConvertParameters(params
->parameters
, ¶meter_value
, &error
);
254 if (!error
.empty()) {
255 return RespondNow(Error(error
));
258 service
->SetParameters(
259 extension_id(), parameter_value
,
260 base::Bind(&VpnProviderSetParametersFunction::
261 SignalCallCompletionSuccessWithWarning
,
263 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
264 SignalCallCompletionFailure
,
267 return RespondLater();
270 VpnProviderSendPacketFunction::~VpnProviderSendPacketFunction() {
273 ExtensionFunction::ResponseAction
VpnProviderSendPacketFunction::Run() {
274 scoped_ptr
<api_vpn::SendPacket::Params
> params(
275 api_vpn::SendPacket::Params::Create(*args_
));
277 return RespondNow(Error("Invalid arguments."));
280 chromeos::VpnService
* service
=
281 chromeos::VpnServiceFactory::GetForBrowserContext(browser_context());
283 return RespondNow(Error("Invalid profile."));
287 extension_id(), params
->data
,
288 base::Bind(&VpnProviderSendPacketFunction::SignalCallCompletionSuccess
,
290 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
291 SignalCallCompletionFailure
,
294 return RespondLater();
297 VpnProviderNotifyConnectionStateChangedFunction::
298 ~VpnProviderNotifyConnectionStateChangedFunction() {
301 ExtensionFunction::ResponseAction
302 VpnProviderNotifyConnectionStateChangedFunction::Run() {
303 scoped_ptr
<api_vpn::NotifyConnectionStateChanged::Params
> params(
304 api_vpn::NotifyConnectionStateChanged::Params::Create(*args_
));
306 return RespondNow(Error("Invalid arguments."));
309 chromeos::VpnService
* service
=
310 chromeos::VpnServiceFactory::GetForBrowserContext(browser_context());
312 return RespondNow(Error("Invalid profile."));
315 service
->NotifyConnectionStateChanged(
316 extension_id(), params
->state
,
317 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
318 SignalCallCompletionSuccess
,
320 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
321 SignalCallCompletionFailure
,
324 return RespondLater();
327 } // namespace extensions