2012-09-15 08:56:18 +02:00
|
|
|
#include <getopt.h> // for getopt_long
|
|
|
|
#include <stdlib.h> // for atoi
|
|
|
|
|
2012-09-10 01:10:20 +02:00
|
|
|
#include <string>
|
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
|
|
|
#include <signal.h>
|
|
|
|
|
|
|
|
#include <boost/asio.hpp>
|
|
|
|
#include <boost/bind.hpp>
|
|
|
|
#include <boost/thread/thread.hpp>
|
|
|
|
|
|
|
|
#define OPENVPN_CORE_API_VISIBILITY_HIDDEN // don't export core symbols
|
|
|
|
|
2012-09-12 01:51:37 +02:00
|
|
|
#include <openvpn/common/exception.hpp>
|
2012-09-15 08:56:18 +02:00
|
|
|
#include <openvpn/common/file.hpp>
|
|
|
|
#include <openvpn/time/timestr.hpp>
|
2012-09-12 01:51:37 +02:00
|
|
|
|
2012-09-10 01:10:20 +02:00
|
|
|
#include <client/ovpncli.cpp>
|
|
|
|
|
2012-09-15 08:56:18 +02:00
|
|
|
using namespace openvpn;
|
2012-09-10 01:10:20 +02:00
|
|
|
|
2012-09-15 08:56:18 +02:00
|
|
|
class Client : public ClientAPI::OpenVPNClient
|
2012-09-10 01:10:20 +02:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
virtual bool socket_protect(int socket)
|
|
|
|
{
|
|
|
|
std::cout << "*** socket_protect " << socket << std::endl;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-09-15 08:56:18 +02:00
|
|
|
virtual void event(const ClientAPI::Event& ev)
|
2012-09-10 01:10:20 +02:00
|
|
|
{
|
2012-09-15 08:56:18 +02:00
|
|
|
std::cout << date_time() << " EVENT: " << ev.name;
|
|
|
|
if (!ev.info.empty())
|
|
|
|
std::cout << ' ' << ev.info;
|
|
|
|
if (ev.error)
|
|
|
|
std::cout << " [ERR]";
|
|
|
|
std::cout << std::endl << std::flush;
|
2012-09-10 01:10:20 +02:00
|
|
|
}
|
|
|
|
|
2012-09-15 08:56:18 +02:00
|
|
|
virtual void log(const ClientAPI::LogInfo& log)
|
2012-09-10 01:10:20 +02:00
|
|
|
{
|
2012-09-15 08:56:18 +02:00
|
|
|
std::cout << date_time() << ' ' << log.text << std::flush;
|
2012-09-10 01:10:20 +02:00
|
|
|
}
|
|
|
|
|
2012-09-15 08:56:18 +02:00
|
|
|
virtual void external_pki_cert_request(ClientAPI::ExternalPKICertRequest& certreq)
|
2012-09-10 01:10:20 +02:00
|
|
|
{
|
|
|
|
std::cout << "*** external_pki_cert_request" << std::endl;
|
|
|
|
certreq.error = true;
|
|
|
|
certreq.errorText = "external_pki_cert_request not implemented";
|
|
|
|
}
|
|
|
|
|
2012-09-15 08:56:18 +02:00
|
|
|
virtual void external_pki_sign_request(ClientAPI::ExternalPKISignRequest& signreq)
|
2012-09-10 01:10:20 +02:00
|
|
|
{
|
|
|
|
std::cout << "*** external_pki_sign_request" << std::endl;
|
|
|
|
signreq.error = true;
|
|
|
|
signreq.errorText = "external_pki_sign_request not implemented";
|
|
|
|
}
|
2012-10-24 08:38:20 +02:00
|
|
|
|
|
|
|
virtual bool pause_on_connection_timeout()
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2012-09-10 01:10:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
Client *the_client = NULL;
|
|
|
|
|
|
|
|
void worker_thread()
|
|
|
|
{
|
|
|
|
boost::asio::detail::signal_blocker signal_blocker; // signals should be handled by parent thread
|
|
|
|
try {
|
|
|
|
std::cout << "Thread starting..." << std::endl;
|
2012-09-15 08:56:18 +02:00
|
|
|
ClientAPI::Status connect_status = the_client->connect();
|
2012-09-10 01:10:20 +02:00
|
|
|
if (connect_status.error)
|
2012-11-16 05:13:48 +01:00
|
|
|
{
|
|
|
|
std::cout << "connect error: ";
|
|
|
|
if (!connect_status.status.empty())
|
|
|
|
std::cout << connect_status.status << ": ";
|
|
|
|
std::cout << connect_status.message << std::endl;
|
|
|
|
}
|
2012-09-10 01:10:20 +02:00
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
2012-09-15 08:56:18 +02:00
|
|
|
std::cout << "Connect thread exception: " << e.what() << std::endl;
|
2012-09-10 01:10:20 +02:00
|
|
|
}
|
|
|
|
std::cout << "Thread finished" << std::endl;
|
|
|
|
}
|
|
|
|
|
2012-09-12 01:51:37 +02:00
|
|
|
void handler(int signum)
|
2012-09-10 01:10:20 +02:00
|
|
|
{
|
2012-09-12 01:51:37 +02:00
|
|
|
switch (signum)
|
|
|
|
{
|
|
|
|
case SIGTERM:
|
|
|
|
case SIGINT:
|
2012-09-15 08:56:18 +02:00
|
|
|
std::cout << "received stop signal " << signum << std::endl;
|
2012-09-12 01:51:37 +02:00
|
|
|
if (the_client)
|
|
|
|
the_client->stop();
|
|
|
|
break;
|
|
|
|
case SIGHUP:
|
2012-09-15 08:56:18 +02:00
|
|
|
std::cout << "received reconnect signal " << signum << std::endl;
|
2012-09-12 01:51:37 +02:00
|
|
|
if (the_client)
|
|
|
|
the_client->reconnect(2);
|
|
|
|
break;
|
|
|
|
default:
|
2012-09-15 08:56:18 +02:00
|
|
|
std::cout << "received unknown signal " << signum << std::endl;
|
2012-09-12 01:51:37 +02:00
|
|
|
break;
|
|
|
|
}
|
2012-09-10 01:10:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2012-09-15 08:56:18 +02:00
|
|
|
static const struct option longopts[] = {
|
2012-11-15 23:48:13 +01:00
|
|
|
{ "username", required_argument, NULL, 'u' },
|
|
|
|
{ "password", required_argument, NULL, 'p' },
|
2012-11-18 19:53:10 +01:00
|
|
|
{ "response", required_argument, NULL, 'r' },
|
2012-11-15 23:48:13 +01:00
|
|
|
{ "proto", required_argument, NULL, 'P' },
|
|
|
|
{ "server", required_argument, NULL, 's' },
|
|
|
|
{ "timeout", required_argument, NULL, 't' },
|
|
|
|
{ "compress", required_argument, NULL, 'c' },
|
|
|
|
{ "pk-password", required_argument, NULL, 'z' },
|
|
|
|
{ "proxy-host", required_argument, NULL, 'h' },
|
|
|
|
{ "proxy-port", required_argument, NULL, 'q' },
|
|
|
|
{ "proxy-username", required_argument, NULL, 'U' },
|
|
|
|
{ "proxy-password", required_argument, NULL, 'W' },
|
|
|
|
{ "eval", no_argument, NULL, 'e' },
|
2012-11-18 19:53:10 +01:00
|
|
|
{ "cache-password", no_argument, NULL, 'C' },
|
2012-11-15 23:48:13 +01:00
|
|
|
{ NULL, 0, NULL, 0 }
|
2012-09-15 08:56:18 +02:00
|
|
|
};
|
|
|
|
|
2012-09-10 01:10:20 +02:00
|
|
|
try {
|
|
|
|
if (argc >= 2)
|
|
|
|
{
|
2012-09-15 08:56:18 +02:00
|
|
|
std::string username;
|
|
|
|
std::string password;
|
2012-11-18 19:53:10 +01:00
|
|
|
std::string response;
|
2012-09-15 08:56:18 +02:00
|
|
|
std::string proto;
|
|
|
|
std::string server;
|
|
|
|
int timeout = 0;
|
|
|
|
std::string compress;
|
2012-11-15 23:48:13 +01:00
|
|
|
std::string privateKeyPassword;
|
2012-10-24 08:38:20 +02:00
|
|
|
std::string proxyHost;
|
|
|
|
std::string proxyPort;
|
|
|
|
std::string proxyUsername;
|
|
|
|
std::string proxyPassword;
|
2012-11-15 23:48:13 +01:00
|
|
|
bool eval = false;
|
2012-11-18 19:53:10 +01:00
|
|
|
bool cachePassword = false;
|
2012-10-24 08:38:20 +02:00
|
|
|
|
2012-09-15 08:56:18 +02:00
|
|
|
int ch;
|
|
|
|
|
2012-11-18 19:53:10 +01:00
|
|
|
while ((ch = getopt_long(argc, argv, "eCu:p:r:P:s:t:c:z:h:q:U:W:", longopts, NULL)) != -1)
|
2012-09-15 08:56:18 +02:00
|
|
|
{
|
|
|
|
switch (ch)
|
|
|
|
{
|
2012-11-15 23:48:13 +01:00
|
|
|
case 'e':
|
|
|
|
eval = true;
|
|
|
|
break;
|
2012-11-18 19:53:10 +01:00
|
|
|
case 'C':
|
|
|
|
cachePassword = true;
|
|
|
|
break;
|
2012-09-15 08:56:18 +02:00
|
|
|
case 'u':
|
|
|
|
username = optarg;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
password = optarg;
|
|
|
|
break;
|
2012-11-18 19:53:10 +01:00
|
|
|
case 'r':
|
|
|
|
response = optarg;
|
|
|
|
break;
|
2012-09-15 08:56:18 +02:00
|
|
|
case 'P':
|
|
|
|
proto = optarg;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
server = optarg;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
timeout = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
compress = optarg;
|
|
|
|
break;
|
2012-11-15 23:48:13 +01:00
|
|
|
case 'z':
|
|
|
|
privateKeyPassword = optarg;
|
|
|
|
break;
|
2012-10-24 08:38:20 +02:00
|
|
|
case 'h':
|
|
|
|
proxyHost = optarg;
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
proxyPort = optarg;
|
|
|
|
break;
|
|
|
|
case 'U':
|
|
|
|
proxyUsername = optarg;
|
|
|
|
break;
|
|
|
|
case 'W':
|
|
|
|
proxyPassword = optarg;
|
|
|
|
break;
|
2012-09-15 08:56:18 +02:00
|
|
|
default:
|
|
|
|
goto usage;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
argc -= optind;
|
|
|
|
argv += optind;
|
|
|
|
|
2012-09-11 10:45:27 +02:00
|
|
|
Client::init_process();
|
2012-11-15 23:48:13 +01:00
|
|
|
|
2012-09-15 08:56:18 +02:00
|
|
|
if (argc != 1)
|
|
|
|
goto usage;
|
2012-11-12 02:52:03 +01:00
|
|
|
ProfileMerge pm(argv[0], "", true,
|
|
|
|
ProfileParseLimits::MAX_LINE_SIZE, ProfileParseLimits::MAX_PROFILE_SIZE);
|
|
|
|
if (pm.status() != ProfileMerge::MERGE_SUCCESS)
|
|
|
|
OPENVPN_THROW_EXCEPTION("merge config error: " << pm.status_string() << " : " << pm.error());
|
2012-11-15 23:48:13 +01:00
|
|
|
|
|
|
|
ClientAPI::Config config;
|
2012-11-12 02:52:03 +01:00
|
|
|
config.content = pm.profile_content();
|
2012-09-15 08:56:18 +02:00
|
|
|
config.serverOverride = server;
|
|
|
|
config.protoOverride = proto;
|
|
|
|
config.connTimeout = timeout;
|
|
|
|
config.compressionMode = compress;
|
2012-11-15 23:48:13 +01:00
|
|
|
config.privateKeyPassword = privateKeyPassword;
|
2012-10-24 08:38:20 +02:00
|
|
|
config.proxyHost = proxyHost;
|
|
|
|
config.proxyPort = proxyPort;
|
|
|
|
config.proxyUsername = proxyUsername;
|
|
|
|
config.proxyPassword = proxyPassword;
|
2012-11-15 23:48:13 +01:00
|
|
|
|
|
|
|
if (eval)
|
2012-09-10 01:10:20 +02:00
|
|
|
{
|
2012-11-15 23:48:13 +01:00
|
|
|
ClientAPI::EvalConfig eval = ClientAPI::OpenVPNClient::eval_config_static(config);
|
|
|
|
std::cout << "EVAL PROFILE" << std::endl;
|
|
|
|
std::cout << "error=" << eval.error << std::endl;
|
|
|
|
std::cout << "message=" << eval.message << std::endl;
|
|
|
|
std::cout << "userlockedUsername=" << eval.userlockedUsername << std::endl;
|
|
|
|
std::cout << "profileName=" << eval.profileName << std::endl;
|
|
|
|
std::cout << "friendlyName=" << eval.friendlyName << std::endl;
|
|
|
|
std::cout << "autologin=" << eval.autologin << std::endl;
|
|
|
|
std::cout << "externalPki=" << eval.externalPki << std::endl;
|
|
|
|
std::cout << "staticChallenge=" << eval.staticChallenge << std::endl;
|
|
|
|
std::cout << "staticChallengeEcho=" << eval.staticChallengeEcho << std::endl;
|
|
|
|
std::cout << "privateKeyPasswordRequired=" << eval.privateKeyPasswordRequired << std::endl;
|
2012-11-18 09:55:27 +01:00
|
|
|
std::cout << "allowPasswordSave=" << eval.allowPasswordSave << std::endl;
|
2012-11-15 23:48:13 +01:00
|
|
|
|
|
|
|
for (size_t i = 0; i < eval.serverList.size(); ++i)
|
|
|
|
{
|
|
|
|
const ClientAPI::ServerEntry& se = eval.serverList[i];
|
|
|
|
std::cout << '[' << i << "] " << se.server << '/' << se.friendlyName << std::endl;
|
|
|
|
}
|
2012-09-10 01:10:20 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-15 23:48:13 +01:00
|
|
|
Client client;
|
|
|
|
ClientAPI::EvalConfig eval = client.eval_config(config);
|
|
|
|
if (eval.error)
|
|
|
|
OPENVPN_THROW_EXCEPTION("eval config error: " << eval.message);
|
|
|
|
if (eval.autologin)
|
|
|
|
{
|
|
|
|
if (!username.empty() || !password.empty())
|
|
|
|
std::cout << "NOTE: creds were not needed" << std::endl;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (username.empty())
|
|
|
|
OPENVPN_THROW_EXCEPTION("need creds");
|
|
|
|
ClientAPI::ProvideCreds creds;
|
|
|
|
creds.username = username;
|
|
|
|
creds.password = password;
|
2012-11-18 19:53:10 +01:00
|
|
|
creds.response = response;
|
|
|
|
creds.replacePasswordWithSessionID = !cachePassword;
|
2012-11-15 23:48:13 +01:00
|
|
|
ClientAPI::Status creds_status = client.provide_creds(creds);
|
|
|
|
if (creds_status.error)
|
|
|
|
OPENVPN_THROW_EXCEPTION("creds error: " << creds_status.message);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "CONNECTING..." << std::endl;
|
|
|
|
|
|
|
|
// catch signals
|
|
|
|
struct sigaction sa;
|
|
|
|
sa.sa_handler = handler;
|
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
sa.sa_flags = SA_RESTART; // restart functions if interrupted by handler
|
|
|
|
if (sigaction(SIGINT, &sa, NULL) == -1
|
|
|
|
|| sigaction(SIGTERM, &sa, NULL) == -1
|
|
|
|
|| sigaction(SIGHUP, &sa, NULL) == -1)
|
|
|
|
OPENVPN_THROW_EXCEPTION("error setting signal handler");
|
|
|
|
|
|
|
|
// start connect thread
|
|
|
|
the_client = &client;
|
|
|
|
boost::thread* thread = new boost::thread(boost::bind(&worker_thread));
|
2012-09-10 01:10:20 +02:00
|
|
|
|
2012-11-15 23:48:13 +01:00
|
|
|
// wait for connect thread to exit
|
|
|
|
thread->join();
|
|
|
|
the_client = NULL;
|
|
|
|
|
|
|
|
// print closing stats
|
2012-09-15 08:56:18 +02:00
|
|
|
{
|
2012-11-15 23:48:13 +01:00
|
|
|
const int n = client.stats_n();
|
|
|
|
std::vector<long long> stats = client.stats_bundle();
|
|
|
|
|
|
|
|
std::cout << "STATS:" << std::endl;
|
|
|
|
for (int i = 0; i < n; ++i)
|
|
|
|
{
|
|
|
|
const long long value = stats[i];
|
|
|
|
if (value)
|
|
|
|
std::cout << " " << client.stats_name(i) << " : " << value << std::endl;
|
|
|
|
}
|
2012-09-15 08:56:18 +02:00
|
|
|
}
|
2012-11-15 23:48:13 +01:00
|
|
|
}
|
2012-09-10 01:10:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
2012-09-15 08:56:18 +02:00
|
|
|
goto usage;
|
2012-09-10 01:10:20 +02:00
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
the_client = NULL;
|
2012-09-15 08:56:18 +02:00
|
|
|
std::cout << "Main thread exception: " << e.what() << std::endl;
|
2012-09-10 01:10:20 +02:00
|
|
|
return 1;
|
|
|
|
}
|
2012-09-15 08:56:18 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
usage:
|
|
|
|
std::cout << "OpenVPN Client (ovpncli)" << std::endl;
|
2012-11-15 23:48:13 +01:00
|
|
|
std::cout << "usage: cli [options] <config-file>" << std::endl;
|
|
|
|
std::cout << "--eval, -e : evaluate profile only" << std::endl;
|
2012-10-24 08:38:20 +02:00
|
|
|
std::cout << "--username, -u : username" << std::endl;
|
|
|
|
std::cout << "--password, -p : password" << std::endl;
|
2012-11-18 19:53:10 +01:00
|
|
|
std::cout << "--response, -r : static response" << std::endl;
|
2012-10-24 08:38:20 +02:00
|
|
|
std::cout << "--proto, -P : protocol override (udp|tcp)" << std::endl;
|
|
|
|
std::cout << "--server, -s : server override" << std::endl;
|
|
|
|
std::cout << "--timeout, -t : timeout" << std::endl;
|
|
|
|
std::cout << "--compress, -c : compression mode (yes|no|asym)" << std::endl;
|
2012-11-15 23:48:13 +01:00
|
|
|
std::cout << "--pk-password, -z : private key password" << std::endl;
|
2012-10-24 08:38:20 +02:00
|
|
|
std::cout << "--proxy-host, -h : HTTP proxy hostname/IP" << std::endl;
|
|
|
|
std::cout << "--proxy-port, -q : HTTP proxy port" << std::endl;
|
|
|
|
std::cout << "--proxy-username, -U : HTTP proxy username" << std::endl;
|
|
|
|
std::cout << "--proxy-password, -W : HTTP proxy password" << std::endl;
|
2012-11-18 19:53:10 +01:00
|
|
|
std::cout << "--cache-password, -C : cache password rather than use Session ID" << std::endl;
|
2012-10-24 08:38:20 +02:00
|
|
|
std::cout << "" << std::endl;
|
2012-09-15 08:56:18 +02:00
|
|
|
return 2;
|
2012-09-10 01:10:20 +02:00
|
|
|
}
|