blob: a4069e69bd2e64fd3c0f68be2012547c3b7a3094 [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 Petkov85d53172013-03-13 16:43:28 +010026#include <sys/wait.h>
27
Darin Petkov69990222012-11-14 09:25:25 +010028#include <base/bind.h>
Darin Petkovf7ef50a2012-04-16 20:54:31 +020029#include <base/file_util.h>
Darin Petkov209e6292012-04-20 11:33:32 +020030#include <base/string_util.h>
Darin Petkov7476a262012-04-12 16:30:46 +020031#include <chromeos/dbus/service_constants.h>
Darin Petkov85d53172013-03-13 16:43:28 +010032#include <chromeos/vpn-manager/service_error.h>
Darin Petkov7476a262012-04-12 16:30:46 +020033
Paul Stewart5baebb72013-03-14 11:43:29 -070034#include "shill/certificate_file.h"
Darin Petkovf8046b82012-04-24 16:29:23 +020035#include "shill/device_info.h"
Darin Petkovf7ef50a2012-04-16 20:54:31 +020036#include "shill/error.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070037#include "shill/logging.h"
Darin Petkovf7ef50a2012-04-16 20:54:31 +020038#include "shill/manager.h"
39#include "shill/nss.h"
Darin Petkov5a850472012-06-06 15:44:24 +020040#include "shill/process_killer.h"
Darin Petkovf8046b82012-04-24 16:29:23 +020041#include "shill/vpn.h"
Darin Petkov209e6292012-04-20 11:33:32 +020042#include "shill/vpn_service.h"
Darin Petkovf7ef50a2012-04-16 20:54:31 +020043
Darin Petkov69990222012-11-14 09:25:25 +010044using base::Bind;
Darin Petkov5a850472012-06-06 15:44:24 +020045using base::Closure;
Albert Chaulk0e1cdea2013-02-27 15:32:55 -080046using base::FilePath;
Darin Petkov209e6292012-04-20 11:33:32 +020047using std::map;
Darin Petkov7476a262012-04-12 16:30:46 +020048using std::string;
Darin Petkovf7ef50a2012-04-16 20:54:31 +020049using std::vector;
Darin Petkov7476a262012-04-12 16:30:46 +020050
51namespace shill {
52
Darin Petkovf7ef50a2012-04-16 20:54:31 +020053namespace {
54const char kL2TPIPSecIPSecTimeoutProperty[] = "L2TPIPsec.IPsecTimeout";
55const char kL2TPIPSecLeftProtoPortProperty[] = "L2TPIPsec.LeftProtoPort";
56const char kL2TPIPSecLengthBitProperty[] = "L2TPIPsec.LengthBit";
57const char kL2TPIPSecPFSProperty[] = "L2TPIPsec.PFS";
58const char kL2TPIPSecRefusePapProperty[] = "L2TPIPsec.RefusePap";
59const char kL2TPIPSecRekeyProperty[] = "L2TPIPsec.Rekey";
60const char kL2TPIPSecRequireAuthProperty[] = "L2TPIPsec.RequireAuth";
61const char kL2TPIPSecRequireChapProperty[] = "L2TPIPsec.RequireChap";
62const char kL2TPIPSecRightProtoPortProperty[] = "L2TPIPsec.RightProtoPort";
63} // namespace
64
65// static
Darin Petkov95f317f2012-10-22 13:37:43 +020066const char L2TPIPSecDriver::kPPPDPlugin[] = SHIMDIR "/shill-pppd-plugin.so";
Darin Petkovd4325392012-04-23 15:48:22 +020067// static
Darin Petkov209e6292012-04-20 11:33:32 +020068const char L2TPIPSecDriver::kL2TPIPSecVPNPath[] = "/usr/sbin/l2tpipsec_vpn";
Darin Petkovd4325392012-04-23 15:48:22 +020069// static
70const VPNDriver::Property L2TPIPSecDriver::kProperties[] = {
Darin Petkova56bf972012-10-09 12:27:32 +020071 { flimflam::kL2tpIpsecAuthenticationType, 0 },
Darin Petkovd4325392012-04-23 15:48:22 +020072 { flimflam::kL2tpIpsecCaCertNssProperty, 0 },
73 { flimflam::kL2tpIpsecClientCertIdProperty, 0 },
74 { flimflam::kL2tpIpsecClientCertSlotProperty, 0 },
Darin Petkova56bf972012-10-09 12:27:32 +020075 { flimflam::kL2tpIpsecIkeVersion, 0 },
Darin Petkov02236552012-06-11 13:15:19 +020076 { flimflam::kL2tpIpsecPasswordProperty,
77 Property::kCredential | Property::kWriteOnly },
Darin Petkovcb715292012-04-25 13:04:37 +020078 { flimflam::kL2tpIpsecPinProperty, Property::kCredential },
79 { flimflam::kL2tpIpsecPskProperty, Property::kCredential },
Darin Petkovd4325392012-04-23 15:48:22 +020080 { flimflam::kL2tpIpsecUserProperty, 0 },
Darin Petkov2c773c22012-04-26 12:54:11 +020081 { flimflam::kProviderHostProperty, 0 },
Darin Petkov2c773c22012-04-26 12:54:11 +020082 { flimflam::kProviderTypeProperty, 0 },
Paul Stewart5baebb72013-03-14 11:43:29 -070083 { kL2tpIpsecCaCertPemProperty, 0 },
Paul Stewart5bbf93b2013-03-21 12:06:08 -070084 { kL2tpIpsecTunnelGroupProperty, 0 },
Darin Petkovd4325392012-04-23 15:48:22 +020085 { kL2TPIPSecIPSecTimeoutProperty, 0 },
86 { kL2TPIPSecLeftProtoPortProperty, 0 },
87 { kL2TPIPSecLengthBitProperty, 0 },
88 { kL2TPIPSecPFSProperty, 0 },
89 { kL2TPIPSecRefusePapProperty, 0 },
90 { kL2TPIPSecRekeyProperty, 0 },
91 { kL2TPIPSecRequireAuthProperty, 0 },
92 { kL2TPIPSecRequireChapProperty, 0 },
93 { kL2TPIPSecRightProtoPortProperty, 0 },
94};
Darin Petkovf7ef50a2012-04-16 20:54:31 +020095
Darin Petkov209e6292012-04-20 11:33:32 +020096L2TPIPSecDriver::L2TPIPSecDriver(ControlInterface *control,
Darin Petkovf8046b82012-04-24 16:29:23 +020097 EventDispatcher *dispatcher,
98 Metrics *metrics,
Darin Petkov209e6292012-04-20 11:33:32 +020099 Manager *manager,
Darin Petkovf8046b82012-04-24 16:29:23 +0200100 DeviceInfo *device_info,
Darin Petkov209e6292012-04-20 11:33:32 +0200101 GLib *glib)
Darin Petkov602303f2012-06-06 12:15:59 +0200102 : VPNDriver(dispatcher, manager, kProperties, arraysize(kProperties)),
Darin Petkovb451d6e2012-04-23 11:56:41 +0200103 control_(control),
Darin Petkovf8046b82012-04-24 16:29:23 +0200104 metrics_(metrics),
105 device_info_(device_info),
Darin Petkov209e6292012-04-20 11:33:32 +0200106 glib_(glib),
107 nss_(NSS::GetInstance()),
Darin Petkov5a850472012-06-06 15:44:24 +0200108 process_killer_(ProcessKiller::GetInstance()),
Paul Stewart5baebb72013-03-14 11:43:29 -0700109 certificate_file_(new CertificateFile(glib)),
Darin Petkov209e6292012-04-20 11:33:32 +0200110 pid_(0),
111 child_watch_tag_(0) {}
Darin Petkov7476a262012-04-12 16:30:46 +0200112
Darin Petkov209e6292012-04-20 11:33:32 +0200113L2TPIPSecDriver::~L2TPIPSecDriver() {
Darin Petkov85d53172013-03-13 16:43:28 +0100114 IdleService();
Darin Petkov209e6292012-04-20 11:33:32 +0200115}
Darin Petkov7476a262012-04-12 16:30:46 +0200116
117bool L2TPIPSecDriver::ClaimInterface(const string &link_name,
118 int interface_index) {
Darin Petkovf8f970a2012-09-03 11:32:55 +0200119 // TODO(petkov): crosbug.com/29970.
Darin Petkov7476a262012-04-12 16:30:46 +0200120 NOTIMPLEMENTED();
121 return false;
122}
123
124void L2TPIPSecDriver::Connect(const VPNServiceRefPtr &service, Error *error) {
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100125 StartConnectTimeout(kDefaultConnectTimeoutSeconds);
Darin Petkov209e6292012-04-20 11:33:32 +0200126 service_ = service;
127 service_->SetState(Service::kStateConfiguring);
128 rpc_task_.reset(new RPCTask(control_, this));
129 if (!SpawnL2TPIPSecVPN(error)) {
Darin Petkov1c049c72013-03-21 13:15:45 +0100130 FailService(Service::kFailureInternal);
Darin Petkov209e6292012-04-20 11:33:32 +0200131 }
Darin Petkov7476a262012-04-12 16:30:46 +0200132}
133
134void L2TPIPSecDriver::Disconnect() {
Darin Petkova0e645e2012-04-25 11:38:59 +0200135 SLOG(VPN, 2) << __func__;
Darin Petkov85d53172013-03-13 16:43:28 +0100136 IdleService();
Darin Petkov7476a262012-04-12 16:30:46 +0200137}
138
Darin Petkov5eb05422012-05-11 15:45:25 +0200139void L2TPIPSecDriver::OnConnectionDisconnected() {
Darin Petkova42afe32013-02-05 16:53:52 +0100140 LOG(INFO) << "Underlying connection disconnected.";
Darin Petkov85d53172013-03-13 16:43:28 +0100141 IdleService();
Darin Petkova42afe32013-02-05 16:53:52 +0100142}
143
144void L2TPIPSecDriver::OnConnectTimeout() {
145 VPNDriver::OnConnectTimeout();
Darin Petkov85d53172013-03-13 16:43:28 +0100146 FailService(Service::kFailureConnect);
Darin Petkov5eb05422012-05-11 15:45:25 +0200147}
148
Darin Petkov7476a262012-04-12 16:30:46 +0200149string L2TPIPSecDriver::GetProviderType() const {
150 return flimflam::kProviderL2tpIpsec;
151}
152
Darin Petkov85d53172013-03-13 16:43:28 +0100153void L2TPIPSecDriver::IdleService() {
154 Cleanup(Service::kStateIdle, Service::kFailureUnknown);
155}
156
157void L2TPIPSecDriver::FailService(Service::ConnectFailure failure) {
158 Cleanup(Service::kStateFailure, failure);
159}
160
161void L2TPIPSecDriver::Cleanup(Service::ConnectState state,
162 Service::ConnectFailure failure) {
163 SLOG(VPN, 2) << __func__ << "("
164 << Service::ConnectStateToString(state) << ", "
165 << Service::ConnectFailureToString(failure) << ")";
Darin Petkov602303f2012-06-06 12:15:59 +0200166 StopConnectTimeout();
Darin Petkov0e9735d2012-04-24 12:33:45 +0200167 DeletePSKFile();
Darin Petkov209e6292012-04-20 11:33:32 +0200168 if (child_watch_tag_) {
169 glib_->SourceRemove(child_watch_tag_);
170 child_watch_tag_ = 0;
Darin Petkov209e6292012-04-20 11:33:32 +0200171 }
172 if (pid_) {
Darin Petkov5a850472012-06-06 15:44:24 +0200173 process_killer_->Kill(pid_, Closure());
Darin Petkov209e6292012-04-20 11:33:32 +0200174 pid_ = 0;
175 }
Darin Petkovf8046b82012-04-24 16:29:23 +0200176 if (device_) {
177 device_->OnDisconnected();
178 device_->SetEnabled(false);
179 device_ = NULL;
180 }
Darin Petkov209e6292012-04-20 11:33:32 +0200181 rpc_task_.reset();
182 if (service_) {
Darin Petkov85d53172013-03-13 16:43:28 +0100183 if (state == Service::kStateFailure) {
184 service_->SetFailure(failure);
185 } else {
186 service_->SetState(state);
187 }
Darin Petkov209e6292012-04-20 11:33:32 +0200188 service_ = NULL;
189 }
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200190}
191
Darin Petkov0e9735d2012-04-24 12:33:45 +0200192void L2TPIPSecDriver::DeletePSKFile() {
193 if (!psk_file_.empty()) {
194 file_util::Delete(psk_file_, false);
195 psk_file_.clear();
196 }
197}
198
Darin Petkov209e6292012-04-20 11:33:32 +0200199bool L2TPIPSecDriver::SpawnL2TPIPSecVPN(Error *error) {
200 SLOG(VPN, 2) << __func__;
201
202 vector<string> options;
203 if (!InitOptions(&options, error)) {
204 return false;
205 }
Darin Petkov85d53172013-03-13 16:43:28 +0100206 LOG(INFO) << "L2TP/IPSec VPN process options: " << JoinString(options, ' ');
Darin Petkov209e6292012-04-20 11:33:32 +0200207
208 // TODO(petkov): This code needs to be abstracted away in a separate external
209 // process module (crosbug.com/27131).
210 vector<char *> process_args;
211 process_args.push_back(const_cast<char *>(kL2TPIPSecVPNPath));
212 for (vector<string>::const_iterator it = options.begin();
213 it != options.end(); ++it) {
214 process_args.push_back(const_cast<char *>(it->c_str()));
215 }
216 process_args.push_back(NULL);
217
218 vector<string> environment;
219 InitEnvironment(&environment);
220
221 vector<char *> process_env;
222 for (vector<string>::const_iterator it = environment.begin();
223 it != environment.end(); ++it) {
224 process_env.push_back(const_cast<char *>(it->c_str()));
225 }
226 process_env.push_back(NULL);
227
228 CHECK(!pid_);
Darin Petkov68710d72013-02-13 14:22:56 +0100229 if (!glib_->SpawnAsync(NULL,
230 process_args.data(),
231 process_env.data(),
232 G_SPAWN_DO_NOT_REAP_CHILD,
233 NULL,
234 NULL,
235 &pid_,
236 NULL)) {
Darin Petkov209e6292012-04-20 11:33:32 +0200237 Error::PopulateAndLog(error, Error::kInternalError,
238 string("Unable to spawn: ") + process_args[0]);
239 return false;
240 }
241 CHECK(!child_watch_tag_);
242 child_watch_tag_ = glib_->ChildWatchAdd(pid_, OnL2TPIPSecVPNDied, this);
243 return true;
244}
245
246void L2TPIPSecDriver::InitEnvironment(vector<string> *environment) {
Darin Petkov95f317f2012-10-22 13:37:43 +0200247 environment->push_back(string(kRPCTaskServiceVariable) + "=" +
248 rpc_task_->GetRpcConnectionIdentifier());
249 environment->push_back(string(kRPCTaskPathVariable) + "=" +
250 rpc_task_->GetRpcIdentifier());
Darin Petkov209e6292012-04-20 11:33:32 +0200251}
252
253bool L2TPIPSecDriver::InitOptions(vector<string> *options, Error *error) {
Darin Petkov01c66042012-04-26 11:10:45 +0200254 string vpnhost = args()->LookupString(flimflam::kProviderHostProperty, "");
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200255 if (vpnhost.empty()) {
256 Error::PopulateAndLog(
257 error, Error::kInvalidArguments, "VPN host not specified.");
Darin Petkov209e6292012-04-20 11:33:32 +0200258 return false;
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200259 }
260
261 if (!InitPSKOptions(options, error)) {
Darin Petkov209e6292012-04-20 11:33:32 +0200262 return false;
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200263 }
264
265 options->push_back("--remote_host");
266 options->push_back(vpnhost);
267 options->push_back("--pppd_plugin");
268 options->push_back(kPPPDPlugin);
269 // Disable pppd from configuring IP addresses, routes, DNS.
270 options->push_back("--nosystemconfig");
271
Paul Stewart5baebb72013-03-14 11:43:29 -0700272 // Accept a PEM CA certificate or an NSS certificate, but not both.
273 // Prefer PEM to NSS.
274 if (!InitPEMOptions(options)) {
275 InitNSSOptions(options);
276 }
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200277
278 AppendValueOption(flimflam::kL2tpIpsecClientCertIdProperty,
279 "--client_cert_id", options);
280 AppendValueOption(flimflam::kL2tpIpsecClientCertSlotProperty,
281 "--client_cert_slot", options);
282 AppendValueOption(flimflam::kL2tpIpsecPinProperty, "--user_pin", options);
283 AppendValueOption(flimflam::kL2tpIpsecUserProperty, "--user", options);
284 AppendValueOption(kL2TPIPSecIPSecTimeoutProperty, "--ipsec_timeout", options);
285 AppendValueOption(kL2TPIPSecLeftProtoPortProperty,
286 "--leftprotoport", options);
287 AppendFlag(kL2TPIPSecPFSProperty, "--pfs", "--nopfs", options);
288 AppendFlag(kL2TPIPSecRekeyProperty, "--rekey", "--norekey", options);
289 AppendValueOption(kL2TPIPSecRightProtoPortProperty,
290 "--rightprotoport", options);
291 AppendFlag(kL2TPIPSecRequireChapProperty,
292 "--require_chap", "--norequire_chap", options);
293 AppendFlag(kL2TPIPSecRefusePapProperty,
294 "--refuse_pap", "--norefuse_pap", options);
295 AppendFlag(kL2TPIPSecRequireAuthProperty,
296 "--require_authentication", "--norequire_authentication", options);
297 AppendFlag(kL2TPIPSecLengthBitProperty,
298 "--length_bit", "--nolength_bit", options);
Paul Stewart5bbf93b2013-03-21 12:06:08 -0700299 AppendValueOption(kL2tpIpsecTunnelGroupProperty, "--tunnel_group", options);
Darin Petkov209e6292012-04-20 11:33:32 +0200300 if (SLOG_IS_ON(VPN, 0)) {
301 options->push_back("--debug");
302 }
303 return true;
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200304}
305
306bool L2TPIPSecDriver::InitPSKOptions(vector<string> *options, Error *error) {
Darin Petkov01c66042012-04-26 11:10:45 +0200307 string psk = args()->LookupString(flimflam::kL2tpIpsecPskProperty, "");
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200308 if (!psk.empty()) {
309 if (!file_util::CreateTemporaryFileInDir(
Darin Petkov0e9735d2012-04-24 12:33:45 +0200310 manager()->run_path(), &psk_file_) ||
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200311 chmod(psk_file_.value().c_str(), S_IRUSR | S_IWUSR) ||
312 file_util::WriteFile(psk_file_, psk.data(), psk.size()) !=
313 static_cast<int>(psk.size())) {
314 Error::PopulateAndLog(
315 error, Error::kInternalError, "Unable to setup psk file.");
316 return false;
317 }
318 options->push_back("--psk_file");
319 options->push_back(psk_file_.value());
320 }
321 return true;
322}
323
324void L2TPIPSecDriver::InitNSSOptions(vector<string> *options) {
325 string ca_cert =
Darin Petkov01c66042012-04-26 11:10:45 +0200326 args()->LookupString(flimflam::kL2tpIpsecCaCertNssProperty, "");
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200327 if (!ca_cert.empty()) {
Darin Petkov01c66042012-04-26 11:10:45 +0200328 const string &vpnhost = args()->GetString(flimflam::kProviderHostProperty);
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200329 vector<char> id(vpnhost.begin(), vpnhost.end());
330 FilePath certfile = nss_->GetDERCertfile(ca_cert, id);
331 if (certfile.empty()) {
332 LOG(ERROR) << "Unable to extract certificate: " << ca_cert;
333 } else {
334 options->push_back("--server_ca_file");
335 options->push_back(certfile.value());
336 }
337 }
338}
339
Paul Stewart5baebb72013-03-14 11:43:29 -0700340bool L2TPIPSecDriver::InitPEMOptions(vector<string> *options) {
341 string ca_cert = args()->LookupString(kL2tpIpsecCaCertPemProperty, "");
342 if (ca_cert.empty()) {
343 return false;
344 }
345 FilePath certfile = certificate_file_->CreateDERFromString(ca_cert);
346 if (certfile.empty()) {
347 LOG(ERROR) << "Unable to extract certificate from PEM string.";
348 return false;
349 }
350 options->push_back("--server_ca_file");
351 options->push_back(certfile.value());
352 return true;
353}
354
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200355bool L2TPIPSecDriver::AppendValueOption(
356 const string &property, const string &option, vector<string> *options) {
Darin Petkov01c66042012-04-26 11:10:45 +0200357 string value = args()->LookupString(property, "");
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200358 if (!value.empty()) {
359 options->push_back(option);
360 options->push_back(value);
361 return true;
362 }
363 return false;
364}
365
366bool L2TPIPSecDriver::AppendFlag(const string &property,
367 const string &true_option,
368 const string &false_option,
369 vector<string> *options) {
Darin Petkov01c66042012-04-26 11:10:45 +0200370 string value = args()->LookupString(property, "");
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200371 if (!value.empty()) {
372 options->push_back(value == "true" ? true_option : false_option);
373 return true;
374 }
375 return false;
376}
377
Darin Petkov209e6292012-04-20 11:33:32 +0200378// static
379void L2TPIPSecDriver::OnL2TPIPSecVPNDied(GPid pid, gint status, gpointer data) {
Darin Petkov85d53172013-03-13 16:43:28 +0100380 LOG(INFO) << __func__ << "(" << pid << ", " << status << ")";
Darin Petkov209e6292012-04-20 11:33:32 +0200381 L2TPIPSecDriver *me = reinterpret_cast<L2TPIPSecDriver *>(data);
382 me->child_watch_tag_ = 0;
383 CHECK_EQ(pid, me->pid_);
Darin Petkov5a850472012-06-06 15:44:24 +0200384 me->pid_ = 0;
Darin Petkov85d53172013-03-13 16:43:28 +0100385 me->FailService(TranslateExitStatusToFailure(status));
Darin Petkov209e6292012-04-20 11:33:32 +0200386 // TODO(petkov): Figure if we need to restart the connection.
387}
388
Darin Petkov85d53172013-03-13 16:43:28 +0100389// static
390Service::ConnectFailure L2TPIPSecDriver::TranslateExitStatusToFailure(
391 int status) {
392 if (!WIFEXITED(status)) {
Darin Petkov1c049c72013-03-21 13:15:45 +0100393 return Service::kFailureInternal;
Darin Petkov85d53172013-03-13 16:43:28 +0100394 }
395 switch (WEXITSTATUS(status)) {
396 case vpn_manager::kServiceErrorResolveHostnameFailed:
397 return Service::kFailureDNSLookup;
398 case vpn_manager::kServiceErrorIpsecConnectionFailed:
399 case vpn_manager::kServiceErrorL2tpConnectionFailed:
400 case vpn_manager::kServiceErrorPppConnectionFailed:
401 return Service::kFailureConnect;
402 case vpn_manager::kServiceErrorIpsecPresharedKeyAuthenticationFailed:
403 return Service::kFailureIPSecPSKAuth;
404 case vpn_manager::kServiceErrorIpsecCertificateAuthenticationFailed:
405 return Service::kFailureIPSecCertAuth;
406 case vpn_manager::kServiceErrorPppAuthenticationFailed:
407 return Service::kFailurePPPAuth;
408 default:
409 break;
410 }
411 return Service::kFailureUnknown;
412}
413
Darin Petkov209e6292012-04-20 11:33:32 +0200414void L2TPIPSecDriver::GetLogin(string *user, string *password) {
Darin Petkov602303f2012-06-06 12:15:59 +0200415 LOG(INFO) << "Login requested.";
Darin Petkov209e6292012-04-20 11:33:32 +0200416 string user_property =
Darin Petkov01c66042012-04-26 11:10:45 +0200417 args()->LookupString(flimflam::kL2tpIpsecUserProperty, "");
Darin Petkov209e6292012-04-20 11:33:32 +0200418 if (user_property.empty()) {
419 LOG(ERROR) << "User not set.";
420 return;
421 }
422 string password_property =
Darin Petkov01c66042012-04-26 11:10:45 +0200423 args()->LookupString(flimflam::kL2tpIpsecPasswordProperty, "");
Darin Petkov209e6292012-04-20 11:33:32 +0200424 if (password_property.empty()) {
425 LOG(ERROR) << "Password not set.";
426 return;
427 }
428 *user = user_property;
429 *password = password_property;
430}
431
Darin Petkov0e9735d2012-04-24 12:33:45 +0200432void L2TPIPSecDriver::ParseIPConfiguration(
433 const map<string, string> &configuration,
434 IPConfig::Properties *properties,
435 string *interface_name) {
436 properties->address_family = IPAddress::kFamilyIPv4;
437 properties->subnet_prefix = IPAddress::GetMaxPrefixLength(
438 properties->address_family);
439 for (map<string, string>::const_iterator it = configuration.begin();
440 it != configuration.end(); ++it) {
441 const string &key = it->first;
442 const string &value = it->second;
443 SLOG(VPN, 2) << "Processing: " << key << " -> " << value;
Darin Petkov95f317f2012-10-22 13:37:43 +0200444 if (key == kL2TPIPSecInternalIP4Address) {
Darin Petkov0e9735d2012-04-24 12:33:45 +0200445 properties->address = value;
Darin Petkov95f317f2012-10-22 13:37:43 +0200446 } else if (key == kL2TPIPSecExternalIP4Address) {
Darin Petkov0e9735d2012-04-24 12:33:45 +0200447 properties->peer_address = value;
Darin Petkov95f317f2012-10-22 13:37:43 +0200448 } else if (key == kL2TPIPSecGatewayAddress) {
Darin Petkov0e9735d2012-04-24 12:33:45 +0200449 properties->gateway = value;
Darin Petkov95f317f2012-10-22 13:37:43 +0200450 } else if (key == kL2TPIPSecDNS1) {
Darin Petkov0e9735d2012-04-24 12:33:45 +0200451 properties->dns_servers.insert(properties->dns_servers.begin(), value);
Darin Petkov95f317f2012-10-22 13:37:43 +0200452 } else if (key == kL2TPIPSecDNS2) {
Darin Petkov0e9735d2012-04-24 12:33:45 +0200453 properties->dns_servers.push_back(value);
Darin Petkov95f317f2012-10-22 13:37:43 +0200454 } else if (key == kL2TPIPSecInterfaceName) {
Darin Petkov0e9735d2012-04-24 12:33:45 +0200455 *interface_name = value;
Darin Petkov95f317f2012-10-22 13:37:43 +0200456 } else if (key == kL2TPIPSecLNSAddress) {
Darin Petkov0e9735d2012-04-24 12:33:45 +0200457 properties->trusted_ip = value;
458 } else {
459 SLOG(VPN, 2) << "Key ignored.";
460 }
461 }
Ben Chana0163122012-09-25 15:10:52 -0700462
463 // There is no IPv6 support for L2TP/IPsec VPN at this moment, so create a
464 // blackhole route for IPv6 traffic after establishing a IPv4 VPN.
465 // TODO(benchan): Generalize this when IPv6 support is added.
466 properties->blackhole_ipv6 = true;
Darin Petkov0e9735d2012-04-24 12:33:45 +0200467}
468
Darin Petkov209e6292012-04-20 11:33:32 +0200469void L2TPIPSecDriver::Notify(
470 const string &reason, const map<string, string> &dict) {
Darin Petkov602303f2012-06-06 12:15:59 +0200471 LOG(INFO) << "IP configuration received: " << reason;
Darin Petkov0e9735d2012-04-24 12:33:45 +0200472
Darin Petkov95f317f2012-10-22 13:37:43 +0200473 if (reason != kL2TPIPSecReasonConnect) {
Darin Petkov69990222012-11-14 09:25:25 +0100474 DCHECK(reason == kL2TPIPSecReasonDisconnect);
475 // Avoid destroying the RPC task inside the adaptor callback by doing it
476 // from the main event loop.
477 dispatcher()->PostTask(Bind(&DeleteRPCTask, rpc_task_.release()));
Darin Petkov85d53172013-03-13 16:43:28 +0100478 FailService(Service::kFailureUnknown);
Darin Petkov0e9735d2012-04-24 12:33:45 +0200479 return;
480 }
481
Darin Petkovf8046b82012-04-24 16:29:23 +0200482 DeletePSKFile();
483
Darin Petkov0e9735d2012-04-24 12:33:45 +0200484 IPConfig::Properties properties;
485 string interface_name;
486 ParseIPConfiguration(dict, &properties, &interface_name);
Darin Petkovf8046b82012-04-24 16:29:23 +0200487
488 int interface_index = device_info_->GetIndex(interface_name);
489 if (interface_index < 0) {
490 // TODO(petkov): Consider handling the race when the RTNL notification about
491 // the new PPP device has not been received yet. We can keep the IP
Darin Petkovf8f970a2012-09-03 11:32:55 +0200492 // configuration and apply it when ClaimInterface is
493 // invoked. crosbug.com/29970.
Darin Petkovf8046b82012-04-24 16:29:23 +0200494 NOTIMPLEMENTED() << ": No device info for " << interface_name << ".";
495 return;
496 }
497
498 if (!device_) {
Darin Petkov602303f2012-06-06 12:15:59 +0200499 device_ = new VPN(control_, dispatcher(), metrics_, manager(),
Darin Petkovf8046b82012-04-24 16:29:23 +0200500 interface_name, interface_index);
501 }
502 device_->SetEnabled(true);
503 device_->SelectService(service_);
Darin Petkovf8046b82012-04-24 16:29:23 +0200504 device_->UpdateIPConfig(properties);
Paul Stewart91a43cb2013-03-02 21:34:15 -0800505 ReportConnectionMetrics();
Darin Petkov602303f2012-06-06 12:15:59 +0200506 StopConnectTimeout();
Darin Petkov209e6292012-04-20 11:33:32 +0200507}
508
Darin Petkov69990222012-11-14 09:25:25 +0100509// static
510void L2TPIPSecDriver::DeleteRPCTask(RPCTask *rpc_task) {
511 delete rpc_task;
512}
513
Darin Petkovb536a742012-04-26 11:31:28 +0200514KeyValueStore L2TPIPSecDriver::GetProvider(Error *error) {
515 SLOG(VPN, 2) << __func__;
516 KeyValueStore props = VPNDriver::GetProvider(error);
517 props.SetBool(flimflam::kPassphraseRequiredProperty,
518 args()->LookupString(
519 flimflam::kL2tpIpsecPasswordProperty, "").empty());
520 props.SetBool(flimflam::kL2tpIpsecPskRequiredProperty,
521 args()->LookupString(
522 flimflam::kL2tpIpsecPskProperty, "").empty());
523 return props;
524}
525
Paul Stewart91a43cb2013-03-02 21:34:15 -0800526void L2TPIPSecDriver::ReportConnectionMetrics() {
527 metrics_->SendEnumToUMA(
528 Metrics::kMetricVpnDriver,
529 Metrics::kVpnDriverL2tpIpsec,
530 Metrics::kMetricVpnDriverMax);
531
532 // We output an enum for each of the authentication types specified,
533 // even if more than one is set at the same time.
534 bool has_remote_authentication = false;
Paul Stewarte8e71da2013-03-20 08:48:33 -0700535 if (args()->LookupString(flimflam::kL2tpIpsecCaCertNssProperty, "") != "") {
Paul Stewart91a43cb2013-03-02 21:34:15 -0800536 metrics_->SendEnumToUMA(
537 Metrics::kMetricVpnRemoteAuthenticationType,
538 Metrics::kVpnRemoteAuthenticationTypeL2tpIpsecCertificate,
539 Metrics::kMetricVpnRemoteAuthenticationTypeMax);
540 has_remote_authentication = true;
541 }
Paul Stewarte8e71da2013-03-20 08:48:33 -0700542 if (args()->LookupString(flimflam::kL2tpIpsecPskProperty, "") != "") {
Paul Stewart91a43cb2013-03-02 21:34:15 -0800543 metrics_->SendEnumToUMA(
544 Metrics::kMetricVpnRemoteAuthenticationType,
545 Metrics::kVpnRemoteAuthenticationTypeL2tpIpsecPsk,
546 Metrics::kMetricVpnRemoteAuthenticationTypeMax);
547 has_remote_authentication = true;
548 }
549 if (!has_remote_authentication) {
550 metrics_->SendEnumToUMA(
551 Metrics::kMetricVpnRemoteAuthenticationType,
552 Metrics::kVpnRemoteAuthenticationTypeL2tpIpsecDefault,
553 Metrics::kMetricVpnRemoteAuthenticationTypeMax);
554 }
555
556 bool has_user_authentication = false;
Paul Stewarte8e71da2013-03-20 08:48:33 -0700557 if (args()->LookupString(flimflam::kL2tpIpsecClientCertIdProperty,
558 "") != "") {
Paul Stewart91a43cb2013-03-02 21:34:15 -0800559 metrics_->SendEnumToUMA(
560 Metrics::kMetricVpnUserAuthenticationType,
561 Metrics::kVpnUserAuthenticationTypeL2tpIpsecCertificate,
562 Metrics::kMetricVpnUserAuthenticationTypeMax);
563 has_user_authentication = true;
564 }
Paul Stewarte8e71da2013-03-20 08:48:33 -0700565 if (args()->LookupString(flimflam::kL2tpIpsecPasswordProperty, "") != "") {
Paul Stewart91a43cb2013-03-02 21:34:15 -0800566 metrics_->SendEnumToUMA(
567 Metrics::kMetricVpnUserAuthenticationType,
568 Metrics::kVpnUserAuthenticationTypeL2tpIpsecUsernamePassword,
569 Metrics::kMetricVpnUserAuthenticationTypeMax);
570 has_user_authentication = true;
571 }
572 if (!has_user_authentication) {
573 metrics_->SendEnumToUMA(
574 Metrics::kMetricVpnUserAuthenticationType,
575 Metrics::kVpnUserAuthenticationTypeL2tpIpsecNone,
576 Metrics::kMetricVpnUserAuthenticationTypeMax);
577 }
578}
579
Darin Petkov7476a262012-04-12 16:30:46 +0200580} // namespace shill