blob: 14a628532bcad10f054446033d37c955a7631c86 [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
5#include "shill/l2tp_ipsec_driver.h"
6
Ben Chan11c213f2014-09-05 08:21:06 -07007#include <base/files/file_util.h>
Paul Stewart5ad16062013-02-21 18:10:48 -08008#include <base/files/scoped_temp_dir.h>
mukesh agrawalae30e9e2013-05-28 14:09:16 -07009#include <base/memory/weak_ptr.h>
Ben Chana0ddf462014-02-06 11:32:42 -080010#include <base/strings/string_util.h>
Steve Fungfca1a042014-10-07 15:10:16 -070011#include <base/strings/stringprintf.h>
Darin Petkov7476a262012-04-12 16:30:46 +020012#include <gtest/gtest.h>
Alex Vakulenkoa41ab512014-07-23 14:24:23 -070013#include <vpn-manager/service_error.h>
Darin Petkov7476a262012-04-12 16:30:46 +020014
15#include "shill/event_dispatcher.h"
Darin Petkov209e6292012-04-20 11:33:32 +020016#include "shill/mock_adaptors.h"
Paul Stewart5baebb72013-03-14 11:43:29 -070017#include "shill/mock_certificate_file.h"
Darin Petkov0e9735d2012-04-24 12:33:45 +020018#include "shill/mock_device_info.h"
mukesh agrawalae30e9e2013-05-28 14:09:16 -070019#include "shill/mock_external_task.h"
Darin Petkov7476a262012-04-12 16:30:46 +020020#include "shill/mock_glib.h"
21#include "shill/mock_manager.h"
22#include "shill/mock_metrics.h"
mukesh agrawal9da07772013-05-15 14:15:17 -070023#include "shill/mock_ppp_device.h"
mukesh agrawal2e382632013-08-01 13:41:15 -070024#include "shill/mock_ppp_device_factory.h"
Darin Petkov7476a262012-04-12 16:30:46 +020025#include "shill/mock_vpn_service.h"
Alex Vakulenkoa41ab512014-07-23 14:24:23 -070026#include "shill/nice_mock_control.h"
Darin Petkov7476a262012-04-12 16:30:46 +020027
Albert Chaulk0e1cdea2013-02-27 15:32:55 -080028using base::FilePath;
Darin Petkovf7ef50a2012-04-16 20:54:31 +020029using std::find;
Darin Petkov209e6292012-04-20 11:33:32 +020030using std::map;
Darin Petkovf7ef50a2012-04-16 20:54:31 +020031using std::string;
32using std::vector;
33using testing::_;
34using testing::ElementsAreArray;
mukesh agrawalae30e9e2013-05-28 14:09:16 -070035using testing::Mock;
Darin Petkov0e9735d2012-04-24 12:33:45 +020036using testing::NiceMock;
Darin Petkovf7ef50a2012-04-16 20:54:31 +020037using testing::Return;
38using testing::ReturnRef;
Darin Petkov209e6292012-04-20 11:33:32 +020039using testing::SetArgumentPointee;
Darin Petkov0e9735d2012-04-24 12:33:45 +020040using testing::StrictMock;
Darin Petkovf7ef50a2012-04-16 20:54:31 +020041
Darin Petkov7476a262012-04-12 16:30:46 +020042namespace shill {
43
Darin Petkov209e6292012-04-20 11:33:32 +020044class L2TPIPSecDriverTest : public testing::Test,
45 public RPCTaskDelegate {
Darin Petkov7476a262012-04-12 16:30:46 +020046 public:
47 L2TPIPSecDriverTest()
Darin Petkov0e9735d2012-04-24 12:33:45 +020048 : device_info_(&control_, &dispatcher_, &metrics_, &manager_),
Thieu Le6c1e3bb2013-02-06 15:20:35 -080049 metrics_(&dispatcher_),
Darin Petkov0e9735d2012-04-24 12:33:45 +020050 manager_(&control_, &dispatcher_, &metrics_, &glib_),
Darin Petkovf8046b82012-04-24 16:29:23 +020051 driver_(new L2TPIPSecDriver(&control_, &dispatcher_, &metrics_,
52 &manager_, &device_info_, &glib_)),
Darin Petkov7476a262012-04-12 16:30:46 +020053 service_(new MockVPNService(&control_, &dispatcher_, &metrics_,
Darin Petkovf8046b82012-04-24 16:29:23 +020054 &manager_, driver_)),
mukesh agrawal9da07772013-05-15 14:15:17 -070055 device_(new MockPPPDevice(&control_, &dispatcher_, &metrics_, &manager_,
56 kInterfaceName, kInterfaceIndex)),
Paul Stewart5baebb72013-03-14 11:43:29 -070057 certificate_file_(new MockCertificateFile()),
mukesh agrawalae30e9e2013-05-28 14:09:16 -070058 weak_ptr_factory_(this) {
Paul Stewart5baebb72013-03-14 11:43:29 -070059 driver_->certificate_file_.reset(certificate_file_); // Passes ownership.
Darin Petkovf7ef50a2012-04-16 20:54:31 +020060 }
Darin Petkov7476a262012-04-12 16:30:46 +020061
62 virtual ~L2TPIPSecDriverTest() {}
63
Darin Petkovf7ef50a2012-04-16 20:54:31 +020064 virtual void SetUp() {
65 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
66 }
67
68 virtual void TearDown() {
Ben Chan4168b2c2014-09-30 13:16:07 -070069 driver_->device_ = nullptr;
70 driver_->service_ = nullptr;
Darin Petkovf7ef50a2012-04-16 20:54:31 +020071 ASSERT_TRUE(temp_dir_.Delete());
72 }
73
Darin Petkov7476a262012-04-12 16:30:46 +020074 protected:
Darin Petkovf8046b82012-04-24 16:29:23 +020075 static const char kInterfaceName[];
76 static const int kInterfaceIndex;
77
Darin Petkovf7ef50a2012-04-16 20:54:31 +020078 void SetArg(const string &arg, const string &value) {
Darin Petkov01c66042012-04-26 11:10:45 +020079 driver_->args()->SetString(arg, value);
Darin Petkovf7ef50a2012-04-16 20:54:31 +020080 }
81
Paul Stewarteb713e82013-06-28 14:51:54 -070082 void SetArgArray(const string &arg, const vector<string> &value) {
83 driver_->args()->SetStrings(arg, value);
84 }
85
Darin Petkovd4325392012-04-23 15:48:22 +020086 KeyValueStore *GetArgs() {
87 return driver_->args();
88 }
89
Darin Petkova42afe32013-02-05 16:53:52 +010090 string GetProviderType() {
91 return driver_->GetProviderType();
92 }
93
mukesh agrawal9da07772013-05-15 14:15:17 -070094 void SetDevice(const PPPDeviceRefPtr &device) {
Darin Petkov0cd0d1e2013-02-11 12:49:10 +010095 driver_->device_ = device;
96 }
97
Darin Petkova42afe32013-02-05 16:53:52 +010098 void SetService(const VPNServiceRefPtr &service) {
99 driver_->service_ = service;
100 }
101
102 VPNServiceRefPtr GetService() {
103 return driver_->service_;
104 }
105
106 void OnConnectTimeout() {
107 driver_->OnConnectTimeout();
108 }
109
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100110 void StartConnectTimeout(int timeout_seconds) {
111 driver_->StartConnectTimeout(timeout_seconds);
Darin Petkova42afe32013-02-05 16:53:52 +0100112 }
113
Paul Stewart3f713262013-12-24 20:12:53 -0800114 bool IsConnectTimeoutStarted() const {
Darin Petkova42afe32013-02-05 16:53:52 +0100115 return driver_->IsConnectTimeoutStarted();
116 }
117
Paul Stewart3f713262013-12-24 20:12:53 -0800118 bool IsPSKFileCleared(const FilePath &psk_file_path) const {
Ben Chana0ddf462014-02-06 11:32:42 -0800119 return !base::PathExists(psk_file_path) && GetPSKFile().empty();
mukesh agrawal2e382632013-08-01 13:41:15 -0700120 }
121
Paul Stewart3f713262013-12-24 20:12:53 -0800122 bool IsXauthCredentialsFileCleared(
123 const FilePath &xauth_credentials_file_path) const {
Ben Chana0ddf462014-02-06 11:32:42 -0800124 return !base::PathExists(xauth_credentials_file_path) &&
Paul Stewart3f713262013-12-24 20:12:53 -0800125 GetXauthCredentialsFile().empty();
126 }
127
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200128 // Used to assert that a flag appears in the options.
129 void ExpectInFlags(const vector<string> &options, const string &flag,
130 const string &value);
131
Darin Petkov0e9735d2012-04-24 12:33:45 +0200132 FilePath SetupPSKFile();
Paul Stewart3f713262013-12-24 20:12:53 -0800133 FilePath SetupXauthCredentialsFile();
Darin Petkov0e9735d2012-04-24 12:33:45 +0200134
Paul Stewart3f713262013-12-24 20:12:53 -0800135 FilePath GetPSKFile() const { return driver_->psk_file_; }
136 FilePath GetXauthCredentialsFile() const {
137 return driver_->xauth_credentials_file_;
138 }
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100139
140 void InvokeNotify(const string &reason, const map<string, string> &dict) {
141 driver_->Notify(reason, dict);
142 }
143
Paul Stewart3f713262013-12-24 20:12:53 -0800144 void FakeUpConnect(FilePath *psk_file, FilePath *xauth_credentials_file) {
145 *psk_file = SetupPSKFile();
146 *xauth_credentials_file = SetupXauthCredentialsFile();
mukesh agrawal2e382632013-08-01 13:41:15 -0700147 SetService(service_);
148 StartConnectTimeout(0);
mukesh agrawal2e382632013-08-01 13:41:15 -0700149 }
150
151 void ExpectDeviceConnected(const map<string, string> &ppp_config) {
152 EXPECT_CALL(*device_, SetEnabled(true));
153 EXPECT_CALL(*device_, SelectService(static_cast<ServiceRefPtr>(service_)));
154 EXPECT_CALL(*device_, UpdateIPConfigFromPPP(ppp_config, _));
155 }
156
157 void ExpectMetricsReported() {
158 Error unused_error;
159 PropertyStore store;
160 driver_->InitPropertyStore(&store);
Ben Chan73728782013-09-20 13:40:54 -0700161 store.SetStringProperty(kL2tpIpsecPskProperty, "x", &unused_error);
162 store.SetStringProperty(kL2tpIpsecPasswordProperty, "y", &unused_error);
mukesh agrawal2e382632013-08-01 13:41:15 -0700163 EXPECT_CALL(metrics_, SendEnumToUMA(
164 Metrics::kMetricVpnDriver,
165 Metrics::kVpnDriverL2tpIpsec,
166 Metrics::kMetricVpnDriverMax));
167 EXPECT_CALL(metrics_, SendEnumToUMA(
168 Metrics::kMetricVpnRemoteAuthenticationType,
169 Metrics::kVpnRemoteAuthenticationTypeL2tpIpsecPsk,
170 Metrics::kVpnRemoteAuthenticationTypeMax));
171 EXPECT_CALL(metrics_, SendEnumToUMA(
172 Metrics::kMetricVpnUserAuthenticationType,
173 Metrics::kVpnUserAuthenticationTypeL2tpIpsecUsernamePassword,
174 Metrics::kVpnUserAuthenticationTypeMax));
175 }
176
Darin Petkov209e6292012-04-20 11:33:32 +0200177 // Inherited from RPCTaskDelegate.
178 virtual void GetLogin(string *user, string *password);
179 virtual void Notify(const string &reason, const map<string, string> &dict);
180
Paul Stewart5ad16062013-02-21 18:10:48 -0800181 base::ScopedTempDir temp_dir_;
Darin Petkov7476a262012-04-12 16:30:46 +0200182 NiceMockControl control_;
Darin Petkov0e9735d2012-04-24 12:33:45 +0200183 NiceMock<MockDeviceInfo> device_info_;
Darin Petkov7476a262012-04-12 16:30:46 +0200184 EventDispatcher dispatcher_;
185 MockMetrics metrics_;
186 MockGLib glib_;
187 MockManager manager_;
188 L2TPIPSecDriver *driver_; // Owned by |service_|.
189 scoped_refptr<MockVPNService> service_;
mukesh agrawal9da07772013-05-15 14:15:17 -0700190 scoped_refptr<MockPPPDevice> device_;
Paul Stewart5baebb72013-03-14 11:43:29 -0700191 MockCertificateFile *certificate_file_; // Owned by |driver_|.
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700192 base::WeakPtrFactory<L2TPIPSecDriverTest> weak_ptr_factory_;
Darin Petkov7476a262012-04-12 16:30:46 +0200193};
194
Darin Petkovf8046b82012-04-24 16:29:23 +0200195const char L2TPIPSecDriverTest::kInterfaceName[] = "ppp0";
196const int L2TPIPSecDriverTest::kInterfaceIndex = 123;
197
Darin Petkov209e6292012-04-20 11:33:32 +0200198void L2TPIPSecDriverTest::GetLogin(string */*user*/, string */*password*/) {}
199
200void L2TPIPSecDriverTest::Notify(
201 const string &/*reason*/, const map<string, string> &/*dict*/) {}
202
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200203void L2TPIPSecDriverTest::ExpectInFlags(
204 const vector<string> &options, const string &flag, const string &value) {
Steve Fungfca1a042014-10-07 15:10:16 -0700205 string flagValue = base::StringPrintf("%s=%s", flag.c_str(), value.c_str());
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200206 vector<string>::const_iterator it =
Steve Fungfca1a042014-10-07 15:10:16 -0700207 find(options.begin(), options.end(), flagValue);
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200208
Steve Fungfca1a042014-10-07 15:10:16 -0700209 EXPECT_TRUE(it != options.end());
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200210}
211
Darin Petkov0e9735d2012-04-24 12:33:45 +0200212FilePath L2TPIPSecDriverTest::SetupPSKFile() {
213 FilePath psk_file;
Ben Chana0ddf462014-02-06 11:32:42 -0800214 EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &psk_file));
Darin Petkov0e9735d2012-04-24 12:33:45 +0200215 EXPECT_FALSE(psk_file.empty());
Ben Chana0ddf462014-02-06 11:32:42 -0800216 EXPECT_TRUE(base::PathExists(psk_file));
Darin Petkov0e9735d2012-04-24 12:33:45 +0200217 driver_->psk_file_ = psk_file;
218 return psk_file;
219}
220
Paul Stewart3f713262013-12-24 20:12:53 -0800221FilePath L2TPIPSecDriverTest::SetupXauthCredentialsFile() {
222 FilePath xauth_credentials_file;
Ben Chana0ddf462014-02-06 11:32:42 -0800223 EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(),
224 &xauth_credentials_file));
Paul Stewart3f713262013-12-24 20:12:53 -0800225 EXPECT_FALSE(xauth_credentials_file.empty());
Ben Chana0ddf462014-02-06 11:32:42 -0800226 EXPECT_TRUE(base::PathExists(xauth_credentials_file));
Paul Stewart3f713262013-12-24 20:12:53 -0800227 driver_->xauth_credentials_file_ = xauth_credentials_file;
228 return xauth_credentials_file;
229}
230
Darin Petkov7476a262012-04-12 16:30:46 +0200231TEST_F(L2TPIPSecDriverTest, GetProviderType) {
Ben Chan73728782013-09-20 13:40:54 -0700232 EXPECT_EQ(kProviderL2tpIpsec, GetProviderType());
Darin Petkov7476a262012-04-12 16:30:46 +0200233}
234
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200235TEST_F(L2TPIPSecDriverTest, Cleanup) {
Darin Petkov85d53172013-03-13 16:43:28 +0100236 driver_->IdleService(); // Ensure no crash.
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200237
Paul Stewart3f713262013-12-24 20:12:53 -0800238 FilePath psk_file;
239 FilePath xauth_credentials_file;
240 FakeUpConnect(&psk_file, &xauth_credentials_file);
Darin Petkova0e645e2012-04-25 11:38:59 +0200241 driver_->device_ = device_;
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700242 driver_->external_task_.reset(
243 new MockExternalTask(&control_,
244 &glib_,
245 weak_ptr_factory_.GetWeakPtr(),
246 base::Callback<void(pid_t, int)>()));
mukesh agrawal9da07772013-05-15 14:15:17 -0700247 EXPECT_CALL(*device_, DropConnection());
Darin Petkova0e645e2012-04-25 11:38:59 +0200248 EXPECT_CALL(*device_, SetEnabled(false));
Darin Petkov85d53172013-03-13 16:43:28 +0100249 EXPECT_CALL(*service_, SetFailure(Service::kFailureBadPassphrase));
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700250 driver_->FailService(Service::kFailureBadPassphrase); // Trigger Cleanup.
mukesh agrawal2e382632013-08-01 13:41:15 -0700251 EXPECT_TRUE(IsPSKFileCleared(psk_file));
Paul Stewart3f713262013-12-24 20:12:53 -0800252 EXPECT_TRUE(IsXauthCredentialsFileCleared(xauth_credentials_file));
Darin Petkova0e645e2012-04-25 11:38:59 +0200253 EXPECT_FALSE(driver_->device_);
Darin Petkov209e6292012-04-20 11:33:32 +0200254 EXPECT_FALSE(driver_->service_);
Darin Petkov602303f2012-06-06 12:15:59 +0200255 EXPECT_FALSE(driver_->IsConnectTimeoutStarted());
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700256 EXPECT_FALSE(driver_->external_task_);
Darin Petkov85d53172013-03-13 16:43:28 +0100257
258 driver_->service_ = service_;
259 EXPECT_CALL(*service_, SetState(Service::kStateIdle));
260 driver_->IdleService();
261 EXPECT_FALSE(driver_->service_);
Darin Petkov209e6292012-04-20 11:33:32 +0200262}
263
Paul Stewart3f713262013-12-24 20:12:53 -0800264TEST_F(L2TPIPSecDriverTest, DeleteTemporaryFiles) {
Darin Petkov0e9735d2012-04-24 12:33:45 +0200265 FilePath psk_file = SetupPSKFile();
Paul Stewart3f713262013-12-24 20:12:53 -0800266 FilePath xauth_credentials_file = SetupXauthCredentialsFile();
267 driver_->DeleteTemporaryFiles();
mukesh agrawal2e382632013-08-01 13:41:15 -0700268 EXPECT_TRUE(IsPSKFileCleared(psk_file));
Paul Stewart3f713262013-12-24 20:12:53 -0800269 EXPECT_TRUE(IsXauthCredentialsFileCleared(xauth_credentials_file));
Darin Petkov0e9735d2012-04-24 12:33:45 +0200270}
271
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200272TEST_F(L2TPIPSecDriverTest, InitOptionsNoHost) {
273 Error error;
274 vector<string> options;
Darin Petkov209e6292012-04-20 11:33:32 +0200275 EXPECT_FALSE(driver_->InitOptions(&options, &error));
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200276 EXPECT_EQ(Error::kInvalidArguments, error.type());
277 EXPECT_TRUE(options.empty());
278}
279
280TEST_F(L2TPIPSecDriverTest, InitOptions) {
281 static const char kHost[] = "192.168.2.254";
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200282 static const char kPSK[] = "foobar";
Paul Stewart3f713262013-12-24 20:12:53 -0800283 static const char kXauthUser[] = "silly";
284 static const char kXauthPassword[] = "rabbit";
Paul Stewartc350e682014-06-19 15:44:30 -0700285 const vector<string> kCaCertPEM{ "Insert PEM encoded data here" };
286 static const char kPEMCertfile[] = "/tmp/der-file-from-pem-cert";
287 FilePath pem_cert(kPEMCertfile);
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200288
Ben Chan73728782013-09-20 13:40:54 -0700289 SetArg(kProviderHostProperty, kHost);
Ben Chan73728782013-09-20 13:40:54 -0700290 SetArg(kL2tpIpsecPskProperty, kPSK);
Paul Stewart3f713262013-12-24 20:12:53 -0800291 SetArg(kL2tpIpsecXauthUserProperty, kXauthUser);
292 SetArg(kL2tpIpsecXauthPasswordProperty, kXauthPassword);
Paul Stewartc350e682014-06-19 15:44:30 -0700293 SetArgArray(kL2tpIpsecCaCertPemProperty, kCaCertPEM);
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200294
Paul Stewartc350e682014-06-19 15:44:30 -0700295 EXPECT_CALL(*certificate_file_, CreatePEMFromStrings(kCaCertPEM))
296 .WillOnce(Return(pem_cert));
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200297 const FilePath temp_dir(temp_dir_.path());
Paul Stewart3f713262013-12-24 20:12:53 -0800298 // Once each for PSK and Xauth options.
299 EXPECT_CALL(manager_, run_path())
300 .WillOnce(ReturnRef(temp_dir))
301 .WillOnce(ReturnRef(temp_dir));
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200302
303 Error error;
304 vector<string> options;
Darin Petkov209e6292012-04-20 11:33:32 +0200305 EXPECT_TRUE(driver_->InitOptions(&options, &error));
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200306 EXPECT_TRUE(error.IsSuccess());
307
308 ExpectInFlags(options, "--remote_host", kHost);
309 ASSERT_FALSE(driver_->psk_file_.empty());
310 ExpectInFlags(options, "--psk_file", driver_->psk_file_.value());
Paul Stewart3f713262013-12-24 20:12:53 -0800311 ASSERT_FALSE(driver_->xauth_credentials_file_.empty());
312 ExpectInFlags(options, "--xauth_credentials_file",
313 driver_->xauth_credentials_file_.value());
Paul Stewartc350e682014-06-19 15:44:30 -0700314 ExpectInFlags(options, "--server_ca_file", kPEMCertfile);
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200315}
316
317TEST_F(L2TPIPSecDriverTest, InitPSKOptions) {
318 Error error;
319 vector<string> options;
320 static const char kPSK[] = "foobar";
321 const FilePath bad_dir("/non/existent/directory");
322 const FilePath temp_dir(temp_dir_.path());
323 EXPECT_CALL(manager_, run_path())
324 .WillOnce(ReturnRef(bad_dir))
325 .WillOnce(ReturnRef(temp_dir));
326
327 EXPECT_TRUE(driver_->InitPSKOptions(&options, &error));
328 EXPECT_TRUE(options.empty());
329 EXPECT_TRUE(error.IsSuccess());
330
Ben Chan73728782013-09-20 13:40:54 -0700331 SetArg(kL2tpIpsecPskProperty, kPSK);
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200332
333 EXPECT_FALSE(driver_->InitPSKOptions(&options, &error));
334 EXPECT_TRUE(options.empty());
335 EXPECT_EQ(Error::kInternalError, error.type());
336 error.Reset();
337
338 EXPECT_TRUE(driver_->InitPSKOptions(&options, &error));
339 ASSERT_FALSE(driver_->psk_file_.empty());
340 ExpectInFlags(options, "--psk_file", driver_->psk_file_.value());
341 EXPECT_TRUE(error.IsSuccess());
342 string contents;
Ben Chana0ddf462014-02-06 11:32:42 -0800343 EXPECT_TRUE(base::ReadFileToString(driver_->psk_file_, &contents));
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200344 EXPECT_EQ(kPSK, contents);
345 struct stat buf;
346 ASSERT_EQ(0, stat(driver_->psk_file_.value().c_str(), &buf));
347 EXPECT_EQ(S_IFREG | S_IRUSR | S_IWUSR, buf.st_mode);
348}
349
Paul Stewart5baebb72013-03-14 11:43:29 -0700350TEST_F(L2TPIPSecDriverTest, InitPEMOptions) {
Paul Stewarteb713e82013-06-28 14:51:54 -0700351 const vector<string> kCaCertPEM{ "Insert PEM encoded data here" };
Paul Stewart5baebb72013-03-14 11:43:29 -0700352 static const char kPEMCertfile[] = "/tmp/der-file-from-pem-cert";
353 FilePath empty_cert;
354 FilePath pem_cert(kPEMCertfile);
Paul Stewarteb713e82013-06-28 14:51:54 -0700355 SetArgArray(kL2tpIpsecCaCertPemProperty, kCaCertPEM);
356 EXPECT_CALL(*certificate_file_, CreatePEMFromStrings(kCaCertPEM))
Paul Stewart5baebb72013-03-14 11:43:29 -0700357 .WillOnce(Return(empty_cert))
358 .WillOnce(Return(pem_cert));
359
360 vector<string> options;
361 driver_->InitPEMOptions(&options);
362 EXPECT_TRUE(options.empty());
363 driver_->InitPEMOptions(&options);
364 ExpectInFlags(options, "--server_ca_file", kPEMCertfile);
365}
366
Paul Stewart3f713262013-12-24 20:12:53 -0800367TEST_F(L2TPIPSecDriverTest, InitXauthOptions) {
368 vector<string> options;
369 EXPECT_CALL(manager_, run_path()).Times(0);
370 {
371 Error error;
372 EXPECT_TRUE(driver_->InitXauthOptions(&options, &error));
373 EXPECT_TRUE(error.IsSuccess());
374 }
375 EXPECT_TRUE(options.empty());
376
377 static const char kUser[] = "foobar";
378 SetArg(kL2tpIpsecXauthUserProperty, kUser);
379 {
380 Error error;
381 EXPECT_FALSE(driver_->InitXauthOptions(&options, &error));
382 EXPECT_EQ(Error::kInvalidArguments, error.type());
383 }
384 EXPECT_TRUE(options.empty());
385
386 static const char kPassword[] = "foobar";
387 SetArg(kL2tpIpsecXauthUserProperty, "");
388 SetArg(kL2tpIpsecXauthPasswordProperty, kPassword);
389 {
390 Error error;
391 EXPECT_FALSE(driver_->InitXauthOptions(&options, &error));
392 EXPECT_EQ(Error::kInvalidArguments, error.type());
393 }
394 EXPECT_TRUE(options.empty());
395 Mock::VerifyAndClearExpectations(&manager_);
396
397 SetArg(kL2tpIpsecXauthUserProperty, kUser);
398 const FilePath bad_dir("/non/existent/directory");
399 const FilePath temp_dir(temp_dir_.path());
400 EXPECT_CALL(manager_, run_path())
401 .WillOnce(ReturnRef(bad_dir))
402 .WillOnce(ReturnRef(temp_dir));
403
404 {
405 Error error;
406 EXPECT_FALSE(driver_->InitXauthOptions(&options, &error));
407 EXPECT_EQ(Error::kInternalError, error.type());
408 }
409 EXPECT_TRUE(options.empty());
410
411 {
412 Error error;
413 EXPECT_TRUE(driver_->InitXauthOptions(&options, &error));
414 EXPECT_TRUE(error.IsSuccess());
415 }
416 ASSERT_FALSE(driver_->xauth_credentials_file_.empty());
417 ExpectInFlags(options, "--xauth_credentials_file",
418 driver_->xauth_credentials_file_.value());
419 string contents;
420 EXPECT_TRUE(
Ben Chana0ddf462014-02-06 11:32:42 -0800421 base::ReadFileToString(driver_->xauth_credentials_file_, &contents));
Paul Stewart3f713262013-12-24 20:12:53 -0800422 string expected_contents(string(kUser) + "\n" + kPassword + "\n");
423 EXPECT_EQ(expected_contents, contents);
424 struct stat buf;
425 ASSERT_EQ(0, stat(driver_->xauth_credentials_file_.value().c_str(), &buf));
426 EXPECT_EQ(S_IFREG | S_IRUSR | S_IWUSR, buf.st_mode);
427}
428
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200429TEST_F(L2TPIPSecDriverTest, AppendValueOption) {
430 static const char kOption[] = "--l2tpipsec-option";
431 static const char kProperty[] = "L2TPIPSec.SomeProperty";
432 static const char kValue[] = "some-property-value";
433 static const char kOption2[] = "--l2tpipsec-option2";
434 static const char kProperty2[] = "L2TPIPSec.SomeProperty2";
435 static const char kValue2[] = "some-property-value2";
436
437 vector<string> options;
438 EXPECT_FALSE(
439 driver_->AppendValueOption(
440 "L2TPIPSec.UnknownProperty", kOption, &options));
441 EXPECT_TRUE(options.empty());
442
443 SetArg(kProperty, "");
444 EXPECT_FALSE(driver_->AppendValueOption(kProperty, kOption, &options));
445 EXPECT_TRUE(options.empty());
446
447 SetArg(kProperty, kValue);
448 SetArg(kProperty2, kValue2);
449 EXPECT_TRUE(driver_->AppendValueOption(kProperty, kOption, &options));
450 EXPECT_TRUE(driver_->AppendValueOption(kProperty2, kOption2, &options));
Steve Fungfca1a042014-10-07 15:10:16 -0700451 EXPECT_EQ(2, options.size());
452 EXPECT_EQ(base::StringPrintf("%s=%s", kOption, kValue), options[0]);
453 EXPECT_EQ(base::StringPrintf("%s=%s", kOption2, kValue2), options[1]);
Darin Petkovf7ef50a2012-04-16 20:54:31 +0200454}
455
456TEST_F(L2TPIPSecDriverTest, AppendFlag) {
457 static const char kTrueOption[] = "--l2tpipsec-option";
458 static const char kFalseOption[] = "--nol2tpipsec-option";
459 static const char kProperty[] = "L2TPIPSec.SomeProperty";
460 static const char kTrueOption2[] = "--l2tpipsec-option2";
461 static const char kFalseOption2[] = "--nol2tpipsec-option2";
462 static const char kProperty2[] = "L2TPIPSec.SomeProperty2";
463
464 vector<string> options;
465 EXPECT_FALSE(driver_->AppendFlag("L2TPIPSec.UnknownProperty",
466 kTrueOption, kFalseOption, &options));
467 EXPECT_TRUE(options.empty());
468
469 SetArg(kProperty, "");
470 EXPECT_FALSE(
471 driver_->AppendFlag(kProperty, kTrueOption, kFalseOption, &options));
472 EXPECT_TRUE(options.empty());
473
474 SetArg(kProperty, "true");
475 SetArg(kProperty2, "false");
476 EXPECT_TRUE(
477 driver_->AppendFlag(kProperty, kTrueOption, kFalseOption, &options));
478 EXPECT_TRUE(
479 driver_->AppendFlag(kProperty2, kTrueOption2, kFalseOption2, &options));
480 EXPECT_EQ(2, options.size());
481 EXPECT_EQ(kTrueOption, options[0]);
482 EXPECT_EQ(kFalseOption2, options[1]);
483}
484
Darin Petkov209e6292012-04-20 11:33:32 +0200485TEST_F(L2TPIPSecDriverTest, GetLogin) {
486 static const char kUser[] = "joesmith";
487 static const char kPassword[] = "random-password";
488 string user, password;
Ben Chan73728782013-09-20 13:40:54 -0700489 SetArg(kL2tpIpsecUserProperty, kUser);
Darin Petkov209e6292012-04-20 11:33:32 +0200490 driver_->GetLogin(&user, &password);
491 EXPECT_TRUE(user.empty());
492 EXPECT_TRUE(password.empty());
Ben Chan73728782013-09-20 13:40:54 -0700493 SetArg(kL2tpIpsecUserProperty, "");
494 SetArg(kL2tpIpsecPasswordProperty, kPassword);
Darin Petkov209e6292012-04-20 11:33:32 +0200495 driver_->GetLogin(&user, &password);
496 EXPECT_TRUE(user.empty());
497 EXPECT_TRUE(password.empty());
Ben Chan73728782013-09-20 13:40:54 -0700498 SetArg(kL2tpIpsecUserProperty, kUser);
Darin Petkov209e6292012-04-20 11:33:32 +0200499 driver_->GetLogin(&user, &password);
500 EXPECT_EQ(kUser, user);
501 EXPECT_EQ(kPassword, password);
502}
503
504TEST_F(L2TPIPSecDriverTest, OnL2TPIPSecVPNDied) {
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700505 const int kPID = 123456;
Darin Petkov85d53172013-03-13 16:43:28 +0100506 driver_->service_ = service_;
507 EXPECT_CALL(*service_, SetFailure(Service::kFailureDNSLookup));
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700508 driver_->OnL2TPIPSecVPNDied(
509 kPID, vpn_manager::kServiceErrorResolveHostnameFailed << 8);
Darin Petkov85d53172013-03-13 16:43:28 +0100510 EXPECT_FALSE(driver_->service_);
Darin Petkov209e6292012-04-20 11:33:32 +0200511}
512
Darin Petkov209e6292012-04-20 11:33:32 +0200513TEST_F(L2TPIPSecDriverTest, SpawnL2TPIPSecVPN) {
514 Error error;
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700515 // Fail without sufficient arguments.
Darin Petkov209e6292012-04-20 11:33:32 +0200516 EXPECT_FALSE(driver_->SpawnL2TPIPSecVPN(&error));
517 EXPECT_TRUE(error.IsFailure());
518
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700519 // Provide the required arguments.
Darin Petkov209e6292012-04-20 11:33:32 +0200520 static const char kHost[] = "192.168.2.254";
Ben Chan73728782013-09-20 13:40:54 -0700521 SetArg(kProviderHostProperty, kHost);
Darin Petkov209e6292012-04-20 11:33:32 +0200522
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700523 // TODO(quiche): Instead of setting expectations based on what
524 // ExternalTask will call, mock out ExternalTask. Non-trivial,
525 // though, because ExternalTask is constructed during the
526 // call to driver_->Connect.
527 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _)).
528 WillOnce(Return(false)).
529 WillOnce(Return(true));
530 EXPECT_CALL(glib_, ChildWatchAdd(_, _, _));
531
Darin Petkov209e6292012-04-20 11:33:32 +0200532 EXPECT_FALSE(driver_->SpawnL2TPIPSecVPN(&error));
mukesh agrawal2e382632013-08-01 13:41:15 -0700533 EXPECT_FALSE(driver_->external_task_);
Darin Petkov209e6292012-04-20 11:33:32 +0200534 EXPECT_TRUE(driver_->SpawnL2TPIPSecVPN(&error));
Ben Chand5dce942014-10-16 12:29:42 -0700535 EXPECT_NE(nullptr, driver_->external_task_);
Darin Petkov209e6292012-04-20 11:33:32 +0200536}
537
538TEST_F(L2TPIPSecDriverTest, Connect) {
539 EXPECT_CALL(*service_, SetState(Service::kStateConfiguring));
540 static const char kHost[] = "192.168.2.254";
Ben Chan73728782013-09-20 13:40:54 -0700541 SetArg(kProviderHostProperty, kHost);
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700542
543 // TODO(quiche): Instead of setting expectations based on what
544 // ExternalTask will call, mock out ExternalTask. Non-trivial,
545 // though, because ExternalTask is constructed during the
546 // call to driver_->Connect.
Darin Petkov68710d72013-02-13 14:22:56 +0100547 EXPECT_CALL(glib_, SpawnAsync(_, _, _, _, _, _, _, _)).WillOnce(Return(true));
Darin Petkov209e6292012-04-20 11:33:32 +0200548 EXPECT_CALL(glib_, ChildWatchAdd(_, _, _)).WillOnce(Return(1));
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700549
Darin Petkov209e6292012-04-20 11:33:32 +0200550 Error error;
551 driver_->Connect(service_, &error);
552 EXPECT_TRUE(error.IsSuccess());
Darin Petkov602303f2012-06-06 12:15:59 +0200553 EXPECT_TRUE(driver_->IsConnectTimeoutStarted());
Darin Petkov209e6292012-04-20 11:33:32 +0200554}
555
Darin Petkova0e645e2012-04-25 11:38:59 +0200556TEST_F(L2TPIPSecDriverTest, Disconnect) {
557 driver_->device_ = device_;
558 driver_->service_ = service_;
mukesh agrawal9da07772013-05-15 14:15:17 -0700559 EXPECT_CALL(*device_, DropConnection());
Darin Petkova0e645e2012-04-25 11:38:59 +0200560 EXPECT_CALL(*device_, SetEnabled(false));
561 EXPECT_CALL(*service_, SetState(Service::kStateIdle));
562 driver_->Disconnect();
563 EXPECT_FALSE(driver_->device_);
564 EXPECT_FALSE(driver_->service_);
565}
566
Darin Petkov5eb05422012-05-11 15:45:25 +0200567TEST_F(L2TPIPSecDriverTest, OnConnectionDisconnected) {
568 driver_->service_ = service_;
Darin Petkova42afe32013-02-05 16:53:52 +0100569 EXPECT_CALL(*service_, SetState(Service::kStateIdle));
Darin Petkov5eb05422012-05-11 15:45:25 +0200570 driver_->OnConnectionDisconnected();
571 EXPECT_FALSE(driver_->service_);
572}
573
Darin Petkova42afe32013-02-05 16:53:52 +0100574TEST_F(L2TPIPSecDriverTest, OnConnectTimeout) {
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100575 StartConnectTimeout(0);
Darin Petkova42afe32013-02-05 16:53:52 +0100576 SetService(service_);
Darin Petkov85d53172013-03-13 16:43:28 +0100577 EXPECT_CALL(*service_, SetFailure(Service::kFailureConnect));
Darin Petkova42afe32013-02-05 16:53:52 +0100578 OnConnectTimeout();
579 EXPECT_FALSE(GetService());
580 EXPECT_FALSE(IsConnectTimeoutStarted());
581}
582
Darin Petkovd4325392012-04-23 15:48:22 +0200583TEST_F(L2TPIPSecDriverTest, InitPropertyStore) {
584 // Sanity test property store initialization.
585 PropertyStore store;
586 driver_->InitPropertyStore(&store);
587 const string kUser = "joe";
588 Error error;
Ben Chan73728782013-09-20 13:40:54 -0700589 EXPECT_TRUE(store.SetStringProperty(kL2tpIpsecUserProperty, kUser, &error));
Darin Petkovd4325392012-04-23 15:48:22 +0200590 EXPECT_TRUE(error.IsSuccess());
Ben Chan73728782013-09-20 13:40:54 -0700591 EXPECT_EQ(kUser, GetArgs()->LookupString(kL2tpIpsecUserProperty, ""));
Darin Petkovb536a742012-04-26 11:31:28 +0200592}
593
594TEST_F(L2TPIPSecDriverTest, GetProvider) {
595 PropertyStore store;
596 driver_->InitPropertyStore(&store);
597 {
Darin Petkovb536a742012-04-26 11:31:28 +0200598 KeyValueStore props;
Paul Stewarte6e8e492013-01-17 11:00:50 -0800599 Error error;
Paul Stewartba8f1412013-09-30 17:52:03 -0700600 SetArg(kL2tpIpsecClientCertIdProperty, "");
Darin Petkov4682aa82012-05-31 16:24:11 +0200601 EXPECT_TRUE(
Ben Chan73728782013-09-20 13:40:54 -0700602 store.GetKeyValueStoreProperty(kProviderProperty, &props, &error));
603 EXPECT_TRUE(props.LookupBool(kPassphraseRequiredProperty, false));
604 EXPECT_TRUE(props.LookupBool(kL2tpIpsecPskRequiredProperty, false));
Darin Petkovb536a742012-04-26 11:31:28 +0200605 }
606 {
Darin Petkovb536a742012-04-26 11:31:28 +0200607 KeyValueStore props;
Paul Stewartba8f1412013-09-30 17:52:03 -0700608 Error error;
609 SetArg(kL2tpIpsecClientCertIdProperty, "some-cert-id");
610 EXPECT_TRUE(
611 store.GetKeyValueStoreProperty(kProviderProperty, &props, &error));
612 EXPECT_TRUE(props.LookupBool(kPassphraseRequiredProperty, false));
613 EXPECT_FALSE(props.LookupBool(kL2tpIpsecPskRequiredProperty, true));
614 SetArg(kL2tpIpsecClientCertIdProperty, "");
615 }
616 {
617 KeyValueStore props;
Ben Chan73728782013-09-20 13:40:54 -0700618 SetArg(kL2tpIpsecPasswordProperty, "random-password");
619 SetArg(kL2tpIpsecPskProperty, "random-psk");
Paul Stewarte6e8e492013-01-17 11:00:50 -0800620 Error error;
Darin Petkov4682aa82012-05-31 16:24:11 +0200621 EXPECT_TRUE(
Ben Chan73728782013-09-20 13:40:54 -0700622 store.GetKeyValueStoreProperty(kProviderProperty, &props, &error));
623 EXPECT_FALSE(props.LookupBool(kPassphraseRequiredProperty, true));
Darin Petkovb536a742012-04-26 11:31:28 +0200624 EXPECT_FALSE(
Ben Chan73728782013-09-20 13:40:54 -0700625 props.LookupBool(kL2tpIpsecPskRequiredProperty, true));
626 EXPECT_FALSE(props.ContainsString(kL2tpIpsecPasswordProperty));
Darin Petkovb536a742012-04-26 11:31:28 +0200627 }
Darin Petkovd4325392012-04-23 15:48:22 +0200628}
629
Darin Petkov0e9735d2012-04-24 12:33:45 +0200630namespace {
631MATCHER_P(IsIPAddress, address, "") {
632 IPAddress ip_address(IPAddress::kFamilyIPv4);
633 EXPECT_TRUE(ip_address.SetAddressFromString(address));
634 return ip_address.Equals(arg);
635}
636} // namespace
637
638TEST_F(L2TPIPSecDriverTest, Notify) {
mukesh agrawal2e382632013-08-01 13:41:15 -0700639 map<string, string> config{{kPPPInterfaceName, kInterfaceName}};
640 MockPPPDeviceFactory *mock_ppp_device_factory =
641 MockPPPDeviceFactory::GetInstance();
Paul Stewart3f713262013-12-24 20:12:53 -0800642 FilePath psk_file;
643 FilePath xauth_credentials_file;
644 FakeUpConnect(&psk_file, &xauth_credentials_file);
mukesh agrawal2e382632013-08-01 13:41:15 -0700645 driver_->ppp_device_factory_ = mock_ppp_device_factory;
Darin Petkovf8046b82012-04-24 16:29:23 +0200646 EXPECT_CALL(device_info_, GetIndex(kInterfaceName))
647 .WillOnce(Return(kInterfaceIndex));
mukesh agrawal2e382632013-08-01 13:41:15 -0700648 EXPECT_CALL(*mock_ppp_device_factory,
649 CreatePPPDevice(_, _, _, _, kInterfaceName, kInterfaceIndex))
650 .WillOnce(Return(device_));
Paul Stewart16de98c2013-08-12 15:21:06 -0700651
652 // Make sure that a notification of an intermediate state doesn't cause
653 // the driver to fail the connection.
654 ASSERT_TRUE(driver_->service_);
655 VPNServiceConstRefPtr service = driver_->service_;
656 InvokeNotify(kPPPReasonAuthenticating, config);
657 InvokeNotify(kPPPReasonAuthenticated, config);
658 EXPECT_TRUE(driver_->service_);
659 EXPECT_FALSE(service->IsFailed());
660
mukesh agrawal2e382632013-08-01 13:41:15 -0700661 ExpectDeviceConnected(config);
662 ExpectMetricsReported();
mukesh agrawal9da07772013-05-15 14:15:17 -0700663 InvokeNotify(kPPPReasonConnect, config);
mukesh agrawal2e382632013-08-01 13:41:15 -0700664 EXPECT_TRUE(IsPSKFileCleared(psk_file));
Paul Stewart3f713262013-12-24 20:12:53 -0800665 EXPECT_TRUE(IsXauthCredentialsFileCleared(xauth_credentials_file));
mukesh agrawal2e382632013-08-01 13:41:15 -0700666 EXPECT_FALSE(IsConnectTimeoutStarted());
667}
668
669
670TEST_F(L2TPIPSecDriverTest, NotifyWithExistingDevice) {
671 map<string, string> config{{kPPPInterfaceName, kInterfaceName}};
672 MockPPPDeviceFactory *mock_ppp_device_factory =
673 MockPPPDeviceFactory::GetInstance();
Paul Stewart3f713262013-12-24 20:12:53 -0800674 FilePath psk_file;
675 FilePath xauth_credentials_file;
676 FakeUpConnect(&psk_file, &xauth_credentials_file);
mukesh agrawal2e382632013-08-01 13:41:15 -0700677 driver_->ppp_device_factory_ = mock_ppp_device_factory;
678 SetDevice(device_);
679 EXPECT_CALL(device_info_, GetIndex(kInterfaceName))
680 .WillOnce(Return(kInterfaceIndex));
681 EXPECT_CALL(*mock_ppp_device_factory,
682 CreatePPPDevice(_, _, _, _, _, _)).Times(0);
683 ExpectDeviceConnected(config);
684 ExpectMetricsReported();
685 InvokeNotify(kPPPReasonConnect, config);
686 EXPECT_TRUE(IsPSKFileCleared(psk_file));
Paul Stewart3f713262013-12-24 20:12:53 -0800687 EXPECT_TRUE(IsXauthCredentialsFileCleared(xauth_credentials_file));
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100688 EXPECT_FALSE(IsConnectTimeoutStarted());
Darin Petkov0e9735d2012-04-24 12:33:45 +0200689}
690
Darin Petkov69990222012-11-14 09:25:25 +0100691TEST_F(L2TPIPSecDriverTest, NotifyDisconnected) {
Darin Petkova0e645e2012-04-25 11:38:59 +0200692 map<string, string> dict;
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700693 base::Callback<void(pid_t, int)> death_callback;
694 MockExternalTask *local_external_task =
695 new MockExternalTask(&control_, &glib_, weak_ptr_factory_.GetWeakPtr(),
696 death_callback);
Darin Petkova0e645e2012-04-25 11:38:59 +0200697 driver_->device_ = device_;
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700698 driver_->external_task_.reset(local_external_task); // passes ownership
mukesh agrawal9da07772013-05-15 14:15:17 -0700699 EXPECT_CALL(*device_, DropConnection());
Darin Petkov69990222012-11-14 09:25:25 +0100700 EXPECT_CALL(*device_, SetEnabled(false));
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700701 EXPECT_CALL(*local_external_task, OnDelete())
702 .Times(0); // Not until event loop.
mukesh agrawal9da07772013-05-15 14:15:17 -0700703 driver_->Notify(kPPPReasonDisconnect, dict);
Darin Petkov69990222012-11-14 09:25:25 +0100704 EXPECT_FALSE(driver_->device_);
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700705 EXPECT_FALSE(driver_->external_task_.get());
706 Mock::VerifyAndClearExpectations(local_external_task);
707
708 EXPECT_CALL(*local_external_task, OnDelete());
Ben Chana0ddf462014-02-06 11:32:42 -0800709 dispatcher_.PostTask(base::MessageLoop::QuitClosure());
Darin Petkov69990222012-11-14 09:25:25 +0100710 dispatcher_.DispatchForever();
Darin Petkova0e645e2012-04-25 11:38:59 +0200711}
712
Darin Petkov7476a262012-04-12 16:30:46 +0200713} // namespace shill