blob: 68ea8812981597f878e1d1c248459b4d1b266519 [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <poll.h>
#include <signal.h>
#include <stddef.h>
#include <sys/wait.h>
#include <string>
#include <base/command_line.h>
#include <base/files/scoped_temp_dir.h>
#include <base/logging.h>
#include <chromeos/flag_helper.h>
#include <chromeos/process.h>
#include <chromeos/syslog_logging.h>
#include "vpn-manager/daemon.h"
#include "vpn-manager/ipsec_manager.h"
#include "vpn-manager/l2tp_manager.h"
using vpn_manager::IpsecManager;
using vpn_manager::L2tpManager;
using vpn_manager::ServiceManager;
// True if a signal has requested termination.
static bool s_terminate_request = false;
void HandleSignal(int sig_num) {
LOG(INFO) << "Caught signal " << sig_num;
switch (sig_num) {
case SIGTERM:
case SIGINT:
s_terminate_request = true;
break;
case SIGALRM:
break;
}
}
static void InstallSignalHandlers() {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = HandleSignal;
sigaction(SIGTERM, &sa, nullptr);
sigaction(SIGINT, &sa, nullptr);
sigaction(SIGALRM, &sa, nullptr);
}
static void LockDownUmask() {
// Only user and group may access configuration files we create.
umask(S_IWGRP | S_IROTH | S_IWOTH);
}
// Run the main event loop. The events to handle are:
// 1) timeout from poll
// 2) caught signal
// 3) stdout/err of child process ready
// 4) child process dies
static void RunEventLoop(IpsecManager* ipsec, L2tpManager* l2tp) {
do {
int status;
int ipsec_poll_timeout = ipsec->Poll();
int l2tp_poll_timeout = l2tp->Poll();
int poll_timeout = (ipsec_poll_timeout > l2tp_poll_timeout) ?
ipsec_poll_timeout : l2tp_poll_timeout;
const int poll_input_count = 3;
struct pollfd poll_inputs[poll_input_count] = {
{ ipsec->output_fd(), POLLIN }, // ipsec output
{ l2tp->output_fd(), POLLIN }, // l2tp output
{ l2tp->ppp_output_fd(), POLLIN } // ppp output
};
int poll_result = poll(poll_inputs, poll_input_count, poll_timeout);
if (poll_result < 0 && errno != EINTR) {
int saved_errno = errno;
LOG(ERROR) << "Unexpected poll error: " << saved_errno;
return;
}
// Check if there are any child processes to be reaped without
// blocking.
pid_t pid = waitpid(-1, &status, WNOHANG);
if (pid > 0 && (ipsec->IsChild(pid) || l2tp->IsChild(pid))) {
LOG(WARNING) << "Child process " << pid << " stopped early";
s_terminate_request = true;
}
if (poll_inputs[0].revents & POLLIN)
ipsec->ProcessOutput();
if (poll_inputs[1].revents & POLLIN)
l2tp->ProcessOutput();
if (poll_inputs[2].revents & POLLIN)
l2tp->ProcessPppOutput();
} while (!ipsec->was_stopped() && !s_terminate_request);
}
int main(int argc, char* argv[]) {
DEFINE_string(client_cert_id, "", "PKCS#11 slot with client certificate");
DEFINE_string(client_cert_slot, "", "PKCS#11 key ID for client certificate");
DEFINE_bool(debug, false, "Log debugging information");
DEFINE_string(psk_file, "", "File with IPsec pre-shared key");
DEFINE_string(remote_host, "", "VPN server hostname");
DEFINE_string(server_ca_file, "", "File with IPsec server CA in DER format");
DEFINE_string(server_id, "", "ID expected from server");
DEFINE_string(user_pin, "", "PKCS#11 User PIN");
DEFINE_string(xauth_credentials_file, "", "File with Xauth user credentials");
// IpsecManager related flags.
// Cisco ASA L2TP/IPsec setup instructions indicate using md5 for
// authentication for the IPsec SA. Default StrongS/WAN setup is
// to only propose SHA1.
DEFINE_string(esp, "aes128-sha1,3des-sha1,aes128-md5,3des-md5",
"esp proposals");
// Windows RRAS requires modp1024 dh-group. Strongswan's
// default is modp1536 which it does not support.
DEFINE_string(ike, "3des-sha1-modp1024", "ike proposals");
DEFINE_int32(ipsec_timeout, 30, "timeout for ipsec to be established");
DEFINE_string(leftprotoport, "17/1701", "client protocol/port");
DEFINE_bool(nat_traversal, true, "Enable NAT-T nat traversal");
DEFINE_bool(pfs, false, "pfs");
DEFINE_bool(rekey, true, "rekey");
DEFINE_string(rightprotoport, "17/1701", "server protocol/port");
DEFINE_string(tunnel_group, "", "Cisco Tunnel Group Name");
DEFINE_string(type, "transport", "IPsec type (transport or tunnel)");
// L2tpManager related flags.
DEFINE_bool(defaultroute, true, "defaultroute");
DEFINE_bool(length_bit, true, "length bit");
DEFINE_bool(require_chap, true, "require chap");
DEFINE_bool(refuse_pap, false, "refuse chap");
DEFINE_bool(require_authentication, true, "require authentication");
DEFINE_string(password, "", "password (insecure - use pppd plugin instead)");
DEFINE_bool(ppp_debug, true, "ppp debug");
DEFINE_int32(ppp_setup_timeout, 10, "timeout to setup ppp (seconds)");
DEFINE_string(pppd_plugin, "", "pppd plugin");
DEFINE_bool(usepeerdns, true, "usepeerdns - ask peer for DNS");
DEFINE_string(user, "", "user name");
DEFINE_bool(systemconfig, true, "enable ppp to configure IPs/routes/DNS");
base::ScopedTempDir temp_dir;
chromeos::FlagHelper::Init(argc, argv, "Chromium OS l2tpipsec VPN");
int log_flags = chromeos::kLogToSyslog;
if (isatty(STDOUT_FILENO)) log_flags |= chromeos::kLogToStderr;
chromeos::InitLog(log_flags);
chromeos::OpenLog("l2tpipsec_vpn", true);
IpsecManager ipsec(FLAGS_esp, FLAGS_ike, FLAGS_ipsec_timeout,
FLAGS_leftprotoport, FLAGS_rekey, FLAGS_rightprotoport,
FLAGS_tunnel_group, FLAGS_type);
L2tpManager l2tp(FLAGS_defaultroute, FLAGS_length_bit, FLAGS_require_chap,
FLAGS_refuse_pap, FLAGS_require_authentication,
FLAGS_password, FLAGS_ppp_debug, FLAGS_ppp_setup_timeout,
FLAGS_pppd_plugin, FLAGS_usepeerdns, FLAGS_user,
FLAGS_systemconfig);
LockDownUmask();
ipsec.set_debug(FLAGS_debug);
l2tp.set_debug(FLAGS_debug);
ServiceManager::InitializeDirectories(&temp_dir);
struct sockaddr remote_address;
if (!ServiceManager::ResolveNameToSockAddr(FLAGS_remote_host,
&remote_address)) {
LOG(ERROR) << "Unable to resolve hostname " << FLAGS_remote_host;
return vpn_manager::kServiceErrorResolveHostnameFailed;
}
if (FLAGS_psk_file.empty() && !FLAGS_xauth_credentials_file.empty()) {
LOG(ERROR) << "Providing XAUTH credentials without a PSK is invalid";
return vpn_manager::kServiceErrorInvalidArgument;
}
if (!ipsec.Initialize(1,
remote_address,
FLAGS_psk_file,
FLAGS_xauth_credentials_file,
FLAGS_server_ca_file,
FLAGS_server_id,
FLAGS_client_cert_slot,
FLAGS_client_cert_id,
FLAGS_user_pin)) {
return ipsec.GetError();
}
if (!l2tp.Initialize(remote_address)) {
return l2tp.GetError();
}
ServiceManager::SetLayerOrder(&ipsec, &l2tp);
InstallSignalHandlers();
if (!ipsec.Start()) {
LOG(ERROR) << "Unable to start IPsec layer";
return ipsec.GetError();
}
RunEventLoop(&ipsec, &l2tp);
LOG(INFO) << "Shutting down...";
l2tp.Stop();
return ipsec.GetError();
}