blob: ea96ce081eaf763b3c9afef652a1b8642278e284 [file] [log] [blame]
Darin Petkov7476a262012-04-12 16:30:46 +02001// 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
Paul Stewart5bbf93b2013-03-21 12:06:08 -07005// The term "L2TP / IPSec" refers to a pair of layered protocols used
6// together to establish a tunneled VPN connection. First, an "IPSec"
7// link is created, which secures a single IP traffic pair between the
8// client and server. For this link to complete, one or two levels of
9// authentication are performed. The first, inner mandatory authentication
10// ensures the two parties establishing the IPSec link are correct. This
11// can use a certificate exchange or a less secure "shared group key"
12// (PSK) authentication. An optional outer IPSec authentication can also be
13// performed, which is not fully supported by shill's implementation.
14// In order to support "tunnel groups" from some vendor VPNs shill supports
15// supplying the authentication realm portion during the outer authentication.
16// Notably, XAUTH and other forms of user authentication on this outer link
17// are not supported.
18//
19// When IPSec authentication completes, traffic is tunneled through a
20// layer 2 tunnel, called "L2TP". Using the secured link, we tunnel a
21// PPP link, through which a second layer of authentication is performed,
22// using the provided "user" and "password" properties.
23
Darin Petkov7476a262012-04-12 16:30:46 +020024#include "shill/l2tp_ipsec_driver.h"
25
Darin Petkov69990222012-11-14 09:25:25 +010026#include <base/bind.h>
Darin Petkovf7ef50a2012-04-16 20:54:31 +020027#include <base/file_util.h>
Darin Petkov209e6292012-04-20 11:33:32 +020028#include <base/string_util.h>
Darin Petkov7476a262012-04-12 16:30:46 +020029#include <chromeos/dbus/service_constants.h>
Darin Petkov85d53172013-03-13 16:43:28 +010030#include <chromeos/vpn-manager/service_error.h>
Darin Petkov7476a262012-04-12 16:30:46 +020031
Paul Stewart5baebb72013-03-14 11:43:29 -070032#include "shill/certificate_file.h"
Darin Petkovf8046b82012-04-24 16:29:23 +020033#include "shill/device_info.h"
Darin Petkovf7ef50a2012-04-16 20:54:31 +020034#include "shill/error.h"
mukesh agrawalae30e9e2013-05-28 14:09:16 -070035#include "shill/external_task.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070036#include "shill/logging.h"
Darin Petkovf7ef50a2012-04-16 20:54:31 +020037#include "shill/manager.h"
38#include "shill/nss.h"
mukesh agrawal9da07772013-05-15 14:15:17 -070039#include "shill/ppp_device.h"
Darin Petkov209e6292012-04-20 11:33:32 +020040#include "shill/vpn_service.h"
Darin Petkovf7ef50a2012-04-16 20:54:31 +020041
Darin Petkov69990222012-11-14 09:25:25 +010042using base::Bind;
Darin Petkov5a850472012-06-06 15:44:24 +020043using base::Closure;
Albert Chaulk0e1cdea2013-02-27 15:32:55 -080044using base::FilePath;
Darin Petkov209e6292012-04-20 11:33:32 +020045using std::map;
Darin Petkov7476a262012-04-12 16:30:46 +020046using std::string;
Darin Petkovf7ef50a2012-04-16 20:54:31 +020047using std::vector;
Darin Petkov7476a262012-04-12 16:30:46 +020048
49namespace shill {
50
Darin Petkovf7ef50a2012-04-16 20:54:31 +020051namespace {
52const char kL2TPIPSecIPSecTimeoutProperty[] = "L2TPIPsec.IPsecTimeout";
53const char kL2TPIPSecLeftProtoPortProperty[] = "L2TPIPsec.LeftProtoPort";
54const char kL2TPIPSecLengthBitProperty[] = "L2TPIPsec.LengthBit";
55const char kL2TPIPSecPFSProperty[] = "L2TPIPsec.PFS";
56const char kL2TPIPSecRefusePapProperty[] = "L2TPIPsec.RefusePap";
57const char kL2TPIPSecRekeyProperty[] = "L2TPIPsec.Rekey";
58const char kL2TPIPSecRequireAuthProperty[] = "L2TPIPsec.RequireAuth";
59const char kL2TPIPSecRequireChapProperty[] = "L2TPIPsec.RequireChap";
60const char kL2TPIPSecRightProtoPortProperty[] = "L2TPIPsec.RightProtoPort";
61} // namespace
62
63// static
Darin Petkov209e6292012-04-20 11:33:32 +020064const char L2TPIPSecDriver::kL2TPIPSecVPNPath[] = "/usr/sbin/l2tpipsec_vpn";
Darin Petkovd4325392012-04-23 15:48:22 +020065// static
66const VPNDriver::Property L2TPIPSecDriver::kProperties[] = {
Darin Petkova56bf972012-10-09 12:27:32 +020067 { flimflam::kL2tpIpsecAuthenticationType, 0 },
Darin Petkovd4325392012-04-23 15:48:22 +020068 { flimflam::kL2tpIpsecCaCertNssProperty, 0 },
69 { flimflam::kL2tpIpsecClientCertIdProperty, 0 },
70 { flimflam::kL2tpIpsecClientCertSlotProperty, 0 },
Darin Petkova56bf972012-10-09 12:27:32 +020071 { flimflam::kL2tpIpsecIkeVersion, 0 },
Darin Petkov02236552012-06-11 13:15:19 +020072 { flimflam::kL2tpIpsecPasswordProperty,
73 Property::kCredential | Property::kWriteOnly },
Darin Petkovcb715292012-04-25 13:04:37 +020074 { flimflam::kL2tpIpsecPinProperty, Property::kCredential },
75 { flimflam::kL2tpIpsecPskProperty, Property::kCredential },
Darin Petkovd4325392012-04-23 15:48:22 +020076 { flimflam::kL2tpIpsecUserProperty, 0 },
Darin Petkov2c773c22012-04-26 12:54:11 +020077 { flimflam::kProviderHostProperty, 0 },
Darin Petkov2c773c22012-04-26 12:54:11 +020078 { flimflam::kProviderTypeProperty, 0 },
Paul Stewart5baebb72013-03-14 11:43:29 -070079 { kL2tpIpsecCaCertPemProperty, 0 },
Paul Stewart5bbf93b2013-03-21 12:06:08 -070080 { kL2tpIpsecTunnelGroupProperty, 0 },
Darin Petkovd4325392012-04-23 15:48:22 +020081 { kL2TPIPSecIPSecTimeoutProperty, 0 },
82 { kL2TPIPSecLeftProtoPortProperty, 0 },
83 { kL2TPIPSecLengthBitProperty, 0 },
84 { kL2TPIPSecPFSProperty, 0 },
85 { kL2TPIPSecRefusePapProperty, 0 },
86 { kL2TPIPSecRekeyProperty, 0 },
87 { kL2TPIPSecRequireAuthProperty, 0 },
88 { kL2TPIPSecRequireChapProperty, 0 },
89 { kL2TPIPSecRightProtoPortProperty, 0 },
90};
Darin Petkovf7ef50a2012-04-16 20:54:31 +020091
Darin Petkov209e6292012-04-20 11:33:32 +020092L2TPIPSecDriver::L2TPIPSecDriver(ControlInterface *control,
Darin Petkovf8046b82012-04-24 16:29:23 +020093 EventDispatcher *dispatcher,
94 Metrics *metrics,
Darin Petkov209e6292012-04-20 11:33:32 +020095 Manager *manager,
Darin Petkovf8046b82012-04-24 16:29:23 +020096 DeviceInfo *device_info,
Darin Petkov209e6292012-04-20 11:33:32 +020097 GLib *glib)
Darin Petkov602303f2012-06-06 12:15:59 +020098 : VPNDriver(dispatcher, manager, kProperties, arraysize(kProperties)),
Darin Petkovb451d6e2012-04-23 11:56:41 +020099 control_(control),
Darin Petkovf8046b82012-04-24 16:29:23 +0200100 metrics_(metrics),
101 device_info_(device_info),
Darin Petkov209e6292012-04-20 11:33:32 +0200102 glib_(glib),
103 nss_(NSS::GetInstance()),
Paul Stewart5baebb72013-03-14 11:43:29 -0700104 certificate_file_(new CertificateFile(glib)),
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700105 weak_ptr_factory_(this) {}
Darin Petkov7476a262012-04-12 16:30:46 +0200106
Darin Petkov209e6292012-04-20 11:33:32 +0200107L2TPIPSecDriver::~L2TPIPSecDriver() {
Darin Petkov85d53172013-03-13 16:43:28 +0100108 IdleService();
Darin Petkov209e6292012-04-20 11:33:32 +0200109}
Darin Petkov7476a262012-04-12 16:30:46 +0200110
111bool L2TPIPSecDriver::ClaimInterface(const string &link_name,
112 int interface_index) {
Darin Petkovf8f970a2012-09-03 11:32:55 +0200113 // TODO(petkov): crosbug.com/29970.
Darin Petkov7476a262012-04-12 16:30:46 +0200114 NOTIMPLEMENTED();
115 return false;
116}
117
118void L2TPIPSecDriver::Connect(const VPNServiceRefPtr &service, Error *error) {
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100119 StartConnectTimeout(kDefaultConnectTimeoutSeconds);
Darin Petkov209e6292012-04-20 11:33:32 +0200120 service_ = service;
121 service_->SetState(Service::kStateConfiguring);
Darin Petkov209e6292012-04-20 11:33:32 +0200122 if (!SpawnL2TPIPSecVPN(error)) {
Darin Petkov1c049c72013-03-21 13:15:45 +0100123 FailService(Service::kFailureInternal);
Darin Petkov209e6292012-04-20 11:33:32 +0200124 }
Darin Petkov7476a262012-04-12 16:30:46 +0200125}
126
127void L2TPIPSecDriver::Disconnect() {
Darin Petkova0e645e2012-04-25 11:38:59 +0200128 SLOG(VPN, 2) << __func__;
Darin Petkov85d53172013-03-13 16:43:28 +0100129 IdleService();
Darin Petkov7476a262012-04-12 16:30:46 +0200130}
131
Darin Petkov5eb05422012-05-11 15:45:25 +0200132void L2TPIPSecDriver::OnConnectionDisconnected() {
Darin Petkova42afe32013-02-05 16:53:52 +0100133 LOG(INFO) << "Underlying connection disconnected.";
Darin Petkov85d53172013-03-13 16:43:28 +0100134 IdleService();
Darin Petkova42afe32013-02-05 16:53:52 +0100135}
136
137void L2TPIPSecDriver::OnConnectTimeout() {
138 VPNDriver::OnConnectTimeout();
Darin Petkov85d53172013-03-13 16:43:28 +0100139 FailService(Service::kFailureConnect);
Darin Petkov5eb05422012-05-11 15:45:25 +0200140}
141
Darin Petkov7476a262012-04-12 16:30:46 +0200142string L2TPIPSecDriver::GetProviderType() const {
143 return flimflam::kProviderL2tpIpsec;
144}
145
Darin Petkov85d53172013-03-13 16:43:28 +0100146void L2TPIPSecDriver::IdleService() {
147 Cleanup(Service::kStateIdle, Service::kFailureUnknown);
148}
149
150void L2TPIPSecDriver::FailService(Service::ConnectFailure failure) {
151 Cleanup(Service::kStateFailure, failure);
152}
153
154void L2TPIPSecDriver::Cleanup(Service::ConnectState state,
155 Service::ConnectFailure failure) {
156 SLOG(VPN, 2) << __func__ << "("
157 << Service::ConnectStateToString(state) << ", "
158 << Service::ConnectFailureToString(failure) << ")";
Darin Petkov602303f2012-06-06 12:15:59 +0200159 StopConnectTimeout();
Darin Petkov0e9735d2012-04-24 12:33:45 +0200160 DeletePSKFile();
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700161 external_task_.reset();
Darin Petkovf8046b82012-04-24 16:29:23 +0200162 if (device_) {
mukesh agrawal9da07772013-05-15 14:15:17 -0700163 device_->DropConnection();
Darin Petkovf8046b82012-04-24 16:29:23 +0200164 device_->SetEnabled(false);
165 device_ = NULL;
166 }
Darin Petkov209e6292012-04-20 11:33:32 +0200167 if (service_) {
Darin Petkov85d53172013-03-13 16:43:28 +0100168 if (state == Service::kStateFailure) {
169 service_->SetFailure(failure);
170 } else {
171 service_->SetState(state);
172 }
Darin Petkov209e6292012-04-20 11:33:32 +0200173 service_ = NULL;
174 }
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200175}
176
Darin Petkov0e9735d2012-04-24 12:33:45 +0200177void L2TPIPSecDriver::DeletePSKFile() {
178 if (!psk_file_.empty()) {
179 file_util::Delete(psk_file_, false);
180 psk_file_.clear();
181 }
182}
183
Darin Petkov209e6292012-04-20 11:33:32 +0200184bool L2TPIPSecDriver::SpawnL2TPIPSecVPN(Error *error) {
185 SLOG(VPN, 2) << __func__;
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700186 scoped_ptr<ExternalTask> external_task_local(
187 new ExternalTask(control_, glib_,
188 weak_ptr_factory_.GetWeakPtr(),
189 Bind(&L2TPIPSecDriver::OnL2TPIPSecVPNDied,
190 weak_ptr_factory_.GetWeakPtr())));
Darin Petkov209e6292012-04-20 11:33:32 +0200191
192 vector<string> options;
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700193 map<string, string> environment; // No env vars passed.
Darin Petkov209e6292012-04-20 11:33:32 +0200194 if (!InitOptions(&options, error)) {
195 return false;
196 }
Darin Petkov85d53172013-03-13 16:43:28 +0100197 LOG(INFO) << "L2TP/IPSec VPN process options: " << JoinString(options, ' ');
Darin Petkov209e6292012-04-20 11:33:32 +0200198
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700199 if (external_task_local->Start(
200 FilePath(kL2TPIPSecVPNPath), options, environment, error)) {
mukesh agrawal9da07772013-05-15 14:15:17 -0700201 external_task_ = external_task_local.Pass();
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700202 return true;
Darin Petkov209e6292012-04-20 11:33:32 +0200203 }
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700204 return false;
Darin Petkov209e6292012-04-20 11:33:32 +0200205}
206
207bool L2TPIPSecDriver::InitOptions(vector<string> *options, Error *error) {
Darin Petkov01c66042012-04-26 11:10:45 +0200208 string vpnhost = args()->LookupString(flimflam::kProviderHostProperty, "");
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200209 if (vpnhost.empty()) {
210 Error::PopulateAndLog(
211 error, Error::kInvalidArguments, "VPN host not specified.");
Darin Petkov209e6292012-04-20 11:33:32 +0200212 return false;
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200213 }
214
215 if (!InitPSKOptions(options, error)) {
Darin Petkov209e6292012-04-20 11:33:32 +0200216 return false;
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200217 }
218
219 options->push_back("--remote_host");
220 options->push_back(vpnhost);
221 options->push_back("--pppd_plugin");
mukesh agrawal9da07772013-05-15 14:15:17 -0700222 options->push_back(PPPDevice::kPluginPath);
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200223 // Disable pppd from configuring IP addresses, routes, DNS.
224 options->push_back("--nosystemconfig");
225
Paul Stewart5baebb72013-03-14 11:43:29 -0700226 // Accept a PEM CA certificate or an NSS certificate, but not both.
227 // Prefer PEM to NSS.
228 if (!InitPEMOptions(options)) {
229 InitNSSOptions(options);
230 }
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200231
232 AppendValueOption(flimflam::kL2tpIpsecClientCertIdProperty,
233 "--client_cert_id", options);
234 AppendValueOption(flimflam::kL2tpIpsecClientCertSlotProperty,
235 "--client_cert_slot", options);
236 AppendValueOption(flimflam::kL2tpIpsecPinProperty, "--user_pin", options);
237 AppendValueOption(flimflam::kL2tpIpsecUserProperty, "--user", options);
238 AppendValueOption(kL2TPIPSecIPSecTimeoutProperty, "--ipsec_timeout", options);
239 AppendValueOption(kL2TPIPSecLeftProtoPortProperty,
240 "--leftprotoport", options);
241 AppendFlag(kL2TPIPSecPFSProperty, "--pfs", "--nopfs", options);
242 AppendFlag(kL2TPIPSecRekeyProperty, "--rekey", "--norekey", options);
243 AppendValueOption(kL2TPIPSecRightProtoPortProperty,
244 "--rightprotoport", options);
245 AppendFlag(kL2TPIPSecRequireChapProperty,
246 "--require_chap", "--norequire_chap", options);
247 AppendFlag(kL2TPIPSecRefusePapProperty,
248 "--refuse_pap", "--norefuse_pap", options);
249 AppendFlag(kL2TPIPSecRequireAuthProperty,
250 "--require_authentication", "--norequire_authentication", options);
251 AppendFlag(kL2TPIPSecLengthBitProperty,
252 "--length_bit", "--nolength_bit", options);
Paul Stewart5bbf93b2013-03-21 12:06:08 -0700253 AppendValueOption(kL2tpIpsecTunnelGroupProperty, "--tunnel_group", options);
Darin Petkov209e6292012-04-20 11:33:32 +0200254 if (SLOG_IS_ON(VPN, 0)) {
255 options->push_back("--debug");
256 }
257 return true;
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200258}
259
260bool L2TPIPSecDriver::InitPSKOptions(vector<string> *options, Error *error) {
Darin Petkov01c66042012-04-26 11:10:45 +0200261 string psk = args()->LookupString(flimflam::kL2tpIpsecPskProperty, "");
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200262 if (!psk.empty()) {
263 if (!file_util::CreateTemporaryFileInDir(
Darin Petkov0e9735d2012-04-24 12:33:45 +0200264 manager()->run_path(), &psk_file_) ||
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200265 chmod(psk_file_.value().c_str(), S_IRUSR | S_IWUSR) ||
266 file_util::WriteFile(psk_file_, psk.data(), psk.size()) !=
267 static_cast<int>(psk.size())) {
268 Error::PopulateAndLog(
269 error, Error::kInternalError, "Unable to setup psk file.");
270 return false;
271 }
272 options->push_back("--psk_file");
273 options->push_back(psk_file_.value());
274 }
275 return true;
276}
277
278void L2TPIPSecDriver::InitNSSOptions(vector<string> *options) {
279 string ca_cert =
Darin Petkov01c66042012-04-26 11:10:45 +0200280 args()->LookupString(flimflam::kL2tpIpsecCaCertNssProperty, "");
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200281 if (!ca_cert.empty()) {
Darin Petkov01c66042012-04-26 11:10:45 +0200282 const string &vpnhost = args()->GetString(flimflam::kProviderHostProperty);
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200283 vector<char> id(vpnhost.begin(), vpnhost.end());
284 FilePath certfile = nss_->GetDERCertfile(ca_cert, id);
285 if (certfile.empty()) {
286 LOG(ERROR) << "Unable to extract certificate: " << ca_cert;
287 } else {
288 options->push_back("--server_ca_file");
289 options->push_back(certfile.value());
290 }
291 }
292}
293
Paul Stewart5baebb72013-03-14 11:43:29 -0700294bool L2TPIPSecDriver::InitPEMOptions(vector<string> *options) {
295 string ca_cert = args()->LookupString(kL2tpIpsecCaCertPemProperty, "");
296 if (ca_cert.empty()) {
297 return false;
298 }
299 FilePath certfile = certificate_file_->CreateDERFromString(ca_cert);
300 if (certfile.empty()) {
301 LOG(ERROR) << "Unable to extract certificate from PEM string.";
302 return false;
303 }
304 options->push_back("--server_ca_file");
305 options->push_back(certfile.value());
306 return true;
307}
308
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200309bool L2TPIPSecDriver::AppendValueOption(
310 const string &property, const string &option, vector<string> *options) {
Darin Petkov01c66042012-04-26 11:10:45 +0200311 string value = args()->LookupString(property, "");
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200312 if (!value.empty()) {
313 options->push_back(option);
314 options->push_back(value);
315 return true;
316 }
317 return false;
318}
319
320bool L2TPIPSecDriver::AppendFlag(const string &property,
321 const string &true_option,
322 const string &false_option,
323 vector<string> *options) {
Darin Petkov01c66042012-04-26 11:10:45 +0200324 string value = args()->LookupString(property, "");
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200325 if (!value.empty()) {
326 options->push_back(value == "true" ? true_option : false_option);
327 return true;
328 }
329 return false;
330}
331
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700332void L2TPIPSecDriver::OnL2TPIPSecVPNDied(pid_t /*pid*/, int status) {
333 FailService(TranslateExitStatusToFailure(status));
Darin Petkov209e6292012-04-20 11:33:32 +0200334 // TODO(petkov): Figure if we need to restart the connection.
335}
336
Darin Petkov85d53172013-03-13 16:43:28 +0100337// static
338Service::ConnectFailure L2TPIPSecDriver::TranslateExitStatusToFailure(
339 int status) {
340 if (!WIFEXITED(status)) {
Darin Petkov1c049c72013-03-21 13:15:45 +0100341 return Service::kFailureInternal;
Darin Petkov85d53172013-03-13 16:43:28 +0100342 }
343 switch (WEXITSTATUS(status)) {
344 case vpn_manager::kServiceErrorResolveHostnameFailed:
345 return Service::kFailureDNSLookup;
346 case vpn_manager::kServiceErrorIpsecConnectionFailed:
347 case vpn_manager::kServiceErrorL2tpConnectionFailed:
348 case vpn_manager::kServiceErrorPppConnectionFailed:
349 return Service::kFailureConnect;
350 case vpn_manager::kServiceErrorIpsecPresharedKeyAuthenticationFailed:
351 return Service::kFailureIPSecPSKAuth;
352 case vpn_manager::kServiceErrorIpsecCertificateAuthenticationFailed:
353 return Service::kFailureIPSecCertAuth;
354 case vpn_manager::kServiceErrorPppAuthenticationFailed:
355 return Service::kFailurePPPAuth;
356 default:
357 break;
358 }
359 return Service::kFailureUnknown;
360}
361
Darin Petkov209e6292012-04-20 11:33:32 +0200362void L2TPIPSecDriver::GetLogin(string *user, string *password) {
Darin Petkov602303f2012-06-06 12:15:59 +0200363 LOG(INFO) << "Login requested.";
Darin Petkov209e6292012-04-20 11:33:32 +0200364 string user_property =
Darin Petkov01c66042012-04-26 11:10:45 +0200365 args()->LookupString(flimflam::kL2tpIpsecUserProperty, "");
Darin Petkov209e6292012-04-20 11:33:32 +0200366 if (user_property.empty()) {
367 LOG(ERROR) << "User not set.";
368 return;
369 }
370 string password_property =
Darin Petkov01c66042012-04-26 11:10:45 +0200371 args()->LookupString(flimflam::kL2tpIpsecPasswordProperty, "");
Darin Petkov209e6292012-04-20 11:33:32 +0200372 if (password_property.empty()) {
373 LOG(ERROR) << "Password not set.";
374 return;
375 }
376 *user = user_property;
377 *password = password_property;
378}
379
380void L2TPIPSecDriver::Notify(
381 const string &reason, const map<string, string> &dict) {
Darin Petkov602303f2012-06-06 12:15:59 +0200382 LOG(INFO) << "IP configuration received: " << reason;
Darin Petkov0e9735d2012-04-24 12:33:45 +0200383
mukesh agrawal9da07772013-05-15 14:15:17 -0700384 if (reason != kPPPReasonConnect) {
385 DCHECK_EQ(kPPPReasonDisconnect, reason);
386 // DestroyLater, rather than while on stack.
387 external_task_.release()->DestroyLater(dispatcher());
Darin Petkov85d53172013-03-13 16:43:28 +0100388 FailService(Service::kFailureUnknown);
Darin Petkov0e9735d2012-04-24 12:33:45 +0200389 return;
390 }
391
Darin Petkovf8046b82012-04-24 16:29:23 +0200392 DeletePSKFile();
393
mukesh agrawal9da07772013-05-15 14:15:17 -0700394 string interface_name = PPPDevice::GetInterfaceName(dict);
Darin Petkovf8046b82012-04-24 16:29:23 +0200395 int interface_index = device_info_->GetIndex(interface_name);
396 if (interface_index < 0) {
397 // TODO(petkov): Consider handling the race when the RTNL notification about
398 // the new PPP device has not been received yet. We can keep the IP
Darin Petkovf8f970a2012-09-03 11:32:55 +0200399 // configuration and apply it when ClaimInterface is
400 // invoked. crosbug.com/29970.
Darin Petkovf8046b82012-04-24 16:29:23 +0200401 NOTIMPLEMENTED() << ": No device info for " << interface_name << ".";
402 return;
403 }
404
mukesh agrawal9da07772013-05-15 14:15:17 -0700405 // There is no IPv6 support for L2TP/IPsec VPN at this moment, so create a
406 // blackhole route for IPv6 traffic after establishing a IPv4 VPN.
407 // TODO(benchan): Generalize this when IPv6 support is added.
408 bool blackhole_ipv6 = true;
409
Darin Petkovf8046b82012-04-24 16:29:23 +0200410 if (!device_) {
mukesh agrawal9da07772013-05-15 14:15:17 -0700411 device_ = new PPPDevice(control_, dispatcher(), metrics_, manager(),
412 interface_name, interface_index);
Darin Petkovf8046b82012-04-24 16:29:23 +0200413 }
414 device_->SetEnabled(true);
415 device_->SelectService(service_);
mukesh agrawal9da07772013-05-15 14:15:17 -0700416 device_->UpdateIPConfigFromPPP(dict, blackhole_ipv6);
Paul Stewart91a43cb2013-03-02 21:34:15 -0800417 ReportConnectionMetrics();
Darin Petkov602303f2012-06-06 12:15:59 +0200418 StopConnectTimeout();
Darin Petkov209e6292012-04-20 11:33:32 +0200419}
420
Darin Petkovb536a742012-04-26 11:31:28 +0200421KeyValueStore L2TPIPSecDriver::GetProvider(Error *error) {
422 SLOG(VPN, 2) << __func__;
423 KeyValueStore props = VPNDriver::GetProvider(error);
424 props.SetBool(flimflam::kPassphraseRequiredProperty,
425 args()->LookupString(
426 flimflam::kL2tpIpsecPasswordProperty, "").empty());
427 props.SetBool(flimflam::kL2tpIpsecPskRequiredProperty,
428 args()->LookupString(
429 flimflam::kL2tpIpsecPskProperty, "").empty());
430 return props;
431}
432
Paul Stewart91a43cb2013-03-02 21:34:15 -0800433void L2TPIPSecDriver::ReportConnectionMetrics() {
434 metrics_->SendEnumToUMA(
435 Metrics::kMetricVpnDriver,
436 Metrics::kVpnDriverL2tpIpsec,
437 Metrics::kMetricVpnDriverMax);
438
439 // We output an enum for each of the authentication types specified,
440 // even if more than one is set at the same time.
441 bool has_remote_authentication = false;
Paul Stewarte8e71da2013-03-20 08:48:33 -0700442 if (args()->LookupString(flimflam::kL2tpIpsecCaCertNssProperty, "") != "") {
Paul Stewart91a43cb2013-03-02 21:34:15 -0800443 metrics_->SendEnumToUMA(
444 Metrics::kMetricVpnRemoteAuthenticationType,
445 Metrics::kVpnRemoteAuthenticationTypeL2tpIpsecCertificate,
446 Metrics::kMetricVpnRemoteAuthenticationTypeMax);
447 has_remote_authentication = true;
448 }
Paul Stewarte8e71da2013-03-20 08:48:33 -0700449 if (args()->LookupString(flimflam::kL2tpIpsecPskProperty, "") != "") {
Paul Stewart91a43cb2013-03-02 21:34:15 -0800450 metrics_->SendEnumToUMA(
451 Metrics::kMetricVpnRemoteAuthenticationType,
452 Metrics::kVpnRemoteAuthenticationTypeL2tpIpsecPsk,
453 Metrics::kMetricVpnRemoteAuthenticationTypeMax);
454 has_remote_authentication = true;
455 }
456 if (!has_remote_authentication) {
457 metrics_->SendEnumToUMA(
458 Metrics::kMetricVpnRemoteAuthenticationType,
459 Metrics::kVpnRemoteAuthenticationTypeL2tpIpsecDefault,
460 Metrics::kMetricVpnRemoteAuthenticationTypeMax);
461 }
462
463 bool has_user_authentication = false;
Paul Stewarte8e71da2013-03-20 08:48:33 -0700464 if (args()->LookupString(flimflam::kL2tpIpsecClientCertIdProperty,
465 "") != "") {
Paul Stewart91a43cb2013-03-02 21:34:15 -0800466 metrics_->SendEnumToUMA(
467 Metrics::kMetricVpnUserAuthenticationType,
468 Metrics::kVpnUserAuthenticationTypeL2tpIpsecCertificate,
469 Metrics::kMetricVpnUserAuthenticationTypeMax);
470 has_user_authentication = true;
471 }
Paul Stewarte8e71da2013-03-20 08:48:33 -0700472 if (args()->LookupString(flimflam::kL2tpIpsecPasswordProperty, "") != "") {
Paul Stewart91a43cb2013-03-02 21:34:15 -0800473 metrics_->SendEnumToUMA(
474 Metrics::kMetricVpnUserAuthenticationType,
475 Metrics::kVpnUserAuthenticationTypeL2tpIpsecUsernamePassword,
476 Metrics::kMetricVpnUserAuthenticationTypeMax);
477 has_user_authentication = true;
478 }
479 if (!has_user_authentication) {
480 metrics_->SendEnumToUMA(
481 Metrics::kMetricVpnUserAuthenticationType,
482 Metrics::kVpnUserAuthenticationTypeL2tpIpsecNone,
483 Metrics::kMetricVpnUserAuthenticationTypeMax);
484 }
485}
486
Darin Petkov7476a262012-04-12 16:30:46 +0200487} // namespace shill