OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 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 "vpn-manager/l2tp_manager.h" |
| 6 |
| 7 #include "base/file_util.h" |
| 8 #include "base/logging.h" |
| 9 #include "base/string_util.h" |
| 10 #include "chromeos/process.h" |
| 11 #include "gflags/gflags.h" |
| 12 |
| 13 #pragma GCC diagnostic ignored "-Wstrict-aliasing" |
| 14 DEFINE_bool(require_chap, true, "require chap"); |
| 15 DEFINE_bool(refuse_pap, true, "refuse chap"); |
| 16 DEFINE_bool(require_authentication, true, "require authentication"); |
| 17 DEFINE_bool(ppp_debug, true, "ppp debug"); |
| 18 DEFINE_bool(length_bit, true, "length bit"); |
| 19 DEFINE_int32(ppp_setup_timeout, 10, "timeout to setup ppp (seconds)"); |
| 20 DEFINE_string(pppd_plugin, "", "pppd plugin"); |
| 21 DEFINE_string(user, "", "user name"); |
| 22 DEFINE_string(password, "", "password"); |
| 23 #pragma GCC diagnostic error "-Wstrict-aliasing" |
| 24 |
| 25 const char kL2tpConnectionName[] = "managed"; |
| 26 const char kPppInterfacePath[] = "/sys/class/net/ppp0"; |
| 27 |
| 28 using ::chromeos::ProcessImpl; |
| 29 |
| 30 L2tpManager::L2tpManager() |
| 31 : ServiceManager("l2tp"), |
| 32 was_initiated_(false), |
| 33 output_fd_(-1), |
| 34 ppp_interface_path_(kPppInterfacePath), |
| 35 l2tpd_(new ProcessImpl) { |
| 36 } |
| 37 |
| 38 bool L2tpManager::Initialize(const std::string& remote_address) { |
| 39 remote_address_ = remote_address; |
| 40 if (FLAGS_user.empty()) { |
| 41 LOG(ERROR) << "l2tp layer requires user name"; |
| 42 return false; |
| 43 } |
| 44 if (!FLAGS_pppd_plugin.empty() && |
| 45 !file_util::PathExists(FilePath(FLAGS_pppd_plugin))) { |
| 46 LOG(WARNING) << "pppd_plugin (" << FLAGS_pppd_plugin << ") does not exist"; |
| 47 } |
| 48 if (!FLAGS_password.empty()) { |
| 49 LOG(WARNING) << "Passing a password on the command-line is insecure"; |
| 50 } |
| 51 return true; |
| 52 } |
| 53 |
| 54 static void AddString(std::string* config, const char* key, |
| 55 const std::string& value) { |
| 56 config->append(StringPrintf("%s = %s\n", key, value.c_str())); |
| 57 } |
| 58 |
| 59 static void AddBool(std::string* config, const char* key, bool value) { |
| 60 config->append(StringPrintf("%s = %s\n", key, value ? "yes" : "no")); |
| 61 } |
| 62 |
| 63 std::string L2tpManager::FormatL2tpdConfiguration( |
| 64 const std::string& ppp_config_path) { |
| 65 std::string l2tpd_config; |
| 66 l2tpd_config.append(StringPrintf("[lac %s]\n", kL2tpConnectionName)); |
| 67 AddString(&l2tpd_config, "lns", remote_address_); |
| 68 AddBool(&l2tpd_config, "require chap", FLAGS_require_chap); |
| 69 AddBool(&l2tpd_config, "refuse pap", FLAGS_refuse_pap); |
| 70 AddBool(&l2tpd_config, "require authentication", |
| 71 FLAGS_require_authentication); |
| 72 AddString(&l2tpd_config, "name", FLAGS_user); |
| 73 AddBool(&l2tpd_config, "ppp debug", FLAGS_ppp_debug); |
| 74 AddString(&l2tpd_config, "pppoptfile", ppp_config_path); |
| 75 AddBool(&l2tpd_config, "length bit", FLAGS_length_bit); |
| 76 return l2tpd_config; |
| 77 } |
| 78 |
| 79 std::string L2tpManager::FormatPppdConfiguration() { |
| 80 std::string pppd_config = StringPrintf( |
| 81 "ipcp-accept-local\n" |
| 82 "ipcp-accept-remote\n" |
| 83 "refuse-eap\n" |
| 84 "noccp\n" |
| 85 "noauth\n" |
| 86 "crtscts\n" |
| 87 "idle 1800\n" |
| 88 "mtu 1410\n" |
| 89 "mru 1410\n" |
| 90 "nodefaultroute\n" |
| 91 "debug\n" |
| 92 "lock\n" |
| 93 "connect-delay 5000\n"); |
| 94 if (!FLAGS_pppd_plugin.empty()) { |
| 95 DLOG(INFO) << "Using pppd plugin " << FLAGS_pppd_plugin; |
| 96 pppd_config.append(StringPrintf("plugin %s\n", FLAGS_pppd_plugin.c_str())); |
| 97 } |
| 98 return pppd_config; |
| 99 } |
| 100 |
| 101 bool L2tpManager::Initiate() { |
| 102 std::string control_string; |
| 103 control_string = StringPrintf("c %s", kL2tpConnectionName); |
| 104 if (FLAGS_pppd_plugin.empty()) { |
| 105 control_string.append(StringPrintf(" %s %s\n", |
| 106 FLAGS_user.c_str(), |
| 107 FLAGS_password.c_str())); |
| 108 } else { |
| 109 // otherwise the plugin must specify username and password. |
| 110 control_string.append("\n"); |
| 111 } |
| 112 if (!file_util::WriteFile(l2tpd_control_path_, control_string.c_str(), |
| 113 control_string.size())) { |
| 114 return false; |
| 115 } |
| 116 was_initiated_ = true; |
| 117 return true; |
| 118 } |
| 119 |
| 120 bool L2tpManager::Terminate() { |
| 121 std::string control_string = StringPrintf("d %s\n", |
| 122 kL2tpConnectionName); |
| 123 if (!file_util::WriteFile(l2tpd_control_path_, control_string.c_str(), |
| 124 control_string.size())) { |
| 125 return false; |
| 126 } |
| 127 return true; |
| 128 } |
| 129 |
| 130 bool L2tpManager::Start() { |
| 131 FilePath pppd_config_path = temp_path()->Append("pppd.conf"); |
| 132 std::string l2tpd_config = FormatL2tpdConfiguration(pppd_config_path.value()); |
| 133 FilePath l2tpd_config_path = temp_path()->Append("l2tpd.conf"); |
| 134 if (!file_util::WriteFile(l2tpd_config_path, l2tpd_config.c_str(), |
| 135 l2tpd_config.size())) { |
| 136 LOG(ERROR) << "Unable to write l2tpd config to " |
| 137 << l2tpd_config_path.value(); |
| 138 return false; |
| 139 } |
| 140 std::string pppd_config = FormatPppdConfiguration(); |
| 141 if (!file_util::WriteFile(pppd_config_path, pppd_config.c_str(), |
| 142 pppd_config.size())) { |
| 143 LOG(ERROR) << "Unable to write pppd config to " << pppd_config_path.value(); |
| 144 return false; |
| 145 } |
| 146 l2tpd_control_path_ = temp_path()->Append("l2tpd.control"); |
| 147 file_util::Delete(l2tpd_control_path_, false); |
| 148 |
| 149 l2tpd_->Reset(0); |
| 150 l2tpd_->AddArg(L2TPD); |
| 151 l2tpd_->AddStringOption("-c", l2tpd_config_path.value()); |
| 152 l2tpd_->AddStringOption("-C", l2tpd_control_path_.value()); |
| 153 l2tpd_->AddArg("-D"); |
| 154 l2tpd_->RedirectUsingPipe(STDERR_FILENO, false); |
| 155 l2tpd_->Start(); |
| 156 output_fd_ = l2tpd_->GetPipe(STDERR_FILENO); |
| 157 start_ticks_ = base::TimeTicks::Now(); |
| 158 return true; |
| 159 } |
| 160 |
| 161 int L2tpManager::Poll() { |
| 162 if (is_running()) return -1; |
| 163 if (start_ticks_.is_null()) return -1; |
| 164 if (!was_initiated_ && file_util::PathExists(l2tpd_control_path_)) { |
| 165 if (!Initiate()) { |
| 166 LOG(ERROR) << "Unable to initiate connection"; |
| 167 Terminate(); |
| 168 OnStopped(false); |
| 169 return -1; |
| 170 } |
| 171 // With the connection initated, check if it's up in 1s. |
| 172 return 1000; |
| 173 } |
| 174 if (was_initiated_ && file_util::PathExists(FilePath(ppp_interface_path_))) { |
| 175 LOG(INFO) << "L2TP connection now up"; |
| 176 OnStarted(); |
| 177 return -1; |
| 178 } |
| 179 // Check for the ppp setup timeout. This includes the time |
| 180 // to start pppd, it to set up its control file, l2tp connection |
| 181 // setup, ppp connection setup. Authentication happens after |
| 182 // the ppp device is created. |
| 183 if (base::TimeTicks::Now() - start_ticks_ > |
| 184 base::TimeDelta::FromSeconds(FLAGS_ppp_setup_timeout)) { |
| 185 LOG(ERROR) << "PPP setup timed out"; |
| 186 // Cleanly terminate if the control file exists. |
| 187 if (was_initiated_) Terminate(); |
| 188 OnStopped(false); |
| 189 // Poll in 1 second in order to check if clean shutdown worked. |
| 190 } |
| 191 return 1000; |
| 192 } |
| 193 |
| 194 void L2tpManager::ProcessOutput() { |
| 195 ServiceManager::WriteFdToSyslog(output_fd_, "", &partial_output_line_); |
| 196 } |
| 197 |
| 198 bool L2tpManager::IsChild(pid_t pid) { |
| 199 return pid == l2tpd_->pid(); |
| 200 } |
| 201 |
| 202 void L2tpManager::Stop() { |
| 203 if (l2tpd_->pid()) { |
| 204 LOG(INFO) << "Shutting down L2TP"; |
| 205 Terminate(); |
| 206 } |
| 207 OnStopped(false); |
| 208 } |
OLD | NEW |