mirror of
https://github.com/deneraraujo/OpenVPNAdapter.git
synced 2026-04-24 00:00:05 +08:00
Merge commit 'f65d76170b26155358c2fc27686f87e0475f6a94' as 'OpenVPN Adapter/Vendors/openvpn'
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
build
|
||||
ovpncli_wrap.cxx
|
||||
ovpncli_wrap.h
|
||||
ovpncli.java
|
||||
ovpncliJNI.java
|
||||
ClientAPI_*.java
|
||||
SWIGTYPE_*.java
|
||||
@@ -0,0 +1,144 @@
|
||||
// OpenVPN -- An application to securely tunnel IP networks
|
||||
// over a single port, with support for SSL/TLS-based
|
||||
// session authentication and key exchange,
|
||||
// packet encryption, packet authentication, and
|
||||
// packet compression.
|
||||
//
|
||||
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// TESTING_ONLY
|
||||
|
||||
public class Client implements OpenVPNClientThread.EventReceiver {
|
||||
private OpenVPNClientThread client_thread;
|
||||
|
||||
public static class ConfigError extends Exception {
|
||||
public ConfigError(String msg) { super(msg); }
|
||||
}
|
||||
|
||||
public static class CredsUnspecifiedError extends Exception {
|
||||
public CredsUnspecifiedError(String msg) { super(msg); }
|
||||
}
|
||||
|
||||
// Load OpenVPN core (implements ClientAPI_OpenVPNClient) from shared library
|
||||
static {
|
||||
System.loadLibrary("ovpncli");
|
||||
ClientAPI_OpenVPNClient.init_process();
|
||||
String test = ClientAPI_OpenVPNClient.crypto_self_test();
|
||||
System.out.format("CRYPTO SELF TEST: %s", test);
|
||||
}
|
||||
|
||||
public Client(String config_text, String username, String password) throws ConfigError, CredsUnspecifiedError {
|
||||
// init client implementation object
|
||||
client_thread = new OpenVPNClientThread();
|
||||
|
||||
// load/eval config
|
||||
ClientAPI_Config config = new ClientAPI_Config();
|
||||
config.setContent(config_text);
|
||||
config.setCompressionMode("yes");
|
||||
ClientAPI_EvalConfig ec = client_thread.eval_config(config);
|
||||
if (ec.getError())
|
||||
throw new ConfigError("OpenVPN config file parse error: " + ec.getMessage());
|
||||
|
||||
// handle creds
|
||||
ClientAPI_ProvideCreds creds = new ClientAPI_ProvideCreds();
|
||||
if (!ec.getAutologin())
|
||||
{
|
||||
if (username.length() > 0)
|
||||
{
|
||||
creds.setUsername(username);
|
||||
creds.setPassword(password);
|
||||
creds.setReplacePasswordWithSessionID(true);
|
||||
}
|
||||
else
|
||||
throw new CredsUnspecifiedError("OpenVPN config file requires username/password but none provided");
|
||||
}
|
||||
client_thread.provide_creds(creds);
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
// connect
|
||||
client_thread.connect(this);
|
||||
|
||||
// wait for worker thread to exit
|
||||
client_thread.wait_thread_long();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
client_thread.stop();
|
||||
}
|
||||
|
||||
public void show_stats() {
|
||||
int n = client_thread.stats_n();
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
String name = client_thread.stats_name(i);
|
||||
long value = client_thread.stats_value(i);
|
||||
if (value > 0)
|
||||
System.out.format("STAT %s=%s%n", name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void event(ClientAPI_Event event) {
|
||||
boolean error = event.getError();
|
||||
String name = event.getName();
|
||||
String info = event.getInfo();
|
||||
System.out.format("EVENT: err=%b name=%s info='%s'%n", error, name, info);
|
||||
}
|
||||
|
||||
// Callback to get a certificate
|
||||
@Override
|
||||
public void external_pki_cert_request(ClientAPI_ExternalPKICertRequest req) {
|
||||
req.setError(true);
|
||||
req.setErrorText("cert request failed: external PKI not implemented");
|
||||
}
|
||||
|
||||
// Callback to sign data
|
||||
@Override
|
||||
public void external_pki_sign_request(ClientAPI_ExternalPKISignRequest req) {
|
||||
req.setError(true);
|
||||
req.setErrorText("sign request failed: external PKI not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(ClientAPI_LogInfo loginfo) {
|
||||
String text = loginfo.getText();
|
||||
System.out.format("LOG: %s", text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void done(ClientAPI_Status status) {
|
||||
System.out.format("DONE ClientAPI_Status: err=%b msg='%s'%n", status.getError(), status.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean socket_protect(int socket)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pause_on_connection_timeout()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenVPNClientThread.TunBuilder tun_builder_new()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
// OpenVPN -- An application to securely tunnel IP networks
|
||||
// over a single port, with support for SSL/TLS-based
|
||||
// session authentication and key exchange,
|
||||
// packet encryption, packet authentication, and
|
||||
// packet compression.
|
||||
//
|
||||
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// TESTING_ONLY
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class Main {
|
||||
// utility method to read a file and return as a String
|
||||
public static String readFile(String filename) throws IOException {
|
||||
return readStream(new FileInputStream(filename));
|
||||
}
|
||||
|
||||
private static String readStream(InputStream stream) throws IOException {
|
||||
// No real need to close the BufferedReader/InputStreamReader
|
||||
// as they're only wrapping the stream
|
||||
try {
|
||||
Reader reader = new BufferedReader(new InputStreamReader(stream));
|
||||
StringBuilder builder = new StringBuilder();
|
||||
char[] buffer = new char[4096];
|
||||
int read;
|
||||
while ((read = reader.read(buffer, 0, buffer.length)) > 0) {
|
||||
builder.append(buffer, 0, read);
|
||||
}
|
||||
return builder.toString();
|
||||
} finally {
|
||||
// Potential issue here: if this throws an IOException,
|
||||
// it will mask any others. Normally I'd use a utility
|
||||
// method which would log exceptions and swallow them
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException, Client.ConfigError, Client.CredsUnspecifiedError {
|
||||
if (args.length >= 1)
|
||||
{
|
||||
// load config file
|
||||
String config = readFile(args[0]);
|
||||
|
||||
// get creds
|
||||
String username = "";
|
||||
String password = "";
|
||||
if (args.length >= 3)
|
||||
{
|
||||
username = args[1];
|
||||
password = args[2];
|
||||
}
|
||||
|
||||
// instantiate client object
|
||||
final Client client = new Client(config, username, password);
|
||||
|
||||
// catch signals
|
||||
final Thread mainThread = Thread.currentThread();
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
public void run() {
|
||||
client.stop();
|
||||
try {
|
||||
mainThread.join();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// execute client session
|
||||
client.connect();
|
||||
|
||||
// show stats before exit
|
||||
client.show_stats();
|
||||
}
|
||||
else
|
||||
{
|
||||
System.err.println("OpenVPN Java client");
|
||||
System.err.println("Usage: java Client <client.ovpn> [username] [password]");
|
||||
System.exit(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,359 @@
|
||||
// OpenVPN -- An application to securely tunnel IP networks
|
||||
// over a single port, with support for SSL/TLS-based
|
||||
// session authentication and key exchange,
|
||||
// packet encryption, packet authentication, and
|
||||
// packet compression.
|
||||
//
|
||||
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// package OPENVPN_PACKAGE
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
public class OpenVPNClientThread extends ClientAPI_OpenVPNClient implements Runnable {
|
||||
private EventReceiver parent;
|
||||
private TunBuilder tun_builder;
|
||||
private Thread thread;
|
||||
private ClientAPI_Status m_connect_status;
|
||||
private boolean connect_called = false;
|
||||
|
||||
private int bytes_in_index = -1;
|
||||
private int bytes_out_index = -1;
|
||||
|
||||
// thrown if instantiator attempts to call connect more than once
|
||||
public static class ConnectCalledTwice extends RuntimeException {
|
||||
}
|
||||
|
||||
public interface EventReceiver {
|
||||
// Called with events from core
|
||||
void event(ClientAPI_Event event);
|
||||
|
||||
// Called with log text from core
|
||||
void log(ClientAPI_LogInfo loginfo);
|
||||
|
||||
// Called when connect() thread exits
|
||||
void done(ClientAPI_Status status);
|
||||
|
||||
// Called to "protect" a socket from being routed through the tunnel
|
||||
boolean socket_protect(int socket);
|
||||
|
||||
// When a connection is close to timeout, the core will call this
|
||||
// method. If it returns false, the core will disconnect with a
|
||||
// CONNECTION_TIMEOUT event. If true, the core will enter a PAUSE
|
||||
// state.
|
||||
boolean pause_on_connection_timeout();
|
||||
|
||||
// Callback to construct a new tun builder
|
||||
TunBuilder tun_builder_new();
|
||||
|
||||
// Callback to get a certificate
|
||||
void external_pki_cert_request(ClientAPI_ExternalPKICertRequest req);
|
||||
|
||||
// Callback to sign data
|
||||
void external_pki_sign_request(ClientAPI_ExternalPKISignRequest req);
|
||||
}
|
||||
|
||||
public interface TunBuilder {
|
||||
// Tun builder methods.
|
||||
// Methods documented in openvpn/tun/builder/base.hpp
|
||||
|
||||
boolean tun_builder_set_remote_address(String address, boolean ipv6);
|
||||
boolean tun_builder_add_address(String address, int prefix_length, String gateway, boolean ipv6, boolean net30);
|
||||
boolean tun_builder_reroute_gw(boolean ipv4, boolean ipv6, long flags);
|
||||
boolean tun_builder_add_route(String address, int prefix_length, boolean ipv6);
|
||||
boolean tun_builder_exclude_route(String address, int prefix_length, boolean ipv6);
|
||||
boolean tun_builder_add_dns_server(String address, boolean ipv6);
|
||||
boolean tun_builder_add_search_domain(String domain);
|
||||
boolean tun_builder_set_mtu(int mtu);
|
||||
boolean tun_builder_set_session_name(String name);
|
||||
int tun_builder_establish();
|
||||
void tun_builder_teardown(boolean disconnect);
|
||||
}
|
||||
|
||||
public OpenVPNClientThread() {
|
||||
final int n = stats_n();
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
String name = stats_name(i);
|
||||
if (name.equals("BYTES_IN"))
|
||||
bytes_in_index = i;
|
||||
if (name.equals("BYTES_OUT"))
|
||||
bytes_out_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
// start connect session in worker thread
|
||||
public void connect(EventReceiver parent_arg) {
|
||||
if (connect_called)
|
||||
throw new ConnectCalledTwice();
|
||||
connect_called = true;
|
||||
|
||||
// direct client callbacks to parent
|
||||
parent = parent_arg;
|
||||
|
||||
// clear status
|
||||
m_connect_status = null;
|
||||
|
||||
// execute client in a worker thread
|
||||
thread = new Thread(this, "OpenVPNClientThread");
|
||||
thread.start();
|
||||
}
|
||||
|
||||
// Wait for worker thread to complete; to stop thread,
|
||||
// first call super stop() method then wait_thread().
|
||||
// This method will give the thread one second to
|
||||
// exit and will abandon it after this time.
|
||||
public void wait_thread_short() {
|
||||
final int wait_millisecs = 5000; // max time that we will wait for thread to exit
|
||||
Thread th = thread;
|
||||
if (th != null) {
|
||||
try {
|
||||
th.join(wait_millisecs);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
}
|
||||
|
||||
// thread failed to stop?
|
||||
if (th.isAlive()) {
|
||||
// abandon thread and deliver our own status object to instantiator.
|
||||
ClientAPI_Status status = new ClientAPI_Status();
|
||||
status.setError(true);
|
||||
status.setMessage("CORE_THREAD_ABANDONED");
|
||||
call_done(status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for worker thread to complete; to stop thread,
|
||||
// first call super stop() method then wait_thread().
|
||||
// This method will wait forever for the thread to exit.
|
||||
public void wait_thread_long() {
|
||||
if (thread != null) {
|
||||
boolean interrupted;
|
||||
do {
|
||||
interrupted = false;
|
||||
try {
|
||||
thread.join();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
interrupted = true;
|
||||
super.stop(); // send thread a stop message
|
||||
}
|
||||
} while (interrupted);
|
||||
}
|
||||
}
|
||||
|
||||
public long bytes_in()
|
||||
{
|
||||
return super.stats_value(bytes_in_index);
|
||||
}
|
||||
|
||||
public long bytes_out()
|
||||
{
|
||||
return super.stats_value(bytes_out_index);
|
||||
}
|
||||
|
||||
private void call_done(ClientAPI_Status status)
|
||||
{
|
||||
EventReceiver p = finalize_thread(status);
|
||||
if (p != null)
|
||||
p.done(m_connect_status);
|
||||
}
|
||||
|
||||
private synchronized EventReceiver finalize_thread(ClientAPI_Status connect_status)
|
||||
{
|
||||
EventReceiver p = parent;
|
||||
if (p != null) {
|
||||
// save thread connection status
|
||||
m_connect_status = connect_status;
|
||||
|
||||
// disassociate client callbacks from parent
|
||||
parent = null;
|
||||
tun_builder = null;
|
||||
thread = null;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
// Runnable overrides
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// Call out to core to start connection.
|
||||
// Doesn't return until connection has terminated.
|
||||
ClientAPI_Status status = super.connect();
|
||||
call_done(status);
|
||||
}
|
||||
|
||||
// ClientAPI_OpenVPNClient (C++ class) overrides
|
||||
|
||||
@Override
|
||||
public boolean socket_protect(int socket) {
|
||||
EventReceiver p = parent;
|
||||
if (p != null)
|
||||
return p.socket_protect(socket);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pause_on_connection_timeout() {
|
||||
EventReceiver p = parent;
|
||||
if (p != null)
|
||||
return p.pause_on_connection_timeout();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void event(ClientAPI_Event event) {
|
||||
EventReceiver p = parent;
|
||||
if (p != null)
|
||||
p.event(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(ClientAPI_LogInfo loginfo) {
|
||||
EventReceiver p = parent;
|
||||
if (p != null)
|
||||
p.log(loginfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void external_pki_cert_request(ClientAPI_ExternalPKICertRequest req) {
|
||||
EventReceiver p = parent;
|
||||
if (p != null)
|
||||
p.external_pki_cert_request(req);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void external_pki_sign_request(ClientAPI_ExternalPKISignRequest req) {
|
||||
EventReceiver p = parent;
|
||||
if (p != null)
|
||||
p.external_pki_sign_request(req);
|
||||
}
|
||||
|
||||
// TunBuilderBase (C++ class) overrides
|
||||
|
||||
@Override
|
||||
public boolean tun_builder_new() {
|
||||
EventReceiver p = parent;
|
||||
if (p != null) {
|
||||
tun_builder = p.tun_builder_new();
|
||||
return tun_builder != null;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tun_builder_set_remote_address(String address, boolean ipv6) {
|
||||
TunBuilder tb = tun_builder;
|
||||
if (tb != null)
|
||||
return tb.tun_builder_set_remote_address(address, ipv6);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tun_builder_add_address(String address, int prefix_length, String gateway, boolean ipv6, boolean net30) {
|
||||
TunBuilder tb = tun_builder;
|
||||
if (tb != null)
|
||||
return tb.tun_builder_add_address(address, prefix_length, gateway, ipv6, net30);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tun_builder_reroute_gw(boolean ipv4, boolean ipv6, long flags) {
|
||||
TunBuilder tb = tun_builder;
|
||||
if (tb != null)
|
||||
return tb.tun_builder_reroute_gw(ipv4, ipv6, flags);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tun_builder_add_route(String address, int prefix_length, int metric, boolean ipv6) {
|
||||
TunBuilder tb = tun_builder;
|
||||
if (tb != null)
|
||||
return tb.tun_builder_add_route(address, prefix_length, ipv6);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tun_builder_exclude_route(String address, int prefix_length, int metric, boolean ipv6) {
|
||||
TunBuilder tb = tun_builder;
|
||||
if (tb != null)
|
||||
return tb.tun_builder_exclude_route(address, prefix_length, ipv6);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tun_builder_add_dns_server(String address, boolean ipv6) {
|
||||
TunBuilder tb = tun_builder;
|
||||
if (tb != null)
|
||||
return tb.tun_builder_add_dns_server(address, ipv6);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tun_builder_add_search_domain(String domain)
|
||||
{
|
||||
TunBuilder tb = tun_builder;
|
||||
if (tb != null)
|
||||
return tb.tun_builder_add_search_domain(domain);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tun_builder_set_mtu(int mtu) {
|
||||
TunBuilder tb = tun_builder;
|
||||
if (tb != null)
|
||||
return tb.tun_builder_set_mtu(mtu);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tun_builder_set_session_name(String name)
|
||||
{
|
||||
TunBuilder tb = tun_builder;
|
||||
if (tb != null)
|
||||
return tb.tun_builder_set_session_name(name);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int tun_builder_establish() {
|
||||
TunBuilder tb = tun_builder;
|
||||
if (tb != null)
|
||||
return tb.tun_builder_establish();
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tun_builder_teardown(boolean disconnect) {
|
||||
TunBuilder tb = tun_builder;
|
||||
if (tb != null)
|
||||
tb.tun_builder_teardown(disconnect);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// OpenVPN -- An application to securely tunnel IP networks
|
||||
// over a single port, with support for SSL/TLS-based
|
||||
// session authentication and key exchange,
|
||||
// packet encryption, packet authentication, and
|
||||
// packet compression.
|
||||
//
|
||||
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <jni.h>
|
||||
|
||||
#ifdef SWIGEXPORT
|
||||
#define EXPORT SWIGEXPORT
|
||||
#else
|
||||
#define EXPORT
|
||||
#endif
|
||||
|
||||
#ifndef OPENVPN_PACKAGE_ID
|
||||
#error OPENVPN_PACKAGE_ID must be defined
|
||||
#endif
|
||||
|
||||
#define MAKE_SYM2(pkg_id, suffix) Java_ ## pkg_id ## _CPUUsage_ ## suffix
|
||||
#define MAKE_SYM(pkg_id, suffix) MAKE_SYM2(pkg_id, suffix)
|
||||
|
||||
#define CPU_USAGE MAKE_SYM(OPENVPN_PACKAGE_ID, cpu_1usage)
|
||||
|
||||
extern "C" {
|
||||
jdouble CPU_USAGE(JNIEnv* env, jclass);
|
||||
};
|
||||
|
||||
EXPORT jdouble CPU_USAGE(JNIEnv* env, jclass)
|
||||
{
|
||||
char fnbuf[64];
|
||||
const pid_t pid = getpid();
|
||||
double ret = 0.0;
|
||||
|
||||
snprintf(fnbuf, sizeof(fnbuf), "/proc/%u/stat", (unsigned int)pid);
|
||||
FILE *fp = fopen(fnbuf, "r");
|
||||
if (fp)
|
||||
{
|
||||
double user = 0.0;
|
||||
double system = 0.0;
|
||||
if (fscanf(fp, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %lf %lf", &user, &system) == 2)
|
||||
ret = (user + system) / sysconf(_SC_CLK_TCK);
|
||||
fclose(fp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
// OpenVPN -- An application to securely tunnel IP networks
|
||||
// over a single port, with support for SSL/TLS-based
|
||||
// session authentication and key exchange,
|
||||
// packet encryption, packet authentication, and
|
||||
// packet compression.
|
||||
//
|
||||
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Native companion code for JellyBeanHack.java
|
||||
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
#include <jni.h>
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#ifdef SWIGEXPORT
|
||||
#define EXPORT SWIGEXPORT
|
||||
#else
|
||||
#define EXPORT
|
||||
#endif
|
||||
|
||||
#ifndef OPENVPN_PACKAGE_ID
|
||||
#error OPENVPN_PACKAGE_ID must be defined
|
||||
#endif
|
||||
|
||||
#define MAKE_SYM2(pkg_id, suffix) Java_ ## pkg_id ## _JellyBeanHack_ ## suffix
|
||||
#define MAKE_SYM(pkg_id, suffix) MAKE_SYM2(pkg_id, suffix)
|
||||
|
||||
#define RSA_SIGN_INIT MAKE_SYM(OPENVPN_PACKAGE_ID, rsa_1sign_1init)
|
||||
#define RSA_SIGN MAKE_SYM(OPENVPN_PACKAGE_ID, rsa_1sign)
|
||||
#define PKEY_RETAIN MAKE_SYM(OPENVPN_PACKAGE_ID, pkey_1retain)
|
||||
|
||||
extern "C" {
|
||||
jint RSA_SIGN_INIT(JNIEnv* env, jclass);
|
||||
jbyteArray RSA_SIGN(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef);
|
||||
void PKEY_RETAIN(JNIEnv* env, jclass, jint pkeyRef);
|
||||
};
|
||||
|
||||
typedef void *RSA;
|
||||
|
||||
enum {
|
||||
NID_md5_sha1=114,
|
||||
CRYPTO_LOCK_EVP_PKEY=10,
|
||||
};
|
||||
|
||||
struct EVP_PKEY
|
||||
{
|
||||
int type;
|
||||
int save_type;
|
||||
int references;
|
||||
void *ameth;
|
||||
void *engine;
|
||||
union {
|
||||
RSA *rsa;
|
||||
} pkey;
|
||||
};
|
||||
|
||||
typedef int (*RSA_size_func_t)(const RSA *);
|
||||
|
||||
typedef int (*RSA_sign_func_t)(int type, const unsigned char *m, unsigned int m_length,
|
||||
unsigned char *sigret, unsigned int *siglen, RSA *rsa);
|
||||
|
||||
typedef void (*ERR_print_errors_fp_func_t)(FILE *fp);
|
||||
|
||||
typedef int (*CRYPTO_add_lock_func_t)(int *pointer, int amount, int type, const char *file, int line);
|
||||
|
||||
static bool initialized;
|
||||
static RSA_size_func_t RSA_size;
|
||||
static RSA_sign_func_t RSA_sign;
|
||||
static ERR_print_errors_fp_func_t ERR_print_errors_fp;
|
||||
static CRYPTO_add_lock_func_t CRYPTO_add_lock;
|
||||
|
||||
inline bool callbacks_defined()
|
||||
{
|
||||
return RSA_size != NULL
|
||||
&& RSA_sign != NULL
|
||||
&& ERR_print_errors_fp != NULL
|
||||
&& CRYPTO_add_lock != NULL;
|
||||
}
|
||||
|
||||
EXPORT jint RSA_SIGN_INIT(JNIEnv* env, jclass)
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
void *handle = dlopen("libcrypto.so", RTLD_NOW);
|
||||
if (handle)
|
||||
{
|
||||
RSA_size = (RSA_size_func_t) dlsym(handle, "RSA_size");
|
||||
RSA_sign = (RSA_sign_func_t) dlsym(handle, "RSA_sign");
|
||||
ERR_print_errors_fp = (ERR_print_errors_fp_func_t) dlsym(handle, "ERR_print_errors_fp");
|
||||
CRYPTO_add_lock = (CRYPTO_add_lock_func_t) dlsym(handle, "CRYPTO_add_lock");
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
return callbacks_defined();
|
||||
}
|
||||
|
||||
static int jni_throw(JNIEnv* env, const char* className, const char* msg)
|
||||
{
|
||||
jclass exceptionClass = env->FindClass(className);
|
||||
|
||||
if (exceptionClass == NULL) {
|
||||
// ClassNotFoundException now pending
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (env->ThrowNew( exceptionClass, msg) != JNI_OK) {
|
||||
// an exception, most likely OOM, will now be pending
|
||||
return -1;
|
||||
}
|
||||
|
||||
env->DeleteLocalRef(exceptionClass);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT jbyteArray RSA_SIGN(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef)
|
||||
{
|
||||
if (!callbacks_defined())
|
||||
{
|
||||
jni_throw(env, "java/lang/NullPointerException", "rsa_sign: OpenSSL callbacks undefined");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
|
||||
if (pkey == NULL || from == NULL)
|
||||
{
|
||||
jni_throw(env, "java/lang/NullPointerException", "rsa_sign: from/pkey is NULL");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jbyte* data = env->GetByteArrayElements(from, NULL);
|
||||
if (data == NULL)
|
||||
{
|
||||
jni_throw(env, "java/lang/NullPointerException", "rsa_sign: data is NULL");
|
||||
return NULL;
|
||||
}
|
||||
int datalen = env->GetArrayLength(from);
|
||||
|
||||
unsigned int siglen;
|
||||
unsigned char* sigret = new unsigned char[(*RSA_size)(pkey->pkey.rsa)];
|
||||
|
||||
if ((*RSA_sign)(NID_md5_sha1, (unsigned char*) data, datalen,
|
||||
sigret, &siglen, pkey->pkey.rsa) <= 0)
|
||||
{
|
||||
jni_throw(env, "java/security/InvalidKeyException", "OpenSSL RSA_sign failed");
|
||||
(*ERR_print_errors_fp)(stderr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jbyteArray jb = env->NewByteArray(siglen);
|
||||
env->SetByteArrayRegion(jb, 0, siglen, (jbyte *)sigret);
|
||||
delete [] sigret;
|
||||
return jb;
|
||||
}
|
||||
|
||||
EXPORT void PKEY_RETAIN(JNIEnv* env, jclass, jint pkeyRef)
|
||||
{
|
||||
EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
|
||||
if (pkey && CRYPTO_add_lock)
|
||||
{
|
||||
const int newref = (*CRYPTO_add_lock)(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY, __FILE__, __LINE__);
|
||||
__android_log_print(ANDROID_LOG_DEBUG, "openvpn", "pkey_retain ref=%d", newref);
|
||||
}
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env bash
|
||||
# generate expire time in python: time.mktime((2012, 5, 1, 0, 0, 0, 0, 0, -1))
|
||||
# -DAPP_EXPIRE_TIME=1364796000 \
|
||||
set -e
|
||||
|
||||
if [ -z "$O3" ]; then
|
||||
echo O3 var must point to ovpn3 tree
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd $O3/core
|
||||
. vars/android-sdk-path
|
||||
cd javacli
|
||||
git clean -q -fXd .
|
||||
|
||||
if [ "$PKG" ]; then
|
||||
pkg=$PKG
|
||||
pkg_id_def="-DOPENVPN_PACKAGE_ID=${PKG//./_}"
|
||||
else
|
||||
pkg=net.openvpn.openvpn
|
||||
pkg_id_def="-DOPENVPN_PACKAGE_ID=net_openvpn_openvpn"
|
||||
fi
|
||||
echo PACKAGE $PKG
|
||||
|
||||
if [ "$PT_PROXY" = "1" ] && [ -d "$O3/common" ]; then
|
||||
common="-I$O3/common -DPRIVATE_TUNNEL_PROXY"
|
||||
else
|
||||
common=""
|
||||
fi
|
||||
|
||||
echo SWIG
|
||||
swig -c++ -java -package $pkg -I$O3/core/client -I$O3/core ovpncli.i
|
||||
|
||||
# fixme: removed "android" from TARGET list due to compile failures in Asio
|
||||
for TARGET in android-a8a android-a7a ; do
|
||||
|
||||
if [ "$DEBUG_BUILD" = "1" ]; then
|
||||
. ../vars/vars-${TARGET}-dbg
|
||||
vis1=""
|
||||
vis2=""
|
||||
opt2="$pkg_id_def $LIB_OPT_LEVEL"
|
||||
else
|
||||
. ../vars/vars-${TARGET}
|
||||
vis1="-fvisibility=hidden"
|
||||
vis2='-DSWIGEXPORT=__attribute__((visibility("default")))'
|
||||
opt2="$pkg_id_def -Os"
|
||||
fi
|
||||
|
||||
if [ "$OPENSSL" = "1" ]; then
|
||||
ssl_def="-DUSE_OPENSSL"
|
||||
ssl_inc="-I$DEP_DIR/openssl/openssl-$PLATFORM/include"
|
||||
ssl_lib="-lssl -lcrypto"
|
||||
ssl_libdir="-L$DEP_DIR/openssl/openssl-$PLATFORM/lib"
|
||||
else
|
||||
ssl_def="-DUSE_MBEDTLS"
|
||||
ssl_inc="-I$DEP_DIR/mbedtls/mbedtls-$PLATFORM/include"
|
||||
ssl_lib="-lmbedtls"
|
||||
ssl_libdir="-L$DEP_DIR/mbedtls/mbedtls-$PLATFORM/library"
|
||||
fi
|
||||
|
||||
echo CORE $ABI
|
||||
g++ \
|
||||
$CXX_COMPILER_FLAGS \
|
||||
$PLATFORM_FLAGS \
|
||||
$LIB_OPT_LEVEL $LIB_FPIC \
|
||||
-Wall -Wno-sign-compare -Wno-unused-parameter \
|
||||
-Wno-unused-local-typedefs \
|
||||
$vis1 \
|
||||
$ssl_def \
|
||||
-DUSE_ASIO \
|
||||
-DASIO_STANDALONE \
|
||||
-DASIO_NO_DEPRECATED \
|
||||
-DHAVE_LZ4 \
|
||||
-I$O3/core/client \
|
||||
-I$O3/core \
|
||||
$common \
|
||||
-I$DEP_DIR/asio/asio/include \
|
||||
$ssl_inc \
|
||||
-I$DEP_DIR/lz4/lz4-$PLATFORM/include \
|
||||
-c $O3/core/client/ovpncli.cpp
|
||||
|
||||
echo WRAP $ABI
|
||||
g++ \
|
||||
$CXX_COMPILER_FLAGS \
|
||||
$PLATFORM_FLAGS \
|
||||
$opt2 $LIB_FPIC \
|
||||
-fno-strict-aliasing \
|
||||
-Wall \
|
||||
$vis1 $vis2 \
|
||||
-I$O3/core/client \
|
||||
-I$O3/core \
|
||||
$common \
|
||||
$ssl_libdir \
|
||||
-L$DEP_DIR/lz4/lz4-$PLATFORM/lib \
|
||||
ovpncli_wrap.cxx \
|
||||
android/jellybean_hack.cpp \
|
||||
android/cpu.cpp \
|
||||
ovpncli.o \
|
||||
-o libovpncli.so \
|
||||
-shared -Wl,-soname,libovpncli.so \
|
||||
$ssl_lib \
|
||||
-llz4 \
|
||||
-llog
|
||||
|
||||
if [ "$DEBUG_BUILD" != "1" ]; then
|
||||
echo STRIP $ABI
|
||||
strip libovpncli.so
|
||||
fi
|
||||
|
||||
mkdir -p build/libs/$ABI
|
||||
mv libovpncli.so build/libs/$ABI/
|
||||
rm ovpncli.o
|
||||
done
|
||||
|
||||
mv ovpncli.java ovpncliJNI.java SWIGTYPE_*.java ClientAPI_*.java build/
|
||||
git clean -q -fX .
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Build OpenVPN 3 core on Linux as a callable module from Java:
|
||||
#
|
||||
# ./build-linux
|
||||
# java -Djava.library.path=. Main profile.ovpn
|
||||
|
||||
set -e
|
||||
|
||||
if [ -z "$O3" ]; then
|
||||
echo O3 var must point to ovpn3 tree
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TARGET=linux
|
||||
JINC="-I/usr/local/java/jdk1.7.0_55/include -I/usr/local/java/jdk1.7.0_55/include/linux"
|
||||
|
||||
cd $O3/core/javacli
|
||||
git clean -q -fXd .
|
||||
git clean -q -fd .
|
||||
|
||||
if [ "$DEBUG_BUILD" = "1" ]; then
|
||||
. $O3/core/vars/vars-${TARGET}-dbg
|
||||
vis1=""
|
||||
vis2=""
|
||||
opt2="$pkg_id_def $LIB_OPT_LEVEL"
|
||||
else
|
||||
. $O3/core/vars/vars-${TARGET}
|
||||
vis1="-fvisibility=hidden"
|
||||
vis2='-DSWIGEXPORT=__attribute__((visibility("default")))'
|
||||
opt2="$pkg_id_def -Os"
|
||||
fi
|
||||
|
||||
if [ "$OPENSSL" = "1" ]; then
|
||||
ssl_def="-DUSE_OPENSSL"
|
||||
ssl_inc="-I$DEP_DIR/openssl/openssl-$PLATFORM/include"
|
||||
ssl_lib="-lssl -lcrypto"
|
||||
ssl_libdir="-L$DEP_DIR/openssl/openssl-$PLATFORM/lib"
|
||||
else
|
||||
ssl_def="-DUSE_MBEDTLS"
|
||||
ssl_inc="-I$DEP_DIR/mbedtls/mbedtls-$PLATFORM/include"
|
||||
ssl_lib="-lmbedtls"
|
||||
ssl_libdir="-L$DEP_DIR/mbedtls/mbedtls-$PLATFORM/library"
|
||||
fi
|
||||
|
||||
echo SWIG
|
||||
swig -c++ -java -I$O3/core/client -I$O3/core ovpncli.i
|
||||
|
||||
echo JAVA
|
||||
javac *.java
|
||||
|
||||
echo CORE
|
||||
g++ \
|
||||
$CXX_COMPILER_FLAGS \
|
||||
$PLATFORM_FLAGS \
|
||||
$LIB_OPT_LEVEL $LIB_FPIC \
|
||||
-Wall -Wno-sign-compare -Wno-unused-parameter \
|
||||
-Wno-unused-local-typedefs \
|
||||
$vis1 \
|
||||
$ssl_def \
|
||||
-DUSE_ASIO \
|
||||
-DASIO_STANDALONE \
|
||||
-DASIO_NO_DEPRECATED \
|
||||
-DHAVE_LZ4 \
|
||||
-I$O3/core/client \
|
||||
-I$O3/core \
|
||||
-I$DEP_DIR/asio/asio/include \
|
||||
$ssl_inc \
|
||||
-I$DEP_DIR/lz4/lz4-$PLATFORM/include \
|
||||
-c $O3/core/client/ovpncli.cpp
|
||||
|
||||
echo WRAP
|
||||
g++ \
|
||||
$CXX_COMPILER_FLAGS \
|
||||
$PLATFORM_FLAGS \
|
||||
$opt2 $LIB_FPIC \
|
||||
-fno-strict-aliasing \
|
||||
-Wall \
|
||||
$vis1 $vis2 \
|
||||
-I$O3/core/client \
|
||||
-I$O3/core \
|
||||
$JINC \
|
||||
$ssl_libdir \
|
||||
-L$DEP_DIR/lz4/lz4-$PLATFORM/lib \
|
||||
ovpncli_wrap.cxx \
|
||||
ovpncli.o \
|
||||
-o libovpncli.so \
|
||||
-shared -Wl,-soname,libovpncli.so \
|
||||
$ssl_lib \
|
||||
-llz4
|
||||
|
||||
if [ "$DEBUG_BUILD" != "1" ]; then
|
||||
echo STRIP $ABI
|
||||
strip libovpncli.so
|
||||
fi
|
||||
@@ -0,0 +1,50 @@
|
||||
// SWIG interface file for OpenVPN client
|
||||
|
||||
// enable director feature for OpenVPNClientBase virtual method callbacks
|
||||
%module(directors="1") ovpncli
|
||||
%feature("director") OpenVPNClient;
|
||||
|
||||
%include "std_string.i" // for std::string typemaps
|
||||
%include "std_vector.i"
|
||||
|
||||
// top-level C++ implementation file
|
||||
%{
|
||||
#include "ovpncli.hpp"
|
||||
%}
|
||||
|
||||
// ignore ClientAPI::OpenVPNClient bases other than TunBuilderBase
|
||||
%ignore openvpn::ClientAPI::LogReceiver;
|
||||
|
||||
// modify exported C++ class names to incorporate their enclosing namespace
|
||||
%rename(ClientAPI_OpenVPNClient) OpenVPNClient;
|
||||
%rename(ClientAPI_TunBuilderBase) TunBuilderBase;
|
||||
%rename(ClientAPI_ExternalPKIBase) ExternalPKIBase;
|
||||
%rename(ClientAPI_ServerEntry) ServerEntry;
|
||||
%rename(ClientAPI_EvalConfig) EvalConfig;
|
||||
%rename(ClientAPI_ProvideCreds) ProvideCreds;
|
||||
%rename(ClientAPI_SessionToken) SessionToken;
|
||||
%rename(ClientAPI_DynamicChallenge) DynamicChallenge;
|
||||
%rename(ClientAPI_KeyValue) KeyValue;
|
||||
%rename(ClientAPI_Config) Config;
|
||||
%rename(ClientAPI_Event) Event;
|
||||
%rename(ClientAPI_ConnectionInfo) ConnectionInfo;
|
||||
%rename(ClientAPI_Status) Status;
|
||||
%rename(ClientAPI_LogInfo) LogInfo;
|
||||
%rename(ClientAPI_InterfaceStats) InterfaceStats;
|
||||
%rename(ClientAPI_TransportStats) TransportStats;
|
||||
%rename(ClientAPI_MergeConfig) MergeConfig;
|
||||
%rename(ClientAPI_ExternalPKIRequestBase) ExternalPKIRequestBase;
|
||||
%rename(ClientAPI_ExternalPKICertRequest) ExternalPKICertRequest;
|
||||
%rename(ClientAPI_ExternalPKISignRequest) ExternalPKISignRequest;
|
||||
%rename(ClientAPI_RemoteOverride) RemoteOverride;
|
||||
|
||||
// declare vectors
|
||||
namespace std {
|
||||
%template(ClientAPI_ServerEntryVector) vector<openvpn::ClientAPI::ServerEntry>;
|
||||
%template(ClientAPI_LLVector) vector<long long>;
|
||||
};
|
||||
|
||||
// interface to be bridged between C++ and target language
|
||||
%include "openvpn/pki/epkibase.hpp"
|
||||
%include "openvpn/tun/builder/base.hpp"
|
||||
%include "ovpncli.hpp"
|
||||
Reference in New Issue
Block a user