mirror of
https://github.com/deneraraujo/OpenVPNAdapter.git
synced 2026-02-11 00:00:08 +08:00
Merge branch 'feature/update-dependencies' into develop
This commit is contained in:
@@ -865,8 +865,6 @@ public:
|
||||
asio::error_code ec;
|
||||
const protocol_type protocol = peer_endpoint.protocol();
|
||||
this->get_service().open(this->get_implementation(), protocol, ec);
|
||||
if (!ec)
|
||||
async_connect_post_open(protocol, ec);
|
||||
if (ec)
|
||||
{
|
||||
async_completion<ConnectHandler,
|
||||
@@ -1743,11 +1741,6 @@ protected:
|
||||
}
|
||||
|
||||
private:
|
||||
// optional user code hook immediately after socket open in async_connect
|
||||
virtual void async_connect_post_open(const protocol_type& protocol, asio::error_code& ec)
|
||||
{
|
||||
}
|
||||
|
||||
// Disallow copying and assignment.
|
||||
basic_socket(const basic_socket&) ASIO_DELETED;
|
||||
basic_socket& operator=(const basic_socket&) ASIO_DELETED;
|
||||
|
||||
@@ -3338,23 +3338,6 @@ asio::error_code getaddrinfo(const char* host,
|
||||
# endif
|
||||
#elif !defined(ASIO_HAS_GETADDRINFO)
|
||||
int error = getaddrinfo_emulation(host, service, &hints, result);
|
||||
return ec = translate_addrinfo_error(error);
|
||||
#elif defined(ASIO_HAS_GETADDRINFO) && defined(ASIO_APPLE_NAT64)
|
||||
// For NAT64 compatibility, Apple recommends to set AI_DEFAULT flags
|
||||
addrinfo_type new_hints = hints;
|
||||
new_hints.ai_flags |= AI_DEFAULT;
|
||||
int error = ::getaddrinfo(host, service, &new_hints, result);
|
||||
|
||||
// iOS bug workaround: sometimes iOS getaddrinfo() returns a non-zero scope ID
|
||||
// for non-link-local addresses. Workaround by forcing scope ID to 0 for
|
||||
// non-link-local addresses.
|
||||
if (!error && (*result)->ai_family == AF_INET6)
|
||||
{
|
||||
sockaddr_in6* a6 = (sockaddr_in6*)(*result)->ai_addr;
|
||||
if (a6->sin6_scope_id && !(IN6_IS_ADDR_LINKLOCAL(&a6->sin6_addr) || IN6_IS_ADDR_MC_NODELOCAL(&a6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&a6->sin6_addr)))
|
||||
a6->sin6_scope_id = 0;
|
||||
}
|
||||
|
||||
return ec = translate_addrinfo_error(error);
|
||||
#else
|
||||
int error = ::getaddrinfo(host, service, &hints, result);
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "asio/detail/config.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include "asio/detail/socket_ops.hpp"
|
||||
#include "asio/detail/socket_types.hpp"
|
||||
#include "asio/ip/basic_resolver_iterator.hpp"
|
||||
@@ -300,12 +299,6 @@ public:
|
||||
return !a.equal(b);
|
||||
}
|
||||
|
||||
template <typename Random>
|
||||
void randomize(Random& r)
|
||||
{
|
||||
std::shuffle(this->values_->begin(), this->values_->end(), r);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,324 @@
|
||||
//
|
||||
// address_v4.cpp
|
||||
// ~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
// Disable autolinking for unit tests.
|
||||
#if !defined(BOOST_ALL_NO_LIB)
|
||||
#define BOOST_ALL_NO_LIB 1
|
||||
#endif // !defined(BOOST_ALL_NO_LIB)
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include "asio/ip/address_v4.hpp"
|
||||
|
||||
#include "../unit_test.hpp"
|
||||
#include <sstream>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// ip_address_v4_compile test
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// The following test checks that all public member functions on the class
|
||||
// ip::address_v4 compile and link correctly. Runtime failures are ignored.
|
||||
|
||||
namespace ip_address_v4_compile {
|
||||
|
||||
void test()
|
||||
{
|
||||
using namespace asio;
|
||||
namespace ip = asio::ip;
|
||||
|
||||
try
|
||||
{
|
||||
asio::error_code ec;
|
||||
|
||||
// address_v4 constructors.
|
||||
|
||||
ip::address_v4 addr1;
|
||||
const ip::address_v4::bytes_type const_bytes_value = { { 127, 0, 0, 1 } };
|
||||
ip::address_v4 addr2(const_bytes_value);
|
||||
const unsigned long const_ulong_value = 0x7F000001;
|
||||
ip::address_v4 addr3(const_ulong_value);
|
||||
|
||||
// address_v4 functions.
|
||||
|
||||
bool b = addr1.is_loopback();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_unspecified();
|
||||
(void)b;
|
||||
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
b = addr1.is_class_a();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_class_b();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_class_c();
|
||||
(void)b;
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
b = addr1.is_multicast();
|
||||
(void)b;
|
||||
|
||||
ip::address_v4::bytes_type bytes_value = addr1.to_bytes();
|
||||
(void)bytes_value;
|
||||
|
||||
ip::address_v4::uint_type uint_value = addr1.to_uint();
|
||||
(void)uint_value;
|
||||
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
unsigned long ulong_value = addr1.to_ulong();
|
||||
(void)ulong_value;
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
std::string string_value = addr1.to_string();
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
string_value = addr1.to_string(ec);
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
// address_v4 static functions.
|
||||
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
addr1 = ip::address_v4::from_string("127.0.0.1");
|
||||
addr1 = ip::address_v4::from_string("127.0.0.1", ec);
|
||||
addr1 = ip::address_v4::from_string(string_value);
|
||||
addr1 = ip::address_v4::from_string(string_value, ec);
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
addr1 = ip::address_v4::any();
|
||||
|
||||
addr1 = ip::address_v4::loopback();
|
||||
|
||||
addr1 = ip::address_v4::broadcast();
|
||||
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
addr1 = ip::address_v4::broadcast(addr2, addr3);
|
||||
|
||||
addr1 = ip::address_v4::netmask(addr2);
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
// address_v4 comparisons.
|
||||
|
||||
b = (addr1 == addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 != addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 < addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 > addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 <= addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 >= addr2);
|
||||
(void)b;
|
||||
|
||||
// address_v4 creation functions.
|
||||
|
||||
addr1 = ip::make_address_v4(const_bytes_value);
|
||||
addr1 = ip::make_address_v4(const_ulong_value);
|
||||
addr1 = ip::make_address_v4("127.0.0.1");
|
||||
addr1 = ip::make_address_v4("127.0.0.1", ec);
|
||||
addr1 = ip::make_address_v4(string_value);
|
||||
addr1 = ip::make_address_v4(string_value, ec);
|
||||
#if defined(ASIO_HAS_STD_STRING_VIEW)
|
||||
# if defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
|
||||
std::experimental::string_view string_view_value("127.0.0.1");
|
||||
# else // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
|
||||
std::string_view string_view_value("127.0.0.1");
|
||||
# endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
|
||||
addr1 = ip::make_address_v4(string_view_value);
|
||||
addr1 = ip::make_address_v4(string_view_value, ec);
|
||||
#endif // defined(ASIO_HAS_STD_STRING_VIEW)
|
||||
|
||||
// address_v4 I/O.
|
||||
|
||||
std::ostringstream os;
|
||||
os << addr1;
|
||||
|
||||
#if !defined(BOOST_NO_STD_WSTREAMBUF)
|
||||
std::wostringstream wos;
|
||||
wos << addr1;
|
||||
#endif // !defined(BOOST_NO_STD_WSTREAMBUF)
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ip_address_v4_compile
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// ip_address_v4_runtime test
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// The following test checks that the various public member functions meet the
|
||||
// necessary postconditions.
|
||||
|
||||
namespace ip_address_v4_runtime {
|
||||
|
||||
void test()
|
||||
{
|
||||
using asio::ip::address_v4;
|
||||
|
||||
address_v4 a1;
|
||||
ASIO_CHECK(a1.to_bytes()[0] == 0);
|
||||
ASIO_CHECK(a1.to_bytes()[1] == 0);
|
||||
ASIO_CHECK(a1.to_bytes()[2] == 0);
|
||||
ASIO_CHECK(a1.to_bytes()[3] == 0);
|
||||
ASIO_CHECK(a1.to_uint() == 0);
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
ASIO_CHECK(a1.to_ulong() == 0);
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
address_v4::bytes_type b1 = {{ 1, 2, 3, 4 }};
|
||||
address_v4 a2(b1);
|
||||
ASIO_CHECK(a2.to_bytes()[0] == 1);
|
||||
ASIO_CHECK(a2.to_bytes()[1] == 2);
|
||||
ASIO_CHECK(a2.to_bytes()[2] == 3);
|
||||
ASIO_CHECK(a2.to_bytes()[3] == 4);
|
||||
ASIO_CHECK(((a2.to_uint() >> 24) & 0xFF) == b1[0]);
|
||||
ASIO_CHECK(((a2.to_uint() >> 16) & 0xFF) == b1[1]);
|
||||
ASIO_CHECK(((a2.to_uint() >> 8) & 0xFF) == b1[2]);
|
||||
ASIO_CHECK((a2.to_uint() & 0xFF) == b1[3]);
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
ASIO_CHECK(((a2.to_ulong() >> 24) & 0xFF) == b1[0]);
|
||||
ASIO_CHECK(((a2.to_ulong() >> 16) & 0xFF) == b1[1]);
|
||||
ASIO_CHECK(((a2.to_ulong() >> 8) & 0xFF) == b1[2]);
|
||||
ASIO_CHECK((a2.to_ulong() & 0xFF) == b1[3]);
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
address_v4 a3(0x01020304);
|
||||
ASIO_CHECK(a3.to_bytes()[0] == 1);
|
||||
ASIO_CHECK(a3.to_bytes()[1] == 2);
|
||||
ASIO_CHECK(a3.to_bytes()[2] == 3);
|
||||
ASIO_CHECK(a3.to_bytes()[3] == 4);
|
||||
ASIO_CHECK(a3.to_uint() == 0x01020304);
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
ASIO_CHECK(a3.to_ulong() == 0x01020304);
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
ASIO_CHECK(address_v4(0x7F000001).is_loopback());
|
||||
ASIO_CHECK(address_v4(0x7F000002).is_loopback());
|
||||
ASIO_CHECK(!address_v4(0x00000000).is_loopback());
|
||||
ASIO_CHECK(!address_v4(0x01020304).is_loopback());
|
||||
|
||||
ASIO_CHECK(address_v4(0x00000000).is_unspecified());
|
||||
ASIO_CHECK(!address_v4(0x7F000001).is_unspecified());
|
||||
ASIO_CHECK(!address_v4(0x01020304).is_unspecified());
|
||||
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
ASIO_CHECK(address_v4(0x01000000).is_class_a());
|
||||
ASIO_CHECK(address_v4(0x7F000000).is_class_a());
|
||||
ASIO_CHECK(!address_v4(0x80000000).is_class_a());
|
||||
ASIO_CHECK(!address_v4(0xBFFF0000).is_class_a());
|
||||
ASIO_CHECK(!address_v4(0xC0000000).is_class_a());
|
||||
ASIO_CHECK(!address_v4(0xDFFFFF00).is_class_a());
|
||||
ASIO_CHECK(!address_v4(0xE0000000).is_class_a());
|
||||
ASIO_CHECK(!address_v4(0xEFFFFFFF).is_class_a());
|
||||
ASIO_CHECK(!address_v4(0xF0000000).is_class_a());
|
||||
ASIO_CHECK(!address_v4(0xFFFFFFFF).is_class_a());
|
||||
|
||||
ASIO_CHECK(!address_v4(0x01000000).is_class_b());
|
||||
ASIO_CHECK(!address_v4(0x7F000000).is_class_b());
|
||||
ASIO_CHECK(address_v4(0x80000000).is_class_b());
|
||||
ASIO_CHECK(address_v4(0xBFFF0000).is_class_b());
|
||||
ASIO_CHECK(!address_v4(0xC0000000).is_class_b());
|
||||
ASIO_CHECK(!address_v4(0xDFFFFF00).is_class_b());
|
||||
ASIO_CHECK(!address_v4(0xE0000000).is_class_b());
|
||||
ASIO_CHECK(!address_v4(0xEFFFFFFF).is_class_b());
|
||||
ASIO_CHECK(!address_v4(0xF0000000).is_class_b());
|
||||
ASIO_CHECK(!address_v4(0xFFFFFFFF).is_class_b());
|
||||
|
||||
ASIO_CHECK(!address_v4(0x01000000).is_class_c());
|
||||
ASIO_CHECK(!address_v4(0x7F000000).is_class_c());
|
||||
ASIO_CHECK(!address_v4(0x80000000).is_class_c());
|
||||
ASIO_CHECK(!address_v4(0xBFFF0000).is_class_c());
|
||||
ASIO_CHECK(address_v4(0xC0000000).is_class_c());
|
||||
ASIO_CHECK(address_v4(0xDFFFFF00).is_class_c());
|
||||
ASIO_CHECK(!address_v4(0xE0000000).is_class_c());
|
||||
ASIO_CHECK(!address_v4(0xEFFFFFFF).is_class_c());
|
||||
ASIO_CHECK(!address_v4(0xF0000000).is_class_c());
|
||||
ASIO_CHECK(!address_v4(0xFFFFFFFF).is_class_c());
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
ASIO_CHECK(!address_v4(0x01000000).is_multicast());
|
||||
ASIO_CHECK(!address_v4(0x7F000000).is_multicast());
|
||||
ASIO_CHECK(!address_v4(0x80000000).is_multicast());
|
||||
ASIO_CHECK(!address_v4(0xBFFF0000).is_multicast());
|
||||
ASIO_CHECK(!address_v4(0xC0000000).is_multicast());
|
||||
ASIO_CHECK(!address_v4(0xDFFFFF00).is_multicast());
|
||||
ASIO_CHECK(address_v4(0xE0000000).is_multicast());
|
||||
ASIO_CHECK(address_v4(0xEFFFFFFF).is_multicast());
|
||||
ASIO_CHECK(!address_v4(0xF0000000).is_multicast());
|
||||
ASIO_CHECK(!address_v4(0xFFFFFFFF).is_multicast());
|
||||
|
||||
address_v4 a4 = address_v4::any();
|
||||
ASIO_CHECK(a4.to_bytes()[0] == 0);
|
||||
ASIO_CHECK(a4.to_bytes()[1] == 0);
|
||||
ASIO_CHECK(a4.to_bytes()[2] == 0);
|
||||
ASIO_CHECK(a4.to_bytes()[3] == 0);
|
||||
ASIO_CHECK(a4.to_uint() == 0);
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
ASIO_CHECK(a4.to_ulong() == 0);
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
address_v4 a5 = address_v4::loopback();
|
||||
ASIO_CHECK(a5.to_bytes()[0] == 0x7F);
|
||||
ASIO_CHECK(a5.to_bytes()[1] == 0);
|
||||
ASIO_CHECK(a5.to_bytes()[2] == 0);
|
||||
ASIO_CHECK(a5.to_bytes()[3] == 0x01);
|
||||
ASIO_CHECK(a5.to_uint() == 0x7F000001);
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
ASIO_CHECK(a5.to_ulong() == 0x7F000001);
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
address_v4 a6 = address_v4::broadcast();
|
||||
ASIO_CHECK(a6.to_bytes()[0] == 0xFF);
|
||||
ASIO_CHECK(a6.to_bytes()[1] == 0xFF);
|
||||
ASIO_CHECK(a6.to_bytes()[2] == 0xFF);
|
||||
ASIO_CHECK(a6.to_bytes()[3] == 0xFF);
|
||||
ASIO_CHECK(a6.to_uint() == 0xFFFFFFFF);
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
ASIO_CHECK(a6.to_ulong() == 0xFFFFFFFF);
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
address_v4 class_a_net(0xFF000000);
|
||||
address_v4 class_b_net(0xFFFF0000);
|
||||
address_v4 class_c_net(0xFFFFFF00);
|
||||
address_v4 other_net(0xFFFFFFFF);
|
||||
ASIO_CHECK(address_v4::netmask(address_v4(0x01000000)) == class_a_net);
|
||||
ASIO_CHECK(address_v4::netmask(address_v4(0x7F000000)) == class_a_net);
|
||||
ASIO_CHECK(address_v4::netmask(address_v4(0x80000000)) == class_b_net);
|
||||
ASIO_CHECK(address_v4::netmask(address_v4(0xBFFF0000)) == class_b_net);
|
||||
ASIO_CHECK(address_v4::netmask(address_v4(0xC0000000)) == class_c_net);
|
||||
ASIO_CHECK(address_v4::netmask(address_v4(0xDFFFFF00)) == class_c_net);
|
||||
ASIO_CHECK(address_v4::netmask(address_v4(0xE0000000)) == other_net);
|
||||
ASIO_CHECK(address_v4::netmask(address_v4(0xEFFFFFFF)) == other_net);
|
||||
ASIO_CHECK(address_v4::netmask(address_v4(0xF0000000)) == other_net);
|
||||
ASIO_CHECK(address_v4::netmask(address_v4(0xFFFFFFFF)) == other_net);
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
} // namespace ip_address_v4_runtime
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
ASIO_TEST_SUITE
|
||||
(
|
||||
"ip/address_v4",
|
||||
ASIO_TEST_CASE(ip_address_v4_compile::test)
|
||||
ASIO_TEST_CASE(ip_address_v4_runtime::test)
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// address_v4_iterator.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
// Disable autolinking for unit tests.
|
||||
#if !defined(BOOST_ALL_NO_LIB)
|
||||
#define BOOST_ALL_NO_LIB 1
|
||||
#endif // !defined(BOOST_ALL_NO_LIB)
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include "asio/ip/address_v4_iterator.hpp"
|
||||
|
||||
#include "../unit_test.hpp"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
ASIO_TEST_SUITE
|
||||
(
|
||||
"ip/address_v4_iterator",
|
||||
ASIO_TEST_CASE(null_test)
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// address_v4_range.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
// Disable autolinking for unit tests.
|
||||
#if !defined(BOOST_ALL_NO_LIB)
|
||||
#define BOOST_ALL_NO_LIB 1
|
||||
#endif // !defined(BOOST_ALL_NO_LIB)
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include "asio/ip/address_v4_range.hpp"
|
||||
|
||||
#include "../unit_test.hpp"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
ASIO_TEST_SUITE
|
||||
(
|
||||
"ip/address_v4_range",
|
||||
ASIO_TEST_CASE(null_test)
|
||||
)
|
||||
@@ -0,0 +1,409 @@
|
||||
//
|
||||
// address_v6.cpp
|
||||
// ~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
// Disable autolinking for unit tests.
|
||||
#if !defined(BOOST_ALL_NO_LIB)
|
||||
#define BOOST_ALL_NO_LIB 1
|
||||
#endif // !defined(BOOST_ALL_NO_LIB)
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include "asio/ip/address_v6.hpp"
|
||||
|
||||
#include "../unit_test.hpp"
|
||||
#include <sstream>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// ip_address_v6_compile test
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// The following test checks that all public member functions on the class
|
||||
// ip::address_v6 compile and link correctly. Runtime failures are ignored.
|
||||
|
||||
namespace ip_address_v6_compile {
|
||||
|
||||
void test()
|
||||
{
|
||||
using namespace asio;
|
||||
namespace ip = asio::ip;
|
||||
|
||||
try
|
||||
{
|
||||
asio::error_code ec;
|
||||
|
||||
// address_v6 constructors.
|
||||
|
||||
ip::address_v6 addr1;
|
||||
const ip::address_v6::bytes_type const_bytes_value = { { 0 } };
|
||||
ip::address_v6 addr2(const_bytes_value);
|
||||
|
||||
// address_v6 functions.
|
||||
|
||||
unsigned long scope_id = addr1.scope_id();
|
||||
addr1.scope_id(scope_id);
|
||||
|
||||
bool b = addr1.is_unspecified();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_loopback();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_multicast();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_link_local();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_site_local();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_v4_mapped();
|
||||
(void)b;
|
||||
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
b = addr1.is_v4_compatible();
|
||||
(void)b;
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
b = addr1.is_multicast_node_local();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_multicast_link_local();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_multicast_site_local();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_multicast_org_local();
|
||||
(void)b;
|
||||
|
||||
b = addr1.is_multicast_global();
|
||||
(void)b;
|
||||
|
||||
ip::address_v6::bytes_type bytes_value = addr1.to_bytes();
|
||||
(void)bytes_value;
|
||||
|
||||
std::string string_value = addr1.to_string();
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
string_value = addr1.to_string(ec);
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
ip::address_v4 addr3 = addr1.to_v4();
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
// address_v6 static functions.
|
||||
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
addr1 = ip::address_v6::from_string("0::0");
|
||||
addr1 = ip::address_v6::from_string("0::0", ec);
|
||||
addr1 = ip::address_v6::from_string(string_value);
|
||||
addr1 = ip::address_v6::from_string(string_value, ec);
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
addr1 = ip::address_v6::any();
|
||||
|
||||
addr1 = ip::address_v6::loopback();
|
||||
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
addr1 = ip::address_v6::v4_mapped(addr3);
|
||||
|
||||
addr1 = ip::address_v6::v4_compatible(addr3);
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
// address_v6 comparisons.
|
||||
|
||||
b = (addr1 == addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 != addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 < addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 > addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 <= addr2);
|
||||
(void)b;
|
||||
|
||||
b = (addr1 >= addr2);
|
||||
(void)b;
|
||||
|
||||
// address_v6 creation functions.
|
||||
|
||||
addr1 = ip::make_address_v6(const_bytes_value, scope_id);
|
||||
addr1 = ip::make_address_v6("0::0");
|
||||
addr1 = ip::make_address_v6("0::0", ec);
|
||||
addr1 = ip::make_address_v6(string_value);
|
||||
addr1 = ip::make_address_v6(string_value, ec);
|
||||
#if defined(ASIO_HAS_STD_STRING_VIEW)
|
||||
# if defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
|
||||
std::experimental::string_view string_view_value("0::0");
|
||||
# else // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
|
||||
std::string_view string_view_value("0::0");
|
||||
# endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
|
||||
addr1 = ip::make_address_v6(string_view_value);
|
||||
addr1 = ip::make_address_v6(string_view_value, ec);
|
||||
#endif // defined(ASIO_HAS_STD_STRING_VIEW)
|
||||
|
||||
// address_v6 IPv4-mapped conversion.
|
||||
#if defined(ASIO_NO_DEPRECATED)
|
||||
ip::address_v4 addr3;
|
||||
#endif // defined(ASIO_NO_DEPRECATED)
|
||||
addr1 = ip::make_address_v6(ip::v4_mapped, addr3);
|
||||
addr3 = ip::make_address_v4(ip::v4_mapped, addr1);
|
||||
|
||||
// address_v6 I/O.
|
||||
|
||||
std::ostringstream os;
|
||||
os << addr1;
|
||||
|
||||
#if !defined(BOOST_NO_STD_WSTREAMBUF)
|
||||
std::wostringstream wos;
|
||||
wos << addr1;
|
||||
#endif // !defined(BOOST_NO_STD_WSTREAMBUF)
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ip_address_v6_compile
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// ip_address_v6_runtime test
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// The following test checks that the various public member functions meet the
|
||||
// necessary postconditions.
|
||||
|
||||
namespace ip_address_v6_runtime {
|
||||
|
||||
void test()
|
||||
{
|
||||
using asio::ip::address_v6;
|
||||
|
||||
address_v6 a1;
|
||||
ASIO_CHECK(a1.is_unspecified());
|
||||
ASIO_CHECK(a1.scope_id() == 0);
|
||||
|
||||
address_v6::bytes_type b1 = {{ 1, 2, 3, 4, 5,
|
||||
6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }};
|
||||
address_v6 a2(b1, 12345);
|
||||
ASIO_CHECK(a2.to_bytes()[0] == 1);
|
||||
ASIO_CHECK(a2.to_bytes()[1] == 2);
|
||||
ASIO_CHECK(a2.to_bytes()[2] == 3);
|
||||
ASIO_CHECK(a2.to_bytes()[3] == 4);
|
||||
ASIO_CHECK(a2.to_bytes()[4] == 5);
|
||||
ASIO_CHECK(a2.to_bytes()[5] == 6);
|
||||
ASIO_CHECK(a2.to_bytes()[6] == 7);
|
||||
ASIO_CHECK(a2.to_bytes()[7] == 8);
|
||||
ASIO_CHECK(a2.to_bytes()[8] == 9);
|
||||
ASIO_CHECK(a2.to_bytes()[9] == 10);
|
||||
ASIO_CHECK(a2.to_bytes()[10] == 11);
|
||||
ASIO_CHECK(a2.to_bytes()[11] == 12);
|
||||
ASIO_CHECK(a2.to_bytes()[12] == 13);
|
||||
ASIO_CHECK(a2.to_bytes()[13] == 14);
|
||||
ASIO_CHECK(a2.to_bytes()[14] == 15);
|
||||
ASIO_CHECK(a2.to_bytes()[15] == 16);
|
||||
ASIO_CHECK(a2.scope_id() == 12345);
|
||||
|
||||
address_v6 a3;
|
||||
a3.scope_id(12345);
|
||||
ASIO_CHECK(a3.scope_id() == 12345);
|
||||
|
||||
address_v6 unspecified_address;
|
||||
address_v6::bytes_type loopback_bytes = {{ 0 }};
|
||||
loopback_bytes[15] = 1;
|
||||
address_v6 loopback_address(loopback_bytes);
|
||||
address_v6::bytes_type link_local_bytes = {{ 0xFE, 0x80, 1 }};
|
||||
address_v6 link_local_address(link_local_bytes);
|
||||
address_v6::bytes_type site_local_bytes = {{ 0xFE, 0xC0, 1 }};
|
||||
address_v6 site_local_address(site_local_bytes);
|
||||
address_v6::bytes_type v4_mapped_bytes = {{ 0 }};
|
||||
v4_mapped_bytes[10] = 0xFF, v4_mapped_bytes[11] = 0xFF;
|
||||
v4_mapped_bytes[12] = 1, v4_mapped_bytes[13] = 2;
|
||||
v4_mapped_bytes[14] = 3, v4_mapped_bytes[15] = 4;
|
||||
address_v6 v4_mapped_address(v4_mapped_bytes);
|
||||
address_v6::bytes_type v4_compat_bytes = {{ 0 }};
|
||||
v4_compat_bytes[12] = 1, v4_compat_bytes[13] = 2;
|
||||
v4_compat_bytes[14] = 3, v4_compat_bytes[15] = 4;
|
||||
address_v6 v4_compat_address(v4_compat_bytes);
|
||||
address_v6::bytes_type mcast_global_bytes = {{ 0xFF, 0x0E, 1 }};
|
||||
address_v6 mcast_global_address(mcast_global_bytes);
|
||||
address_v6::bytes_type mcast_link_local_bytes = {{ 0xFF, 0x02, 1 }};
|
||||
address_v6 mcast_link_local_address(mcast_link_local_bytes);
|
||||
address_v6::bytes_type mcast_node_local_bytes = {{ 0xFF, 0x01, 1 }};
|
||||
address_v6 mcast_node_local_address(mcast_node_local_bytes);
|
||||
address_v6::bytes_type mcast_org_local_bytes = {{ 0xFF, 0x08, 1 }};
|
||||
address_v6 mcast_org_local_address(mcast_org_local_bytes);
|
||||
address_v6::bytes_type mcast_site_local_bytes = {{ 0xFF, 0x05, 1 }};
|
||||
address_v6 mcast_site_local_address(mcast_site_local_bytes);
|
||||
|
||||
ASIO_CHECK(!unspecified_address.is_loopback());
|
||||
ASIO_CHECK(loopback_address.is_loopback());
|
||||
ASIO_CHECK(!link_local_address.is_loopback());
|
||||
ASIO_CHECK(!site_local_address.is_loopback());
|
||||
ASIO_CHECK(!v4_mapped_address.is_loopback());
|
||||
ASIO_CHECK(!v4_compat_address.is_loopback());
|
||||
ASIO_CHECK(!mcast_global_address.is_loopback());
|
||||
ASIO_CHECK(!mcast_link_local_address.is_loopback());
|
||||
ASIO_CHECK(!mcast_node_local_address.is_loopback());
|
||||
ASIO_CHECK(!mcast_org_local_address.is_loopback());
|
||||
ASIO_CHECK(!mcast_site_local_address.is_loopback());
|
||||
|
||||
ASIO_CHECK(unspecified_address.is_unspecified());
|
||||
ASIO_CHECK(!loopback_address.is_unspecified());
|
||||
ASIO_CHECK(!link_local_address.is_unspecified());
|
||||
ASIO_CHECK(!site_local_address.is_unspecified());
|
||||
ASIO_CHECK(!v4_mapped_address.is_unspecified());
|
||||
ASIO_CHECK(!v4_compat_address.is_unspecified());
|
||||
ASIO_CHECK(!mcast_global_address.is_unspecified());
|
||||
ASIO_CHECK(!mcast_link_local_address.is_unspecified());
|
||||
ASIO_CHECK(!mcast_node_local_address.is_unspecified());
|
||||
ASIO_CHECK(!mcast_org_local_address.is_unspecified());
|
||||
ASIO_CHECK(!mcast_site_local_address.is_unspecified());
|
||||
|
||||
ASIO_CHECK(!unspecified_address.is_link_local());
|
||||
ASIO_CHECK(!loopback_address.is_link_local());
|
||||
ASIO_CHECK(link_local_address.is_link_local());
|
||||
ASIO_CHECK(!site_local_address.is_link_local());
|
||||
ASIO_CHECK(!v4_mapped_address.is_link_local());
|
||||
ASIO_CHECK(!v4_compat_address.is_link_local());
|
||||
ASIO_CHECK(!mcast_global_address.is_link_local());
|
||||
ASIO_CHECK(!mcast_link_local_address.is_link_local());
|
||||
ASIO_CHECK(!mcast_node_local_address.is_link_local());
|
||||
ASIO_CHECK(!mcast_org_local_address.is_link_local());
|
||||
ASIO_CHECK(!mcast_site_local_address.is_link_local());
|
||||
|
||||
ASIO_CHECK(!unspecified_address.is_site_local());
|
||||
ASIO_CHECK(!loopback_address.is_site_local());
|
||||
ASIO_CHECK(!link_local_address.is_site_local());
|
||||
ASIO_CHECK(site_local_address.is_site_local());
|
||||
ASIO_CHECK(!v4_mapped_address.is_site_local());
|
||||
ASIO_CHECK(!v4_compat_address.is_site_local());
|
||||
ASIO_CHECK(!mcast_global_address.is_site_local());
|
||||
ASIO_CHECK(!mcast_link_local_address.is_site_local());
|
||||
ASIO_CHECK(!mcast_node_local_address.is_site_local());
|
||||
ASIO_CHECK(!mcast_org_local_address.is_site_local());
|
||||
ASIO_CHECK(!mcast_site_local_address.is_site_local());
|
||||
|
||||
ASIO_CHECK(!unspecified_address.is_v4_mapped());
|
||||
ASIO_CHECK(!loopback_address.is_v4_mapped());
|
||||
ASIO_CHECK(!link_local_address.is_v4_mapped());
|
||||
ASIO_CHECK(!site_local_address.is_v4_mapped());
|
||||
ASIO_CHECK(v4_mapped_address.is_v4_mapped());
|
||||
ASIO_CHECK(!v4_compat_address.is_v4_mapped());
|
||||
ASIO_CHECK(!mcast_global_address.is_v4_mapped());
|
||||
ASIO_CHECK(!mcast_link_local_address.is_v4_mapped());
|
||||
ASIO_CHECK(!mcast_node_local_address.is_v4_mapped());
|
||||
ASIO_CHECK(!mcast_org_local_address.is_v4_mapped());
|
||||
ASIO_CHECK(!mcast_site_local_address.is_v4_mapped());
|
||||
|
||||
#if !defined(ASIO_NO_DEPRECATED)
|
||||
ASIO_CHECK(!unspecified_address.is_v4_compatible());
|
||||
ASIO_CHECK(!loopback_address.is_v4_compatible());
|
||||
ASIO_CHECK(!link_local_address.is_v4_compatible());
|
||||
ASIO_CHECK(!site_local_address.is_v4_compatible());
|
||||
ASIO_CHECK(!v4_mapped_address.is_v4_compatible());
|
||||
ASIO_CHECK(v4_compat_address.is_v4_compatible());
|
||||
ASIO_CHECK(!mcast_global_address.is_v4_compatible());
|
||||
ASIO_CHECK(!mcast_link_local_address.is_v4_compatible());
|
||||
ASIO_CHECK(!mcast_node_local_address.is_v4_compatible());
|
||||
ASIO_CHECK(!mcast_org_local_address.is_v4_compatible());
|
||||
ASIO_CHECK(!mcast_site_local_address.is_v4_compatible());
|
||||
#endif // !defined(ASIO_NO_DEPRECATED)
|
||||
|
||||
ASIO_CHECK(!unspecified_address.is_multicast());
|
||||
ASIO_CHECK(!loopback_address.is_multicast());
|
||||
ASIO_CHECK(!link_local_address.is_multicast());
|
||||
ASIO_CHECK(!site_local_address.is_multicast());
|
||||
ASIO_CHECK(!v4_mapped_address.is_multicast());
|
||||
ASIO_CHECK(!v4_compat_address.is_multicast());
|
||||
ASIO_CHECK(mcast_global_address.is_multicast());
|
||||
ASIO_CHECK(mcast_link_local_address.is_multicast());
|
||||
ASIO_CHECK(mcast_node_local_address.is_multicast());
|
||||
ASIO_CHECK(mcast_org_local_address.is_multicast());
|
||||
ASIO_CHECK(mcast_site_local_address.is_multicast());
|
||||
|
||||
ASIO_CHECK(!unspecified_address.is_multicast_global());
|
||||
ASIO_CHECK(!loopback_address.is_multicast_global());
|
||||
ASIO_CHECK(!link_local_address.is_multicast_global());
|
||||
ASIO_CHECK(!site_local_address.is_multicast_global());
|
||||
ASIO_CHECK(!v4_mapped_address.is_multicast_global());
|
||||
ASIO_CHECK(!v4_compat_address.is_multicast_global());
|
||||
ASIO_CHECK(mcast_global_address.is_multicast_global());
|
||||
ASIO_CHECK(!mcast_link_local_address.is_multicast_global());
|
||||
ASIO_CHECK(!mcast_node_local_address.is_multicast_global());
|
||||
ASIO_CHECK(!mcast_org_local_address.is_multicast_global());
|
||||
ASIO_CHECK(!mcast_site_local_address.is_multicast_global());
|
||||
|
||||
ASIO_CHECK(!unspecified_address.is_multicast_link_local());
|
||||
ASIO_CHECK(!loopback_address.is_multicast_link_local());
|
||||
ASIO_CHECK(!link_local_address.is_multicast_link_local());
|
||||
ASIO_CHECK(!site_local_address.is_multicast_link_local());
|
||||
ASIO_CHECK(!v4_mapped_address.is_multicast_link_local());
|
||||
ASIO_CHECK(!v4_compat_address.is_multicast_link_local());
|
||||
ASIO_CHECK(!mcast_global_address.is_multicast_link_local());
|
||||
ASIO_CHECK(mcast_link_local_address.is_multicast_link_local());
|
||||
ASIO_CHECK(!mcast_node_local_address.is_multicast_link_local());
|
||||
ASIO_CHECK(!mcast_org_local_address.is_multicast_link_local());
|
||||
ASIO_CHECK(!mcast_site_local_address.is_multicast_link_local());
|
||||
|
||||
ASIO_CHECK(!unspecified_address.is_multicast_node_local());
|
||||
ASIO_CHECK(!loopback_address.is_multicast_node_local());
|
||||
ASIO_CHECK(!link_local_address.is_multicast_node_local());
|
||||
ASIO_CHECK(!site_local_address.is_multicast_node_local());
|
||||
ASIO_CHECK(!v4_mapped_address.is_multicast_node_local());
|
||||
ASIO_CHECK(!v4_compat_address.is_multicast_node_local());
|
||||
ASIO_CHECK(!mcast_global_address.is_multicast_node_local());
|
||||
ASIO_CHECK(!mcast_link_local_address.is_multicast_node_local());
|
||||
ASIO_CHECK(mcast_node_local_address.is_multicast_node_local());
|
||||
ASIO_CHECK(!mcast_org_local_address.is_multicast_node_local());
|
||||
ASIO_CHECK(!mcast_site_local_address.is_multicast_node_local());
|
||||
|
||||
ASIO_CHECK(!unspecified_address.is_multicast_org_local());
|
||||
ASIO_CHECK(!loopback_address.is_multicast_org_local());
|
||||
ASIO_CHECK(!link_local_address.is_multicast_org_local());
|
||||
ASIO_CHECK(!site_local_address.is_multicast_org_local());
|
||||
ASIO_CHECK(!v4_mapped_address.is_multicast_org_local());
|
||||
ASIO_CHECK(!v4_compat_address.is_multicast_org_local());
|
||||
ASIO_CHECK(!mcast_global_address.is_multicast_org_local());
|
||||
ASIO_CHECK(!mcast_link_local_address.is_multicast_org_local());
|
||||
ASIO_CHECK(!mcast_node_local_address.is_multicast_org_local());
|
||||
ASIO_CHECK(mcast_org_local_address.is_multicast_org_local());
|
||||
ASIO_CHECK(!mcast_site_local_address.is_multicast_org_local());
|
||||
|
||||
ASIO_CHECK(!unspecified_address.is_multicast_site_local());
|
||||
ASIO_CHECK(!loopback_address.is_multicast_site_local());
|
||||
ASIO_CHECK(!link_local_address.is_multicast_site_local());
|
||||
ASIO_CHECK(!site_local_address.is_multicast_site_local());
|
||||
ASIO_CHECK(!v4_mapped_address.is_multicast_site_local());
|
||||
ASIO_CHECK(!v4_compat_address.is_multicast_site_local());
|
||||
ASIO_CHECK(!mcast_global_address.is_multicast_site_local());
|
||||
ASIO_CHECK(!mcast_link_local_address.is_multicast_site_local());
|
||||
ASIO_CHECK(!mcast_node_local_address.is_multicast_site_local());
|
||||
ASIO_CHECK(!mcast_org_local_address.is_multicast_site_local());
|
||||
ASIO_CHECK(mcast_site_local_address.is_multicast_site_local());
|
||||
|
||||
ASIO_CHECK(address_v6::loopback().is_loopback());
|
||||
}
|
||||
|
||||
} // namespace ip_address_v6_runtime
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
ASIO_TEST_SUITE
|
||||
(
|
||||
"ip/address_v6",
|
||||
ASIO_TEST_CASE(ip_address_v6_compile::test)
|
||||
ASIO_TEST_CASE(ip_address_v6_runtime::test)
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// address_v6_iterator.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
// Disable autolinking for unit tests.
|
||||
#if !defined(BOOST_ALL_NO_LIB)
|
||||
#define BOOST_ALL_NO_LIB 1
|
||||
#endif // !defined(BOOST_ALL_NO_LIB)
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include "asio/ip/address_v6_iterator.hpp"
|
||||
|
||||
#include "../unit_test.hpp"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
ASIO_TEST_SUITE
|
||||
(
|
||||
"ip/address_v6_iterator",
|
||||
ASIO_TEST_CASE(null_test)
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// address_v6_range.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
// Disable autolinking for unit tests.
|
||||
#if !defined(BOOST_ALL_NO_LIB)
|
||||
#define BOOST_ALL_NO_LIB 1
|
||||
#endif // !defined(BOOST_ALL_NO_LIB)
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include "asio/ip/address_v6_range.hpp"
|
||||
|
||||
#include "../unit_test.hpp"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
ASIO_TEST_SUITE
|
||||
(
|
||||
"ip/address_v6_range",
|
||||
ASIO_TEST_CASE(null_test)
|
||||
)
|
||||
@@ -88,6 +88,7 @@
|
||||
#endif
|
||||
|
||||
#include <openvpn/init/initprocess.hpp>
|
||||
#include <openvpn/common/bigmutex.hpp>
|
||||
#include <openvpn/common/size.hpp>
|
||||
#include <openvpn/common/platform_string.hpp>
|
||||
#include <openvpn/common/count.hpp>
|
||||
@@ -321,20 +322,28 @@ namespace openvpn {
|
||||
{
|
||||
const std::string title = "remote-override";
|
||||
ClientAPI::RemoteOverride ro;
|
||||
parent->remote_override(ro);
|
||||
if (!ro.error.empty())
|
||||
throw Exception("remote override exception: " + ro.error);
|
||||
try {
|
||||
parent->remote_override(ro);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
ro.error = e.what();
|
||||
}
|
||||
RemoteList::Item::Ptr ri(new RemoteList::Item);
|
||||
if (!ro.ip.empty())
|
||||
ri->set_ip_addr(IP::Addr(ro.ip, title));
|
||||
if (ro.host.empty())
|
||||
ro.host = ro.ip;
|
||||
HostPort::validate_host(ro.host, title);
|
||||
HostPort::validate_port(ro.port, title);
|
||||
ri->server_host = std::move(ro.host);
|
||||
ri->server_port = std::move(ro.port);
|
||||
ri->transport_protocol = Protocol::parse(ro.proto, Protocol::CLIENT_SUFFIX, title.c_str());
|
||||
|
||||
if (ro.error.empty())
|
||||
{
|
||||
if (!ro.ip.empty())
|
||||
ri->set_ip_addr(IP::Addr(ro.ip, title));
|
||||
if (ro.host.empty())
|
||||
ro.host = ro.ip;
|
||||
HostPort::validate_host(ro.host, title);
|
||||
HostPort::validate_port(ro.port, title);
|
||||
ri->server_host = std::move(ro.host);
|
||||
ri->server_port = std::move(ro.port);
|
||||
ri->transport_protocol = Protocol::parse(ro.proto, Protocol::CLIENT_SUFFIX, title.c_str());
|
||||
}
|
||||
else
|
||||
throw Exception("remote override exception: " + ro.error);
|
||||
return ri;
|
||||
}
|
||||
else
|
||||
@@ -542,10 +551,12 @@ namespace openvpn {
|
||||
void setup_async_stop_scopes()
|
||||
{
|
||||
stop_scope_local.reset(new AsioStopScope(*io_context(), async_stop_local(), [this]() {
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
session->graceful_stop();
|
||||
}));
|
||||
|
||||
stop_scope_global.reset(new AsioStopScope(*io_context(), async_stop_global(), [this]() {
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
trigger_async_stop_local();
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -551,7 +551,7 @@ namespace openvpn {
|
||||
virtual bool remote_override_enabled();
|
||||
virtual void remote_override(RemoteOverride&);
|
||||
|
||||
// Periodic convenience clock tick, controlled by Config::clock_tick_ms
|
||||
// Periodic convenience clock tick, controlled by Config::clockTickMS
|
||||
virtual void clock_tick();
|
||||
|
||||
// Do a crypto library self test
|
||||
@@ -610,3 +610,4 @@ namespace openvpn {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
if [ -z "$O3" ]; then
|
||||
echo O3 var must point to ovpn3 tree
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$DEP_DIR" ]; then
|
||||
echo DEP_DIR var must point to dependency build folder
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$DL" ]; then
|
||||
echo DL var must point to the download folder
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$TARGET" ]; then
|
||||
echo TARGET var must be defined
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# source vars
|
||||
. $O3/core/vars/vars-${TARGET}
|
||||
. $O3/core/deps/lib-versions
|
||||
|
||||
# source helper functions
|
||||
. $O3/core/deps/functions.sh
|
||||
|
||||
FNAME=cityhash-${CITYHASH_VERSION}.tar.gz
|
||||
PN=${CITYHASH_VERSION#*-}
|
||||
URL=https://codeload.github.com/google/cityhash/tar.gz/${CITYHASH_VERSION}
|
||||
CSUM=${CITYHASH_CSUM}
|
||||
|
||||
download
|
||||
|
||||
CC=cc
|
||||
LD=ld
|
||||
AR=ar
|
||||
RANLIB=ranlib
|
||||
[ "$GCC_CMD" ] && CC=$GCC_CMD
|
||||
[ "$LD_CMD" ] && LD=$LD_CMD
|
||||
[ "$AR_CMD" ] && AR=$AR_CMD
|
||||
[ "$RANLIB_CMD" ] && RANLIB=$RANLIB_CMD
|
||||
|
||||
if [ "$NO_WIPE" != "1" ]; then
|
||||
rm -rf $CITYHASH_VERSION
|
||||
tar xfz $DL/cityhash-$CITYHASH_VERSION.tar.gz
|
||||
fi
|
||||
|
||||
DIST=$(pwd)/cityhash/cityhash-$PLATFORM
|
||||
rm -rf $DIST
|
||||
mkdir -p $DIST/include
|
||||
mkdir $DIST/lib
|
||||
cd cityhash-$CITYHASH_VERSION
|
||||
CMD=./configure
|
||||
echo $CMD
|
||||
$CMD
|
||||
CMD="$CC $PLATFORM_FLAGS $OTHER_COMPILER_FLAGS $LIB_OPT_LEVEL $LIB_FPIC -I. -Isrc -c src/city.cc"
|
||||
echo $CMD
|
||||
$CMD
|
||||
$AR rc $DIST/lib/libcityhash.a city.o
|
||||
$RANLIB $DIST/lib/libcityhash.a
|
||||
cp src/city.h $DIST/include/
|
||||
exit 0
|
||||
@@ -14,3 +14,6 @@ export JSONCPP_CSUM=c49deac9e0933bcb7044f08516861a2d560988540b23de2ac1ad443b219a
|
||||
|
||||
export TAP_VERSION=0e30f5c13b3c7b0bdd60da915350f653e4c14d92
|
||||
export TAP_CSUM=8ff65f9e741c5ecfe1af904eaa38713f05639ce9457ef92041fd8e6b2a170315
|
||||
|
||||
export CITYHASH_VERSION=8af9b8c2b889d80c22d6bc26ba0df1afb79a30db
|
||||
export CITYHASH_CSUM=f70368facd15735dffc77fe2b27ab505bfdd05be5e9166d94149a8744c212f49
|
||||
@@ -47,6 +47,11 @@ if [ "$NO_WIPE" != "1" ]; then
|
||||
tar xfz $DL/$LZ4_VERSION.tar.gz
|
||||
fi
|
||||
|
||||
if [ "x$NO_BUILD" == x1 ]; then
|
||||
echo "Not building"
|
||||
exit
|
||||
fi
|
||||
|
||||
DIST=$(pwd)/lz4/lz4-$PLATFORM
|
||||
rm -rf $DIST
|
||||
mkdir -p $DIST/include
|
||||
|
||||
@@ -54,6 +54,11 @@ else
|
||||
apply_patches "mbedtls"
|
||||
fi
|
||||
|
||||
if [ "x$NO_BUILD" == x1 ]; then
|
||||
echo "Not building"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "x$TARGET" == xlinux* || "x$TARGET" == xosx* ]]; then
|
||||
# run unit tests and then clean
|
||||
echo RUNNING CHECK
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
From 5d31999442a41c154f6c56e91c8fe7705c74e2be Mon Sep 17 00:00:00 2001
|
||||
From: Arne Schwabe <arne@rfc2549.org>
|
||||
Date: Thu, 28 Dec 2017 00:19:10 +0100
|
||||
Subject: [PATCH] Use current cmake directory instead of source root directory
|
||||
when exuting config.pl
|
||||
|
||||
When mdbedtls is added as a subdirectory to another project this will
|
||||
call config.pl with the right path If mbedtls is build standalone
|
||||
current and root source directory are identical.
|
||||
|
||||
Signed-off-by: Arne Schwabe <arne@rfc2549.org>
|
||||
---
|
||||
CMakeLists.txt | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 3e47224ea1..2883eff270 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -31,7 +31,7 @@ find_package(Perl)
|
||||
if(PERL_FOUND)
|
||||
|
||||
# If NULL Entropy is configured, display an appropriate warning
|
||||
- execute_process(COMMAND ${PERL_EXECUTABLE} ${CMAKE_SOURCE_DIR}/scripts/config.pl -f ${CMAKE_SOURCE_DIR}/include/mbedtls/config.h get MBEDTLS_TEST_NULL_ENTROPY
|
||||
+ execute_process(COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/config.pl -f ${CMAKE_CURRENT_SOURCE_DIR}/include/mbedtls/config.h get MBEDTLS_TEST_NULL_ENTROPY
|
||||
RESULT_VARIABLE result)
|
||||
if(${result} EQUAL 0)
|
||||
message(WARNING ${NULL_ENTROPY_WARNING})
|
||||
@@ -13,6 +13,7 @@
|
||||
DF380AE9201F0DB80003272D /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DF380AE8201F0DB80003272D /* IOKit.framework */; };
|
||||
DF380AEB201F0DDC0003272D /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DF380AEA201F0DDC0003272D /* CoreServices.framework */; };
|
||||
DF380AED201F0E0E0003272D /* libmbedtls.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DF380AEC201F0E0E0003272D /* libmbedtls.a */; };
|
||||
DF838B412090AC2F00B68F90 /* liblz4.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DF838B402090AC2F00B68F90 /* liblz4.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -36,6 +37,7 @@
|
||||
DF380AE8201F0DB80003272D /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
|
||||
DF380AEA201F0DDC0003272D /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
|
||||
DF380AEC201F0E0E0003272D /* libmbedtls.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmbedtls.a; path = "../../../deps/mbedtls/mbedtls-osx/library/libmbedtls.a"; sourceTree = "<group>"; };
|
||||
DF838B402090AC2F00B68F90 /* liblz4.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = liblz4.a; path = "../../../deps/lz4/lz4-osx/lib/liblz4.a"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -43,6 +45,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DF838B412090AC2F00B68F90 /* liblz4.a in Frameworks */,
|
||||
DF380AED201F0E0E0003272D /* libmbedtls.a in Frameworks */,
|
||||
DF380AEB201F0DDC0003272D /* CoreServices.framework in Frameworks */,
|
||||
DF380AE9201F0DB80003272D /* IOKit.framework in Frameworks */,
|
||||
@@ -83,6 +86,7 @@
|
||||
DF380AE3201F0D4F0003272D /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DF838B402090AC2F00B68F90 /* liblz4.a */,
|
||||
DF380AEC201F0E0E0003272D /* libmbedtls.a */,
|
||||
DF380AEA201F0DDC0003272D /* CoreServices.framework */,
|
||||
DF380AE8201F0DB80003272D /* IOKit.framework */,
|
||||
@@ -267,13 +271,19 @@
|
||||
USE_ASIO,
|
||||
ASIO_STANDALONE,
|
||||
USE_MBEDTLS,
|
||||
HAVE_LZ4,
|
||||
LZ4_DISABLE_DEPRECATE_WARNINGS,
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/../..\"",
|
||||
"\"$(SRCROOT)/../../../deps/asio/asio/include\"",
|
||||
"\"$(SRCROOT)/../../../deps/mbedtls/mbedtls-osx/include\"",
|
||||
"\"$(SRCROOT)/../../../deps/lz4/lz4-osx/include\"",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/../../../deps/mbedtls/mbedtls-osx/library\"",
|
||||
"\"$(SRCROOT)/../../../deps/lz4/lz4-osx/lib\"",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../../../deps/mbedtls/mbedtls-osx/library\"";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
STRINGS_FILE_OUTPUT_ENCODING = "UTF-8";
|
||||
};
|
||||
@@ -287,13 +297,19 @@
|
||||
USE_ASIO,
|
||||
ASIO_STANDALONE,
|
||||
USE_MBEDTLS,
|
||||
HAVE_LZ4,
|
||||
LZ4_DISABLE_DEPRECATE_WARNINGS,
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/../..\"",
|
||||
"\"$(SRCROOT)/../../../deps/asio/asio/include\"",
|
||||
"\"$(SRCROOT)/../../../deps/mbedtls/mbedtls-osx/include\"",
|
||||
"\"$(SRCROOT)/../../../deps/lz4/lz4-osx/include\"",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/../../../deps/mbedtls/mbedtls-osx/library\"",
|
||||
"\"$(SRCROOT)/../../../deps/lz4/lz4-osx/lib\"",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../../../deps/mbedtls/mbedtls-osx/library\"";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
STRINGS_FILE_OUTPUT_ENCODING = "UTF-8";
|
||||
};
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// 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 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace openvpn {
|
||||
|
||||
// return ip_addr in brackets if it is IPv6
|
||||
std::string quote_ip(const std::string& ip_addr)
|
||||
{
|
||||
if (ip_addr.find(':') != std::string::npos)
|
||||
return '[' + ip_addr + ']';
|
||||
else
|
||||
return ip_addr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// 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 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <openvpn/addr/route.hpp>
|
||||
#include <openvpn/common/exception.hpp>
|
||||
#include <openvpn/random/randapi.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace IP {
|
||||
|
||||
inline Addr random_addr(const Addr::Version v, RandomAPI& prng)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
case Addr::V4:
|
||||
return Addr::from_ipv4(IPv4::Addr::from_uint32(prng.rand_get<std::uint32_t>()));
|
||||
case Addr::V6:
|
||||
{
|
||||
unsigned char bytes[16];
|
||||
prng.rand_fill(bytes);
|
||||
return Addr::from_ipv6(IPv6::Addr::from_byte_string(bytes));
|
||||
}
|
||||
default:
|
||||
throw ip_exception("address unspecified");
|
||||
}
|
||||
}
|
||||
|
||||
inline Route random_subnet(const Route& templ,
|
||||
const unsigned int prefix_len,
|
||||
RandomAPI& prng)
|
||||
{
|
||||
if (!templ.is_canonical())
|
||||
throw Exception("IP::random_subnet: template route not canonical: " + templ.to_string());
|
||||
return Route(((random_addr(templ.addr.version(), prng) & ~templ.netmask()) | templ.addr)
|
||||
& Addr::netmask_from_prefix_len(templ.addr.version(), prefix_len),
|
||||
prefix_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,6 +176,11 @@ namespace openvpn {
|
||||
return std::tie(prefix_len, addr) == std::tie(other.prefix_len, other.addr);
|
||||
}
|
||||
|
||||
bool operator!=(const RouteType& other) const
|
||||
{
|
||||
return std::tie(prefix_len, addr) != std::tie(other.prefix_len, other.addr);
|
||||
}
|
||||
|
||||
bool operator<(const RouteType& other) const
|
||||
{
|
||||
return std::tie(prefix_len, addr) < std::tie(other.prefix_len, other.addr);
|
||||
|
||||
@@ -55,15 +55,15 @@ namespace openvpn {
|
||||
return !username.empty();
|
||||
}
|
||||
|
||||
bool is_valid_user_pass() const
|
||||
bool is_valid_user_pass(const bool strict) const
|
||||
{
|
||||
return ValidateCreds::is_valid(ValidateCreds::USERNAME, username)
|
||||
&& ValidateCreds::is_valid(ValidateCreds::PASSWORD, password);
|
||||
return ValidateCreds::is_valid(ValidateCreds::USERNAME, username, strict)
|
||||
&& ValidateCreds::is_valid(ValidateCreds::PASSWORD, password, strict);
|
||||
}
|
||||
|
||||
bool is_valid() const
|
||||
bool is_valid(const bool strict) const
|
||||
{
|
||||
return defined() && is_valid_user_pass();
|
||||
return defined() && is_valid_user_pass(strict);
|
||||
}
|
||||
|
||||
void wipe_password()
|
||||
|
||||
@@ -38,22 +38,30 @@ namespace openvpn {
|
||||
};
|
||||
|
||||
template <typename STRING>
|
||||
static bool is_valid(const Type type, const STRING& cred)
|
||||
static bool is_valid(const Type type, const STRING& cred, const bool strict)
|
||||
{
|
||||
size_t max_len_flags;
|
||||
switch (type)
|
||||
if (strict)
|
||||
{
|
||||
case USERNAME:
|
||||
// length <= 256 unicode chars, no control chars allowed
|
||||
max_len_flags = 256 | Unicode::UTF8_NO_CTRL;
|
||||
break;
|
||||
case PASSWORD:
|
||||
case RESPONSE:
|
||||
// length <= 16384 unicode chars
|
||||
max_len_flags = 16384;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
// length <= 512 unicode chars, no control chars allowed
|
||||
max_len_flags = 512 | Unicode::UTF8_NO_CTRL;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case USERNAME:
|
||||
// length <= 512 unicode chars, no control chars allowed
|
||||
max_len_flags = 512 | Unicode::UTF8_NO_CTRL;
|
||||
break;
|
||||
case PASSWORD:
|
||||
case RESPONSE:
|
||||
// length <= 16384 unicode chars
|
||||
max_len_flags = 16384;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return Unicode::is_valid_utf8(cred, max_len_flags);
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <openvpn/common/bigmutex.hpp>
|
||||
#include <openvpn/common/rc.hpp>
|
||||
#include <openvpn/asio/asiowork.hpp>
|
||||
#include <openvpn/error/excode.hpp>
|
||||
@@ -173,6 +174,7 @@ namespace openvpn {
|
||||
if (!halt)
|
||||
openvpn_io::post(io_context, [self=Ptr(this)]()
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->graceful_stop();
|
||||
});
|
||||
}
|
||||
@@ -220,6 +222,7 @@ namespace openvpn {
|
||||
restart_wait_timer.expires_after(Time::Duration::seconds(seconds));
|
||||
restart_wait_timer.async_wait([self=Ptr(this), gen=generation](const openvpn_io::error_code& error)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->restart_wait_callback(gen, error);
|
||||
});
|
||||
}
|
||||
@@ -230,6 +233,7 @@ namespace openvpn {
|
||||
if (!halt)
|
||||
openvpn_io::post(io_context, [self=Ptr(this), reason]()
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->pause(reason);
|
||||
});
|
||||
}
|
||||
@@ -239,6 +243,7 @@ namespace openvpn {
|
||||
if (!halt)
|
||||
openvpn_io::post(io_context, [self=Ptr(this)]()
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->resume();
|
||||
});
|
||||
}
|
||||
@@ -248,6 +253,7 @@ namespace openvpn {
|
||||
if (!halt)
|
||||
openvpn_io::post(io_context, [self=Ptr(this), seconds]()
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->reconnect(seconds);
|
||||
});
|
||||
}
|
||||
@@ -268,6 +274,7 @@ namespace openvpn {
|
||||
if (!halt)
|
||||
openvpn_io::post(io_context, [self=Ptr(this), msg=std::move(msg)]()
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->post_cc_msg(msg);
|
||||
});
|
||||
}
|
||||
@@ -351,6 +358,7 @@ namespace openvpn {
|
||||
conn_timer.expires_after(Time::Duration::seconds(conn_timeout));
|
||||
conn_timer.async_wait([self=Ptr(this), gen=generation](const openvpn_io::error_code& error)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->conn_timer_callback(gen, error);
|
||||
});
|
||||
conn_timer_pending = true;
|
||||
@@ -399,6 +407,7 @@ namespace openvpn {
|
||||
restart_wait_timer.expires_after(Time::Duration::milliseconds(delay_ms));
|
||||
restart_wait_timer.async_wait([self=Ptr(this), gen=generation](const openvpn_io::error_code& error)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->restart_wait_callback(gen, error);
|
||||
});
|
||||
}
|
||||
@@ -602,6 +611,7 @@ namespace openvpn {
|
||||
server_poll_timer.expires_after(client_options->server_poll_timeout());
|
||||
server_poll_timer.async_wait([self=Ptr(this), gen=generation](const openvpn_io::error_code& error)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->server_poll_callback(gen, error);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace openvpn {
|
||||
DISCONNECTED=0,
|
||||
CONNECTED,
|
||||
RECONNECTING,
|
||||
AUTH_PENDING,
|
||||
RESOLVE,
|
||||
WAIT,
|
||||
WAIT_PROXY,
|
||||
@@ -93,6 +94,7 @@ namespace openvpn {
|
||||
"DISCONNECTED",
|
||||
"CONNECTED",
|
||||
"RECONNECTING",
|
||||
"AUTH_PENDING",
|
||||
"RESOLVE",
|
||||
"WAIT",
|
||||
"WAIT_PROXY",
|
||||
@@ -210,6 +212,11 @@ namespace openvpn {
|
||||
Reconnecting() : Base(RECONNECTING) {}
|
||||
};
|
||||
|
||||
struct AuthPending : public Base
|
||||
{
|
||||
AuthPending() : Base(AUTH_PENDING) {}
|
||||
};
|
||||
|
||||
struct GetConfig : public Base
|
||||
{
|
||||
GetConfig() : Base(GET_CONFIG) {}
|
||||
|
||||
@@ -649,6 +649,23 @@ namespace openvpn {
|
||||
else
|
||||
cli_events->add_event(std::move(ev));
|
||||
}
|
||||
else if (info && string::starts_with(msg, "INFO_PRE,"))
|
||||
{
|
||||
// INFO_PRE is like INFO but it is never buffered
|
||||
ClientEvent::Base::Ptr ev = new ClientEvent::Info(msg.substr(9));
|
||||
cli_events->add_event(std::move(ev));
|
||||
}
|
||||
else if (msg == "AUTH_PENDING")
|
||||
{
|
||||
// AUTH_PENDING indicates an out-of-band authentication step must
|
||||
// be performed before the server will send the PUSH_REPLY message.
|
||||
if (!auth_pending)
|
||||
{
|
||||
auth_pending = true;
|
||||
ClientEvent::Base::Ptr ev = new ClientEvent::AuthPending();
|
||||
cli_events->add_event(std::move(ev));
|
||||
}
|
||||
}
|
||||
else if (msg == "RELAY")
|
||||
{
|
||||
if (Base::conf().relay_mode)
|
||||
@@ -761,9 +778,22 @@ namespace openvpn {
|
||||
set_housekeeping_timer();
|
||||
|
||||
{
|
||||
const Time::Duration newdur = std::min(dur + Time::Duration::seconds(1),
|
||||
Time::Duration::seconds(3));
|
||||
schedule_push_request_callback(newdur);
|
||||
if (auth_pending)
|
||||
{
|
||||
// With auth_pending, we can dial back the PUSH_REQUEST
|
||||
// frequency, but we still need back-and-forth network
|
||||
// activity to avoid an inactivity timeout, since the crypto
|
||||
// layer (and hence keepalive ping) is not initialized until
|
||||
// we receive the PUSH_REPLY from the server.
|
||||
schedule_push_request_callback(Time::Duration::seconds(8));
|
||||
}
|
||||
else
|
||||
{
|
||||
// step function with ceiling: 1 sec, 2 secs, 3 secs, 3, 3, ...
|
||||
const Time::Duration newdur = std::min(dur + Time::Duration::seconds(1),
|
||||
Time::Duration::seconds(3));
|
||||
schedule_push_request_callback(newdur);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -780,6 +810,7 @@ namespace openvpn {
|
||||
push_request_timer.expires_after(dur);
|
||||
push_request_timer.async_wait([self=Ptr(this), dur](const openvpn_io::error_code& error)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->send_push_request_callback(dur, error);
|
||||
});
|
||||
}
|
||||
@@ -855,6 +886,7 @@ namespace openvpn {
|
||||
housekeeping_timer.expires_at(next);
|
||||
housekeeping_timer.async_wait([self=Ptr(this)](const openvpn_io::error_code& error)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->housekeeping_callback(error);
|
||||
});
|
||||
}
|
||||
@@ -888,6 +920,7 @@ namespace openvpn {
|
||||
inactive_timer.expires_after(inactive_duration);
|
||||
inactive_timer.async_wait([self=Ptr(this)](const openvpn_io::error_code& error)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->inactive_callback(error);
|
||||
});
|
||||
}
|
||||
@@ -978,6 +1011,7 @@ namespace openvpn {
|
||||
info_hold_timer.expires_after(Time::Duration::seconds(1));
|
||||
info_hold_timer.async_wait([self=Ptr(this)](const openvpn_io::error_code& error)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->info_hold_callback(error);
|
||||
});
|
||||
}
|
||||
@@ -1042,6 +1076,7 @@ namespace openvpn {
|
||||
|
||||
bool first_packet_received_ = false;
|
||||
bool sent_push_request = false;
|
||||
bool auth_pending = false;
|
||||
|
||||
SessionStats::Ptr cli_stats;
|
||||
ClientEvent::Queue::Ptr cli_events;
|
||||
|
||||
@@ -341,6 +341,7 @@ namespace openvpn {
|
||||
resolver.async_resolve(item.server_host, item.server_port,
|
||||
[self=Ptr(this)](const openvpn_io::error_code& error, openvpn_io::ip::tcp::resolver::results_type results)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->resolve_callback(error, results);
|
||||
});
|
||||
return;
|
||||
@@ -587,18 +588,19 @@ namespace openvpn {
|
||||
{
|
||||
if (remote_override)
|
||||
{
|
||||
list.clear();
|
||||
index.reset();
|
||||
Item::Ptr item = remote_override->get();
|
||||
if (item)
|
||||
list.push_back(std::move(item));
|
||||
}
|
||||
else
|
||||
{
|
||||
index.increment(list.size(), secondary_length(index.primary()));
|
||||
if (!enable_cache)
|
||||
reset_item(index.primary());
|
||||
{
|
||||
list.clear();
|
||||
index.reset();
|
||||
list.push_back(std::move(item));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
index.increment(list.size(), secondary_length(index.primary()));
|
||||
if (!enable_cache)
|
||||
reset_item(index.primary());
|
||||
}
|
||||
|
||||
// Return details about current connection entry.
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
// 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 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/>.
|
||||
|
||||
// Macro to maintain thread-safety.
|
||||
|
||||
// Platforms like UWP and iOS may call core methods
|
||||
// from another threads. Since core is not thread-safe,
|
||||
// we provide OPENVPN_ASYNC_HANDLER macro which instantiates
|
||||
// lock guard. It follows RIAA principle and locks global
|
||||
// mutex in constructor and unlocks in destructor. This
|
||||
// guarantees that code in block protected with this macro
|
||||
// won't be called simultaneously from different threads.
|
||||
|
||||
#ifndef OPENVPN_COMMON_BIGMUTEX_H
|
||||
#define OPENVPN_COMMON_BIGMUTEX_H
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace openvpn {
|
||||
namespace bigmutex {
|
||||
std::recursive_mutex the_recursive_mutex;
|
||||
}
|
||||
|
||||
#ifdef OPENVPN_ENABLE_BIGMUTEX
|
||||
#define OPENVPN_ASYNC_HANDLER \
|
||||
std::lock_guard<std::recursive_mutex> lg(bigmutex::the_recursive_mutex);
|
||||
#else
|
||||
#define OPENVPN_ASYNC_HANDLER
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -33,6 +33,18 @@
|
||||
|
||||
namespace openvpn {
|
||||
|
||||
/**
|
||||
* Renders an integer value within the hexadecimal range (0-15)
|
||||
* to a hexadecimal character.
|
||||
*
|
||||
* @param c Integer to render as a hexadecimal character.
|
||||
* @param caps Boolean (default false) which sets the outout to
|
||||
* be either lower case (false) or upper case (true).
|
||||
*
|
||||
* @return Returns a char with the hexadecimal representation of
|
||||
* the input value. If the value is out-of-range (outside
|
||||
* of 0-15), it will be replaced with a questionmark (?).
|
||||
*/
|
||||
inline char render_hex_char(const int c, const bool caps=false)
|
||||
{
|
||||
if (c < 10)
|
||||
@@ -43,6 +55,18 @@ namespace openvpn {
|
||||
return '?';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses a character in the range {0..9,A-F,a-f} to an
|
||||
* integer value. Used to convert hexadecimal character to integer.
|
||||
* Only a single character is parsed by this function.
|
||||
*
|
||||
* @param c Character to be be parsed.
|
||||
*
|
||||
* @return Returns an integer value of the hexadecimal input. If the
|
||||
* input character is invalid, outside of {0..9,A-F,a-f}, it will
|
||||
* return -1.
|
||||
*/
|
||||
inline int parse_hex_char(const char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
@@ -55,9 +79,20 @@ namespace openvpn {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class which Renders a single byte as hexadecimal
|
||||
*/
|
||||
class RenderHexByte
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initializes a new object
|
||||
*
|
||||
* @param byte Unsigned char (one byte) to be processed
|
||||
* @param caps Boolean (default false) which sets the outout to
|
||||
* be either lower case (false) or upper case (true).
|
||||
*/
|
||||
RenderHexByte(const unsigned char byte, const bool caps=false)
|
||||
{
|
||||
c[0] = render_hex_char(byte >> 4, caps);
|
||||
@@ -67,12 +102,31 @@ namespace openvpn {
|
||||
char char1() const { return c[0]; }
|
||||
char char2() const { return c[1]; }
|
||||
|
||||
/**
|
||||
* Retrieve the hexadecimal representation of the value.
|
||||
* Warning: The result is a non-NULL terminated string.
|
||||
*
|
||||
* @return Returns a non-NULL terminated 2 byte string with the hexadecimal
|
||||
* representation of the initial value. The return value is guaranteed
|
||||
* to always be 2 bytes.
|
||||
*/
|
||||
const char *str2() const { return c; } // Note: length=2, NOT null terminated
|
||||
|
||||
private:
|
||||
char c[2];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Render a byte buffer (unsigned char *) as a hexadecimal string.
|
||||
*
|
||||
* @param data Unsigned char pointer to buffer to render.
|
||||
* @param size size_t of the number of bytes to parse from the buffer.
|
||||
* @param caps Boolean (default false) which sets the outout to
|
||||
* be either lower case (false) or upper case (true).
|
||||
*
|
||||
* @return Returns a std::string of the complete hexadecimal representation
|
||||
*/
|
||||
inline std::string render_hex(const unsigned char *data, size_t size, const bool caps=false)
|
||||
{
|
||||
if (!data)
|
||||
@@ -88,11 +142,36 @@ namespace openvpn {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render a byte buffer (void *) as a hexadecimal string.
|
||||
*
|
||||
* @param data Void pointer to buffer to render.
|
||||
* @param size size_t of the number of bytes to parse from the buffer.
|
||||
* @param caps Boolean (default false) which sets the outout to
|
||||
* be either lower case (false) or upper case (true).
|
||||
*
|
||||
* @return Returns a std::string of the complete hexadecimal representation.
|
||||
*/
|
||||
inline std::string render_hex(const void *data, const size_t size, const bool caps=false)
|
||||
{
|
||||
return render_hex((const unsigned char *)data, size, caps);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Variant of @render_hex(const unsiged char *,...) which adds a
|
||||
* separator between each byte
|
||||
*
|
||||
* @param data Unsigned char pointer to buffer to render.
|
||||
* @param size size_t of the number of bytes to parse from the buffer.
|
||||
* @param sep A single character to use as the separator.
|
||||
* @param caps Boolean (default false) which sets the outout to
|
||||
* be either lower case (false) or upper case (true).
|
||||
*
|
||||
* @return Returns a std::string of the complete hexadecimal representation
|
||||
* with each byte separated by a given character.
|
||||
*/
|
||||
inline std::string render_hex_sep(const unsigned char *data, size_t size, const char sep, const bool caps=false)
|
||||
{
|
||||
if (!data)
|
||||
@@ -112,11 +191,36 @@ namespace openvpn {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variant of @render_hex(const void *,...) which adds a
|
||||
* separator between each byte
|
||||
|
||||
* @param data Void pointer to buffer to render.
|
||||
* @param size size_t of the number of bytes to parse from the buffer.
|
||||
* @param sep A single character to use as the separator.
|
||||
* @param caps Boolean (default false) which sets the outout to
|
||||
* be either lower case (false) or upper case (true).
|
||||
*
|
||||
* @return Returns a std::string of the complete hexadecimal representation
|
||||
* with each byte separated by a given character.
|
||||
*/
|
||||
inline std::string render_hex_sep(const void *data, const size_t size, const char sep, const bool caps=false)
|
||||
{
|
||||
return render_hex_sep((const unsigned char *)data, size, sep, caps);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render a std::vector<T> container as a hexadecimal string.
|
||||
* T must be a data type compatible with
|
||||
* RenderHexByte(const unsigned char,...)
|
||||
*
|
||||
* @param data std::vector<T> containing the data to render
|
||||
* @param caps Boolean (default false) which sets the outout to
|
||||
* be either lower case (false) or upper case (true).
|
||||
*
|
||||
* @return Returns a std::string of the complete hexadecimal representation.
|
||||
*/
|
||||
template <typename V>
|
||||
inline std::string render_hex_generic(const V& data, const bool caps=false)
|
||||
{
|
||||
@@ -131,6 +235,18 @@ namespace openvpn {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders a combined hexadecimal and character dump of a buffer,
|
||||
* with the typical 16 bytes split between hexadecimal and character
|
||||
* separation per line.
|
||||
*
|
||||
* @param data Unsigned char pointer to the buffer to dump.
|
||||
* @param size Size of the buffer to render.
|
||||
*
|
||||
* @return Returns a string containing a preformatted output of the
|
||||
* hexadecimal dump.
|
||||
*/
|
||||
inline std::string dump_hex(const unsigned char *data, size_t size)
|
||||
{
|
||||
if (!data)
|
||||
@@ -163,19 +279,56 @@ namespace openvpn {
|
||||
return os.str();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders a combined hexadecimal and character dump of a std::string buffer,
|
||||
* with the typical 16 bytes split between hexadecimal and character
|
||||
* separation per line.
|
||||
*
|
||||
* @param data std::string containing the buffer to render
|
||||
*
|
||||
* @return Returns a string containing a preformatted output of the
|
||||
* hexadecimal dump.
|
||||
*/
|
||||
inline std::string dump_hex(const std::string& str)
|
||||
{
|
||||
return dump_hex((const unsigned char *)str.c_str(), str.length());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders a combined hexadecimal and character dump of a std::vector<T>
|
||||
* based buffer, with the typical 16 bytes split between hexadecimal and
|
||||
* character separation per line.
|
||||
*
|
||||
* @param data std::vector<T> containing the buffer to render
|
||||
*
|
||||
* @return Returns a string containing a preformatted output of the
|
||||
* hexadecimal dump.
|
||||
*/
|
||||
template <typename V>
|
||||
inline std::string dump_hex(const V& data)
|
||||
{
|
||||
return dump_hex(data.c_data(), data.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Declaration of a hexadecimal parsing error exception class
|
||||
*/
|
||||
OPENVPN_SIMPLE_EXCEPTION(parse_hex_error);
|
||||
|
||||
|
||||
/**
|
||||
* Parses a std::string containing a hexadecimal value into
|
||||
* a std::vector<T>.
|
||||
*
|
||||
* @param dest std::vector<T> destination buffer to use.
|
||||
* @param str std::string& containing the hexadecimal string to parse.
|
||||
*
|
||||
* @return Returns nothing on success. Will throw a parse_hex_error
|
||||
* exception if the input is invalid/not parseable as a hexadecimal
|
||||
* number.
|
||||
*/
|
||||
template <typename V>
|
||||
inline void parse_hex(V& dest, const std::string& str)
|
||||
{
|
||||
@@ -193,7 +346,19 @@ namespace openvpn {
|
||||
throw parse_hex_error(); // straggler char
|
||||
}
|
||||
|
||||
// note -- currently doesn't detect overflow
|
||||
|
||||
/**
|
||||
* Parses a char buffer (C string) containing a hexadecimal
|
||||
* string into a templated (T) variable. The input buffer
|
||||
* MUST be NULL terminated.
|
||||
*
|
||||
* WARNING: There are _NO_ overflow checks.
|
||||
*
|
||||
* @param str Char pointer (char *) to the buffer to be parsed.
|
||||
* @param retval Return buffer where the parsed value is stored.
|
||||
*
|
||||
* @return Returns true on successful parsing, otherwise false.
|
||||
*/
|
||||
template <typename T>
|
||||
inline bool parse_hex_number(const char *str, T& retval)
|
||||
{
|
||||
@@ -220,12 +385,37 @@ namespace openvpn {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Variant of @parse_hex_number(const char *, ...) which takes a std::string
|
||||
* as the input.
|
||||
*
|
||||
* @param str std::string containing the hexadecimal string to be parsed.
|
||||
* @param retval Return buffer where the parsed value is stored.
|
||||
*
|
||||
* @return Returns true on successful parsing, otherwise false.
|
||||
*/
|
||||
template <typename T>
|
||||
inline bool parse_hex_number(const std::string& str, T& retval)
|
||||
{
|
||||
return parse_hex_number(str.c_str(), retval);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses a std::string containing a hexadecimal
|
||||
* string into a templated (T) variable.
|
||||
*
|
||||
* NOTE: Currently doesn't detect overflow
|
||||
*
|
||||
* @param str std::string containing the hexadecimal
|
||||
* string to be parsed.
|
||||
*
|
||||
* @return Returns a template T variable containing the
|
||||
* parsed value on success. Will throw the parse_hex_error
|
||||
* exception on parsing errors.
|
||||
*
|
||||
*/
|
||||
template <typename T>
|
||||
inline T parse_hex_number(const std::string& str)
|
||||
{
|
||||
@@ -235,6 +425,18 @@ namespace openvpn {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a templated T variable containing a numeric value
|
||||
* into a std::string containing a hexadecimal representation.
|
||||
*
|
||||
* @param value Numeric (T) value to represent as hexadecimal.
|
||||
* @param caps Boolean (default false) which sets the outout to
|
||||
* be either lower case (false) or upper case (true).
|
||||
*
|
||||
* @return Retuns a std::string containing the hexadecimal
|
||||
* representation on succes. Will throw a parse_hex_error
|
||||
* exception on parsing errors.
|
||||
*/
|
||||
template <typename T>
|
||||
inline std::string render_hex_number(T value, const bool caps=false)
|
||||
{
|
||||
@@ -247,6 +449,18 @@ namespace openvpn {
|
||||
return render_hex(buf, sizeof(T), caps);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders a single byte as a hexadecimal string
|
||||
*
|
||||
* @param value Unsigned char (byte) to be represented as hexadecimal.
|
||||
* @param caps Boolean (default false) which sets the outout to
|
||||
* be either lower case (false) or upper case (true).
|
||||
*
|
||||
* @return Returns a std::string with the hexadecimal representation
|
||||
* of the input value. The result will always contain only
|
||||
* two characters.
|
||||
*/
|
||||
inline std::string render_hex_number(unsigned char uc, const bool caps=false)
|
||||
{
|
||||
RenderHexByte b(uc, caps);
|
||||
|
||||
@@ -313,6 +313,11 @@ namespace openvpn {
|
||||
return rc;
|
||||
}
|
||||
|
||||
static constexpr bool is_thread_safe()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef OPENVPN_RC_NOTIFY
|
||||
void notify_release() noexcept
|
||||
{
|
||||
@@ -394,6 +399,11 @@ namespace openvpn {
|
||||
return rc.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
static constexpr bool is_thread_safe()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef OPENVPN_RC_NOTIFY
|
||||
void notify_release() noexcept
|
||||
{
|
||||
@@ -454,6 +464,11 @@ namespace openvpn {
|
||||
return refcount_.use_count();
|
||||
}
|
||||
|
||||
static constexpr bool is_thread_safe()
|
||||
{
|
||||
return RCImpl::is_thread_safe();
|
||||
}
|
||||
|
||||
private:
|
||||
RC(const RC&) = delete;
|
||||
RC& operator=(const RC&) = delete;
|
||||
|
||||
@@ -54,9 +54,10 @@ namespace openvpn {
|
||||
}
|
||||
|
||||
// Create a random Session ID.
|
||||
explicit SessionIDType(RandomAPI& rng)
|
||||
explicit SessionIDType(RandomAPI& rng, const bool allow_noncrypto_rng=false)
|
||||
{
|
||||
rng.assert_crypto();
|
||||
if (!allow_noncrypto_rng)
|
||||
rng.assert_crypto();
|
||||
rng.rand_bytes(u.data, sizeof(u.data));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// packet encryption, packet authentication, and
|
||||
// packet compression.
|
||||
//
|
||||
// Copyright (C) 2012-2017 OpenVPN Inc.
|
||||
// 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
|
||||
@@ -21,9 +21,8 @@
|
||||
|
||||
// Current version of the OpenVPN core
|
||||
|
||||
#ifndef OPENVPN_COMMON_VERSION_H
|
||||
#define OPENVPN_COMMON_VERSION_H
|
||||
#pragma once
|
||||
|
||||
#ifndef OPENVPN_VERSION
|
||||
#define OPENVPN_VERSION "3.git:master"
|
||||
|
||||
#endif // OPENVPN_COMMON_VERSION_H
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,761 @@
|
||||
// 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_TRANSPORT_DCO_DCOCLI_H
|
||||
#define OPENVPN_TRANSPORT_DCO_DCOCLI_H
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#include <openvpn/common/size.hpp>
|
||||
#include <openvpn/common/exception.hpp>
|
||||
#include <openvpn/common/to_string.hpp>
|
||||
#include <openvpn/buffer/asiobuf.hpp>
|
||||
#include <openvpn/time/time.hpp>
|
||||
#include <openvpn/transport/client/transbase.hpp>
|
||||
#include <openvpn/tun/client/tunbase.hpp>
|
||||
#include <openvpn/tun/builder/capture.hpp>
|
||||
#include <openvpn/tun/linux/client/tuncli.hpp>
|
||||
#include <openvpn/transport/dco.hpp>
|
||||
#include <openvpn/kovpn/kovpn.hpp>
|
||||
#include <openvpn/kovpn/kodev.hpp>
|
||||
#include <openvpn/kovpn/korekey.hpp>
|
||||
#include <openvpn/kovpn/kostats.hpp>
|
||||
#include <openvpn/linux/procfs.hpp>
|
||||
#include <openvpn/dco/ipcollbase.hpp>
|
||||
|
||||
#ifdef ENABLE_PG
|
||||
#include <openvpn/kovpn/kodevtun.hpp>
|
||||
#include <openvpn/kovpn/ipcoll.hpp>
|
||||
#endif
|
||||
|
||||
// client-side DCO (Data Channel Offload) module for Linux/kovpn
|
||||
|
||||
namespace openvpn {
|
||||
namespace DCOTransport {
|
||||
|
||||
OPENVPN_EXCEPTION(dco_error);
|
||||
|
||||
class ClientConfig : public DCO,
|
||||
public TransportClientFactory,
|
||||
public TunClientFactory
|
||||
{
|
||||
public:
|
||||
typedef RCPtr<ClientConfig> Ptr;
|
||||
|
||||
std::string dev_name;
|
||||
|
||||
DCO::TransportConfig transport;
|
||||
DCO::TunConfig tun;
|
||||
|
||||
int trunk_unit = -1;
|
||||
|
||||
virtual TunClientFactory::Ptr new_tun_factory(const DCO::TunConfig& conf, const OptionList& opt) override
|
||||
{
|
||||
tun = conf;
|
||||
|
||||
// set a default MTU
|
||||
if (!tun.tun_prop.mtu)
|
||||
tun.tun_prop.mtu = 1500;
|
||||
|
||||
// parse "dev" option
|
||||
{
|
||||
const Option* dev = opt.get_ptr("dev");
|
||||
if (dev)
|
||||
dev_name = dev->get(1, 64);
|
||||
else
|
||||
dev_name = "ovpnc";
|
||||
}
|
||||
|
||||
// parse trunk-unit
|
||||
trunk_unit = opt.get_num<decltype(trunk_unit)>("trunk-unit", 1, trunk_unit, 0, 511);
|
||||
|
||||
return TunClientFactory::Ptr(this);
|
||||
}
|
||||
|
||||
virtual TransportClientFactory::Ptr new_transport_factory(const DCO::TransportConfig& conf) override
|
||||
{
|
||||
transport = conf;
|
||||
return TransportClientFactory::Ptr(this);
|
||||
}
|
||||
|
||||
virtual TunClient::Ptr new_tun_client_obj(openvpn_io::io_context& io_context,
|
||||
TunClientParent& parent,
|
||||
TransportClient* transcli) override;
|
||||
|
||||
virtual TransportClient::Ptr new_transport_client_obj(openvpn_io::io_context& io_context,
|
||||
TransportClientParent* parent) override;
|
||||
|
||||
static DCO::Ptr new_controller()
|
||||
{
|
||||
return new ClientConfig();
|
||||
}
|
||||
|
||||
private:
|
||||
ClientConfig() {}
|
||||
};
|
||||
|
||||
class Client : public TransportClient,
|
||||
public TunClient,
|
||||
public KoRekey::Receiver,
|
||||
public SessionStats::DCOTransportSource
|
||||
{
|
||||
friend class ClientConfig;
|
||||
|
||||
typedef RCPtr<Client> Ptr;
|
||||
|
||||
struct ProtoBase
|
||||
{
|
||||
ProtoBase() {}
|
||||
virtual IP::Addr server_endpoint_addr() const = 0;
|
||||
virtual void close() = 0;
|
||||
virtual ~ProtoBase() {}
|
||||
|
||||
ProtoBase(const ProtoBase&) = delete;
|
||||
ProtoBase& operator=(const ProtoBase&) = delete;
|
||||
};
|
||||
|
||||
struct UDP : public ProtoBase
|
||||
{
|
||||
UDP(openvpn_io::io_context& io_context)
|
||||
: resolver(io_context),
|
||||
socket(io_context)
|
||||
{
|
||||
}
|
||||
|
||||
virtual IP::Addr server_endpoint_addr() const override
|
||||
{
|
||||
return IP::Addr::from_asio(server_endpoint.address());
|
||||
}
|
||||
|
||||
virtual void close() override
|
||||
{
|
||||
socket.close();
|
||||
resolver.cancel();
|
||||
}
|
||||
|
||||
openvpn_io::ip::udp::resolver resolver;
|
||||
openvpn_io::ip::udp::socket socket;
|
||||
UDPTransport::AsioEndpoint server_endpoint;
|
||||
};
|
||||
|
||||
#ifdef ENABLE_PG
|
||||
typedef KoTun::Tun<Client*> TunImpl;
|
||||
#else
|
||||
typedef KoTun::TunClient<Client*> TunImpl;
|
||||
#endif
|
||||
|
||||
// calls tun_read_handler and tun_error_handler
|
||||
friend TunImpl::Base;
|
||||
|
||||
public:
|
||||
// transport methods
|
||||
|
||||
virtual void transport_start() override
|
||||
{
|
||||
if (halt)
|
||||
OPENVPN_THROW(dco_error, "transport_start called on halted instance");
|
||||
|
||||
KoTun::DevConf devconf;
|
||||
|
||||
if (config->transport.protocol.is_udp())
|
||||
devconf.dc.tcp = false;
|
||||
else if (config->transport.protocol.is_tcp())
|
||||
devconf.dc.tcp = true;
|
||||
else
|
||||
OPENVPN_THROW(dco_error, "protocol " << config->transport.protocol.str() << " not implemented");
|
||||
|
||||
// config settings
|
||||
devconf.set_dev_name(config->dev_name);
|
||||
devconf.dc.max_peers = 1;
|
||||
devconf.dc.max_dev_queues = 1;
|
||||
devconf.dc.dev_tx_queue_len = 4096;
|
||||
devconf.dc.max_tun_queue_len = 4096;
|
||||
devconf.dc.max_tcp_send_queue_len = 64;
|
||||
devconf.dc.peer_lookup = OVPN_PEER_LOOKUP_NONE;
|
||||
devconf.dc.cpu_id = -1;
|
||||
|
||||
// create kovpn tun socket
|
||||
impl.reset(new TunImpl(io_context,
|
||||
devconf,
|
||||
this,
|
||||
config->transport.frame,
|
||||
nullptr,
|
||||
nullptr));
|
||||
|
||||
// set kovpn stats hook
|
||||
config->transport.stats->dco_configure(this);
|
||||
|
||||
// if trunking, set RPS/XPS on iface
|
||||
if (config->trunk_unit >= 0)
|
||||
KoTun::KovpnBase::set_rps_xps(config->dev_name, devconf.dc.queue_index, config->tun.stop);
|
||||
|
||||
if (devconf.dc.tcp)
|
||||
transport_start_tcp();
|
||||
else
|
||||
transport_start_udp();
|
||||
}
|
||||
|
||||
// VPN IP collision detection for multi-channel trunking
|
||||
static void set_vpn_ip_collision(IPCollisionDetectBase* vpn_ip_collision_arg)
|
||||
{
|
||||
vpn_ip_collision = vpn_ip_collision_arg;
|
||||
}
|
||||
|
||||
virtual bool transport_send_const(const Buffer& buf) override
|
||||
{
|
||||
return send(buf);
|
||||
}
|
||||
|
||||
virtual bool transport_send(BufferAllocated& buf) override
|
||||
{
|
||||
return send(buf);
|
||||
}
|
||||
|
||||
virtual bool transport_send_queue_empty() override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool transport_has_send_queue() override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual unsigned int transport_send_queue_size() override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void reset_align_adjust(const size_t align_adjust) override
|
||||
{
|
||||
}
|
||||
|
||||
virtual void transport_stop_requeueing() override
|
||||
{
|
||||
}
|
||||
|
||||
virtual void server_endpoint_info(std::string& host, std::string& port, std::string& proto, std::string& ip_addr) const override
|
||||
{
|
||||
host = server_host;
|
||||
port = server_port;
|
||||
const IP::Addr addr = server_endpoint_addr();
|
||||
proto = "UDP";
|
||||
proto += addr.version_string();
|
||||
proto += "-DCO";
|
||||
ip_addr = addr.to_string();
|
||||
}
|
||||
|
||||
virtual IP::Addr server_endpoint_addr() const override
|
||||
{
|
||||
if (proto)
|
||||
return proto->server_endpoint_addr();
|
||||
else
|
||||
return IP::Addr();
|
||||
}
|
||||
|
||||
virtual Protocol transport_protocol() const override
|
||||
{
|
||||
switch (server_endpoint_addr().version())
|
||||
{
|
||||
case IP::Addr::V4:
|
||||
return Protocol(Protocol::UDPv4);
|
||||
case IP::Addr::V6:
|
||||
return Protocol(Protocol::UDPv6);
|
||||
default:
|
||||
return Protocol();
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~Client() override
|
||||
{
|
||||
stop_();
|
||||
}
|
||||
|
||||
// tun methods
|
||||
|
||||
virtual void tun_start(const OptionList& opt,
|
||||
TransportClient& transcli,
|
||||
CryptoDCSettings& dc_settings) override
|
||||
{
|
||||
if (halt || !tun_parent)
|
||||
OPENVPN_THROW(dco_error, "tun_start called on halted/undefined instance");
|
||||
|
||||
try {
|
||||
const IP::Addr server_addr = server_endpoint_addr();
|
||||
|
||||
// get the iface name
|
||||
state->iface_name = config->dev_name;
|
||||
|
||||
// notify parent
|
||||
tun_parent->tun_pre_tun_config();
|
||||
|
||||
// parse pushed options
|
||||
TunBuilderCapture::Ptr po(new TunBuilderCapture());
|
||||
TunProp::configure_builder(po.get(),
|
||||
state.get(),
|
||||
config->transport.stats.get(),
|
||||
server_addr,
|
||||
config->tun.tun_prop,
|
||||
opt,
|
||||
nullptr,
|
||||
false);
|
||||
|
||||
OPENVPN_LOG("CAPTURED OPTIONS:" << std::endl << po->to_string());
|
||||
|
||||
// add/remove command lists
|
||||
ActionList::Ptr add_cmds = new ActionList();
|
||||
remove_cmds.reset(new ActionListReversed());
|
||||
|
||||
// configure tun properties
|
||||
std::vector<IP::Route> rtvec;
|
||||
if (config->trunk_unit >= 0)
|
||||
{
|
||||
// VPN IP collision detection, will throw on collision
|
||||
if (vpn_ip_collision)
|
||||
detect_vpn_ip_collision(*vpn_ip_collision, *po, config->trunk_unit, *remove_cmds);
|
||||
|
||||
// trunk setup
|
||||
TunLinux::iface_config(state->iface_name,
|
||||
config->trunk_unit,
|
||||
*po,
|
||||
nullptr,
|
||||
*add_cmds,
|
||||
*remove_cmds);
|
||||
|
||||
// Note that in trunking mode, kovpn must be
|
||||
// configured for source routing.
|
||||
add_vpn_ips_as_source_routes(*po, rtvec, IP::Addr::V4);
|
||||
add_vpn_ips_as_source_routes(*po, rtvec, IP::Addr::V6);
|
||||
}
|
||||
else
|
||||
{
|
||||
// non-trunk setup
|
||||
TunLinux::tun_config(state->iface_name,
|
||||
*po,
|
||||
&rtvec,
|
||||
*add_cmds,
|
||||
*remove_cmds);
|
||||
}
|
||||
|
||||
// Add routes to DCO implementation
|
||||
impl->peer_add_routes(peer_id, rtvec);
|
||||
|
||||
// execute commands to bring up interface
|
||||
add_cmds->execute_log();
|
||||
|
||||
// Add a hook so ProtoContext will call back to
|
||||
// rekey() on rekey ops.
|
||||
dc_settings.set_factory(CryptoDCFactory::Ptr(new KoRekey::Factory(dc_settings.factory(), this, config->transport.frame)));
|
||||
|
||||
// signal that we are connected
|
||||
tun_parent->tun_connected();
|
||||
}
|
||||
catch (const IPCollisionDetectBase::ip_collision& e)
|
||||
{
|
||||
// on VPN IP address collision, just reconnect to get a new address
|
||||
stop_();
|
||||
tun_parent->tun_error(Error::TUN_ERROR, e.what());
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
stop_();
|
||||
tun_parent->tun_error(Error::TUN_SETUP_FAILED, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
virtual void set_disconnect() override
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool tun_send(BufferAllocated& buf) override // return true if send succeeded
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual std::string tun_name() const override
|
||||
{
|
||||
if (impl)
|
||||
return impl->name();
|
||||
else
|
||||
return "UNDEF_DCO";
|
||||
}
|
||||
|
||||
virtual std::string vpn_ip4() const override
|
||||
{
|
||||
if (state->vpn_ip4_addr.specified())
|
||||
return state->vpn_ip4_addr.to_string();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
virtual std::string vpn_ip6() const override
|
||||
{
|
||||
if (state->vpn_ip6_addr.specified())
|
||||
return state->vpn_ip6_addr.to_string();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
virtual std::string vpn_gw4() const override
|
||||
{
|
||||
if (state->vpn_ip4_gw.specified())
|
||||
return state->vpn_ip4_gw.to_string();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
virtual std::string vpn_gw6() const override
|
||||
{
|
||||
if (state->vpn_ip6_gw.specified())
|
||||
return state->vpn_ip6_gw.to_string();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
// KoRekey::Receiver methods
|
||||
|
||||
virtual void rekey(const CryptoDCInstance::RekeyType rktype,
|
||||
const KoRekey::Info& rkinfo) override
|
||||
{
|
||||
if (halt)
|
||||
return;
|
||||
|
||||
KoRekey::Key key(rktype, rkinfo, peer_id, false);
|
||||
impl->peer_keys_reset(key());
|
||||
if (transport_parent->is_keepalive_enabled())
|
||||
{
|
||||
struct ovpn_peer_keepalive ka;
|
||||
|
||||
// Disable userspace keepalive, get the userspace
|
||||
// keepalive parameters, and enable kovpn keepalive.
|
||||
ka.peer_id = peer_id;
|
||||
transport_parent->disable_keepalive(ka.keepalive_ping,
|
||||
ka.keepalive_timeout);
|
||||
|
||||
// Modify the peer
|
||||
impl->peer_set_keepalive(&ka);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void explicit_exit_notify() override
|
||||
{
|
||||
impl->peer_xmit_explicit_exit_notify(peer_id);
|
||||
}
|
||||
|
||||
// shared methods
|
||||
|
||||
virtual void stop() override
|
||||
{
|
||||
stop_();
|
||||
}
|
||||
|
||||
private:
|
||||
Client(openvpn_io::io_context& io_context_arg,
|
||||
ClientConfig* config_arg,
|
||||
TransportClientParent* parent_arg)
|
||||
: io_context(io_context_arg),
|
||||
halt(false),
|
||||
state(new TunProp::State()),
|
||||
config(config_arg),
|
||||
transport_parent(parent_arg),
|
||||
tun_parent(nullptr),
|
||||
peer_id(-1)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void transport_reparent(TransportClientParent* parent_arg)
|
||||
{
|
||||
transport_parent = parent_arg;
|
||||
}
|
||||
|
||||
void transport_start_udp()
|
||||
{
|
||||
proto.reset(new UDP(io_context));
|
||||
if (config->transport.remote_list->endpoint_available(&server_host, &server_port, nullptr))
|
||||
{
|
||||
start_connect_udp();
|
||||
}
|
||||
else
|
||||
{
|
||||
transport_parent->transport_pre_resolve();
|
||||
udp().resolver.async_resolve(server_host, server_port,
|
||||
[self=Ptr(this)](const openvpn_io::error_code& error, openvpn_io::ip::udp::resolver::results_type results)
|
||||
{
|
||||
self->do_resolve_udp(error, results);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// called after DNS resolution has succeeded or failed
|
||||
void do_resolve_udp(const openvpn_io::error_code& error,
|
||||
openvpn_io::ip::udp::resolver::results_type results)
|
||||
{
|
||||
if (!halt)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
// save resolved endpoint list in remote_list
|
||||
config->transport.remote_list->set_endpoint_range(results);
|
||||
start_connect_udp();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "DNS resolve error on '" << server_host << "' for UDP session: " << error.message();
|
||||
config->transport.stats->error(Error::RESOLVE_ERROR);
|
||||
stop_();
|
||||
transport_parent->transport_error(Error::UNDEF, os.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// do UDP connect
|
||||
void start_connect_udp()
|
||||
{
|
||||
config->transport.remote_list->get_endpoint(udp().server_endpoint);
|
||||
OPENVPN_LOG("Contacting " << udp().server_endpoint << " via UDP");
|
||||
transport_parent->transport_wait();
|
||||
transport_parent->ip_hole_punch(server_endpoint_addr());
|
||||
udp().socket.open(udp().server_endpoint.protocol());
|
||||
udp().socket.async_connect(udp().server_endpoint, [self=Ptr(this)](const openvpn_io::error_code& error)
|
||||
{
|
||||
self->start_impl_udp(error);
|
||||
});
|
||||
}
|
||||
|
||||
// start I/O on UDP socket
|
||||
void start_impl_udp(const openvpn_io::error_code& error)
|
||||
{
|
||||
if (!halt)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
// attach UDP socket to kovpn
|
||||
peer_id = impl->peer_new_udp_client(udp().socket.native_handle(), 0, 0);
|
||||
|
||||
// queue reads on tun
|
||||
impl->start(8); // parallel reads
|
||||
transport_parent->transport_connecting();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "UDP connect error on '" << server_host << ':' << server_port << "' (" << udp().server_endpoint << "): " << error.message();
|
||||
config->transport.stats->error(Error::UDP_CONNECT_ERROR);
|
||||
stop_();
|
||||
transport_parent->transport_error(Error::UNDEF, os.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void transport_start_tcp()
|
||||
{
|
||||
OPENVPN_THROW(dco_error, "TCP not implemented yet"); // fixme for DCO
|
||||
}
|
||||
|
||||
void tun_read_handler(KoTun::PacketFrom::SPtr& pfp) // called by TunImpl
|
||||
{
|
||||
if (halt)
|
||||
return;
|
||||
|
||||
try {
|
||||
const struct ovpn_tun_head *th = (const struct ovpn_tun_head *)pfp->buf.read_alloc(sizeof(struct ovpn_tun_head));
|
||||
switch (th->type)
|
||||
{
|
||||
case OVPN_TH_TRANS_BY_PEER_ID:
|
||||
{
|
||||
if (peer_id < 0 || th->peer_id != peer_id)
|
||||
{
|
||||
OPENVPN_LOG("dcocli: OVPN_TH_TRANS_BY_PEER_ID unrecognized peer_id=" << th->peer_id);
|
||||
return;
|
||||
}
|
||||
|
||||
transport_parent->transport_recv(pfp->buf);
|
||||
cc_rx_bytes += pfp->buf.size();
|
||||
break;
|
||||
}
|
||||
case OVPN_TH_NOTIFY_STATUS:
|
||||
{
|
||||
const struct ovpn_tun_head_status *thn = (const struct ovpn_tun_head_status *)th;
|
||||
|
||||
if (peer_id < 0 || thn->head.peer_id != peer_id)
|
||||
{
|
||||
OPENVPN_LOG("dcocli: OVPN_TH_NOTIFY_STATUS unrecognized peer_id=" << thn->head.peer_id);
|
||||
return;
|
||||
}
|
||||
|
||||
const bool stop = (thn->head.status != OVPN_STATUS_ACTIVE);
|
||||
OPENVPN_LOG("dcocli: status=" << int(thn->head.status) << " peer_id=" << peer_id << " rx_bytes=" << thn->rx_bytes << " tx_bytes=" << thn->tx_bytes); // fixme
|
||||
if (stop)
|
||||
throw Exception("stop status=" + to_string(thn->head.status));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
OPENVPN_LOG("dcocli: unknown ovpn_tun_head type=" << (int)th->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
const std::string msg = std::string("dcocli: tun_read_handler: ") + e.what();
|
||||
OPENVPN_LOG(msg);
|
||||
stop_();
|
||||
transport_parent->transport_error(Error::TRANSPORT_ERROR, msg);
|
||||
}
|
||||
}
|
||||
|
||||
void tun_error_handler(const Error::Type errtype, // called by TunImpl
|
||||
const openvpn_io::error_code* error)
|
||||
{
|
||||
OPENVPN_LOG("TUN error");
|
||||
stop_();
|
||||
}
|
||||
|
||||
bool send(const Buffer& buf)
|
||||
{
|
||||
struct ovpn_tun_head head;
|
||||
std::memset(&head, 0, sizeof(head));
|
||||
head.type = OVPN_TH_TRANS_BY_PEER_ID;
|
||||
head.peer_id = peer_id;
|
||||
return impl->write_seq(AsioConstBufferSeq2(Buffer(reinterpret_cast<Buffer::type>(&head), sizeof(head), true),
|
||||
buf));
|
||||
}
|
||||
|
||||
void stop_()
|
||||
{
|
||||
if (!halt)
|
||||
{
|
||||
halt = true;
|
||||
config->transport.stats->dco_update(); // final update
|
||||
config->transport.stats->dco_configure(nullptr);
|
||||
if (remove_cmds)
|
||||
remove_cmds->execute_log();
|
||||
if (impl)
|
||||
impl->stop();
|
||||
if (proto)
|
||||
proto->close();
|
||||
}
|
||||
}
|
||||
|
||||
UDP& udp()
|
||||
{
|
||||
return *static_cast<UDP*>(proto.get());
|
||||
}
|
||||
|
||||
static void add_vpn_ips_as_source_routes(const TunBuilderCapture& pull,
|
||||
std::vector<IP::Route>& rtvec,
|
||||
const IP::Addr::Version ver)
|
||||
{
|
||||
const TunBuilderCapture::RouteAddress *ra = pull.vpn_ip(ver);
|
||||
if (ra)
|
||||
rtvec.push_back(IP::route_from_string_prefix(ra->address,
|
||||
IP::Addr::version_size(ver),
|
||||
"DCOTransport::Client::add_vpn_ips_as_source_routes",
|
||||
ver));
|
||||
}
|
||||
|
||||
// Throw an exception of type IPCollisionDetectBase::ip_collision
|
||||
// if VPN IP is already in use by another client thread.
|
||||
// This is intended to force a reconnect and obtain a
|
||||
// new non-colliding address.
|
||||
static void detect_vpn_ip_collision(IPCollisionDetectBase& ipcoll,
|
||||
const TunBuilderCapture& pull,
|
||||
unsigned int unit,
|
||||
ActionList& remove)
|
||||
{
|
||||
const TunBuilderCapture::RouteAddress* local4 = pull.vpn_ipv4();
|
||||
const TunBuilderCapture::RouteAddress* local6 = pull.vpn_ipv6();
|
||||
if (local4)
|
||||
ipcoll.add(local4->address, unit, remove);
|
||||
if (local6)
|
||||
ipcoll.add(local6->address, unit, remove);
|
||||
}
|
||||
|
||||
// override for SessionStats::DCOTransportSource
|
||||
virtual SessionStats::DCOTransportSource::Data dco_transport_stats_delta() override
|
||||
{
|
||||
if (impl)
|
||||
{
|
||||
struct ovpn_peer_status ops;
|
||||
ops.peer_id = peer_id;
|
||||
if (impl->peer_get_status(&ops))
|
||||
{
|
||||
const SessionStats::DCOTransportSource::Data data(ops.rx_bytes + cc_rx_bytes, ops.tx_bytes);
|
||||
const SessionStats::DCOTransportSource::Data delta = data - last_stats;
|
||||
last_stats = data;
|
||||
return delta;
|
||||
}
|
||||
}
|
||||
return SessionStats::DCOTransportSource::Data();
|
||||
}
|
||||
|
||||
openvpn_io::io_context& io_context;
|
||||
bool halt;
|
||||
|
||||
TunProp::State::Ptr state;
|
||||
|
||||
ClientConfig::Ptr config;
|
||||
TransportClientParent* transport_parent;
|
||||
TunClientParent* tun_parent;
|
||||
|
||||
std::unique_ptr<ProtoBase> proto;
|
||||
|
||||
ActionList::Ptr remove_cmds;
|
||||
|
||||
std::string server_host;
|
||||
std::string server_port;
|
||||
|
||||
TunImpl::Ptr impl;
|
||||
int peer_id;
|
||||
|
||||
SessionStats::DCOTransportSource::Data last_stats;
|
||||
__u64 cc_rx_bytes = 0;
|
||||
|
||||
static IPCollisionDetectBase* vpn_ip_collision;
|
||||
};
|
||||
|
||||
inline DCO::Ptr new_controller()
|
||||
{
|
||||
return ClientConfig::new_controller();
|
||||
}
|
||||
|
||||
inline TransportClient::Ptr ClientConfig::new_transport_client_obj(openvpn_io::io_context& io_context,
|
||||
TransportClientParent* parent)
|
||||
{
|
||||
return TransportClient::Ptr(new Client(io_context, this, parent));
|
||||
}
|
||||
|
||||
inline TunClient::Ptr ClientConfig::new_tun_client_obj(openvpn_io::io_context& io_context,
|
||||
TunClientParent& parent,
|
||||
TransportClient* transcli)
|
||||
{
|
||||
Client* cli = static_cast<Client*>(transcli);
|
||||
cli->tun_parent = &parent;
|
||||
return TunClient::Ptr(cli);
|
||||
}
|
||||
|
||||
IPCollisionDetectBase* Client::vpn_ip_collision; // GLOBAL
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
// 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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
|
||||
#include <openvpn/common/exception.hpp>
|
||||
#include <openvpn/common/action.hpp>
|
||||
#include <openvpn/addr/ip.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
class IPCollisionDetectBase
|
||||
{
|
||||
public:
|
||||
OPENVPN_EXCEPTION(ip_collision);
|
||||
|
||||
virtual void add(const std::string& addr_str,
|
||||
const unsigned int unit,
|
||||
ActionList& late_remove) { }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -23,7 +23,7 @@
|
||||
#define OPENVPN_IP_DHCP_H
|
||||
|
||||
#include <openvpn/ip/eth.hpp>
|
||||
#include <openvpn/ip/ip.hpp>
|
||||
#include <openvpn/ip/ip4.hpp>
|
||||
#include <openvpn/ip/udp.hpp>
|
||||
|
||||
#pragma pack(push)
|
||||
@@ -78,7 +78,7 @@ namespace openvpn {
|
||||
|
||||
struct DHCPPacket {
|
||||
EthHeader eth;
|
||||
IPHeader ip;
|
||||
IPv4Header ip;
|
||||
UDPHeader udp;
|
||||
DHCP dhcp;
|
||||
std::uint8_t options[];
|
||||
|
||||
@@ -19,40 +19,42 @@
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Define the ICMP header
|
||||
// Define the ICMPv4 header
|
||||
|
||||
#ifndef OPENVPN_IP_ICMP_H
|
||||
#define OPENVPN_IP_ICMP_H
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // for std::uint32_t, uint16_t, uint8_t
|
||||
|
||||
#include <openvpn/ip/ip.hpp>
|
||||
#include <openvpn/ip/ip4.hpp>
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
namespace openvpn {
|
||||
struct ICMP {
|
||||
struct ICMPv4 {
|
||||
enum {
|
||||
ECHO_REPLY = 0,
|
||||
ECHO_REQUEST = 8,
|
||||
ECHO_REPLY = 0,
|
||||
};
|
||||
|
||||
struct IPHeader head;
|
||||
struct IPv4Header head;
|
||||
|
||||
std::uint8_t type;
|
||||
std::uint8_t code;
|
||||
union {
|
||||
struct {
|
||||
std::uint8_t type;
|
||||
std::uint8_t code;
|
||||
};
|
||||
std::uint16_t type_code;
|
||||
};
|
||||
std::uint16_t checksum;
|
||||
|
||||
union {
|
||||
struct {
|
||||
std::uint16_t id;
|
||||
std::uint16_t seq_num;
|
||||
} echo;
|
||||
} hd;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
// 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 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/>.
|
||||
|
||||
// Define the ICMPv6 header
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // for std::uint32_t, uint16_t, uint8_t
|
||||
|
||||
#include <openvpn/ip/ip6.hpp>
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
namespace openvpn {
|
||||
|
||||
struct ICMPv6 {
|
||||
enum {
|
||||
ECHO_REQUEST = 128,
|
||||
ECHO_REPLY = 129,
|
||||
};
|
||||
|
||||
struct IPv6Header head;
|
||||
|
||||
union {
|
||||
struct {
|
||||
std::uint8_t type;
|
||||
std::uint8_t code;
|
||||
};
|
||||
std::uint16_t type_code;
|
||||
};
|
||||
std::uint16_t checksum;
|
||||
|
||||
union {
|
||||
struct {
|
||||
std::uint16_t id;
|
||||
std::uint16_t seq_num;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#pragma pack(pop)
|
||||
@@ -19,10 +19,9 @@
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Define the IP protocol header
|
||||
// IPv4 header
|
||||
|
||||
#ifndef OPENVPN_IP_IP_H
|
||||
#define OPENVPN_IP_IP_H
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // for std::uint32_t, uint16_t, uint8_t
|
||||
|
||||
@@ -30,13 +29,9 @@
|
||||
#pragma pack(1)
|
||||
|
||||
namespace openvpn {
|
||||
struct IPHeader
|
||||
{
|
||||
static unsigned int version(const std::uint8_t version_len)
|
||||
{
|
||||
return (version_len >> 4) & 0x0F;
|
||||
}
|
||||
|
||||
struct IPv4Header
|
||||
{
|
||||
static unsigned int length(const std::uint8_t version_len)
|
||||
{
|
||||
return (version_len & 0x0F) << 2;
|
||||
@@ -61,12 +56,6 @@ namespace openvpn {
|
||||
|
||||
std::uint8_t ttl;
|
||||
|
||||
enum {
|
||||
ICMP = 1, /* ICMP protocol */
|
||||
IGMP = 2, /* IGMP protocol */
|
||||
TCP = 6, /* TCP protocol */
|
||||
UDP = 17, /* UDP protocol */
|
||||
};
|
||||
std::uint8_t protocol;
|
||||
|
||||
std::uint16_t check;
|
||||
@@ -74,28 +63,6 @@ namespace openvpn {
|
||||
std::uint32_t daddr;
|
||||
/* The options start here. */
|
||||
};
|
||||
|
||||
inline std::uint16_t ip_checksum(const void *ip, unsigned int size)
|
||||
{
|
||||
std::uint16_t *buffer = (std::uint16_t *)ip;
|
||||
std::uint32_t cksum = 0;
|
||||
|
||||
while (size > 1)
|
||||
{
|
||||
cksum += *buffer++;
|
||||
size -= sizeof(uint16_t);
|
||||
}
|
||||
|
||||
if (size)
|
||||
cksum += *(uint8_t*)buffer;
|
||||
|
||||
cksum = (cksum >> 16) + (cksum & 0xffff);
|
||||
cksum += (cksum >> 16);
|
||||
return ~cksum;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
// 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 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/>.
|
||||
|
||||
// IPv6 header
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // for std::uint32_t, uint16_t, uint8_t
|
||||
|
||||
#include <openvpn/common/socktypes.hpp>
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
namespace openvpn {
|
||||
|
||||
struct IPv6Header
|
||||
{
|
||||
std::uint8_t version_prio;
|
||||
|
||||
std::uint8_t flow_lbl[3];
|
||||
|
||||
std::uint16_t payload_len;
|
||||
std::uint8_t nexthdr;
|
||||
std::uint8_t hop_limit;
|
||||
|
||||
struct in6_addr saddr;
|
||||
struct in6_addr daddr;
|
||||
};
|
||||
}
|
||||
|
||||
#pragma pack(pop)
|
||||
@@ -0,0 +1,45 @@
|
||||
// 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 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/>.
|
||||
|
||||
// Common declarations for IPv4 and IPv6
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // for std::uint32_t, uint16_t, uint8_t
|
||||
|
||||
namespace openvpn {
|
||||
namespace IPCommon {
|
||||
|
||||
enum {
|
||||
ICMPv4 = 1, /* ICMPv4 protocol */
|
||||
ICMPv6 = 58, /* ICMPv6 protocol */
|
||||
IGMP = 2, /* IGMP protocol */
|
||||
TCP = 6, /* TCP protocol */
|
||||
UDP = 17, /* UDP protocol */
|
||||
};
|
||||
|
||||
inline unsigned int version(const std::uint8_t version_len_prio)
|
||||
{
|
||||
return (version_len_prio >> 4) & 0x0F;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
#ifndef OPENVPN_IP_UDP_H
|
||||
#define OPENVPN_IP_UDP_H
|
||||
|
||||
#include <openvpn/ip/ip.hpp>
|
||||
#include <openvpn/ip/ipcommon.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace openvpn {
|
||||
}
|
||||
|
||||
/* the protocol number and the length of the UDP packet */
|
||||
sum += (std::uint16_t)IPHeader::UDP + (std::uint16_t)len_udp;
|
||||
sum += (std::uint16_t)IPCommon::UDP + (std::uint16_t)len_udp;
|
||||
|
||||
/* keep only the last 16 bits of the 32 bit calculated sum and add the carries */
|
||||
while (sum >> 16)
|
||||
|
||||
@@ -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,165 @@
|
||||
// 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/kovpn/kovpn.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace kostats_private {
|
||||
# include <kovpn/ovpnerrstr.c>
|
||||
}
|
||||
|
||||
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 = 16;
|
||||
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,36 @@
|
||||
// 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
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
|
||||
extern "C" {
|
||||
#include <kovpn/kovpn.h>
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,108 @@
|
||||
// Private Gateway
|
||||
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||
// All rights reserved
|
||||
|
||||
#ifndef OPENVPN_LINUX_PROCFS_H
|
||||
#define OPENVPN_LINUX_PROCFS_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <openvpn/common/exception.hpp>
|
||||
#include <openvpn/common/file.hpp>
|
||||
#include <openvpn/common/sleep.hpp>
|
||||
#include <openvpn/common/stat.hpp>
|
||||
#include <openvpn/common/format.hpp>
|
||||
#include <openvpn/common/action.hpp>
|
||||
#include <openvpn/common/stop.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
|
||||
class ProcFS : public Action
|
||||
{
|
||||
public:
|
||||
OPENVPN_EXCEPTION(procfs_error);
|
||||
|
||||
ProcFS(std::string fn_arg, std::string text_arg)
|
||||
: fn(std::move(fn_arg)),
|
||||
text(std::move(text_arg))
|
||||
{
|
||||
}
|
||||
|
||||
virtual void execute(std::ostream& os) override
|
||||
{
|
||||
os << to_string() << std::endl;
|
||||
try {
|
||||
write_sys(fn, text);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
os << "ProcFS exception: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::string to_string() const override
|
||||
{
|
||||
return to_string(fn, text);
|
||||
}
|
||||
|
||||
static std::string to_string(const std::string& fn, const std::string& text)
|
||||
{
|
||||
return "ProcFS: " + fn + " -> " + string::trim_crlf_copy(text);
|
||||
}
|
||||
|
||||
static void write_sys(const std::string& fn, const std::string& text, Stop* async_stop=nullptr)
|
||||
{
|
||||
//OPENVPN_LOG(to_string(fn, text));
|
||||
|
||||
const unsigned int n_retries = 200;
|
||||
const unsigned int milliseconds_per_retry = 100;
|
||||
volatile bool stop = false;
|
||||
|
||||
// allow asynchronous stop
|
||||
Stop::Scope stop_scope(async_stop, [&stop]() {
|
||||
stop = true;
|
||||
});
|
||||
|
||||
for (unsigned int i = 0; i < n_retries && !stop; ++i)
|
||||
{
|
||||
if (file_exists(fn))
|
||||
{
|
||||
write_string(fn, text);
|
||||
return;
|
||||
}
|
||||
sleep_milliseconds(milliseconds_per_retry);
|
||||
}
|
||||
if (stop)
|
||||
OPENVPN_THROW(procfs_error, "file " << fn << " : aborting write attempt due to stop signal");
|
||||
else
|
||||
OPENVPN_THROW(procfs_error, "file " << fn << " failed to exist within " << (n_retries * milliseconds_per_retry / 1000) << " seconds");
|
||||
}
|
||||
|
||||
private:
|
||||
std::string fn;
|
||||
std::string text;
|
||||
};
|
||||
|
||||
class IPv4ReversePathFilter : public ProcFS
|
||||
{
|
||||
public:
|
||||
IPv4ReversePathFilter(const std::string& dev, const unsigned int value)
|
||||
: ProcFS(key_fn(dev), openvpn::to_string(value))
|
||||
{
|
||||
OPENVPN_LOG("IPv4ReversePathFilter " << dev << " -> " << value);
|
||||
}
|
||||
|
||||
static void write(const std::string& dev, const unsigned int value, Stop* stop=nullptr)
|
||||
{
|
||||
ProcFS::write_sys(key_fn(dev), openvpn::to_string(value), stop);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::string key_fn(const std::string& dev)
|
||||
{
|
||||
return printfmt("/proc/sys/net/ipv4/conf/%s/rp_filter", dev);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -68,17 +68,14 @@ namespace openvpn {
|
||||
switch (mbedtls_pk_get_type(ctx))
|
||||
{
|
||||
case MBEDTLS_PK_RSA:
|
||||
case MBEDTLS_PK_RSA_ALT:
|
||||
case MBEDTLS_PK_RSASSA_PSS:
|
||||
return SSLConfigAPI::PK_RSA;
|
||||
case MBEDTLS_PK_ECKEY:
|
||||
return SSLConfigAPI::PK_ECKEY;
|
||||
case MBEDTLS_PK_ECKEY_DH:
|
||||
return SSLConfigAPI::PK_ECKEY_DH;
|
||||
return SSLConfigAPI::PK_EC;
|
||||
case MBEDTLS_PK_ECDSA:
|
||||
return SSLConfigAPI::PK_ECDSA;
|
||||
case MBEDTLS_PK_RSA_ALT:
|
||||
return SSLConfigAPI::PK_RSA_ALT;
|
||||
case MBEDTLS_PK_RSASSA_PSS:
|
||||
return SSLConfigAPI::PK_RSASSA_PSS;
|
||||
case MBEDTLS_PK_NONE:
|
||||
return SSLConfigAPI::PK_NONE;
|
||||
default:
|
||||
|
||||
@@ -62,6 +62,38 @@ namespace openvpn {
|
||||
bool defined() const { return pkey_ != nullptr; }
|
||||
EVP_PKEY* obj() const { return pkey_; }
|
||||
|
||||
SSLConfigAPI::PKType key_type() const
|
||||
{
|
||||
switch (EVP_PKEY_id(pkey_))
|
||||
{
|
||||
case EVP_PKEY_RSA:
|
||||
case EVP_PKEY_RSA2:
|
||||
return SSLConfigAPI::PK_RSA;
|
||||
case EVP_PKEY_EC:
|
||||
return SSLConfigAPI::PK_EC;
|
||||
case EVP_PKEY_DSA:
|
||||
case EVP_PKEY_DSA1:
|
||||
case EVP_PKEY_DSA2:
|
||||
case EVP_PKEY_DSA3:
|
||||
case EVP_PKEY_DSA4:
|
||||
return SSLConfigAPI::PK_DSA;
|
||||
case EVP_PKEY_NONE:
|
||||
return SSLConfigAPI::PK_NONE;
|
||||
default:
|
||||
return SSLConfigAPI::PK_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
size_t key_length() const
|
||||
{
|
||||
int ret = i2d_PrivateKey(pkey_, NULL);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
/* convert to bits */
|
||||
return ret * 8;
|
||||
}
|
||||
|
||||
void set_private_key_password(const std::string& pwd)
|
||||
{
|
||||
priv_key_pwd = pwd;
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace openvpn {
|
||||
|
||||
virtual void load_crl(const std::string& crl_txt)
|
||||
{
|
||||
throw ssl_options_error("CRL not implemented yet in OpenSSL driver"); // fixme
|
||||
ca.parse_pem(crl_txt, "crl");
|
||||
}
|
||||
|
||||
virtual void load_cert(const std::string& cert_txt)
|
||||
@@ -159,42 +159,49 @@ namespace openvpn {
|
||||
|
||||
virtual std::string extract_ca() const
|
||||
{
|
||||
throw ssl_options_error("extract_ca not implemented yet in OpenSSL driver"); // fixme
|
||||
return ca.certs.render_pem();
|
||||
}
|
||||
|
||||
virtual std::string extract_crl() const
|
||||
{
|
||||
throw ssl_options_error("CRL not implemented yet in OpenSSL driver"); // fixme
|
||||
return ca.crls.render_pem();
|
||||
}
|
||||
|
||||
virtual std::string extract_cert() const
|
||||
{
|
||||
throw ssl_options_error("extract_cert not implemented yet in OpenSSL driver"); // fixme
|
||||
return cert.render_pem();
|
||||
}
|
||||
|
||||
virtual std::vector<std::string> extract_extra_certs() const
|
||||
{
|
||||
throw ssl_options_error("extract_extra_certs not implemented yet in OpenSSL driver"); // fixme
|
||||
std::vector<std::string> ret;
|
||||
|
||||
for (auto const& cert : extra_certs)
|
||||
ret.push_back(cert->render_pem());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual std::string extract_private_key() const
|
||||
{
|
||||
throw ssl_options_error("extract_priv_key not implemented yet in OpenSSL driver"); // fixme
|
||||
return pkey.render_pem();
|
||||
}
|
||||
|
||||
virtual std::string extract_dh() const
|
||||
{
|
||||
throw ssl_options_error("extract_dh not implemented yet in OpenSSL driver"); // fixme
|
||||
return dh.render_pem();
|
||||
}
|
||||
|
||||
virtual PKType private_key_type() const
|
||||
{
|
||||
throw ssl_options_error("private_key_type not implemented yet in OpenSSL driver"); // fixme
|
||||
if (!pkey.defined())
|
||||
return PK_NONE;
|
||||
return pkey.key_type();
|
||||
}
|
||||
|
||||
virtual size_t private_key_length() const
|
||||
{
|
||||
throw ssl_options_error("private_key_length not implemented yet in OpenSSL driver"); // fixme
|
||||
return pkey.key_length();
|
||||
}
|
||||
|
||||
virtual void set_frame(const Frame::Ptr& frame_arg)
|
||||
@@ -300,7 +307,8 @@ namespace openvpn {
|
||||
|
||||
virtual std::string validate_crl(const std::string& crl_txt) const
|
||||
{
|
||||
throw ssl_options_error("CRL not implemented yet in OpenSSL driver"); // fixme
|
||||
OpenSSLPKI::CRL crl(crl_txt);
|
||||
return crl.render_pem();
|
||||
}
|
||||
|
||||
virtual void load(const OptionList& opt, const unsigned int lflags)
|
||||
@@ -322,6 +330,13 @@ namespace openvpn {
|
||||
load_ca(ca_txt, true);
|
||||
}
|
||||
|
||||
// CRL
|
||||
{
|
||||
const std::string crl_txt = opt.cat("crl-verify");
|
||||
if (!crl_txt.empty())
|
||||
load_crl(crl_txt);
|
||||
}
|
||||
|
||||
// local cert/key
|
||||
if (local_cert_enabled)
|
||||
{
|
||||
@@ -387,7 +402,7 @@ namespace openvpn {
|
||||
|
||||
private:
|
||||
Mode mode;
|
||||
CertCRLList ca; // from OpenVPN "ca" option
|
||||
CertCRLList ca; // from OpenVPN "ca" and "crl-verify" option
|
||||
OpenSSLPKI::X509 cert; // from OpenVPN "cert" option
|
||||
OpenSSLPKI::X509List extra_certs; // from OpenVPN "extra-certs" option
|
||||
OpenSSLPKI::PKey pkey; // private key
|
||||
@@ -926,10 +941,41 @@ namespace openvpn {
|
||||
#endif
|
||||
}
|
||||
|
||||
// tls-cert-profile is not implemented yet in OpenSSL (fixme),
|
||||
// so throw exception if the setting is anything other than LEGACY.
|
||||
/* HAVE_SSL_CTX_SET_SECURITY_LEVEL exists from OpenSSL-1.1.0 up */
|
||||
#ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL
|
||||
switch(TLSCertProfile::default_if_undef(config->tls_cert_profile))
|
||||
{
|
||||
case TLSCertProfile::UNDEF:
|
||||
OPENVPN_THROW(ssl_context_error,
|
||||
"OpenSSLContext: undefined tls-cert-profile");
|
||||
break;
|
||||
#ifdef OPENVPN_USE_TLS_MD5
|
||||
case TLSCertProfile::INSECURE:
|
||||
SSL_CTX_set_security_level(ctx, 0);
|
||||
break;
|
||||
#endif
|
||||
case TLSCertProfile::LEGACY:
|
||||
SSL_CTX_set_security_level(ctx, 1);
|
||||
break;
|
||||
case TLSCertProfile::PREFERRED:
|
||||
SSL_CTX_set_security_level(ctx, 2);
|
||||
break;
|
||||
case TLSCertProfile::SUITEB:
|
||||
SSL_CTX_set_security_level(ctx, 3);
|
||||
break;
|
||||
default:
|
||||
OPENVPN_THROW(ssl_context_error,
|
||||
"OpenSSLContext: unexpected tls-cert-profile value");
|
||||
break;
|
||||
}
|
||||
#else
|
||||
// when OpenSSL does not CertProfile support we force the user to set 'legacy'
|
||||
if (TLSCertProfile::default_if_undef(config->tls_cert_profile) != TLSCertProfile::LEGACY)
|
||||
OPENVPN_THROW(ssl_context_error, "OpenSSLContext: tls-cert-profile not implemented yet");
|
||||
{
|
||||
OPENVPN_THROW(ssl_context_error,
|
||||
"OpenSSLContext: tls-cert-profile not supported by this OpenSSL build. Use 'legacy' instead");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (config->local_cert_enabled)
|
||||
{
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace openvpn {
|
||||
virtual void auth_request(const AuthCreds::Ptr& auth_creds,
|
||||
const AuthCert::Ptr& auth_cert,
|
||||
const PeerAddr::Ptr& peer_addr) = 0;
|
||||
virtual void push_request(const ProtoContext::Config::Ptr& pconf) = 0;
|
||||
virtual void push_request(ProtoContext::Config::Ptr pconf) = 0;
|
||||
|
||||
// INFO notification
|
||||
virtual void info_request(const std::string& imsg) = 0;
|
||||
@@ -85,8 +85,7 @@ namespace openvpn {
|
||||
// set ACL index for user
|
||||
virtual void set_acl_index(const int acl_index,
|
||||
const std::string* username,
|
||||
const bool challenge,
|
||||
const bool throw_on_error) = 0;
|
||||
const bool challenge) = 0;
|
||||
|
||||
// notify of local user properties update
|
||||
virtual void userprop_local_update() = 0;
|
||||
@@ -119,6 +118,9 @@ namespace openvpn {
|
||||
// schedule a low-level connection disconnect in seconds
|
||||
virtual void schedule_disconnect(const unsigned int seconds) = 0;
|
||||
|
||||
// schedule an auth pending disconnect in seconds
|
||||
virtual void schedule_auth_pending_timeout(const unsigned int seconds) = 0;
|
||||
|
||||
// set up relay to target
|
||||
virtual void relay(const IP::Addr& target, const int port) = 0;
|
||||
|
||||
|
||||
@@ -345,16 +345,10 @@ namespace openvpn {
|
||||
Unicode::UTF8_FILTER);
|
||||
if (msg == "PUSH_REQUEST")
|
||||
{
|
||||
if (!did_push)
|
||||
{
|
||||
did_push = true;
|
||||
if (get_management())
|
||||
ManLink::send->push_request(Base::conf_ptr());
|
||||
else
|
||||
{
|
||||
auth_failed("no management provider", false);
|
||||
}
|
||||
}
|
||||
if (get_management())
|
||||
ManLink::send->push_request(Base::conf_ptr());
|
||||
else
|
||||
auth_failed("no management provider", false);
|
||||
}
|
||||
else if (string::starts_with(msg, "INFO,"))
|
||||
{
|
||||
@@ -375,11 +369,14 @@ namespace openvpn {
|
||||
|
||||
virtual void relay(const IP::Addr& target, const int port) override
|
||||
{
|
||||
if (halt || disconnect_type == DT_HALT_RESTART)
|
||||
return;
|
||||
|
||||
Base::update_now();
|
||||
|
||||
if (TunLink::send && !relay_transition)
|
||||
if (TunLink::send && (disconnect_type < DT_RELAY_TRANSITION))
|
||||
{
|
||||
relay_transition = true;
|
||||
disconnect_type = DT_RELAY_TRANSITION;
|
||||
TunLink::send->relay(target, port);
|
||||
disconnect_in(Time::Duration::seconds(10)); // not a real disconnect, just complete transition to relay
|
||||
}
|
||||
@@ -398,9 +395,15 @@ namespace openvpn {
|
||||
|
||||
virtual void push_reply(std::vector<BufferPtr>&& push_msgs) override
|
||||
{
|
||||
if (halt || relay_transition || !Base::primary_defined())
|
||||
if (halt || (disconnect_type >= DT_RELAY_TRANSITION) || !Base::primary_defined())
|
||||
return;
|
||||
|
||||
if (disconnect_type == DT_AUTH_PENDING)
|
||||
{
|
||||
disconnect_type = DT_NONE;
|
||||
cancel_disconnect();
|
||||
}
|
||||
|
||||
Base::update_now();
|
||||
|
||||
if (get_tun())
|
||||
@@ -432,7 +435,7 @@ namespace openvpn {
|
||||
const std::string& reason,
|
||||
const bool tell_client) override
|
||||
{
|
||||
if (halt || did_client_halt_restart)
|
||||
if (halt || disconnect_type == DT_HALT_RESTART)
|
||||
return;
|
||||
|
||||
Base::update_now();
|
||||
@@ -498,7 +501,7 @@ namespace openvpn {
|
||||
|
||||
if (type != HaltRestart::RESTART_PASSIVE)
|
||||
{
|
||||
did_client_halt_restart = true;
|
||||
disconnect_type = DT_HALT_RESTART;
|
||||
disconnect_in(Time::Duration::seconds(1));
|
||||
}
|
||||
|
||||
@@ -514,13 +517,23 @@ namespace openvpn {
|
||||
|
||||
virtual void schedule_disconnect(const unsigned int seconds)
|
||||
{
|
||||
if (halt || did_client_halt_restart)
|
||||
if (halt || disconnect_type == DT_HALT_RESTART)
|
||||
return;
|
||||
Base::update_now();
|
||||
disconnect_in(Time::Duration::seconds(seconds));
|
||||
set_housekeeping_timer();
|
||||
}
|
||||
|
||||
virtual void schedule_auth_pending_timeout(const unsigned int seconds)
|
||||
{
|
||||
if (halt || (disconnect_type >= DT_RELAY_TRANSITION) || !seconds)
|
||||
return;
|
||||
Base::update_now();
|
||||
disconnect_type = DT_AUTH_PENDING;
|
||||
disconnect_in(Time::Duration::seconds(seconds));
|
||||
set_housekeeping_timer();
|
||||
}
|
||||
|
||||
virtual void post_cc_msg(BufferPtr&& msg) override
|
||||
{
|
||||
if (halt || !Base::primary_defined())
|
||||
@@ -582,6 +595,11 @@ namespace openvpn {
|
||||
disconnect_at = now() + dur;
|
||||
}
|
||||
|
||||
void cancel_disconnect()
|
||||
{
|
||||
disconnect_at = Time::infinite();
|
||||
}
|
||||
|
||||
void housekeeping_callback(const openvpn_io::error_code& e)
|
||||
{
|
||||
try {
|
||||
@@ -596,10 +614,21 @@ namespace openvpn {
|
||||
invalidation_error(Base::invalidation_reason());
|
||||
else if (now() >= disconnect_at)
|
||||
{
|
||||
if (relay_transition && !did_client_halt_restart)
|
||||
Base::pre_destroy();
|
||||
else
|
||||
error("disconnect triggered");
|
||||
switch (disconnect_type)
|
||||
{
|
||||
case DT_HALT_RESTART:
|
||||
error("disconnect triggered");
|
||||
break;
|
||||
case DT_RELAY_TRANSITION:
|
||||
Base::pre_destroy();
|
||||
break;
|
||||
case DT_AUTH_PENDING:
|
||||
auth_failed("Auth Pending Timeout", true);
|
||||
break;
|
||||
default:
|
||||
error("unknown disconnect");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
set_housekeeping_timer();
|
||||
@@ -676,9 +705,15 @@ namespace openvpn {
|
||||
openvpn_io::io_context& io_context;
|
||||
|
||||
bool halt = false;
|
||||
bool did_push = false;
|
||||
bool did_client_halt_restart = false;
|
||||
bool relay_transition = false;
|
||||
|
||||
// higher values are higher priority
|
||||
enum DisconnectType {
|
||||
DT_NONE=0,
|
||||
DT_AUTH_PENDING,
|
||||
DT_RELAY_TRANSITION,
|
||||
DT_HALT_RESTART,
|
||||
};
|
||||
int disconnect_type = DT_NONE;
|
||||
|
||||
PeerAddr::Ptr peer_addr;
|
||||
|
||||
|
||||
@@ -559,7 +559,18 @@ namespace openvpn {
|
||||
new_comp = o->get(1, 128);
|
||||
CompressContext::Type meth = CompressContext::parse_method(new_comp);
|
||||
if (meth != CompressContext::NONE)
|
||||
comp_ctx = CompressContext(pco.is_comp() ? meth : CompressContext::stub(meth), pco.is_comp_asym());
|
||||
{
|
||||
// if compression is not availabe, CompressContext ctor throws an exception
|
||||
if (pco.is_comp())
|
||||
comp_ctx = CompressContext(meth, pco.is_comp_asym());
|
||||
else
|
||||
{
|
||||
// server pushes compression but client has compression disabled
|
||||
// degrade to asymmetric compression (downlink only)
|
||||
comp_ctx = CompressContext(meth, true);
|
||||
OPENVPN_LOG("Server has pushed compressor " << comp_ctx.str() << ", but client has disabled compression, switching to asymmetric");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3177,7 +3188,7 @@ namespace openvpn {
|
||||
// configuration
|
||||
const Config& conf() const { return *config; }
|
||||
Config& conf() { return *config; }
|
||||
const Config::Ptr& conf_ptr() const { return config; }
|
||||
Config::Ptr conf_ptr() const { return config; }
|
||||
|
||||
// stats
|
||||
SessionStats& stat() const { return *stats; }
|
||||
|
||||
@@ -102,12 +102,10 @@ namespace openvpn {
|
||||
enum PKType {
|
||||
PK_UNKNOWN = 0,
|
||||
PK_NONE,
|
||||
PK_DSA,
|
||||
PK_RSA,
|
||||
PK_ECKEY,
|
||||
PK_ECKEY_DH,
|
||||
PK_EC,
|
||||
PK_ECDSA,
|
||||
PK_RSA_ALT,
|
||||
PK_RSASSA_PSS,
|
||||
};
|
||||
|
||||
enum LoadFlags {
|
||||
@@ -125,18 +123,14 @@ namespace openvpn {
|
||||
{
|
||||
case PK_NONE:
|
||||
return "None";
|
||||
case PK_DSA:
|
||||
return "DSA";
|
||||
case PK_RSA:
|
||||
return "RSA";
|
||||
case PK_ECKEY:
|
||||
case PK_EC:
|
||||
return "EC";
|
||||
case PK_ECKEY_DH:
|
||||
return "EC_DH";
|
||||
case PK_ECDSA:
|
||||
return "ECDSA";
|
||||
case PK_RSA_ALT:
|
||||
return "RSA_ALT";
|
||||
case PK_RSASSA_PSS:
|
||||
return "RSASSA_PSS";
|
||||
case PK_UNKNOWN:
|
||||
default:
|
||||
return "Unknown";
|
||||
|
||||
@@ -248,6 +248,7 @@ namespace openvpn {
|
||||
resolver.async_resolve(proxy_host, proxy_port,
|
||||
[self=Ptr(this)](const openvpn_io::error_code& error, openvpn_io::ip::tcp::resolver::results_type results)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->do_resolve_(error, results);
|
||||
});
|
||||
}
|
||||
@@ -927,6 +928,7 @@ namespace openvpn {
|
||||
socket.set_option(openvpn_io::ip::tcp::no_delay(true));
|
||||
socket.async_connect(server_endpoint, [self=Ptr(this)](const openvpn_io::error_code& error)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->start_impl_(error);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -93,7 +93,9 @@ namespace openvpn {
|
||||
{
|
||||
halt = false;
|
||||
stop_requeueing = false;
|
||||
if (config->remote_list->endpoint_available(&server_host, &server_port, nullptr))
|
||||
if (config->remote_list->endpoint_available(&server_host,
|
||||
&server_port,
|
||||
&server_protocol))
|
||||
{
|
||||
start_connect_();
|
||||
}
|
||||
@@ -103,6 +105,7 @@ namespace openvpn {
|
||||
resolver.async_resolve(server_host, server_port,
|
||||
[self=Ptr(this)](const openvpn_io::error_code& error, openvpn_io::ip::tcp::resolver::results_type results)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->do_resolve_(error, results);
|
||||
});
|
||||
}
|
||||
@@ -151,8 +154,7 @@ namespace openvpn {
|
||||
host = server_host;
|
||||
port = server_port;
|
||||
const IP::Addr addr = server_endpoint_addr();
|
||||
proto = "TCP";
|
||||
proto += addr.version_string();
|
||||
proto = server_protocol.str();
|
||||
ip_addr = addr.to_string();
|
||||
}
|
||||
|
||||
@@ -163,12 +165,7 @@ namespace openvpn {
|
||||
|
||||
virtual Protocol transport_protocol() const
|
||||
{
|
||||
if (server_endpoint.address().is_v4())
|
||||
return Protocol(Protocol::TCPv4);
|
||||
else if (server_endpoint.address().is_v6())
|
||||
return Protocol(Protocol::TCPv6);
|
||||
else
|
||||
return Protocol();
|
||||
return server_protocol;
|
||||
}
|
||||
|
||||
virtual void stop() { stop_(); }
|
||||
@@ -270,7 +267,7 @@ namespace openvpn {
|
||||
else
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "DNS resolve error on '" << server_host << "' for TCP session: " << error.message();
|
||||
os << "DNS resolve error on '" << server_host << "' for " << server_protocol.str() << " session: " << error.message();
|
||||
config->stats->error(Error::RESOLVE_ERROR);
|
||||
stop();
|
||||
parent->transport_error(Error::UNDEF, os.str());
|
||||
@@ -282,7 +279,8 @@ namespace openvpn {
|
||||
void start_connect_()
|
||||
{
|
||||
config->remote_list->get_endpoint(server_endpoint);
|
||||
OPENVPN_LOG("Contacting " << server_endpoint << " via TCP");
|
||||
OPENVPN_LOG("Contacting " << server_endpoint << " via "
|
||||
<< server_protocol.str());
|
||||
parent->transport_wait();
|
||||
parent->ip_hole_punch(server_endpoint_addr());
|
||||
socket.open(server_endpoint.protocol());
|
||||
@@ -293,7 +291,7 @@ namespace openvpn {
|
||||
{
|
||||
config->stats->error(Error::SOCKET_PROTECT_ERROR);
|
||||
stop();
|
||||
parent->transport_error(Error::UNDEF, "socket_protect error (TCP)");
|
||||
parent->transport_error(Error::UNDEF, "socket_protect error (" + std::string(server_protocol.str()) + ")");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -301,6 +299,7 @@ namespace openvpn {
|
||||
socket.set_option(openvpn_io::ip::tcp::no_delay(true));
|
||||
socket.async_connect(server_endpoint, [self=Ptr(this)](const openvpn_io::error_code& error)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->start_impl_(error);
|
||||
});
|
||||
}
|
||||
@@ -352,7 +351,7 @@ namespace openvpn {
|
||||
else
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "TCP connect error on '" << server_host << ':' << server_port << "' (" << server_endpoint << "): " << error.message();
|
||||
os << server_protocol.str() << " connect error on '" << server_host << ':' << server_port << "' (" << server_endpoint << "): " << error.message();
|
||||
config->stats->error(Error::TCP_CONNECT_ERROR);
|
||||
stop();
|
||||
parent->transport_error(Error::UNDEF, os.str());
|
||||
@@ -362,6 +361,7 @@ namespace openvpn {
|
||||
|
||||
std::string server_host;
|
||||
std::string server_port;
|
||||
Protocol server_protocol;
|
||||
|
||||
openvpn_io::io_context& io_context;
|
||||
openvpn_io::ip::tcp::socket socket;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <openvpn/io/io.hpp>
|
||||
|
||||
#include <openvpn/common/bigmutex.hpp>
|
||||
#include <openvpn/common/likely.hpp>
|
||||
#include <openvpn/common/platform.hpp>
|
||||
#include <openvpn/transport/udplink.hpp>
|
||||
@@ -107,6 +108,7 @@ namespace openvpn {
|
||||
resolver.async_resolve(server_host, server_port,
|
||||
[self=Ptr(this)](const openvpn_io::error_code& error, openvpn_io::ip::udp::resolver::results_type results)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->do_resolve_(error, results);
|
||||
});
|
||||
}
|
||||
@@ -283,6 +285,7 @@ namespace openvpn {
|
||||
#endif
|
||||
socket.async_connect(server_endpoint, [self=Ptr(this)](const openvpn_io::error_code& error)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->start_impl_(error);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -186,9 +186,9 @@ namespace openvpn {
|
||||
case TCPv6:
|
||||
return "TCPv6";
|
||||
case TLSv4:
|
||||
return "TLSv4";
|
||||
return "TLS/TCPv4";
|
||||
case TLSv6:
|
||||
return "TLSv6";
|
||||
return "TLS/TCPv6";
|
||||
case UnixStream:
|
||||
return "UnixStream";
|
||||
case UnixDGram:
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <openvpn/io/io.hpp>
|
||||
|
||||
#include <openvpn/common/bigmutex.hpp>
|
||||
#include <openvpn/common/size.hpp>
|
||||
#include <openvpn/common/rc.hpp>
|
||||
#include <openvpn/common/socktypes.hpp>
|
||||
@@ -73,16 +74,6 @@ namespace openvpn {
|
||||
free_list_max_size_arg, frame_context_arg, stats_arg)
|
||||
{ }
|
||||
|
||||
// Called by LinkCommon and TCPTransport Client class
|
||||
unsigned int send_queue_size() const
|
||||
{
|
||||
return Base::queue.size()
|
||||
#ifdef OPENVPN_GREMLIN
|
||||
+ (gremlin ? gremlin->send_size() : 0)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
private:
|
||||
// Called by LinkCommon
|
||||
virtual void from_app_send_buffer(BufferPtr& buf) override
|
||||
|
||||
@@ -175,6 +175,7 @@ namespace openvpn {
|
||||
socket.async_receive(frame_context.mutable_buffer_clamp(tcpfrom->buf),
|
||||
[self=Ptr(this), tcpfrom=PacketFrom::SPtr(tcpfrom)](const openvpn_io::error_code& error, const size_t bytes_recvd) mutable
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
try
|
||||
{
|
||||
self->handle_recv(std::move(tcpfrom), error, bytes_recvd);
|
||||
@@ -248,6 +249,7 @@ namespace openvpn {
|
||||
socket.async_send(buf.const_buffer_clamp(),
|
||||
[self=Ptr(this)](const openvpn_io::error_code& error, const size_t bytes_sent)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->handle_send(error, bytes_sent);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -143,6 +143,7 @@ namespace openvpn {
|
||||
udpfrom->sender_endpoint,
|
||||
[self=Ptr(this), udpfrom=PacketFrom::SPtr(udpfrom)](const openvpn_io::error_code& error, const size_t bytes_recvd) mutable
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->handle_read(std::move(udpfrom), error, bytes_recvd);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include <openvpn/common/socktypes.hpp>
|
||||
#include <openvpn/buffer/buffer.hpp>
|
||||
#include <openvpn/addr/ipv4.hpp>
|
||||
#include <openvpn/ip/ipcommon.hpp>
|
||||
#include <openvpn/ip/dhcp.hpp>
|
||||
#include <openvpn/tun/builder/capture.hpp>
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace openvpn {
|
||||
return false;
|
||||
|
||||
DHCPPacket* dhcp = (DHCPPacket*)buf.data();
|
||||
if (dhcp->ip.protocol == IPHeader::UDP
|
||||
if (dhcp->ip.protocol == IPCommon::UDP
|
||||
&& dhcp->udp.source == htons(DHCP::BOOTPS_PORT)
|
||||
&& dhcp->udp.dest == htons(DHCP::BOOTPC_PORT)
|
||||
&& dhcp->dhcp.op == DHCP::BOOTREPLY)
|
||||
|
||||
@@ -58,7 +58,8 @@ namespace openvpn {
|
||||
|
||||
Config(const TunBuilderCapture& settings)
|
||||
: dns_servers(get_dns_servers(settings)),
|
||||
search_domains(get_search_domains(settings))
|
||||
search_domains(get_search_domains(settings)),
|
||||
adapter_domain_suffix(settings.adapter_domain_suffix)
|
||||
{
|
||||
// We redirect DNS if either of the following is true:
|
||||
// 1. redirect-gateway (IPv4) is pushed, or
|
||||
@@ -73,6 +74,7 @@ namespace openvpn {
|
||||
os << " SO=" << search_order;
|
||||
os << " DNS=" << CF::array_to_string(dns_servers);
|
||||
os << " DOM=" << CF::array_to_string(search_domains);
|
||||
os << " ADS=" << adapter_domain_suffix;
|
||||
return os.str();
|
||||
}
|
||||
|
||||
@@ -80,6 +82,7 @@ namespace openvpn {
|
||||
int search_order = 5000;
|
||||
CF::Array dns_servers;
|
||||
CF::Array search_domains;
|
||||
std::string adapter_domain_suffix;
|
||||
|
||||
private:
|
||||
static CF::Array get_dns_servers(const TunBuilderCapture& settings)
|
||||
@@ -170,8 +173,14 @@ namespace openvpn {
|
||||
|
||||
// set search domains
|
||||
info->dns.backup_orig("SearchDomains");
|
||||
if (CF::array_len(config.search_domains))
|
||||
CF::dict_set_obj(info->dns.mod, "SearchDomains", config.search_domains());
|
||||
CF::MutableArray search_domains(CF::mutable_array());
|
||||
|
||||
// add adapter_domain_suffix to SearchDomains for domain autocompletion
|
||||
if (config.adapter_domain_suffix.length() > 0)
|
||||
CF::array_append_str(search_domains, config.adapter_domain_suffix);
|
||||
|
||||
if (CF::array_len(search_domains))
|
||||
CF::dict_set_obj(info->dns.mod, "SearchDomains", search_domains());
|
||||
|
||||
// set search order
|
||||
info->dns.backup_orig("SearchOrder");
|
||||
@@ -182,16 +191,22 @@ namespace openvpn {
|
||||
}
|
||||
else
|
||||
{
|
||||
// redirect specific domains
|
||||
// split-DNS - resolve only specific domains
|
||||
info->ovpn.mod_reset();
|
||||
if (CF::array_len(config.dns_servers) && CF::array_len(config.search_domains))
|
||||
{
|
||||
// set DNS servers
|
||||
CF::dict_set_obj(info->ovpn.mod, "ServerAddresses", config.dns_servers());
|
||||
|
||||
// set search domains, reverse domains can be added here as well
|
||||
// DNS will be used only for those domains
|
||||
CF::dict_set_obj(info->ovpn.mod, "SupplementalMatchDomains", config.search_domains());
|
||||
|
||||
// do not use those domains in autocompletion
|
||||
CF::dict_set_int(info->ovpn.mod, "SupplementalMatchDomainsNoSearch", 1);
|
||||
}
|
||||
|
||||
// in case of split-DNS macOS uses domain suffix of network adapter,
|
||||
// not the one provided by VPN (which we put to SearchDomains)
|
||||
|
||||
// push it
|
||||
mod |= info->ovpn.push_to_store();
|
||||
|
||||
@@ -26,10 +26,11 @@
|
||||
|
||||
#include <openvpn/io/io.hpp>
|
||||
|
||||
#include <openvpn/common/bigmutex.hpp>
|
||||
#include <openvpn/common/size.hpp>
|
||||
#include <openvpn/common/rc.hpp>
|
||||
#include <openvpn/frame/frame.hpp>
|
||||
#include <openvpn/ip/ip.hpp>
|
||||
#include <openvpn/ip/ipcommon.hpp>
|
||||
#include <openvpn/common/socktypes.hpp>
|
||||
#include <openvpn/log/sessionstats.hpp>
|
||||
#include <openvpn/tun/tunlog.hpp>
|
||||
@@ -73,7 +74,7 @@ namespace openvpn {
|
||||
{
|
||||
if (buf.offset() >= 4 && buf.size() >= 1)
|
||||
{
|
||||
switch (IPHeader::version(buf[0]))
|
||||
switch (IPCommon::version(buf[0]))
|
||||
{
|
||||
case 4:
|
||||
prepend_pf_inet(buf, PF_INET);
|
||||
@@ -208,6 +209,7 @@ namespace openvpn {
|
||||
stream->async_read_some(frame_context.mutable_buffer(tunfrom->buf),
|
||||
[self=Ptr(this), tunfrom=typename PacketFrom::SPtr(tunfrom)](const openvpn_io::error_code& error, const size_t bytes_recvd) mutable
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
self->handle_read(std::move(tunfrom), error, bytes_recvd);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -391,6 +391,7 @@ namespace openvpn {
|
||||
l2_timer.expires_after(Time::Duration::seconds(seconds));
|
||||
l2_timer.async_wait([self=Ptr(this)](const openvpn_io::error_code& error)
|
||||
{
|
||||
OPENVPN_ASYNC_HANDLER;
|
||||
if (!error && !self->halt)
|
||||
self->layer_2_timer_callback();
|
||||
});
|
||||
|
||||
@@ -294,6 +294,9 @@ namespace openvpn {
|
||||
// Process ifconfig and topology
|
||||
if (!l2_post)
|
||||
{
|
||||
// set lowest interface metric to make Windows use pushed DNS search domain
|
||||
create.add(new WinCmd("netsh interface ip set interface " + tap_index_name + " metric=1"));
|
||||
|
||||
const std::string metric = route_metric_opt(pull, *local4, MT_IFACE);
|
||||
const std::string netmask = IPv4::Addr::netmask_from_prefix_len(local4->prefix_length).to_string();
|
||||
const IP::Addr localaddr = IP::Addr::from_string(local4->address);
|
||||
|
||||
@@ -237,6 +237,8 @@ fi
|
||||
|
||||
# Cityhash
|
||||
if [ "$CITY" = "1" ]; then
|
||||
LIBDIRS="$LIBDIRS -L$DEP_DIR/cityhash/cityhash-$PLATFORM/lib"
|
||||
CPPFLAGS="$CPPFLAGS -I$DEP_DIR/cityhash/cityhash-$PLATFORM/include"
|
||||
LIBS="$LIBS -lcityhash"
|
||||
CPPFLAGS="$CPPFLAGS -DHAVE_CITYHASH"
|
||||
fi
|
||||
|
||||
@@ -12,6 +12,8 @@ echo "******* MBEDTLS"
|
||||
$O3/core/scripts/linux/build-mbedtls
|
||||
echo "******* LZ4"
|
||||
$O3/core/scripts/linux/build-lz4
|
||||
echo "******* CITYHASH"
|
||||
$O3/core/scripts/linux/build-cityhash
|
||||
|
||||
#$O3/core/scripts/linux/build-openssl x64
|
||||
#$O3/core/scripts/linux/build-lzo
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
if [ -z "$O3" ]; then
|
||||
echo O3 var must point to ovpn3 tree ; exit 1
|
||||
fi
|
||||
if [ -z "$DEP_DIR" ]; then
|
||||
echo DEP_DIR var must point to ovpn3 dependency tree
|
||||
exit 1
|
||||
fi
|
||||
cd $DEP_DIR
|
||||
rm -rf cityhash
|
||||
mkdir cityhash
|
||||
TARGET=linux $O3/core/deps/cityhash/build-cityhash
|
||||
exit 0
|
||||
34
Sources/OpenVPNAdapter/Libraries/Vendors/openvpn/scripts/version
Executable file
34
Sources/OpenVPNAdapter/Libraries/Vendors/openvpn/scripts/version
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 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) 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/>.
|
||||
|
||||
set -eu
|
||||
|
||||
# ensure this script works even when core is used as submodule, by setting
|
||||
# O3/core/.git as git folder
|
||||
export GIT_DIR=$(dirname $0)/../.git
|
||||
|
||||
MAJOR=3
|
||||
BRANCH="$(git rev-parse --symbolic-full-name HEAD | cut -d/ -f3- | tr / _)"
|
||||
COMMIT_ID="$(git rev-list HEAD -1 --abbrev-commit)"
|
||||
|
||||
echo "$MAJOR.git:$BRANCH:$COMMIT_ID"
|
||||
@@ -1,4 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Options:
|
||||
# OSSL=1 -- build using OpenSSL
|
||||
# MTLS=1 -- build using mbedTLS
|
||||
# PTPROXY=1 -- build using Private Tunnel proxy
|
||||
|
||||
# Other options
|
||||
GCC_EXTRA="$GCC_EXTRA -DOPENVPN_SHOW_SESSION_TOKEN"
|
||||
[ "$EER" = "1" ] && GCC_EXTRA="$GCC_EXTRA -DTEST_EER"
|
||||
[ "$NULL" = "1" ] && GCC_EXTRA="$GCC_EXTRA -DOPENVPN_FORCE_TUN_NULL"
|
||||
@@ -11,25 +18,26 @@ GCC_EXTRA="$GCC_EXTRA -DOPENVPN_SHOW_SESSION_TOKEN"
|
||||
if [ "$AGENT" = "1" ]; then
|
||||
GCC_EXTRA="$GCC_EXTRA -DOPENVPN_COMMAND_AGENT"
|
||||
fi
|
||||
GCC_EXTRA="$GCC_EXTRA -DOPENVPN_VERSION=\"$($(dirname $0)/../../scripts/version)\""
|
||||
export GCC_EXTRA
|
||||
|
||||
# determine platform
|
||||
if [ "$(uname)" == "Darwin" ]; then
|
||||
cd $O3/core
|
||||
if [ "$DEBUG" = "3" ]; then
|
||||
. vars/vars-osx64-dbg
|
||||
else
|
||||
. vars/vars-osx64
|
||||
fi
|
||||
. vars/setpath
|
||||
cd test/ovpncli
|
||||
ASIO=1 MTLS=1 LZ4=1 PTPROXY=1 build cli 2>&1
|
||||
export PROF=osx64
|
||||
elif [ "$(uname)" == "Linux" ]; then
|
||||
export PROF=linux
|
||||
else
|
||||
cd $O3/core
|
||||
if [ "$DEBUG" = "3" ]; then
|
||||
. vars/vars-linux-dbg
|
||||
else
|
||||
. vars/vars-linux
|
||||
fi
|
||||
. vars/setpath
|
||||
cd test/ovpncli
|
||||
ASIO=1 MTLS=1 LZ4=1 NOSSL=1 PTPROXY=1 build cli 2>&1
|
||||
echo this script only knows how to build on Mac OS or Linux
|
||||
fi
|
||||
|
||||
# use mbedTLS by default
|
||||
[[ -z "$OSSL" && -z "$MTLS" ]] && export MTLS=1
|
||||
|
||||
# don't link with OpenSSL if mbedTLS is specified
|
||||
if [ "$MTLS" = "1" ]; then
|
||||
export OSSL=0
|
||||
export NOSSL=1
|
||||
fi
|
||||
|
||||
# build
|
||||
ASIO=1 LZ4=1 ../../scripts/build cli
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
if [ "$NO_MOD_PATH" != "1" ]; then
|
||||
export PATH="$SDK/tools:$SDK/platform-tools:$PATH"
|
||||
fi
|
||||
export ANDROID_HOME=$SDK
|
||||
@@ -0,0 +1 @@
|
||||
# Nothing in here
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <openvpn/ip/ip.hpp>
|
||||
#include <openvpn/ip/ipcommon.hpp>
|
||||
|
||||
@interface OpenVPNPacket () {
|
||||
NSData *_data;
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
uint32_t protocol = PF_UNSPEC;
|
||||
|
||||
uint32_t version = openvpn::IPHeader::version(header);
|
||||
uint32_t version = openvpn::IPCommon::version(header);
|
||||
switch (version) {
|
||||
case 4:
|
||||
protocol = PF_INET;
|
||||
|
||||
Reference in New Issue
Block a user