mirror of
https://github.com/deneraraujo/OpenVPNAdapter.git
synced 2026-04-24 00:00:05 +08:00
Merge commit '86cc97e55fe346502462284d2e636a2b3708163e' as 'Sources/OpenVPN3'
This commit is contained in:
@@ -0,0 +1,389 @@
|
||||
// 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-2018 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// kovpn crypto wrappers
|
||||
|
||||
#ifndef OPENVPN_KOVPN_KOCRYPTO_H
|
||||
#define OPENVPN_KOVPN_KOCRYPTO_H
|
||||
|
||||
#include <cstring> // for std::memset, std::memcpy
|
||||
#include <utility> // for std::move
|
||||
|
||||
#include <openvpn/common/size.hpp>
|
||||
#include <openvpn/common/exception.hpp>
|
||||
#include <openvpn/common/rc.hpp>
|
||||
#include <openvpn/frame/frame.hpp>
|
||||
#include <openvpn/crypto/cryptodc.hpp>
|
||||
#include <openvpn/crypto/bs64_data_limit.hpp>
|
||||
#include <openvpn/kovpn/kovpn.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace KoRekey {
|
||||
|
||||
OPENVPN_EXCEPTION(korekey_error);
|
||||
|
||||
struct Info {
|
||||
Info() {}
|
||||
|
||||
Info(const CryptoDCContext::Ptr& dc_context_delegate_arg,
|
||||
const unsigned int key_id_arg,
|
||||
const Frame::Ptr& frame_arg)
|
||||
: dc_context_delegate(dc_context_delegate_arg),
|
||||
key_id(key_id_arg),
|
||||
frame(frame_arg)
|
||||
{
|
||||
}
|
||||
|
||||
CryptoDCContext::Ptr dc_context_delegate;
|
||||
CompressContext comp_ctx;
|
||||
unsigned int key_id = 0;
|
||||
int remote_peer_id = -1;
|
||||
bool tcp_linear = false;
|
||||
StaticKey encrypt_cipher;
|
||||
StaticKey encrypt_hmac;
|
||||
StaticKey decrypt_cipher;
|
||||
StaticKey decrypt_hmac;
|
||||
Frame::Ptr frame;
|
||||
};
|
||||
|
||||
class Key
|
||||
{
|
||||
// noncopyable because of "opk.primary = &key" below
|
||||
Key(const Key&) = delete;
|
||||
Key& operator=(const Key&) = delete;
|
||||
|
||||
public:
|
||||
static void validate(const CryptoAlgs::Type cipher,
|
||||
const CryptoAlgs::Type digest)
|
||||
{
|
||||
const CryptoAlgs::Alg& calg = CryptoAlgs::get(cipher);
|
||||
const CryptoAlgs::Alg& halg = CryptoAlgs::get(digest);
|
||||
|
||||
switch (cipher)
|
||||
{
|
||||
case CryptoAlgs::AES_128_GCM:
|
||||
case CryptoAlgs::AES_192_GCM:
|
||||
case CryptoAlgs::AES_256_GCM:
|
||||
case CryptoAlgs::AES_128_CBC:
|
||||
case CryptoAlgs::AES_192_CBC:
|
||||
case CryptoAlgs::AES_256_CBC:
|
||||
case CryptoAlgs::BF_CBC:
|
||||
break;
|
||||
default:
|
||||
OPENVPN_THROW(korekey_error, "cipher alg " << calg.name() << " is not currently supported by kovpn");
|
||||
}
|
||||
|
||||
if (calg.mode() == CryptoAlgs::CBC_HMAC)
|
||||
{
|
||||
switch (digest)
|
||||
{
|
||||
case CryptoAlgs::SHA1:
|
||||
case CryptoAlgs::SHA256:
|
||||
break;
|
||||
default:
|
||||
OPENVPN_THROW(korekey_error, "HMAC alg " << halg.name() << " is not currently supported by kovpn");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Key(const CryptoDCInstance::RekeyType rktype,
|
||||
const Info& rkinfo, // must remain in scope for duration of Key lifetime
|
||||
const int peer_id,
|
||||
const bool verbose)
|
||||
{
|
||||
std::memset(&opk, 0, sizeof(opk));
|
||||
|
||||
// set peer ID
|
||||
opk.peer_id = peer_id;
|
||||
|
||||
// set rekey op
|
||||
bool new_key = false;
|
||||
bool secondary_key = false; // only relevant for non-deactivate ops to secondary
|
||||
switch (rktype)
|
||||
{
|
||||
case CryptoDCInstance::ACTIVATE_PRIMARY:
|
||||
{
|
||||
new_key = true;
|
||||
opk.op = OVPN_KEYS_PRIMARY_ONLY;
|
||||
break;
|
||||
}
|
||||
case CryptoDCInstance::ACTIVATE_PRIMARY_MOVE:
|
||||
{
|
||||
new_key = true;
|
||||
opk.op = OVPN_KEYS_PRIMARY_ASSIGN_MOVE;
|
||||
break;
|
||||
}
|
||||
case CryptoDCInstance::NEW_SECONDARY:
|
||||
{
|
||||
new_key = true;
|
||||
secondary_key = true;
|
||||
opk.op = OVPN_KEYS_SECONDARY_ONLY;
|
||||
break;
|
||||
}
|
||||
case CryptoDCInstance::PRIMARY_SECONDARY_SWAP:
|
||||
{
|
||||
opk.op = OVPN_KEYS_PRIMARY_SECONDARY_SWAP;
|
||||
break;
|
||||
}
|
||||
case CryptoDCInstance::DEACTIVATE_SECONDARY:
|
||||
{
|
||||
opk.op = OVPN_KEYS_SECONDARY_ONLY;
|
||||
break;
|
||||
}
|
||||
case CryptoDCInstance::DEACTIVATE_ALL:
|
||||
{
|
||||
opk.op = OVPN_KEYS_BOTH;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
OPENVPN_THROW(korekey_error, "unrecognized rekey type=" << (int)rktype);
|
||||
}
|
||||
|
||||
if (new_key)
|
||||
{
|
||||
const CryptoDCContext::Info ci = rkinfo.dc_context_delegate->crypto_info();
|
||||
const CryptoAlgs::Alg& calg = CryptoAlgs::get(ci.cipher_alg);
|
||||
|
||||
// set crypto family
|
||||
switch (calg.mode())
|
||||
{
|
||||
case CryptoAlgs::CBC_HMAC:
|
||||
opk.crypto_family = OVPN_CRYPTO_FAMILY_CBC_HMAC;
|
||||
break;
|
||||
case CryptoAlgs::AEAD:
|
||||
opk.crypto_family = OVPN_CRYPTO_FAMILY_AEAD;
|
||||
break;
|
||||
default:
|
||||
opk.crypto_family = OVPN_CRYPTO_FAMILY_UNDEF;
|
||||
break;
|
||||
}
|
||||
|
||||
std::memset(&key, 0, sizeof(key));
|
||||
key.key_id = rkinfo.key_id;
|
||||
key.remote_peer_id = rkinfo.remote_peer_id;
|
||||
|
||||
switch (ci.cipher_alg)
|
||||
{
|
||||
case CryptoAlgs::AES_128_GCM:
|
||||
key.cipher_alg = OVPN_ALG_AES_GCM;
|
||||
key.encrypt.cipher_key_size = 128 / 8;
|
||||
break;
|
||||
case CryptoAlgs::AES_192_GCM:
|
||||
key.cipher_alg = OVPN_ALG_AES_GCM;
|
||||
key.encrypt.cipher_key_size = 192 / 8;
|
||||
break;
|
||||
case CryptoAlgs::AES_256_GCM:
|
||||
key.cipher_alg = OVPN_ALG_AES_GCM;
|
||||
key.encrypt.cipher_key_size = 256 / 8;
|
||||
break;
|
||||
case CryptoAlgs::AES_128_CBC:
|
||||
key.cipher_alg = OVPN_ALG_AES_CBC;
|
||||
key.encrypt.cipher_key_size = 128 / 8;
|
||||
break;
|
||||
case CryptoAlgs::AES_192_CBC:
|
||||
key.cipher_alg = OVPN_ALG_AES_CBC;
|
||||
key.encrypt.cipher_key_size = 192 / 8;
|
||||
break;
|
||||
case CryptoAlgs::AES_256_CBC:
|
||||
key.cipher_alg = OVPN_ALG_AES_CBC;
|
||||
key.encrypt.cipher_key_size = 256 / 8;
|
||||
break;
|
||||
case CryptoAlgs::BF_CBC:
|
||||
key.cipher_alg = OVPN_ALG_BF_CBC;
|
||||
key.encrypt.cipher_key_size = 128 / 8;
|
||||
|
||||
// special data limits for 64-bit block-size ciphers (CVE-2016-6329)
|
||||
key.encrypt.data_limit = key.decrypt.data_limit = OPENVPN_BS64_DATA_LIMIT;
|
||||
break;
|
||||
default:
|
||||
key.cipher_alg = OVPN_ALG_UNDEF;
|
||||
break;
|
||||
}
|
||||
key.decrypt.cipher_key_size = key.encrypt.cipher_key_size;
|
||||
|
||||
// make sure that chosen cipher/family is supported
|
||||
if (opk.crypto_family == OVPN_CRYPTO_FAMILY_UNDEF
|
||||
|| key.cipher_alg == OVPN_ALG_UNDEF)
|
||||
OPENVPN_THROW(korekey_error, "cipher alg " << calg.name() << " is not currently supported by kovpn");
|
||||
|
||||
// set cipher keys
|
||||
key.encrypt.cipher_key = verify_key("cipher encrypt",
|
||||
rkinfo.encrypt_cipher,
|
||||
key.encrypt.cipher_key_size);
|
||||
key.decrypt.cipher_key = verify_key("cipher decrypt",
|
||||
rkinfo.decrypt_cipher,
|
||||
key.decrypt.cipher_key_size);
|
||||
|
||||
switch (calg.mode())
|
||||
{
|
||||
case CryptoAlgs::CBC_HMAC:
|
||||
{
|
||||
// if CBC mode, process HMAC digest
|
||||
const CryptoAlgs::Alg& halg = CryptoAlgs::get(ci.hmac_alg);
|
||||
switch (ci.hmac_alg)
|
||||
{
|
||||
case CryptoAlgs::SHA1:
|
||||
key.hmac_alg = OVPN_ALG_HMAC_SHA1;
|
||||
break;
|
||||
case CryptoAlgs::SHA256:
|
||||
key.hmac_alg = OVPN_ALG_HMAC_SHA256;
|
||||
break;
|
||||
default:
|
||||
OPENVPN_THROW(korekey_error, "HMAC alg " << halg.name() << " is not currently supported by kovpn");
|
||||
}
|
||||
key.encrypt.hmac_key_size = halg.size();
|
||||
key.decrypt.hmac_key_size = key.encrypt.hmac_key_size;
|
||||
|
||||
// set hmac keys
|
||||
key.encrypt.hmac_key = verify_key("hmac encrypt",
|
||||
rkinfo.encrypt_hmac,
|
||||
key.encrypt.hmac_key_size);
|
||||
key.decrypt.hmac_key = verify_key("hmac decrypt",
|
||||
rkinfo.decrypt_hmac,
|
||||
key.decrypt.hmac_key_size);
|
||||
|
||||
// handle compression V1
|
||||
switch (rkinfo.comp_ctx.type())
|
||||
{
|
||||
case CompressContext::LZO_STUB:
|
||||
key.compress.alg = OVPN_COMP_NONE;
|
||||
key.compress.swap = false;
|
||||
break;
|
||||
case CompressContext::COMP_STUB:
|
||||
key.compress.alg = OVPN_COMP_NONE;
|
||||
key.compress.swap = true;
|
||||
break;
|
||||
case CompressContext::LZ4:
|
||||
key.compress.alg = OVPN_COMP_LZ4;
|
||||
key.compress.swap = true;
|
||||
break;
|
||||
default:
|
||||
OPENVPN_THROW(korekey_error, "Compression alg " << rkinfo.comp_ctx.str() << " is not supported by kovpn in CBC/HMAC mode");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CryptoAlgs::AEAD:
|
||||
{
|
||||
// if AEAD mode, copy nonce tail from the HMAC key material
|
||||
set_nonce_tail("AEAD nonce tail encrypt",
|
||||
key.encrypt.nonce_tail,
|
||||
sizeof(key.encrypt.nonce_tail),
|
||||
rkinfo.encrypt_hmac);
|
||||
set_nonce_tail("AEAD nonce tail decrypt",
|
||||
key.decrypt.nonce_tail,
|
||||
sizeof(key.decrypt.nonce_tail),
|
||||
rkinfo.decrypt_hmac);
|
||||
|
||||
// handle compression V2
|
||||
switch (rkinfo.comp_ctx.type())
|
||||
{
|
||||
case CompressContext::COMP_STUBv2:
|
||||
key.compress.alg = OVPN_COMP_NONE;
|
||||
break;
|
||||
case CompressContext::LZ4v2:
|
||||
key.compress.alg = OVPN_COMP_LZ4;
|
||||
break;
|
||||
default:
|
||||
OPENVPN_THROW(korekey_error, "Compression alg " << rkinfo.comp_ctx.str() << " is not supported by kovpn in AEAD mode");
|
||||
}
|
||||
key.compress.swap = false;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// should have been caught above
|
||||
throw korekey_error("internal error");
|
||||
}
|
||||
}
|
||||
|
||||
// handle compression
|
||||
key.compress.asym = rkinfo.comp_ctx.asym();
|
||||
key.compress.max_decompress_size = (*rkinfo.frame)[Frame::DECOMPRESS_WORK].payload();
|
||||
|
||||
// handle TCP linear
|
||||
key.tcp_linear = rkinfo.tcp_linear;
|
||||
|
||||
if (verbose)
|
||||
OPENVPN_LOG("KOREKEY"
|
||||
<< " op=" << int(rktype) << '/' << opk.op
|
||||
<< " rpid=" << key.remote_peer_id
|
||||
<< " pri=" << key.key_id
|
||||
<< " cipher=" << key.cipher_alg
|
||||
<< "[e=" << render_hex(key.encrypt.cipher_key, 8)
|
||||
<< " d=" << render_hex(key.decrypt.cipher_key, 8) << ']'
|
||||
<< " hmac=" << key.hmac_alg
|
||||
<< "[e=" << render_hex(key.encrypt.hmac_key, 8)
|
||||
<< " d=" << render_hex(key.decrypt.hmac_key, 8) << ']'
|
||||
<< " comp=" << key.compress.alg
|
||||
<< " swap=" << key.compress.swap
|
||||
<< " asym=" << key.compress.asym
|
||||
<< " tcp_linear=" << key.tcp_linear
|
||||
<< " dl=[e=" << key.encrypt.data_limit
|
||||
<< " d=" << key.decrypt.data_limit << ']');
|
||||
|
||||
// set key
|
||||
if (secondary_key)
|
||||
opk.secondary = &key;
|
||||
else
|
||||
opk.primary = &key;
|
||||
}
|
||||
else if (verbose)
|
||||
{
|
||||
OPENVPN_LOG("KOREKEY" << " op=" << int(rktype) << '/' << opk.op);
|
||||
}
|
||||
}
|
||||
|
||||
const struct ovpn_peer_keys_reset *operator()() const
|
||||
{
|
||||
return &opk;
|
||||
}
|
||||
|
||||
private:
|
||||
const unsigned char *verify_key(const char *title, const StaticKey& sk, const size_t size_required)
|
||||
{
|
||||
if (sk.size() < size_required)
|
||||
OPENVPN_THROW(korekey_error, title << ": insufficient key material, provided=" << sk.size() << " required=" << size_required);
|
||||
return sk.data();
|
||||
}
|
||||
|
||||
void set_nonce_tail(const char *title, unsigned char *dest, const size_t dest_size, const StaticKey& src)
|
||||
{
|
||||
const int NONCE_TAIL_SIZE = CryptoAlgs::AEAD_NONCE_TAIL_SIZE;
|
||||
|
||||
const unsigned char *k = verify_key(title, src, NONCE_TAIL_SIZE);
|
||||
if (dest_size < NONCE_TAIL_SIZE)
|
||||
OPENVPN_THROW(korekey_error, title << ": cannot set");
|
||||
std::memcpy(dest, k, NONCE_TAIL_SIZE);
|
||||
|
||||
// if dest is larger than NONCE_TAIL_SIZE, zero remaining bytes
|
||||
if (dest_size > NONCE_TAIL_SIZE)
|
||||
std::memset(dest + NONCE_TAIL_SIZE, 0, dest_size - NONCE_TAIL_SIZE);
|
||||
}
|
||||
|
||||
struct ovpn_peer_keys_reset opk;
|
||||
struct ovpn_key_config key;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,391 @@
|
||||
// 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-2018 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// OpenVPN 3 kovpn-based tun interface
|
||||
|
||||
#ifndef OPENVPN_KOVPN_KODEV_H
|
||||
#define OPENVPN_KOVPN_KODEV_H
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <string>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include <openvpn/common/exception.hpp>
|
||||
#include <openvpn/common/scoped_fd.hpp>
|
||||
#include <openvpn/common/to_string.hpp>
|
||||
#include <openvpn/common/strerror.hpp>
|
||||
#include <openvpn/common/valgrind.hpp>
|
||||
#include <openvpn/time/timestr.hpp>
|
||||
#include <openvpn/log/sessionstats.hpp>
|
||||
#include <openvpn/tun/tunio.hpp>
|
||||
#include <openvpn/kovpn/kovpn.hpp>
|
||||
#include <openvpn/kovpn/koroute.hpp>
|
||||
#include <openvpn/kovpn/kostats.hpp>
|
||||
#include <openvpn/linux/procfs.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace KoTun {
|
||||
|
||||
OPENVPN_EXCEPTION(kotun_error);
|
||||
|
||||
struct DevConf
|
||||
{
|
||||
DevConf()
|
||||
{
|
||||
std::memset(&dc, 0, sizeof(dc));
|
||||
}
|
||||
|
||||
void set_dev_name(const std::string& name)
|
||||
{
|
||||
if (name.length() < IFNAMSIZ)
|
||||
::strcpy(dc.dev_name, name.c_str());
|
||||
else
|
||||
OPENVPN_THROW(kotun_error, "ovpn dev name too long");
|
||||
}
|
||||
|
||||
struct ovpn_dev_init dc;
|
||||
};
|
||||
|
||||
// kovpn API methods
|
||||
namespace API {
|
||||
|
||||
// Attach UDP socket to ovpn instance
|
||||
inline void socket_attach_udp(const int kovpn_fd,
|
||||
const int sock_fd)
|
||||
{
|
||||
struct ovpn_socket_attach_udp asock;
|
||||
asock.fd = sock_fd;
|
||||
if (::ioctl(kovpn_fd, OVPN_SOCKET_ATTACH_UDP, &asock) < 0)
|
||||
{
|
||||
const int eno = errno;
|
||||
OPENVPN_THROW(kotun_error, "OVPN_SOCKET_ATTACH_UDP failed, errno=" << eno << ' ' << KovpnStats::errstr(eno));
|
||||
}
|
||||
}
|
||||
|
||||
// New UDP client
|
||||
inline int peer_new_udp_client(const int kovpn_fd,
|
||||
int fd,
|
||||
const __u64 notify_per,
|
||||
const unsigned int notify_seconds)
|
||||
{
|
||||
int peer_id = -1;
|
||||
|
||||
// attach UDP socket fd
|
||||
{
|
||||
struct ovpn_socket_attach_udp asock;
|
||||
asock.fd = fd;
|
||||
if (::ioctl(kovpn_fd, OVPN_SOCKET_ATTACH_UDP, &asock) < 0)
|
||||
{
|
||||
const int eno = errno;
|
||||
OPENVPN_THROW(kotun_error, "OVPN_SOCKET_ATTACH_UDP failed, errno=" << eno << ' ' << KovpnStats::errstr(eno));
|
||||
}
|
||||
}
|
||||
|
||||
// get a new Peer ID
|
||||
{
|
||||
struct ovpn_peer_new opn;
|
||||
opn.peer_float = OVPN_PF_DISABLED;
|
||||
opn.ovpn_file_bind = true;
|
||||
opn.notify_per = notify_per;
|
||||
opn.notify_seconds = notify_seconds;
|
||||
peer_id = ::ioctl(kovpn_fd, OVPN_PEER_NEW, &opn);
|
||||
if (peer_id < 0)
|
||||
{
|
||||
const int eno = errno;
|
||||
OPENVPN_THROW(kotun_error, "OVPN_PEER_NEW failed, errno=" << eno << ' ' << KovpnStats::errstr(eno));
|
||||
}
|
||||
}
|
||||
|
||||
// set up endpoints for peer
|
||||
{
|
||||
struct ovpn_peer_sockaddr_reset psr;
|
||||
std::memset(&psr, 0, sizeof(psr));
|
||||
psr.peer_id = peer_id;
|
||||
psr.fd = fd;
|
||||
if (::ioctl(kovpn_fd, OVPN_PEER_SOCKADDR_RESET, &psr) < 0)
|
||||
{
|
||||
const int eno = errno;
|
||||
OPENVPN_THROW(kotun_error, "OVPN_PEER_SOCKADDR_RESET failed, errno=" << eno << ' ' << KovpnStats::errstr(eno));
|
||||
}
|
||||
}
|
||||
|
||||
return peer_id;
|
||||
}
|
||||
|
||||
// Send explicit-exit-notify message to peer
|
||||
inline void peer_xmit_explicit_exit_notify(const int kovpn_fd,
|
||||
const int peer_id)
|
||||
{
|
||||
if (::ioctl(kovpn_fd, OVPN_PEER_XMIT_EXPLICIT_EXIT_NOTIFY, peer_id) < 0)
|
||||
{
|
||||
const int eno = errno;
|
||||
OPENVPN_LOG("kotun: OVPN_PEER_XMIT_EXPLICIT_EXIT_NOTIFY failed, id=" << peer_id << " errno=" << eno << ' ' << KovpnStats::errstr(eno));
|
||||
}
|
||||
}
|
||||
|
||||
// Set peer crypto keys
|
||||
inline void peer_keys_reset(const int kovpn_fd,
|
||||
const struct ovpn_peer_keys_reset *opk)
|
||||
{
|
||||
if (::ioctl(kovpn_fd, OVPN_PEER_KEYS_RESET, opk) < 0)
|
||||
{
|
||||
const int eno = errno;
|
||||
OPENVPN_THROW(kotun_error, "OVPN_PEER_KEYS_RESET failed, errno=" << eno << ' ' << KovpnStats::errstr(eno));
|
||||
}
|
||||
}
|
||||
|
||||
// Set keepalive
|
||||
inline void peer_set_keepalive(const int kovpn_fd,
|
||||
const struct ovpn_peer_keepalive *ka)
|
||||
{
|
||||
if (::ioctl(kovpn_fd, OVPN_PEER_KEEPALIVE, ka) < 0)
|
||||
{
|
||||
const int eno = errno;
|
||||
OPENVPN_THROW(kotun_error, "OVPN_PEER_KEEPALIVE failed, errno=" << eno << ' ' << KovpnStats::errstr(eno));
|
||||
}
|
||||
}
|
||||
|
||||
// Add routes
|
||||
inline void peer_add_routes(const int kovpn_fd,
|
||||
const int peer_id,
|
||||
const std::vector<IP::Route>& rtvec)
|
||||
{
|
||||
std::unique_ptr<struct ovpn_route[]> routes(KoRoute::from_routes(rtvec));
|
||||
struct ovpn_peer_routes_add r;
|
||||
r.peer_id = peer_id;
|
||||
r.usurp = true;
|
||||
r.n_routes = rtvec.size();
|
||||
r.routes = routes.get();
|
||||
if (::ioctl(kovpn_fd, OVPN_PEER_ROUTES_ADD, &r) < 0)
|
||||
{
|
||||
const int eno = errno;
|
||||
OPENVPN_THROW(kotun_error, "OVPN_PEER_ROUTES_ADD failed, errno=" << eno << ' ' << KovpnStats::errstr(eno));
|
||||
}
|
||||
}
|
||||
|
||||
// Get status info
|
||||
inline bool peer_get_status(const int kovpn_fd,
|
||||
const struct ovpn_peer_status* ops)
|
||||
{
|
||||
if (::ioctl(kovpn_fd, OVPN_PEER_STATUS, ops) >= 0)
|
||||
{
|
||||
OPENVPN_MAKE_MEM_DEFINED(ops, sizeof(*ops));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int eno = errno;
|
||||
OPENVPN_LOG("kotun: OVPN_PEER_STATUS failed, errno=" << eno << ' ' << KovpnStats::errstr(eno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PacketFrom
|
||||
{
|
||||
typedef std::unique_ptr<PacketFrom> SPtr;
|
||||
BufferAllocated buf;
|
||||
};
|
||||
|
||||
class KovpnBase
|
||||
{
|
||||
public:
|
||||
static ScopedFD open_kovpn(DevConf& devconf,
|
||||
KovpnStats* kovpn_stats,
|
||||
bool* first)
|
||||
{
|
||||
if (first)
|
||||
*first = false;
|
||||
|
||||
// Open kovpn device
|
||||
static const char node[] = "/dev/net/ovpn";
|
||||
ScopedFD fd(open(node, O_RDWR));
|
||||
if (!fd.defined())
|
||||
{
|
||||
const int eno = errno;
|
||||
OPENVPN_THROW(kotun_error, "error opening ovpn tunnel device " << node << ": " << strerror_str(eno));
|
||||
}
|
||||
|
||||
// Check kovpn version
|
||||
const int ver_packed = ::ioctl(fd(), OVPN_GET_VERSION, nullptr);
|
||||
if (ver_packed < 0)
|
||||
OPENVPN_THROW(kotun_error, "OVPN_GET_VERSION failed");
|
||||
if (ver_major(ver_packed) != OVPN_VER_MAJOR
|
||||
|| ver_minor(ver_packed) != OVPN_VER_MINOR)
|
||||
OPENVPN_THROW(kotun_error, "version mismatch, pg=" << ver_string() << " installed=" << ver_string(ver_packed));
|
||||
|
||||
// Configure tun
|
||||
const int status = ::ioctl(fd(), OVPN_DEV_INIT, &devconf.dc);
|
||||
if (status < 0)
|
||||
{
|
||||
const int eno = errno;
|
||||
OPENVPN_THROW(kotun_error, "OVPN_DEV_INIT failed: " << KovpnStats::errstr(eno));
|
||||
}
|
||||
|
||||
if (devconf.dc.expire)
|
||||
OPENVPN_LOG("NOTE: this evaluation build expires on " << date_time(devconf.dc.expire));
|
||||
|
||||
if (status == 1)
|
||||
{
|
||||
if (kovpn_stats)
|
||||
kovpn_stats->set_fd(fd());
|
||||
if (first)
|
||||
*first = true;
|
||||
OPENVPN_LOG("KVER pg=" << ver_string() << " installed=" << ver_string(ver_packed));
|
||||
OPENVPN_LOG("IE_NAT=" << devconf.dc.ie_nat);
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void set_rps_xps(const std::string& dev_name, const unsigned int dev_queue_index, Stop* async_stop)
|
||||
{
|
||||
// set RPS/XPS on iface
|
||||
ProcFS::write_sys(fmt_qfn(dev_name, "rx", dev_queue_index, "rps_cpus"), "ffffffff\n", async_stop);
|
||||
ProcFS::write_sys(fmt_qfn(dev_name, "rx", dev_queue_index, "rps_cpus"), "ffffffff\n", async_stop);
|
||||
ProcFS::write_sys(fmt_qfn(dev_name, "rx", dev_queue_index, "rps_flow_cnt"), "1024\n", async_stop);
|
||||
ProcFS::write_sys(fmt_qfn(dev_name, "tx", dev_queue_index, "xps_cpus"), "0\n", async_stop);
|
||||
}
|
||||
|
||||
static void disable_reverse_path_filter(const std::string& dev_name, Stop* async_stop)
|
||||
{
|
||||
// disable reverse path filter on iface
|
||||
IPv4ReversePathFilter::write(dev_name, 0, async_stop);
|
||||
}
|
||||
|
||||
protected:
|
||||
static int ver_major(const int ver_packed)
|
||||
{
|
||||
return (ver_packed >> 16) & 0xFF;
|
||||
}
|
||||
|
||||
static int ver_minor(const int ver_packed)
|
||||
{
|
||||
return (ver_packed >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
static int ver_build(const int ver_packed)
|
||||
{
|
||||
return ver_packed & 0xFF;
|
||||
}
|
||||
|
||||
static std::string ver_string(const int major, const int minor, const int build)
|
||||
{
|
||||
return std::to_string(major) + '.' + std::to_string(minor) + '.' + std::to_string(build);
|
||||
}
|
||||
|
||||
static std::string ver_string(const int ver_packed)
|
||||
{
|
||||
return ver_string(ver_major(ver_packed), ver_minor(ver_packed), ver_build(ver_packed));
|
||||
}
|
||||
|
||||
static std::string ver_string()
|
||||
{
|
||||
return ver_string(OVPN_VER_MAJOR, OVPN_VER_MINOR, OVPN_VER_BUILD);
|
||||
}
|
||||
|
||||
static std::string fmt_qfn(const std::string& dev, const std::string& type, int qnum, const std::string& bn)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "/sys/class/net/" << dev << "/queues/" << type << "-" << qnum << '/' << bn;
|
||||
return os.str();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ReadHandler>
|
||||
struct TunClient : public TunIO<ReadHandler, PacketFrom, openvpn_io::posix::stream_descriptor>, public virtual KovpnBase
|
||||
{
|
||||
typedef TunIO<ReadHandler, PacketFrom, openvpn_io::posix::stream_descriptor> Base;
|
||||
typedef RCPtr<TunClient> Ptr;
|
||||
|
||||
// constructed by start() in in koudp.c/kotcp.c
|
||||
TunClient(openvpn_io::io_context& io_context,
|
||||
DevConf& devconf,
|
||||
ReadHandler read_handler,
|
||||
const Frame::Ptr& frame,
|
||||
KovpnStats* kovpn_stats, // not persisted
|
||||
bool *first)
|
||||
: Base(read_handler, frame, SessionStats::Ptr())
|
||||
{
|
||||
ScopedFD fd(open_kovpn(devconf, kovpn_stats, first));
|
||||
Base::name_ = devconf.dc.dev_name;
|
||||
Base::stream = new openvpn_io::posix::stream_descriptor(io_context, fd.release());
|
||||
}
|
||||
|
||||
// Attach UDP socket to ovpn instance
|
||||
void socket_attach_udp(const int sock_fd)
|
||||
{
|
||||
API::socket_attach_udp(native_handle(), sock_fd);
|
||||
}
|
||||
|
||||
// New UDP client (used by dcocli)
|
||||
int peer_new_udp_client(int fd,
|
||||
const __u64 notify_per,
|
||||
const unsigned int notify_seconds)
|
||||
{
|
||||
return API::peer_new_udp_client(native_handle(), fd, notify_per, notify_seconds);
|
||||
}
|
||||
|
||||
// Add routes (used by dcocli)
|
||||
void peer_add_routes(const int peer_id,
|
||||
const std::vector<IP::Route>& rtvec)
|
||||
{
|
||||
API::peer_add_routes(native_handle(), peer_id, rtvec);
|
||||
}
|
||||
|
||||
// Send explicit-exit-notify message to peer
|
||||
void peer_xmit_explicit_exit_notify(const int peer_id)
|
||||
{
|
||||
API::peer_xmit_explicit_exit_notify(native_handle(), peer_id);
|
||||
}
|
||||
|
||||
// Set peer crypto keys
|
||||
void peer_keys_reset(const struct ovpn_peer_keys_reset *opk)
|
||||
{
|
||||
API::peer_keys_reset(native_handle(), opk);
|
||||
}
|
||||
|
||||
// Set keepalive
|
||||
void peer_set_keepalive(const struct ovpn_peer_keepalive *ka)
|
||||
{
|
||||
API::peer_set_keepalive(native_handle(), ka);
|
||||
}
|
||||
|
||||
// Get status info
|
||||
bool peer_get_status(struct ovpn_peer_status* ops)
|
||||
{
|
||||
return API::peer_get_status(native_handle(), ops);
|
||||
}
|
||||
|
||||
// Return kovpn fd
|
||||
int native_handle() const
|
||||
{
|
||||
return Base::stream->native_handle();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,195 @@
|
||||
// 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-2018 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// OpenVPN 3 wrapper for kovpn crypto
|
||||
|
||||
#ifndef OPENVPN_KOVPN_KOREKEY_H
|
||||
#define OPENVPN_KOVPN_KOREKEY_H
|
||||
|
||||
#include <openvpn/kovpn/kocrypto.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace KoRekey {
|
||||
|
||||
class Receiver : public virtual RC<thread_unsafe_refcount>
|
||||
{
|
||||
public:
|
||||
typedef RCPtr<Receiver> Ptr;
|
||||
|
||||
virtual void rekey(const CryptoDCInstance::RekeyType type,
|
||||
const Info& info) = 0;
|
||||
|
||||
virtual void explicit_exit_notify() {}
|
||||
};
|
||||
|
||||
class Instance : public CryptoDCInstance
|
||||
{
|
||||
public:
|
||||
Instance(const Receiver::Ptr& rcv_arg,
|
||||
const CryptoDCContext::Ptr& dc_context_delegate,
|
||||
const unsigned int key_id,
|
||||
const Frame::Ptr& frame)
|
||||
: rcv(rcv_arg),
|
||||
info(dc_context_delegate, key_id, frame)
|
||||
{
|
||||
}
|
||||
|
||||
// Initialization
|
||||
|
||||
virtual unsigned int defined() const override
|
||||
{
|
||||
return CIPHER_DEFINED|HMAC_DEFINED|EXPLICIT_EXIT_NOTIFY_DEFINED;
|
||||
}
|
||||
|
||||
virtual void init_cipher(StaticKey&& encrypt_key,
|
||||
StaticKey&& decrypt_key) override
|
||||
{
|
||||
info.encrypt_cipher = std::move(encrypt_key);
|
||||
info.decrypt_cipher = std::move(decrypt_key);
|
||||
}
|
||||
|
||||
virtual void init_hmac(StaticKey&& encrypt_key,
|
||||
StaticKey&& decrypt_key) override
|
||||
{
|
||||
info.encrypt_hmac = std::move(encrypt_key);
|
||||
info.decrypt_hmac = std::move(decrypt_key);
|
||||
}
|
||||
|
||||
virtual void init_pid(const int send_form,
|
||||
const int recv_mode,
|
||||
const int recv_form,
|
||||
const char *recv_name,
|
||||
const int recv_unit,
|
||||
const SessionStats::Ptr& recv_stats_arg) override
|
||||
{
|
||||
info.tcp_linear = (recv_mode == PacketIDReceive::TCP_MODE);
|
||||
}
|
||||
|
||||
virtual void init_remote_peer_id(const int remote_peer_id) override
|
||||
{
|
||||
info.remote_peer_id = remote_peer_id;
|
||||
}
|
||||
|
||||
virtual bool consider_compression(const CompressContext& comp_ctx) override
|
||||
{
|
||||
info.comp_ctx = comp_ctx;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Rekeying
|
||||
|
||||
virtual void rekey(const RekeyType type) override
|
||||
{
|
||||
rcv->rekey(type, info);
|
||||
}
|
||||
|
||||
virtual void explicit_exit_notify() override
|
||||
{
|
||||
rcv->explicit_exit_notify();
|
||||
}
|
||||
|
||||
// Encrypt/Decrypt -- data channel handled by kernel, so these methods
|
||||
// should never be reached.
|
||||
|
||||
// returns true if packet ID is close to wrapping
|
||||
virtual bool encrypt(BufferAllocated& buf, const PacketID::time_t now, const unsigned char *op32) override
|
||||
{
|
||||
throw korekey_error("encrypt");
|
||||
}
|
||||
|
||||
virtual Error::Type decrypt(BufferAllocated& buf, const PacketID::time_t now, const unsigned char *op32) override
|
||||
{
|
||||
throw korekey_error("decrypt");
|
||||
}
|
||||
|
||||
private:
|
||||
Receiver::Ptr rcv;
|
||||
Info info;
|
||||
};
|
||||
|
||||
class Context : public CryptoDCContext
|
||||
{
|
||||
public:
|
||||
Context(const CryptoAlgs::Type cipher,
|
||||
const CryptoAlgs::Type digest,
|
||||
CryptoDCFactory& dc_factory_delegate,
|
||||
const Receiver::Ptr& rcv_arg,
|
||||
const Frame::Ptr& frame_arg)
|
||||
: rcv(rcv_arg),
|
||||
dc_context_delegate(dc_factory_delegate.new_obj(cipher, digest)),
|
||||
frame(frame_arg)
|
||||
{
|
||||
Key::validate(cipher, digest);
|
||||
}
|
||||
|
||||
virtual CryptoDCInstance::Ptr new_obj(const unsigned int key_id) override
|
||||
{
|
||||
return new Instance(rcv, dc_context_delegate, key_id, frame);
|
||||
}
|
||||
|
||||
// Info for ProtoContext::options_string
|
||||
|
||||
virtual Info crypto_info() override
|
||||
{
|
||||
return dc_context_delegate->crypto_info();
|
||||
}
|
||||
|
||||
// Info for ProtoContext::link_mtu_adjust
|
||||
|
||||
virtual size_t encap_overhead() const override
|
||||
{
|
||||
return dc_context_delegate->encap_overhead();
|
||||
}
|
||||
|
||||
private:
|
||||
Receiver::Ptr rcv;
|
||||
CryptoDCContext::Ptr dc_context_delegate;
|
||||
Frame::Ptr frame;
|
||||
};
|
||||
|
||||
class Factory : public CryptoDCFactory
|
||||
{
|
||||
public:
|
||||
Factory(const CryptoDCFactory::Ptr& dc_factory_delegate_arg,
|
||||
const Receiver::Ptr& rcv_arg,
|
||||
const Frame::Ptr& frame_arg)
|
||||
: dc_factory_delegate(dc_factory_delegate_arg),
|
||||
rcv(rcv_arg),
|
||||
frame(frame_arg)
|
||||
{
|
||||
}
|
||||
|
||||
virtual CryptoDCContext::Ptr new_obj(const CryptoAlgs::Type cipher,
|
||||
const CryptoAlgs::Type digest) override
|
||||
{
|
||||
return new Context(cipher, digest, *dc_factory_delegate, rcv, frame);
|
||||
}
|
||||
|
||||
private:
|
||||
CryptoDCFactory::Ptr dc_factory_delegate;
|
||||
Receiver::Ptr rcv;
|
||||
Frame::Ptr frame;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
// 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-2018 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// OpenVPN 3 wrapper for kovpn
|
||||
|
||||
#ifndef OPENVPN_KOVPN_KOROUTE_H
|
||||
#define OPENVPN_KOVPN_KOROUTE_H
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <openvpn/kovpn/kovpn.hpp>
|
||||
#include <openvpn/addr/route.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace KoRoute {
|
||||
inline struct ovpn_route from_route(const IP::Route& r)
|
||||
{
|
||||
struct ovpn_route ret;
|
||||
ret.prefix_len = r.prefix_len;
|
||||
ret.addr.v6 = (r.addr.version() == IP::Addr::V6);
|
||||
switch (r.addr.version())
|
||||
{
|
||||
case IP::Addr::V6:
|
||||
ret.addr.u.a6 = r.addr.to_ipv6_nocheck().to_in6_addr();
|
||||
break;
|
||||
case IP::Addr::V4:
|
||||
ret.addr.u.a4 = r.addr.to_ipv4_nocheck().to_in_addr();
|
||||
break;
|
||||
default:
|
||||
throw IP::ip_exception("route address unspecified");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline struct ovpn_route *from_routes(const std::vector<IP::Route>& rtvec)
|
||||
{
|
||||
if (rtvec.size())
|
||||
{
|
||||
std::unique_ptr<struct ovpn_route[]> routes(new ovpn_route[rtvec.size()]);
|
||||
for (size_t i = 0; i < rtvec.size(); ++i)
|
||||
routes[i] = from_route(rtvec[i]);
|
||||
return routes.release();
|
||||
}
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,166 @@
|
||||
// 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-2018 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef OPENVPN_KOVPN_KOSTATS_H
|
||||
#define OPENVPN_KOVPN_KOSTATS_H
|
||||
|
||||
#include <algorithm> // for std::min, std::max
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <openvpn/common/size.hpp>
|
||||
#include <openvpn/common/arraysize.hpp>
|
||||
#include <openvpn/common/core.hpp>
|
||||
#include <openvpn/kovpn/kovpn.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace kostats_private {
|
||||
# include "kovpn/ovpnerrstr.h"
|
||||
}
|
||||
|
||||
class KovpnStats
|
||||
{
|
||||
public:
|
||||
void set_fd(const int fd)
|
||||
{
|
||||
kovpn_fd.store(fd, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void output_stats(std::ostream& os) const
|
||||
{
|
||||
struct ovpn_stats stats;
|
||||
if (::ioctl(get_fd(), OVPN_DEV_STATS, &stats) < 0)
|
||||
return;
|
||||
os << "STAT.BYTES_IN," << (stats.rx_bytes + cc_rx_bytes.load(std::memory_order_relaxed)) << '\n';
|
||||
os << "STAT.BYTES_OUT," << stats.tx_bytes << '\n';
|
||||
}
|
||||
|
||||
void output_percpu(std::ostream& os) const
|
||||
{
|
||||
std::unique_ptr<struct ovpn_percpu_stats> pcs;
|
||||
unsigned int stats_cap = std::max(16, n_cores());
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
const size_t pcs_size = sizeof(struct ovpn_percpu_stats) +
|
||||
sizeof(struct ovpn_percpu_stat) * stats_cap;
|
||||
pcs.reset((struct ovpn_percpu_stats *) ::operator new(pcs_size));
|
||||
pcs->total_stats = 0;
|
||||
pcs->n_stats = stats_cap;
|
||||
if (::ioctl(get_fd(), OVPN_PERCPU_STATS, (void *)pcs.get()) < 0)
|
||||
return;
|
||||
stats_cap = std::max(stats_cap, pcs->total_stats);
|
||||
if (pcs->total_stats <= pcs->n_stats)
|
||||
break;
|
||||
}
|
||||
const size_t n = std::min(pcs->total_stats, pcs->n_stats);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
const struct ovpn_percpu_stat *s = &pcs->stats[i];
|
||||
if (s->rx_bytes || s->tx_bytes)
|
||||
{
|
||||
os << "KOVPN.STAT.CPU-" << i << ".BYTES_IN," << s->rx_bytes << '\n';
|
||||
os << "KOVPN.STAT.CPU-" << i << ".BYTES_OUT," << s->tx_bytes << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void output_err_counters(std::ostream& os) const
|
||||
{
|
||||
std::unique_ptr<struct ovpn_err_stats> esp;
|
||||
unsigned int stats_cap = 128;
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
const size_t es_size = sizeof(struct ovpn_err_stats) +
|
||||
sizeof(struct ovpn_err_stat) * stats_cap;
|
||||
esp.reset((struct ovpn_err_stats *) ::operator new(es_size));
|
||||
esp->total_stats = 0;
|
||||
esp->n_stats = stats_cap;
|
||||
if (::ioctl(get_fd(), OVPN_ERR_STATS, (void *)esp.get()) < 0)
|
||||
return;
|
||||
stats_cap = std::max(stats_cap, esp->total_stats);
|
||||
if (esp->total_stats <= esp->n_stats)
|
||||
break;
|
||||
}
|
||||
const size_t n = std::min(esp->total_stats, esp->n_stats);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
const struct ovpn_err_stat *s = &esp->stats[i];
|
||||
os << "KOVPN";
|
||||
const char *cat = cat_name(s->category);
|
||||
if (cat)
|
||||
{
|
||||
os << '.';
|
||||
os << cat;
|
||||
}
|
||||
const char *err = err_name(s->errcode);
|
||||
if (err)
|
||||
{
|
||||
os << '.';
|
||||
os << err;
|
||||
}
|
||||
os << ',' << s->count << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
void increment_cc_rx_bytes(const std::uint64_t value)
|
||||
{
|
||||
cc_rx_bytes.fetch_add(value, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
static const char *errstr(const size_t i)
|
||||
{
|
||||
const char *ret = err_name(i);
|
||||
if (ret)
|
||||
return ret;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
private:
|
||||
static const char *err_name(const size_t i)
|
||||
{
|
||||
if (i < array_size(kostats_private::ovpn_err_names))
|
||||
return kostats_private::ovpn_err_names[i];
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const char *cat_name(const size_t i)
|
||||
{
|
||||
if (i < array_size(kostats_private::ovpn_errcat_names))
|
||||
return kostats_private::ovpn_errcat_names[i];
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int get_fd() const
|
||||
{
|
||||
return kovpn_fd.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
std::atomic<int> kovpn_fd{-1};
|
||||
std::atomic<uint_fast64_t> cc_rx_bytes{0};
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
// 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-2018 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// OpenVPN 3 wrapper for kovpn
|
||||
|
||||
#ifndef OPENVPN_KOVPN_KOVPN_HPP
|
||||
#define OPENVPN_KOVPN_KOVPN_HPP
|
||||
|
||||
// Not including this file causes redefinition errors
|
||||
// when the sys/ and linux/ headers below are included
|
||||
// before Asio.
|
||||
#include <openvpn/io/io.hpp>
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
extern "C" {
|
||||
#include <kovpn/kovpn.h>
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user