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_split.h"
13 #include "base/strings/string_util.h"
14 #include "base/values.h"
15 #include "extensions/browser/api/vpn_provider/vpn_service.h"
16 #include "extensions/browser/api/vpn_provider/vpn_service_factory.h"
17 #include "extensions/common/api/vpn_provider.h"
18 #include "third_party/cros_system_api/dbus/service_constants.h"
20 namespace extensions
{
24 namespace api_vpn
= extensions::core_api::vpn_provider
;
26 const char kCIDRSeperator
[] = "/";
28 bool CheckIPCIDRSanity(const std::string
& value
, bool cidr
, bool ipv6
) {
29 int dots
= ipv6
? 0 : 3;
30 int sep
= cidr
? 1 : 0;
31 int colon
= ipv6
? 7 : 0;
32 bool hex_allowed
= ipv6
;
35 for (const auto& elem
: value
) {
36 if (base::IsAsciiDigit(elem
)) {
44 } else if (elem
== kCIDRSeperator
[0]) {
45 if (!sep
|| dots
|| colon
== 7 || !counter
)
47 // Separator observed, no more dots and colons, only digits are allowed
48 // after observing separator. So setting hex_allowed to false.
53 } else if (elem
== ':') {
57 } else if (!hex_allowed
|| !base::IsHexDigit(elem
)) {
63 return !sep
&& !dots
&& (colon
< 7) && counter
;
66 bool CheckIPCIDRSanityList(const std::vector
<std::string
>& list
,
69 for (const auto& address
: list
) {
70 if (!CheckIPCIDRSanity(address
, cidr
, ipv6
)) {
77 void ConvertParameters(const api_vpn::Parameters
& parameters
,
78 base::DictionaryValue
* parameter_value
,
80 if (!CheckIPCIDRSanity(parameters
.address
, true /* CIDR */,
82 *error
= "Address CIDR sanity check failed.";
86 if (!CheckIPCIDRSanityList(parameters
.exclusion_list
, true /* CIDR */,
88 *error
= "Exclusion list CIDR sanity check failed.";
92 if (!CheckIPCIDRSanityList(parameters
.inclusion_list
, true /* CIDR */,
94 *error
= "Inclusion list CIDR sanity check failed.";
98 if (!CheckIPCIDRSanityList(parameters
.dns_servers
, false /* Not CIDR */,
100 *error
= "DNS server IP sanity check failed.";
104 std::vector
<std::string
> cidr_parts
= base::SplitString(
105 parameters
.address
, kCIDRSeperator
, base::KEEP_WHITESPACE
,
106 base::SPLIT_WANT_NONEMPTY
);
107 CHECK_EQ(2u, cidr_parts
.size());
109 parameter_value
->SetStringWithoutPathExpansion(
110 shill::kAddressParameterThirdPartyVpn
, cidr_parts
[0]);
112 parameter_value
->SetStringWithoutPathExpansion(
113 shill::kSubnetPrefixParameterThirdPartyVpn
, cidr_parts
[1]);
115 std::string
ip_delimiter(1, shill::kIPDelimiter
);
116 parameter_value
->SetStringWithoutPathExpansion(
117 shill::kExclusionListParameterThirdPartyVpn
,
118 base::JoinString(parameters
.exclusion_list
, ip_delimiter
));
120 parameter_value
->SetStringWithoutPathExpansion(
121 shill::kInclusionListParameterThirdPartyVpn
,
122 base::JoinString(parameters
.inclusion_list
, ip_delimiter
));
124 if (parameters
.mtu
) {
125 parameter_value
->SetStringWithoutPathExpansion(
126 shill::kMtuParameterThirdPartyVpn
, *parameters
.mtu
);
129 if (parameters
.broadcast_address
) {
130 parameter_value
->SetStringWithoutPathExpansion(
131 shill::kBroadcastAddressParameterThirdPartyVpn
,
132 *parameters
.broadcast_address
);
135 std::string
non_ip_delimiter(1, shill::kNonIPDelimiter
);
136 if (parameters
.domain_search
) {
137 parameter_value
->SetStringWithoutPathExpansion(
138 shill::kDomainSearchParameterThirdPartyVpn
,
139 base::JoinString(*parameters
.domain_search
, non_ip_delimiter
));
142 parameter_value
->SetStringWithoutPathExpansion(
143 shill::kDnsServersParameterThirdPartyVpn
,
144 base::JoinString(parameters
.dns_servers
, ip_delimiter
));
151 VpnThreadExtensionFunction::~VpnThreadExtensionFunction() {
154 void VpnThreadExtensionFunction::SignalCallCompletionSuccess() {
155 Respond(NoArguments());
158 void VpnThreadExtensionFunction::SignalCallCompletionSuccessWithId(
159 const std::string
& configuration_id
) {
160 Respond(OneArgument(new base::StringValue(configuration_id
)));
163 void VpnThreadExtensionFunction::SignalCallCompletionSuccessWithWarning(
164 const std::string
& warning
) {
165 if (!warning
.empty()) {
166 WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_WARNING
, warning
);
168 Respond(NoArguments());
171 void VpnThreadExtensionFunction::SignalCallCompletionFailure(
172 const std::string
& error_name
,
173 const std::string
& error_message
) {
174 if (!error_name
.empty() && !error_message
.empty()) {
175 Respond(Error(error_name
+ ": " + error_message
));
176 } else if (!error_name
.empty()) {
177 Respond(Error(error_name
));
179 Respond(Error(error_message
));
183 VpnProviderCreateConfigFunction::~VpnProviderCreateConfigFunction() {
186 ExtensionFunction::ResponseAction
VpnProviderCreateConfigFunction::Run() {
187 scoped_ptr
<api_vpn::CreateConfig::Params
> params(
188 api_vpn::CreateConfig::Params::Create(*args_
));
190 return RespondNow(Error("Invalid arguments."));
193 chromeos::VpnService
* service
=
194 chromeos::VpnServiceFactory::GetForBrowserContext(browser_context());
196 return RespondNow(Error("Invalid profile."));
199 // Use the configuration name as ID. In the future, a different ID scheme may
200 // be used, requiring a mapping between the two.
201 service
->CreateConfiguration(
202 extension_id(), extension()->name(), params
->name
,
204 &VpnProviderCreateConfigFunction::SignalCallCompletionSuccessWithId
,
206 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
207 SignalCallCompletionFailure
,
210 return RespondLater();
213 VpnProviderDestroyConfigFunction::~VpnProviderDestroyConfigFunction() {
216 ExtensionFunction::ResponseAction
VpnProviderDestroyConfigFunction::Run() {
217 scoped_ptr
<api_vpn::DestroyConfig::Params
> params(
218 api_vpn::DestroyConfig::Params::Create(*args_
));
220 return RespondNow(Error("Invalid arguments."));
223 chromeos::VpnService
* service
=
224 chromeos::VpnServiceFactory::GetForBrowserContext(browser_context());
226 return RespondNow(Error("Invalid profile."));
229 service
->DestroyConfiguration(
230 extension_id(), params
->id
,
231 base::Bind(&VpnProviderDestroyConfigFunction::SignalCallCompletionSuccess
,
233 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
234 SignalCallCompletionFailure
,
237 return RespondLater();
240 VpnProviderSetParametersFunction::~VpnProviderSetParametersFunction() {
243 ExtensionFunction::ResponseAction
VpnProviderSetParametersFunction::Run() {
244 scoped_ptr
<api_vpn::SetParameters::Params
> params(
245 api_vpn::SetParameters::Params::Create(*args_
));
247 return RespondNow(Error("Invalid arguments."));
250 chromeos::VpnService
* service
=
251 chromeos::VpnServiceFactory::GetForBrowserContext(browser_context());
253 return RespondNow(Error("Invalid profile."));
256 base::DictionaryValue parameter_value
;
258 ConvertParameters(params
->parameters
, ¶meter_value
, &error
);
259 if (!error
.empty()) {
260 return RespondNow(Error(error
));
263 service
->SetParameters(
264 extension_id(), parameter_value
,
265 base::Bind(&VpnProviderSetParametersFunction::
266 SignalCallCompletionSuccessWithWarning
,
268 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
269 SignalCallCompletionFailure
,
272 return RespondLater();
275 VpnProviderSendPacketFunction::~VpnProviderSendPacketFunction() {
278 ExtensionFunction::ResponseAction
VpnProviderSendPacketFunction::Run() {
279 scoped_ptr
<api_vpn::SendPacket::Params
> params(
280 api_vpn::SendPacket::Params::Create(*args_
));
282 return RespondNow(Error("Invalid arguments."));
285 chromeos::VpnService
* service
=
286 chromeos::VpnServiceFactory::GetForBrowserContext(browser_context());
288 return RespondNow(Error("Invalid profile."));
292 extension_id(), params
->data
,
293 base::Bind(&VpnProviderSendPacketFunction::SignalCallCompletionSuccess
,
295 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
296 SignalCallCompletionFailure
,
299 return RespondLater();
302 VpnProviderNotifyConnectionStateChangedFunction::
303 ~VpnProviderNotifyConnectionStateChangedFunction() {
306 ExtensionFunction::ResponseAction
307 VpnProviderNotifyConnectionStateChangedFunction::Run() {
308 scoped_ptr
<api_vpn::NotifyConnectionStateChanged::Params
> params(
309 api_vpn::NotifyConnectionStateChanged::Params::Create(*args_
));
311 return RespondNow(Error("Invalid arguments."));
314 chromeos::VpnService
* service
=
315 chromeos::VpnServiceFactory::GetForBrowserContext(browser_context());
317 return RespondNow(Error("Invalid profile."));
320 service
->NotifyConnectionStateChanged(
321 extension_id(), params
->state
,
322 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
323 SignalCallCompletionSuccess
,
325 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
326 SignalCallCompletionFailure
,
329 return RespondLater();
332 } // namespace extensions