blob: 45d5ae845a6d67722e9479f96a07ffa1bb6c43a1 [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
Darin Petkova42afe32013-02-05 16:53:52 +01005#ifndef SHILL_OPENVPN_DRIVER_H_
6#define SHILL_OPENVPN_DRIVER_H_
Darin Petkov33af05c2012-02-28 10:10:30 +01007
Darin Petkov14c29ec2012-03-02 11:34:19 +01008#include <map>
Darin Petkovfe6a9372012-02-28 16:25:06 +01009#include <string>
10#include <vector>
11
Darin Petkov1fa81942012-04-02 11:38:08 +020012#include <base/file_path.h>
Darin Petkova9b1fed2012-02-29 11:49:05 +010013#include <base/memory/scoped_ptr.h>
Darin Petkovfe6a9372012-02-28 16:25:06 +010014#include <gtest/gtest_prod.h> // for FRIEND_TEST
15
Darin Petkov36a3ace2012-03-06 17:22:14 +010016#include "shill/glib.h"
Paul Stewarte93b0382012-04-24 13:11:28 -070017#include "shill/ipconfig.h"
Darin Petkovf20994f2012-03-05 16:12:19 +010018#include "shill/refptr_types.h"
Darin Petkov36a3ace2012-03-06 17:22:14 +010019#include "shill/rpc_task.h"
Darin Petkov3f9131c2012-03-20 11:37:32 +010020#include "shill/service.h"
Darin Petkov46463022012-03-29 14:57:32 +020021#include "shill/sockets.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010022#include "shill/vpn_driver.h"
23
Darin Petkov5a850472012-06-06 15:44:24 +020024namespace base {
25
26template<typename T>
27class WeakPtr;
28
29} // namespace base;
30
Darin Petkov33af05c2012-02-28 10:10:30 +010031namespace shill {
32
Paul Stewart5baebb72013-03-14 11:43:29 -070033class CertificateFile;
Darin Petkova9b1fed2012-02-29 11:49:05 +010034class ControlInterface;
Paul Stewartca6abd42012-03-01 15:45:29 -080035class DeviceInfo;
Darin Petkov33af05c2012-02-28 10:10:30 +010036class Error;
Darin Petkovf20994f2012-03-05 16:12:19 +010037class Metrics;
Darin Petkov3c5e4dc2012-04-02 14:44:27 +020038class NSS;
Darin Petkov46463022012-03-29 14:57:32 +020039class OpenVPNManagementServer;
Darin Petkov5a850472012-06-06 15:44:24 +020040class ProcessKiller;
Darin Petkov33af05c2012-02-28 10:10:30 +010041
Darin Petkov36a3ace2012-03-06 17:22:14 +010042class OpenVPNDriver : public VPNDriver,
43 public RPCTaskDelegate {
Darin Petkov33af05c2012-02-28 10:10:30 +010044 public:
Darin Petkov0cd0d1e2013-02-11 12:49:10 +010045 enum ReconnectReason {
46 kReconnectReasonUnknown,
47 kReconnectReasonOffline,
48 kReconnectReasonTLSError,
49 };
50
Paul Stewartca6abd42012-03-01 15:45:29 -080051 OpenVPNDriver(ControlInterface *control,
Darin Petkovf20994f2012-03-05 16:12:19 +010052 EventDispatcher *dispatcher,
53 Metrics *metrics,
54 Manager *manager,
Paul Stewartca6abd42012-03-01 15:45:29 -080055 DeviceInfo *device_info,
Paul Stewart451aa7f2012-04-11 19:07:58 -070056 GLib *glib);
Darin Petkov33af05c2012-02-28 10:10:30 +010057 virtual ~OpenVPNDriver();
58
Darin Petkov0cd0d1e2013-02-11 12:49:10 +010059 virtual void OnReconnecting(ReconnectReason reason);
Darin Petkov271fe522012-03-27 13:47:29 +020060
Darin Petkovaba89322013-03-11 14:48:22 +010061 // Resets the VPN state and deallocates all resources. If there's a service
62 // associated through Connect, sets its state to Service::kStateIdle and
63 // disassociates from the service.
64 virtual void IdleService();
Darin Petkov0440b9b2012-04-17 16:11:56 +020065
Darin Petkovaba89322013-03-11 14:48:22 +010066 // Resets the VPN state and deallocates all resources. If there's a service
67 // associated through Connect, sets its state to Service::kStateFailure, sets
Darin Petkov1c049c72013-03-21 13:15:45 +010068 // the failure reason to |failure|, sets its ErrorDetails property to
69 // |error_details|, and disassociates from the service.
70 virtual void FailService(Service::ConnectFailure failure,
71 const std::string &error_details);
Darin Petkovaba89322013-03-11 14:48:22 +010072
Paul Stewart406c4732013-08-01 09:30:12 -070073 // Append zero-valued, single-valued and double-valued options to the
74 // |options| array.
75 static void AppendOption(
76 const std::string &option,
77 std::vector<std::vector<std::string>> *options);
78 static void AppendOption(
79 const std::string &option,
80 const std::string &value,
81 std::vector<std::vector<std::string>> *options);
82 static void AppendOption(
83 const std::string &option,
84 const std::string &value0,
85 const std::string &value1,
86 std::vector<std::vector<std::string>> *options);
87
Darin Petkovaba89322013-03-11 14:48:22 +010088 // Returns true if an option was appended.
Darin Petkov46463022012-03-29 14:57:32 +020089 bool AppendValueOption(const std::string &property,
90 const std::string &option,
Paul Stewart406c4732013-08-01 09:30:12 -070091 std::vector<std::vector<std::string>> *options);
Darin Petkov46463022012-03-29 14:57:32 +020092
93 // Returns true if a flag was appended.
94 bool AppendFlag(const std::string &property,
95 const std::string &option,
Paul Stewart406c4732013-08-01 09:30:12 -070096 std::vector<std::vector<std::string>> *options);
Darin Petkov46463022012-03-29 14:57:32 +020097
Darin Petkova42afe32013-02-05 16:53:52 +010098 protected:
99 // Inherited from VPNDriver. |Connect| initiates the VPN connection by
100 // creating a tunnel device. When the device index becomes available, this
101 // instance is notified through |ClaimInterface| and resumes the connection
102 // process by setting up and spawning an external 'openvpn' process. IP
103 // configuration settings are passed back from the external process through
104 // the |Notify| RPC service method.
105 virtual void Connect(const VPNServiceRefPtr &service, Error *error);
106 virtual bool ClaimInterface(const std::string &link_name,
107 int interface_index);
108 virtual void Disconnect();
109 virtual std::string GetProviderType() const;
110 virtual void OnConnectionDisconnected();
111 virtual void OnConnectTimeout();
112
Darin Petkov33af05c2012-02-28 10:10:30 +0100113 private:
Darin Petkovfe6a9372012-02-28 16:25:06 +0100114 friend class OpenVPNDriverTest;
Paul Stewartca6abd42012-03-01 15:45:29 -0800115 FRIEND_TEST(OpenVPNDriverTest, ClaimInterface);
Darin Petkov36a3ace2012-03-06 17:22:14 +0100116 FRIEND_TEST(OpenVPNDriverTest, Cleanup);
Darin Petkovf20994f2012-03-05 16:12:19 +0100117 FRIEND_TEST(OpenVPNDriverTest, Connect);
Darin Petkov79d74c92012-03-07 17:20:32 +0100118 FRIEND_TEST(OpenVPNDriverTest, ConnectTunnelFailure);
Darin Petkov5a850472012-06-06 15:44:24 +0200119 FRIEND_TEST(OpenVPNDriverTest, DeleteInterface);
Darin Petkov6aa21872012-03-09 16:10:19 +0100120 FRIEND_TEST(OpenVPNDriverTest, Disconnect);
Darin Petkov60596742012-03-05 12:17:17 +0100121 FRIEND_TEST(OpenVPNDriverTest, GetRouteOptionEntry);
Darin Petkovca8a0e62012-09-26 13:16:52 +0200122 FRIEND_TEST(OpenVPNDriverTest, InitCAOptions);
Paul Stewart8343c0b2013-09-30 11:58:54 -0700123 FRIEND_TEST(OpenVPNDriverTest, InitCertificateVerifyOptions);
Darin Petkov4e1b3f82012-09-27 13:22:37 +0200124 FRIEND_TEST(OpenVPNDriverTest, InitClientAuthOptions);
Darin Petkov1a462de2012-05-02 11:10:48 +0200125 FRIEND_TEST(OpenVPNDriverTest, InitEnvironment);
Paul Stewart8343c0b2013-09-30 11:58:54 -0700126 FRIEND_TEST(OpenVPNDriverTest, InitExtraCertOptions);
Darin Petkov55771b72012-04-25 09:25:19 +0200127 FRIEND_TEST(OpenVPNDriverTest, InitLoggingOptions);
Darin Petkovfe6a9372012-02-28 16:25:06 +0100128 FRIEND_TEST(OpenVPNDriverTest, InitOptions);
Darin Petkov4b944842012-09-21 10:48:48 +0200129 FRIEND_TEST(OpenVPNDriverTest, InitOptionsHostWithPort);
Darin Petkovfe6a9372012-02-28 16:25:06 +0100130 FRIEND_TEST(OpenVPNDriverTest, InitOptionsNoHost);
Darin Petkove0d5dd12012-04-04 16:10:48 +0200131 FRIEND_TEST(OpenVPNDriverTest, InitPKCS11Options);
Darin Petkov36a3ace2012-03-06 17:22:14 +0100132 FRIEND_TEST(OpenVPNDriverTest, Notify);
Paul Stewart91a43cb2013-03-02 21:34:15 -0800133 FRIEND_TEST(OpenVPNDriverTest, NotifyUMA);
Darin Petkov79d74c92012-03-07 17:20:32 +0100134 FRIEND_TEST(OpenVPNDriverTest, NotifyFail);
Darin Petkova5e07ef2012-07-09 14:27:57 +0200135 FRIEND_TEST(OpenVPNDriverTest, OnDefaultServiceChanged);
Darin Petkov36a3ace2012-03-06 17:22:14 +0100136 FRIEND_TEST(OpenVPNDriverTest, OnOpenVPNDied);
Darin Petkov14c29ec2012-03-02 11:34:19 +0100137 FRIEND_TEST(OpenVPNDriverTest, ParseForeignOption);
138 FRIEND_TEST(OpenVPNDriverTest, ParseForeignOptions);
139 FRIEND_TEST(OpenVPNDriverTest, ParseIPConfiguration);
Darin Petkov1a462de2012-05-02 11:10:48 +0200140 FRIEND_TEST(OpenVPNDriverTest, ParseLSBRelease);
Darin Petkov60596742012-03-05 12:17:17 +0100141 FRIEND_TEST(OpenVPNDriverTest, ParseRouteOption);
142 FRIEND_TEST(OpenVPNDriverTest, SetRoutes);
Darin Petkov36a3ace2012-03-06 17:22:14 +0100143 FRIEND_TEST(OpenVPNDriverTest, SpawnOpenVPN);
Darin Petkov4b944842012-09-21 10:48:48 +0200144 FRIEND_TEST(OpenVPNDriverTest, SplitPortFromHost);
Paul Stewartb26347a2013-08-02 12:12:09 -0700145 FRIEND_TEST(OpenVPNDriverTest, WriteConfigFile);
Paul Stewart291a4732012-03-14 19:19:02 -0700146
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100147 // The map is a sorted container that allows us to iterate through the options
148 // in order.
149 typedef std::map<int, std::string> ForeignOptions;
150 typedef std::map<int, IPConfig::Route> RouteOptions;
151
Darin Petkovc418b4b2012-10-05 11:42:52 +0200152 static const char kDefaultCACertificates[];
Darin Petkovca8a0e62012-09-26 13:16:52 +0200153
Paul Stewart291a4732012-03-14 19:19:02 -0700154 static const char kOpenVPNPath[];
155 static const char kOpenVPNScript[];
Paul Stewartebd38562012-03-23 13:06:40 -0700156 static const Property kProperties[];
Darin Petkov14c29ec2012-03-02 11:34:19 +0100157
Darin Petkov1a462de2012-05-02 11:10:48 +0200158 static const char kLSBReleaseFile[];
159 static const char kChromeOSReleaseName[];
160 static const char kChromeOSReleaseVersion[];
161
Paul Stewartb26347a2013-08-02 12:12:09 -0700162 static const char kDefaultOpenVPNConfigurationDirectory[];
163
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100164 static const int kReconnectOfflineTimeoutSeconds;
165 static const int kReconnectTLSErrorTimeoutSeconds;
Darin Petkov14c29ec2012-03-02 11:34:19 +0100166
167 static void ParseIPConfiguration(
168 const std::map<std::string, std::string> &configuration,
169 IPConfig::Properties *properties);
170 static void ParseForeignOptions(const ForeignOptions &options,
171 IPConfig::Properties *properties);
172 static void ParseForeignOption(const std::string &option,
Darin Petkove8587e32012-07-02 13:56:07 +0200173 std::vector<std::string> *domain_search,
174 std::vector<std::string> *dns_servers);
Darin Petkov60596742012-03-05 12:17:17 +0100175 static IPConfig::Route *GetRouteOptionEntry(const std::string &prefix,
176 const std::string &key,
177 RouteOptions *routes);
178 static void ParseRouteOption(const std::string &key,
179 const std::string &value,
180 RouteOptions *routes);
181 static void SetRoutes(const RouteOptions &routes,
182 IPConfig::Properties *properties);
Darin Petkovfe6a9372012-02-28 16:25:06 +0100183
Darin Petkov4b944842012-09-21 10:48:48 +0200184 // If |host| is in the "name:port" format, sets up |name| and |port|
185 // appropriately and returns true. Otherwise, returns false.
186 static bool SplitPortFromHost(const std::string &host,
187 std::string *name,
188 std::string *port);
189
Paul Stewart406c4732013-08-01 09:30:12 -0700190 void InitOptions(
191 std::vector<std::vector<std::string>> *options, Error *error);
192 bool InitCAOptions(
193 std::vector<std::vector<std::string>> *options, Error *error);
Paul Stewart8343c0b2013-09-30 11:58:54 -0700194 void InitCertificateVerifyOptions(
195 std::vector<std::vector<std::string>> *options);
Paul Stewart406c4732013-08-01 09:30:12 -0700196 void InitClientAuthOptions(std::vector<std::vector<std::string>> *options);
Paul Stewart8343c0b2013-09-30 11:58:54 -0700197 bool InitExtraCertOptions(
198 std::vector<std::vector<std::string>> *options, Error *error);
Paul Stewart406c4732013-08-01 09:30:12 -0700199 void InitPKCS11Options(std::vector<std::vector<std::string>> *options);
Darin Petkove0d5dd12012-04-04 16:10:48 +0200200 bool InitManagementChannelOptions(
Paul Stewart406c4732013-08-01 09:30:12 -0700201 std::vector<std::vector<std::string>> *options, Error *error);
202 void InitLoggingOptions(std::vector<std::vector<std::string>> *options);
Darin Petkovfe6a9372012-02-28 16:25:06 +0100203
Darin Petkov1a462de2012-05-02 11:10:48 +0200204 void InitEnvironment(std::vector<std::string> *environment);
205 bool ParseLSBRelease(std::map<std::string, std::string> *lsb_release);
206
Darin Petkov36a3ace2012-03-06 17:22:14 +0100207 bool SpawnOpenVPN();
Darin Petkov36a3ace2012-03-06 17:22:14 +0100208
Darin Petkovaba89322013-03-11 14:48:22 +0100209 // Implements the public IdleService and FailService methods. Resets the VPN
210 // state and deallocates all resources. If there's a service associated
Darin Petkov1c049c72013-03-21 13:15:45 +0100211 // through Connect, sets its state |state|; if |state| is
212 // Service::kStateFailure, sets the failure reason to |failure| and its
213 // ErrorDetails property to |error_details|; disassociates from the service.
214 void Cleanup(Service::ConnectState state,
215 Service::ConnectFailure failure,
216 const std::string &error_details);
Darin Petkovaba89322013-03-11 14:48:22 +0100217
Darin Petkov0cd0d1e2013-02-11 12:49:10 +0100218 static int GetReconnectTimeoutSeconds(ReconnectReason reason);
219
Paul Stewart406c4732013-08-01 09:30:12 -0700220 // Join a list of options into a single string.
221 static std::string JoinOptions(
Paul Stewartb26347a2013-08-02 12:12:09 -0700222 const std::vector<std::vector<std::string>> &options, char separator);
223
224 // Output an OpenVPN configuration.
225 bool WriteConfigFile(const std::vector<std::vector<std::string>> &options,
226 base::FilePath *config_file);
Paul Stewart406c4732013-08-01 09:30:12 -0700227
Darin Petkov36a3ace2012-03-06 17:22:14 +0100228 // Called when the openpvn process exits.
229 static void OnOpenVPNDied(GPid pid, gint status, gpointer data);
230
Darin Petkov5a850472012-06-06 15:44:24 +0200231 // Standalone callback used to delete the tunnel interface when the openvpn
232 // process dies.
Darin Petkov5dbd2612012-06-07 16:22:16 +0200233 static void DeleteInterface(const base::WeakPtr<DeviceInfo> &device_info,
Darin Petkov5a850472012-06-06 15:44:24 +0200234 int interface_index);
235
Darin Petkovb536a742012-04-26 11:31:28 +0200236 // Inherit from VPNDriver to add custom properties.
237 virtual KeyValueStore GetProvider(Error *error);
238
Darin Petkov36a3ace2012-03-06 17:22:14 +0100239 // Implements RPCTaskDelegate.
Darin Petkov209e6292012-04-20 11:33:32 +0200240 virtual void GetLogin(std::string *user, std::string *password);
Darin Petkov36a3ace2012-03-06 17:22:14 +0100241 virtual void Notify(const std::string &reason,
242 const std::map<std::string, std::string> &dict);
243
Darin Petkova5e07ef2012-07-09 14:27:57 +0200244 void OnDefaultServiceChanged(const ServiceRefPtr &service);
245
Paul Stewart91a43cb2013-03-02 21:34:15 -0800246 void ReportConnectionMetrics();
247
Darin Petkova9b1fed2012-02-29 11:49:05 +0100248 ControlInterface *control_;
Darin Petkovf20994f2012-03-05 16:12:19 +0100249 Metrics *metrics_;
Paul Stewartca6abd42012-03-01 15:45:29 -0800250 DeviceInfo *device_info_;
Darin Petkov36a3ace2012-03-06 17:22:14 +0100251 GLib *glib_;
Darin Petkov46463022012-03-29 14:57:32 +0200252 Sockets sockets_;
253 scoped_ptr<OpenVPNManagementServer> management_server_;
Darin Petkov3c5e4dc2012-04-02 14:44:27 +0200254 NSS *nss_;
Paul Stewart5baebb72013-03-14 11:43:29 -0700255 scoped_ptr<CertificateFile> certificate_file_;
Paul Stewart8343c0b2013-09-30 11:58:54 -0700256 scoped_ptr<CertificateFile> extra_certificates_file_;
Darin Petkov5a850472012-06-06 15:44:24 +0200257 ProcessKiller *process_killer_;
Albert Chaulk0e1cdea2013-02-27 15:32:55 -0800258 base::FilePath lsb_release_file_;
Darin Petkov79d74c92012-03-07 17:20:32 +0100259
260 VPNServiceRefPtr service_;
Darin Petkova9b1fed2012-02-29 11:49:05 +0100261 scoped_ptr<RPCTask> rpc_task_;
Paul Stewartca6abd42012-03-01 15:45:29 -0800262 std::string tunnel_interface_;
mukesh agrawal9da07772013-05-15 14:15:17 -0700263 VirtualDeviceRefPtr device_;
Albert Chaulk0e1cdea2013-02-27 15:32:55 -0800264 base::FilePath tls_auth_file_;
Paul Stewartb26347a2013-08-02 12:12:09 -0700265 base::FilePath openvpn_config_directory_;
266 base::FilePath openvpn_config_file_;
Darin Petkov3189a472012-10-05 09:55:33 +0200267 IPConfig::Properties ip_properties_;
Darin Petkovfe6a9372012-02-28 16:25:06 +0100268
Darin Petkov36a3ace2012-03-06 17:22:14 +0100269 // The PID of the spawned openvpn process. May be 0 if no process has been
270 // spawned yet or the process has died.
271 int pid_;
272
273 // Child exit watch callback source tag.
274 unsigned int child_watch_tag_;
275
Darin Petkova5e07ef2012-07-09 14:27:57 +0200276 // Default service watch callback tag.
277 int default_service_callback_tag_;
278
Darin Petkov33af05c2012-02-28 10:10:30 +0100279 DISALLOW_COPY_AND_ASSIGN(OpenVPNDriver);
280};
281
282} // namespace shill
283
Darin Petkova42afe32013-02-05 16:53:52 +0100284#endif // SHILL_OPENVPN_DRIVER_H_