blob: 61cd99ad954365b58cfc968f0eaa3606dcdeb245 [file] [log] [blame]
Darin Petkov33af05c2012-02-28 10:10:30 +01001// Copyright (c) 2012 The Chromium OS 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 "shill/vpn_provider.h"
6
Paul Stewart65512e12012-03-26 18:01:08 -07007#include <algorithm>
8
Ben Chana0ddf462014-02-06 11:32:42 -08009#include <base/strings/string_util.h>
Darin Petkov33af05c2012-02-28 10:10:30 +010010#include <chromeos/dbus/service_constants.h>
11
12#include "shill/error.h"
Darin Petkov9d1bbe72012-04-25 10:58:59 +020013#include "shill/l2tp_ipsec_driver.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070014#include "shill/logging.h"
Paul Stewartca6abd42012-03-01 15:45:29 -080015#include "shill/manager.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010016#include "shill/openvpn_driver.h"
Paul Stewart66815332012-04-09 18:09:36 -070017#include "shill/profile.h"
18#include "shill/store_interface.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010019#include "shill/vpn_service.h"
20
Paul Stewart66815332012-04-09 18:09:36 -070021using std::set;
Darin Petkov33af05c2012-02-28 10:10:30 +010022using std::string;
Paul Stewartca6abd42012-03-01 15:45:29 -080023using std::vector;
Darin Petkov33af05c2012-02-28 10:10:30 +010024
25namespace shill {
26
27VPNProvider::VPNProvider(ControlInterface *control_interface,
28 EventDispatcher *dispatcher,
29 Metrics *metrics,
30 Manager *manager)
31 : control_interface_(control_interface),
32 dispatcher_(dispatcher),
33 metrics_(metrics),
34 manager_(manager) {}
35
36VPNProvider::~VPNProvider() {}
37
38void VPNProvider::Start() {}
39
40void VPNProvider::Stop() {}
41
Paul Stewartbc14fb72013-07-30 08:21:58 -070042// static
43bool VPNProvider::GetServiceParametersFromArgs(const KeyValueStore &args,
44 string *type_ptr,
45 string *name_ptr,
46 string *host_ptr,
47 Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070048 SLOG(VPN, 2) << __func__;
Ben Chan73728782013-09-20 13:40:54 -070049 string type = args.LookupString(kProviderTypeProperty, "");
Darin Petkov7f060332012-03-14 11:46:47 +010050 if (type.empty()) {
Darin Petkov33af05c2012-02-28 10:10:30 +010051 Error::PopulateAndLog(
52 error, Error::kNotSupported, "Missing VPN type property.");
Paul Stewartbc14fb72013-07-30 08:21:58 -070053 return false;
Darin Petkov33af05c2012-02-28 10:10:30 +010054 }
Paul Stewartca6abd42012-03-01 15:45:29 -080055
Ben Chan73728782013-09-20 13:40:54 -070056 string host = args.LookupString(kProviderHostProperty, "");
Darin Petkov9c6e9812013-03-26 13:49:07 +010057 if (host.empty()) {
58 Error::PopulateAndLog(
59 error, Error::kNotSupported, "Missing VPN host property.");
Paul Stewartbc14fb72013-07-30 08:21:58 -070060 return false;
61 }
62
63 *type_ptr = type,
64 *host_ptr = host,
Ben Chan73728782013-09-20 13:40:54 -070065 *name_ptr = args.LookupString(kNameProperty, "");
Paul Stewartbc14fb72013-07-30 08:21:58 -070066
67 return true;
68}
69
70ServiceRefPtr VPNProvider::GetService(const KeyValueStore &args,
71 Error *error) {
72 SLOG(VPN, 2) << __func__;
73 string type;
74 string name;
75 string host;
76
77 if (!GetServiceParametersFromArgs(args, &type, &name, &host, error)) {
Darin Petkov9c6e9812013-03-26 13:49:07 +010078 return NULL;
79 }
80
Darin Petkov02867712012-03-12 14:25:05 +010081 string storage_id = VPNService::CreateStorageIdentifier(args, error);
82 if (storage_id.empty()) {
83 return NULL;
84 }
85
Darin Petkov9c6e9812013-03-26 13:49:07 +010086 // Find a service in the provider list which matches these parameters.
87 VPNServiceRefPtr service = FindService(type, name, host);
88 if (service == NULL) {
89 service = CreateService(type, name, storage_id, error);
90 }
Darin Petkov79d74c92012-03-07 17:20:32 +010091 return service;
Paul Stewartca6abd42012-03-01 15:45:29 -080092}
93
Paul Stewartbc14fb72013-07-30 08:21:58 -070094ServiceRefPtr VPNProvider::FindSimilarService(const KeyValueStore &args,
95 Error *error) const {
96 SLOG(VPN, 2) << __func__;
97 string type;
98 string name;
99 string host;
100
101 if (!GetServiceParametersFromArgs(args, &type, &name, &host, error)) {
102 return NULL;
103 }
104
105 // Find a service in the provider list which matches these parameters.
106 VPNServiceRefPtr service = FindService(type, name, host);
107 if (!service) {
108 error->Populate(Error::kNotFound, "Matching service was not found");
109 }
110
111 return service;
112}
113
Paul Stewartca6abd42012-03-01 15:45:29 -0800114bool VPNProvider::OnDeviceInfoAvailable(const string &link_name,
115 int interface_index) {
Paul Stewart6db7b242014-05-02 15:34:21 -0700116 for (const auto &service : services_) {
117 if (service->driver()->ClaimInterface(link_name, interface_index)) {
Paul Stewartca6abd42012-03-01 15:45:29 -0800118 return true;
119 }
120 }
121
122 return false;
Darin Petkov33af05c2012-02-28 10:10:30 +0100123}
124
Paul Stewart65512e12012-03-26 18:01:08 -0700125void VPNProvider::RemoveService(VPNServiceRefPtr service) {
Paul Stewart6db7b242014-05-02 15:34:21 -0700126 const auto it = std::find(services_.begin(), services_.end(), service);
Paul Stewart65512e12012-03-26 18:01:08 -0700127 if (it != services_.end()) {
128 services_.erase(it);
129 }
130}
131
Paul Stewart0e51ad92013-07-26 14:42:55 -0700132void VPNProvider::CreateServicesFromProfile(const ProfileRefPtr &profile) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700133 SLOG(VPN, 2) << __func__;
Paul Stewart66815332012-04-09 18:09:36 -0700134 const StoreInterface *storage = profile->GetConstStorage();
Paul Stewart6db7b242014-05-02 15:34:21 -0700135 for (const auto &group : storage->GetGroupsWithKey(kProviderTypeProperty)) {
136 if (!StartsWithASCII(group, "vpn_", false)) {
Paul Stewart66815332012-04-09 18:09:36 -0700137 continue;
138 }
139
140 string type;
Paul Stewart6db7b242014-05-02 15:34:21 -0700141 if (!storage->GetString(group, kProviderTypeProperty, &type)) {
142 LOG(ERROR) << "Group " << group << " is missing the "
Ben Chan73728782013-09-20 13:40:54 -0700143 << kProviderTypeProperty << " property.";
Paul Stewart66815332012-04-09 18:09:36 -0700144 continue;
145 }
146
Paul Stewart451aa7f2012-04-11 19:07:58 -0700147 string name;
Paul Stewart6db7b242014-05-02 15:34:21 -0700148 if (!storage->GetString(group, kNameProperty, &name)) {
149 LOG(ERROR) << "Group " << group << " is missing the "
Ben Chan73728782013-09-20 13:40:54 -0700150 << kNameProperty << " property.";
Paul Stewart451aa7f2012-04-11 19:07:58 -0700151 continue;
152 }
153
Darin Petkov9c6e9812013-03-26 13:49:07 +0100154 string host;
Paul Stewart6db7b242014-05-02 15:34:21 -0700155 if (!storage->GetString(group, kProviderHostProperty, &host)) {
156 LOG(ERROR) << "Group " << group << " is missing the "
Ben Chan73728782013-09-20 13:40:54 -0700157 << kProviderHostProperty << " property.";
Darin Petkov9c6e9812013-03-26 13:49:07 +0100158 continue;
159 }
160
161 VPNServiceRefPtr service = FindService(type, name, host);
Paul Stewart66815332012-04-09 18:09:36 -0700162 if (service != NULL) {
163 // If the service already exists, it does not need to be configured,
164 // since PushProfile would have already called ConfigureService on it.
Paul Stewart6db7b242014-05-02 15:34:21 -0700165 SLOG(VPN, 2) << "Service already exists " << group;
Paul Stewart66815332012-04-09 18:09:36 -0700166 continue;
167 }
168
Paul Stewart66815332012-04-09 18:09:36 -0700169 Error error;
Paul Stewart6db7b242014-05-02 15:34:21 -0700170 service = CreateService(type, name, group, &error);
Paul Stewart66815332012-04-09 18:09:36 -0700171
172 if (service == NULL) {
Paul Stewart6db7b242014-05-02 15:34:21 -0700173 LOG(ERROR) << "Could not create service for " << group;
Paul Stewart66815332012-04-09 18:09:36 -0700174 continue;
175 }
176
177 if (!profile->ConfigureService(service)) {
Paul Stewart6db7b242014-05-02 15:34:21 -0700178 LOG(ERROR) << "Could not configure service for " << group;
Paul Stewart66815332012-04-09 18:09:36 -0700179 continue;
180 }
181 }
182}
183
Paul Stewartbc14fb72013-07-30 08:21:58 -0700184VPNServiceRefPtr VPNProvider::CreateServiceInner(const string &type,
185 const string &name,
186 const string &storage_id,
187 Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700188 SLOG(VPN, 2) << __func__ << " type " << type << " name " << name
189 << " storage id " << storage_id;
Darin Petkovc3505a52013-03-18 15:13:29 +0100190#if defined(DISABLE_VPN)
191
192 Error::PopulateAndLog(error, Error::kNotSupported, "VPN is not supported.");
193 return NULL;
194
195#else
196
Paul Stewart66815332012-04-09 18:09:36 -0700197 scoped_ptr<VPNDriver> driver;
Ben Chan73728782013-09-20 13:40:54 -0700198 if (type == kProviderOpenVpn) {
Paul Stewart66815332012-04-09 18:09:36 -0700199 driver.reset(new OpenVPNDriver(
200 control_interface_, dispatcher_, metrics_, manager_,
Paul Stewart451aa7f2012-04-11 19:07:58 -0700201 manager_->device_info(), manager_->glib()));
Ben Chan73728782013-09-20 13:40:54 -0700202 } else if (type == kProviderL2tpIpsec) {
Darin Petkov9d1bbe72012-04-25 10:58:59 +0200203 driver.reset(new L2TPIPSecDriver(
204 control_interface_, dispatcher_, metrics_, manager_,
205 manager_->device_info(), manager_->glib()));
Paul Stewart66815332012-04-09 18:09:36 -0700206 } else {
207 Error::PopulateAndLog(
208 error, Error::kNotSupported, "Unsupported VPN type: " + type);
209 return NULL;
210 }
211
212 VPNServiceRefPtr service = new VPNService(
213 control_interface_, dispatcher_, metrics_, manager_, driver.release());
214 service->set_storage_id(storage_id);
215 service->InitDriverPropertyStore();
Paul Stewart66815332012-04-09 18:09:36 -0700216 if (!name.empty()) {
217 service->set_friendly_name(name);
218 }
Paul Stewart66815332012-04-09 18:09:36 -0700219 return service;
Darin Petkovc3505a52013-03-18 15:13:29 +0100220
221#endif // DISABLE_VPN
Paul Stewart66815332012-04-09 18:09:36 -0700222}
223
Paul Stewartbc14fb72013-07-30 08:21:58 -0700224VPNServiceRefPtr VPNProvider::CreateService(const string &type,
225 const string &name,
226 const string &storage_id,
227 Error *error) {
228 VPNServiceRefPtr service = CreateServiceInner(type, name, storage_id, error);
229 if (service) {
230 services_.push_back(service);
231 manager_->RegisterService(service);
232 }
233
234 return service;
235}
236
Darin Petkov9c6e9812013-03-26 13:49:07 +0100237VPNServiceRefPtr VPNProvider::FindService(const string &type,
238 const string &name,
Paul Stewartbc14fb72013-07-30 08:21:58 -0700239 const string &host) const {
Paul Stewart6db7b242014-05-02 15:34:21 -0700240 for (const auto &service : services_) {
241 if (type == service->driver()->GetProviderType() &&
242 name == service->friendly_name() &&
243 host == service->driver()->GetHost()) {
244 return service;
Paul Stewart66815332012-04-09 18:09:36 -0700245 }
246 }
Paul Stewart66815332012-04-09 18:09:36 -0700247 return NULL;
248}
249
Paul Stewartbc14fb72013-07-30 08:21:58 -0700250ServiceRefPtr VPNProvider::CreateTemporaryService(
251 const KeyValueStore &args, Error *error) {
252 string type;
253 string name;
254 string host;
255
256 if (!GetServiceParametersFromArgs(args, &type, &name, &host, error)) {
257 return NULL;
258 }
259
260 string storage_id = VPNService::CreateStorageIdentifier(args, error);
261 if (storage_id.empty()) {
262 return NULL;
263 }
264
265 return CreateServiceInner(type, name, storage_id, error);
266}
267
Darin Petkov4cbff5b2013-01-29 16:29:05 +0100268bool VPNProvider::HasActiveService() const {
Paul Stewart6db7b242014-05-02 15:34:21 -0700269 for (const auto &service : services_) {
270 if (service->IsConnecting() || service->IsConnected()) {
Darin Petkov4cbff5b2013-01-29 16:29:05 +0100271 return true;
272 }
273 }
274 return false;
275}
276
Darin Petkov33af05c2012-02-28 10:10:30 +0100277} // namespace shill