Merge branch 'feature/update-dependencies' into develop

This commit is contained in:
Sergey Abramchuk
2018-07-27 18:25:40 +03:00
74 changed files with 4118 additions and 252 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
};

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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)
)

View File

@@ -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();
}));
}

View File

@@ -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

View File

@@ -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

View File

@@ -14,3 +14,6 @@ export JSONCPP_CSUM=c49deac9e0933bcb7044f08516861a2d560988540b23de2ac1ad443b219a
export TAP_VERSION=0e30f5c13b3c7b0bdd60da915350f653e4c14d92
export TAP_CSUM=8ff65f9e741c5ecfe1af904eaa38713f05639ce9457ef92041fd8e6b2a170315
export CITYHASH_VERSION=8af9b8c2b889d80c22d6bc26ba0df1afb79a30db
export CITYHASH_CSUM=f70368facd15735dffc77fe2b27ab505bfdd05be5e9166d94149a8744c212f49

View File

@@ -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

View File

@@ -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

View File

@@ -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})

View File

@@ -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";
};

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);

View File

@@ -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()

View File

@@ -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);
}

View File

@@ -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);
});
}

View File

@@ -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) {}

View File

@@ -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;

View File

@@ -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.

View File

@@ -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

View File

@@ -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);

View File

@@ -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;

View File

@@ -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));
}

View File

@@ -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

View File

@@ -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

View File

@@ -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) { }
};
}

View File

@@ -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[];

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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;
}
}
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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;

View File

@@ -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; }

View File

@@ -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";

View File

@@ -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);
});
}

View File

@@ -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;

View File

@@ -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);
});
}

View File

@@ -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:

View File

@@ -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

View File

@@ -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);
});
}

View File

@@ -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);
});
}

View File

@@ -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)

View File

@@ -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();

View File

@@ -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);
});
}

View File

@@ -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();
});

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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"

View File

@@ -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

View File

@@ -4,3 +4,4 @@
if [ "$NO_MOD_PATH" != "1" ]; then
export PATH="$SDK/tools:$SDK/platform-tools:$PATH"
fi
export ANDROID_HOME=$SDK

View File

@@ -0,0 +1 @@
# Nothing in here

View File

@@ -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;