Squashed 'Sources/OpenVPNAdapter/Libraries/Vendors/openvpn/' changes from 554d8b888..cc90cde57

cc90cde57 win: use 'MSVC 2017 Professional' as default compiler
4b072bce1 [OVPN3-311] function.hpp: fix Windows build
48b9b78de [OVPN3-310] logging: fix 'OPENVPN_LOG_NTNL': identifier not found
5a4a87552 cosmetics: helper function to check registry errors
fc52fd8a5 [OC-78] proxy: support PROXY_AUTO_CONFIG_URL on Windows
f5178cff9 [OC-77] proxy: refactor proxy settings code
18e50ec3f ReplyParser: added undefined status
8178ae06f unix file utils: added update_file_mod_time_nanoseconds()
8f20f7693 build: use LZ4_SYS=1 default when target is Linux
4bd996e61 timestr: added date_time_utc() and nanosec_time_to_string()
0eaa2586f string: added remove_spaces() method
d47ae03cc OptionList: added get_c_str() method
1eb9cd657 unix file utils: added mtime_ns parameter to write_binary_unix() and write_binary_atomic()
bf00c6e3e Time::delta_str(): use "INF" to denote infinite time
0e598a87b kovpn.hpp: asio must be included before sys/ and linux/ headers to avoid redefinition conflicts
1d2ce460d BufferType: added read_alloc_buf() method
148ae6085 BufferType: added reset_offset() method
6218ed618 Factor out IP::random_addr_v4() and IP::random_addr_v6() from IP::random_addr().
5468670b9 pool: minor changes
36a885a82 route: allow for specialized IPv4/v6 RouteType
5e29e6628 BufferType: added typedef T value_type
d92021c99 strerror.hpp: added #include <errno.h> for benefit of users
363cbece3 Function: misc cleanup
d88435ecd IP::Route: added defined() method
3371cb745 kovpn.hpp: fix centos build with DCO enabled
dc9e48d98 Fix bug in macos tunnel interface setup. Second ip address should be gateway address
bcdb27993 Merged in schwabe/fix_clang_warnings (pull request #25)
ede5e90ff Merged in schabe/fix_swig_ipadr (pull request #27)
c0d580d24 Merged in schwabe/fix_openvpn_extern (pull request #26)
0965882e5 Merged in schwabe/stats_morecpus (pull request #23)
5f1f8470b Revert bugfix for not compiling IA32 ASM of 2.7.5
bde2c41be dep: switch from mbeTLS 2.7.0 to 2.7.5
9d06b5c97 [OC-77] proxy: support PROXY_AUTO_CONFIG_URL on macOS
3f2ad8e8c Hide const std::string IP methods from SWIG
ba264862a Send also kovpn statistics of CPU Cores >= 16 via status message
2991d38b3 Fix warnings reported by LLVM/Clang
02d2a7975 Fix multiple inclusion of OpenVPN3 header with OPENPVN_EXTERN

git-subtree-dir: Sources/OpenVPNAdapter/Libraries/Vendors/openvpn
git-subtree-split: cc90cde5769dcf9e13fdd9e85d6d0857963dabce
This commit is contained in:
Sergey Abramchuk
2018-09-27 20:56:53 +03:00
parent e2ad2ab5d5
commit a01ecd6c88
52 changed files with 2314 additions and 4947 deletions
+10
View File
@@ -78,10 +78,16 @@ namespace openvpn {
{
}
#ifndef SWIGPYTHON
// When calling IP:Addr with None as the second parameter, Swig will
// always pick this function and complain about not being able to convert
// a null pointer to a const std::string reference. Hide this function, so
// swig is forced to take the const char* variant of this function instead
Addr(const std::string& ipstr, const std::string& title, Version required_version = UNSPEC)
: Addr(from_string(ipstr, title.c_str(), required_version))
{
}
#endif
void validate_version(const char *title, Version required_version) const
{
@@ -89,10 +95,12 @@ namespace openvpn {
throw ip_exception(internal::format_error(to_string(), title, version_string_static(required_version), "wrong IP version"));
}
#ifndef SWIGPYTHON
void validate_version(const std::string& title, Version required_version) const
{
validate_version(title.c_str(), required_version);
}
#endif
static std::string validate(const std::string& ipstr, const char *title = nullptr, Version required_version = UNSPEC)
{
@@ -100,10 +108,12 @@ namespace openvpn {
return a.to_string();
}
#ifndef SWIGPYTHON
static std::string validate(const std::string& ipstr, const std::string& title, Version required_version = UNSPEC)
{
return validate(ipstr, title.c_str(), required_version);
}
#endif
static bool is_valid(const std::string& ipstr)
{
+18
View File
@@ -58,6 +58,11 @@ namespace openvpn {
typedef std::uint32_t base_type;
typedef std::int32_t signed_base_type;
bool defined() const
{
return true;
}
static Addr from_addr(const Addr& addr)
{
return addr;
@@ -498,6 +503,15 @@ namespace openvpn {
h(u.addr);
}
#ifdef HAVE_CITYHASH
std::size_t hashval() const
{
HashSizeT h;
hash(h);
return h.value();
}
#endif
#ifdef OPENVPN_IP_IMMUTABLE
private:
#endif
@@ -566,4 +580,8 @@ namespace openvpn {
}
}
#ifdef HAVE_CITYHASH
OPENVPN_HASH_METHOD(openvpn::IPv4::Addr, hashval);
#endif
#endif // OPENVPN_ADDR_IPV4_H
+18
View File
@@ -55,6 +55,11 @@ namespace openvpn {
public:
enum { SIZE=128 };
bool defined() const
{
return true;
}
static Addr from_addr(const Addr& addr)
{
return addr;
@@ -540,6 +545,15 @@ namespace openvpn {
h(u.bytes, sizeof(u.bytes));
}
#ifdef HAVE_CITYHASH
std::size_t hashval() const
{
HashSizeT h;
hash(h);
return h.value();
}
#endif
#ifdef OPENVPN_IP_IMMUTABLE
private:
#endif
@@ -825,4 +839,8 @@ namespace openvpn {
}
}
#ifdef HAVE_CITYHASH
OPENVPN_HASH_METHOD(openvpn::IPv6::Addr, hashval);
#endif
#endif // OPENVPN_ADDR_IPV6_H
+31 -5
View File
@@ -47,7 +47,7 @@ namespace openvpn {
// Add range of addresses to pool (pool will own the addresses).
void add_range(const RangeType<ADDR>& range)
{
typename RangeType<ADDR>::Iterator iter = range.iterator();
auto iter = range.iterator();
while (iter.more())
{
const ADDR& a = iter.addr();
@@ -59,7 +59,7 @@ namespace openvpn {
// Add single address to pool (pool will own the address).
void add_addr(const ADDR& addr)
{
typename std::unordered_map<ADDR, bool>::const_iterator e = map.find(addr);
auto e = map.find(addr);
if (e == map.end())
{
freelist.push_back(addr);
@@ -73,16 +73,23 @@ namespace openvpn {
return map.size() - freelist.size();
}
// Return number of pool addresses currently in use.
size_t n_free() const
{
return freelist.size();
}
// Acquire an address from pool. Returns true if successful,
// with address placed in dest, or false if pool depleted.
bool acquire_addr(ADDR& dest)
{
while (true)
{
freelist_fill();
if (freelist.empty())
return false;
const ADDR& a = freelist.front();
typename std::unordered_map<ADDR, bool>::iterator e = map.find(a);
auto e = map.find(a);
if (e == map.end()) // any address in freelist must exist in map
throw Exception("PoolType: address in freelist doesn't exist in map");
if (!e->second)
@@ -100,7 +107,7 @@ namespace openvpn {
// successful, or false if the address is not available.
bool acquire_specific_addr(const ADDR& addr)
{
typename std::unordered_map<ADDR, bool>::iterator e = map.find(addr);
auto e = map.find(addr);
if (e != map.end() && !e->second)
{
e->second = true;
@@ -115,7 +122,7 @@ namespace openvpn {
// (b) the address is not owned by the pool.
void release_addr(const ADDR& addr)
{
typename std::unordered_map<ADDR, bool>::iterator e = map.find(addr);
auto e = map.find(addr);
if (e != map.end() && e->second)
{
freelist.push_back(addr);
@@ -126,6 +133,25 @@ namespace openvpn {
// DEBUGGING -- get the map load factor
float load_factor() const { return map.load_factor(); }
// Override to refill freelist on demand
virtual void freelist_fill()
{
}
std::string to_string() const
{
std::string ret;
for (const auto& e : map)
{
if (e.second)
{
ret += e.first.to_string();
ret += '\n';
}
}
return ret;
}
private:
std::deque<ADDR> freelist;
std::unordered_map<ADDR, bool> map;
+14 -6
View File
@@ -28,18 +28,26 @@
namespace openvpn {
namespace IP {
inline IPv4::Addr random_addr_v4(RandomAPI& prng)
{
return IPv4::Addr::from_uint32(prng.rand_get<std::uint32_t>());
}
inline IPv6::Addr random_addr_v6(RandomAPI& prng)
{
unsigned char bytes[16];
prng.rand_fill(bytes);
return IPv6::Addr::from_byte_string(bytes);
}
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>()));
return Addr::from_ipv4(random_addr_v4(prng));
case Addr::V6:
{
unsigned char bytes[16];
prng.rand_fill(bytes);
return Addr::from_ipv6(IPv6::Addr::from_byte_string(bytes));
}
return Addr::from_ipv6(random_addr_v6(prng));
default:
throw ip_exception("address unspecified");
}
+58 -6
View File
@@ -40,8 +40,9 @@ namespace openvpn {
namespace IP {
// Basic route object
template <typename ADDR>
struct RouteType
class RouteType
{
public:
typedef ADDR Addr;
ADDR addr;
@@ -89,6 +90,11 @@ namespace openvpn {
return r;
}
bool defined() const
{
return addr.defined();
}
IP::Addr::Version version() const
{
return addr.version();
@@ -99,9 +105,19 @@ namespace openvpn {
return addr.version_mask();
}
RouteType<IPv4::Addr> to_ipv4() const
{
return RouteType<IPv4::Addr>(addr.to_ipv4(), prefix_len);
}
RouteType<IPv6::Addr> to_ipv6() const
{
return RouteType<IPv6::Addr>(addr.to_ipv6(), prefix_len);
}
ADDR netmask() const
{
return ADDR::netmask_from_prefix_len(version(), prefix_len);
return netmask_(addr, prefix_len);
}
size_t extent() const
@@ -119,6 +135,12 @@ namespace openvpn {
addr = addr & netmask();
}
void verify_canonical() const
{
if (!is_canonical())
throw route_error("route not canonical: " + to_string());
}
bool is_host() const
{
return addr.defined() && prefix_len == addr.size();
@@ -134,7 +156,7 @@ namespace openvpn {
bool contains(const ADDR& a) const // assumes canonical address/routes
{
if (addr.defined() && addr.version() == a.version())
if (addr.defined() && version_eq(addr, a))
return (a & netmask()) == addr;
else
return false;
@@ -153,7 +175,7 @@ namespace openvpn {
r1.addr = addr;
r1.prefix_len = newpl;
r2.addr = addr + ADDR::netmask_from_prefix_len(addr.version(), newpl).extent_from_netmask();
r2.addr = addr + netmask_(addr, newpl).extent_from_netmask();
r2.prefix_len = newpl;
return true;
@@ -201,6 +223,37 @@ namespace openvpn {
return h.value();
}
#endif
private:
static IPv4::Addr netmask_(const IPv4::Addr&, unsigned int prefix_len)
{
return IPv4::Addr::netmask_from_prefix_len(prefix_len);
}
static IPv6::Addr netmask_(const IPv6::Addr&, unsigned int prefix_len)
{
return IPv6::Addr::netmask_from_prefix_len(prefix_len);
}
static IP::Addr netmask_(const IP::Addr& addr, unsigned int prefix_len)
{
return IP::Addr::netmask_from_prefix_len(addr.version(), prefix_len);
}
static bool version_eq(const IPv4::Addr&, const IPv4::Addr&)
{
return true;
}
static bool version_eq(const IPv6::Addr&, const IPv6::Addr&)
{
return true;
}
static bool version_eq(const IP::Addr& a1, const IP::Addr& a2)
{
return a1.version() == a2.version();
}
};
template <typename ADDR>
@@ -229,8 +282,7 @@ namespace openvpn {
void verify_canonical() const
{
for (auto &r : *this)
if (!r.is_canonical())
throw route_list_error("route not canonical: " + r.to_string());
r.verify_canonical();
}
template <typename R>
+26
View File
@@ -82,6 +82,7 @@ namespace openvpn {
buffer_headroom,
buffer_underflow,
buffer_overflow,
buffer_offset,
buffer_index,
buffer_const_index,
buffer_push_front_headroom,
@@ -108,6 +109,8 @@ namespace openvpn {
return "buffer_underflow";
case buffer_overflow:
return "buffer_overflow";
case buffer_offset:
return "buffer_offset";
case buffer_index:
return "buffer_index";
case buffer_const_index:
@@ -144,6 +147,7 @@ namespace openvpn {
template <typename, typename> friend class BufferAllocatedType;
public:
typedef T value_type;
typedef T* type;
typedef const T* const_type;
typedef typename std::remove_const<T>::type NCT; // non-const type
@@ -177,6 +181,15 @@ namespace openvpn {
size_ = 0;
}
void reset_offset(const size_t offset)
{
const size_t size = size_ + offset_ - offset;
if (offset > capacity_ || size > capacity_ || offset + size > capacity_)
OPENVPN_BUFFER_THROW(buffer_offset);
offset_ = offset;
size_ = size;
}
void reset_size()
{
size_ = 0;
@@ -519,6 +532,19 @@ namespace openvpn {
OPENVPN_BUFFER_THROW(buffer_underflow);
}
BufferType read_alloc_buf(const size_t size)
{
if (size <= size_)
{
BufferType ret(data_, offset_, size, capacity_);
offset_ += size;
size_ -= size;
return ret;
}
else
OPENVPN_BUFFER_THROW(buffer_underflow);
}
void reset(const size_t min_capacity, const unsigned int flags)
{
if (min_capacity > capacity_)
+1 -1
View File
@@ -36,7 +36,7 @@
namespace openvpn {
namespace bigmutex {
std::recursive_mutex the_recursive_mutex;
OPENVPN_EXTERN std::recursive_mutex the_recursive_mutex;
}
#ifdef OPENVPN_ENABLE_BIGMUTEX
+6 -1
View File
@@ -40,8 +40,13 @@ namespace openvpn {
inline int n_cores()
{
int count = std::thread::hardware_concurrency();
// C++11 allows thread::hardware_concurrency() to return 0, fall back
// to specific solution if we detect this
if (count > 0)
return count;
#if defined(OPENVPN_PLATFORM_TYPE_APPLE)
int count;
size_t count_len = sizeof(count);
if (::sysctlbyname("hw.logicalcpu", &count, &count_len, NULL, 0) != 0)
count = 1;
+4 -4
View File
@@ -89,14 +89,14 @@ namespace openvpn {
class C : public openvpn::Exception { \
public: \
C() : openvpn::Exception(#C OPENVPN_FILE_LINE) {} \
C(std::string err) : openvpn::Exception(#C OPENVPN_FILE_LINE ": " + err) {} \
C(const std::string err) : openvpn::Exception(#C OPENVPN_FILE_LINE ": " + err) {} \
}
// define a custom exception class that allows extra info, but does not emit a tag
# define OPENVPN_UNTAGGED_EXCEPTION(C) \
class C : public openvpn::Exception { \
public: \
C(std::string err) : openvpn::Exception(err) {} \
C(const std::string err) : openvpn::Exception(err) {} \
}
// define a custom exception class that allows extra info, and inherits from a custom base
@@ -104,7 +104,7 @@ namespace openvpn {
class C : public B { \
public: \
C() : B(#C OPENVPN_FILE_LINE) {} \
C(std::string err) : B(#C OPENVPN_FILE_LINE ": " + err) {} \
C(const std::string err) : B(#C OPENVPN_FILE_LINE ": " + err) {} \
}
// define a custom exception class that allows extra info, and inherits from a custom base,
@@ -112,7 +112,7 @@ namespace openvpn {
# define OPENVPN_UNTAGGED_EXCEPTION_INHERIT(B, C) \
class C : public B { \
public: \
C(std::string err) : B(err) {} \
C(const std::string err) : B(err) {} \
}
// throw an Exception with stringstream concatenation allowed
+4 -2
View File
@@ -47,6 +47,7 @@ namespace openvpn {
inline void write_binary_atomic(const std::string& fn,
const std::string& tmpdir,
const mode_t mode,
const std::uint64_t mtime_ns, // set explicit modification-time in nanoseconds since epoch, or 0 to defer to system
const ConstBuffer& buf,
RandomAPI& rng)
{
@@ -56,7 +57,7 @@ namespace openvpn {
const std::string tfn = path::join(tmpdir, '.' + path::basename(fn) + '.' + render_hex(data, sizeof(data)));
// write to temporary file
write_binary_unix(tfn, mode, buf);
write_binary_unix(tfn, mode, mtime_ns, buf);
// then move into position
if (::rename(tfn.c_str(), fn.c_str()) == -1)
@@ -69,10 +70,11 @@ namespace openvpn {
inline void write_binary_atomic(const std::string& fn,
const std::string& tmpdir,
const mode_t mode,
const std::uint64_t mtime_ns,
const Buffer& buf,
RandomAPI& rng)
{
return write_binary_atomic(fn, tmpdir, mode, const_buffer_ref(buf), rng);
return write_binary_atomic(fn, tmpdir, mode, mtime_ns, const_buffer_ref(buf), rng);
}
}
+19 -8
View File
@@ -35,12 +35,14 @@
#include <sys/types.h> // for lseek, open
#include <sys/stat.h> // for open
#include <fcntl.h> // for open
#include <cstdint>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/size.hpp>
#include <openvpn/common/scoped_fd.hpp>
#include <openvpn/common/write.hpp>
#include <openvpn/common/strerror.hpp>
#include <openvpn/common/modstat.hpp>
#include <openvpn/buffer/bufread.hpp>
namespace openvpn {
@@ -49,6 +51,7 @@ namespace openvpn {
// write binary buffer to file
inline void write_binary_unix(const std::string& fn,
const mode_t mode,
const std::uint64_t mtime_ns, // set explicit modification-time in nanoseconds since epoch, or 0 to defer to system
const void *buf,
const size_t size)
{
@@ -61,11 +64,16 @@ namespace openvpn {
}
// write
{
const ssize_t len = write_retry(fd(), buf, size);
if (len != size)
throw file_unix_error(fn + " : incomplete write");
}
if (size)
{
const ssize_t len = write_retry(fd(), buf, size);
if (len != size)
throw file_unix_error(fn + " : incomplete write");
}
// explicit modification time
if (mtime_ns)
update_file_mod_time_nanoseconds(fd(), mtime_ns);
// close
{
@@ -77,23 +85,26 @@ namespace openvpn {
inline void write_binary_unix(const std::string& fn,
const mode_t mode,
const std::uint64_t mtime_ns,
const Buffer& buf)
{
write_binary_unix(fn, mode, buf.c_data(), buf.size());
write_binary_unix(fn, mode, mtime_ns, buf.c_data(), buf.size());
}
inline void write_binary_unix(const std::string& fn,
const mode_t mode,
const std::uint64_t mtime_ns,
const ConstBuffer& buf)
{
write_binary_unix(fn, mode, buf.c_data(), buf.size());
write_binary_unix(fn, mode, mtime_ns, buf.c_data(), buf.size());
}
inline void write_text_unix(const std::string& fn,
const mode_t mode,
const std::uint64_t mtime_ns,
const std::string& content)
{
write_binary_unix(fn, mode, content.c_str(), content.length());
write_binary_unix(fn, mode, mtime_ns, content.c_str(), content.length());
}
enum { // MUST be distinct from BufferAllocated flags
+43 -13
View File
@@ -26,6 +26,7 @@
#include <cstddef> // for std::size_t
#include <utility> // for std::move
#include <type_traits>
#include <new>
namespace openvpn {
@@ -35,7 +36,7 @@ namespace openvpn {
template <typename F, std::size_t N=3, bool INTERN_ONLY=false>
class Function;
template <typename R, typename ... A, std::size_t N, bool INTERN_ONLY>
template <typename R, typename... A, std::size_t N, bool INTERN_ONLY>
class Function<R(A...), N, INTERN_ONLY>
{
public:
@@ -92,7 +93,7 @@ namespace openvpn {
}
}
R operator()(A... args)
R operator()(A... args) const
{
return methods->invoke(data, std::forward<A>(args)...);
}
@@ -103,6 +104,7 @@ namespace openvpn {
}
private:
#ifdef _MSC_VER
template <typename T>
void construct(T&& functor) noexcept
{
@@ -123,10 +125,38 @@ namespace openvpn {
new (data) Extern<T>(std::move(functor));
}
}
#else
template <typename T>
static constexpr bool is_intern()
{
return sizeof(Intern<T>) <= sizeof(data);
}
template <typename T,
typename std::enable_if<is_intern<T>(), int>::type = 0>
void construct(T&& functor) noexcept
{
// store functor internally (in data)
setup_methods_intern<T>();
new (data) Intern<T>(std::move(functor));
}
template <typename T,
typename std::enable_if<!is_intern<T>(), int>::type = 0>
void construct(T&& functor) noexcept
{
static_assert(!INTERN_ONLY, "Function: Intern<T> doesn't fit in data[] and INTERN_ONLY=true");
static_assert(sizeof(Extern<T>) <= sizeof(data), "Function: Extern<T> doesn't fit in data[]");
// store functor externally (using new)
setup_methods_extern<T>();
new (data) Extern<T>(std::move(functor));
}
#endif
struct Methods
{
R (*invoke)(void *, A...);
R (*invoke)(void *, A&&...);
void (*move)(void *, void *);
void (*destruct)(void *);
};
@@ -163,21 +193,21 @@ namespace openvpn {
{
}
static R invoke(void *ptr, A... args)
static R invoke(void* ptr, A&&... args)
{
Intern* self = reinterpret_cast<Intern<T>*>(ptr);
Intern* self = reinterpret_cast<Intern*>(ptr);
return self->functor_(std::forward<A>(args)...);
}
static void move(void *dest, void *src)
{
Intern* s = reinterpret_cast<Intern<T>*>(src);
Intern* s = reinterpret_cast<Intern*>(src);
new (dest) Intern(std::move(*s));
}
static void destruct(void *ptr)
{
Intern* self = reinterpret_cast<Intern<T>*>(ptr);
Intern* self = reinterpret_cast<Intern*>(ptr);
self->~Intern();
}
@@ -195,23 +225,23 @@ namespace openvpn {
{
}
static R invoke(void *ptr, A... args)
static R invoke(void* ptr, A&&... args)
{
Extern* self = reinterpret_cast<Extern<T>*>(ptr);
Extern* self = reinterpret_cast<Extern *>(ptr);
return (*self->functor_)(std::forward<A>(args)...);
}
static void move(void *dest, void *src)
{
Extern* d = reinterpret_cast<Extern<T>*>(dest);
Extern* s = reinterpret_cast<Extern<T>*>(src);
Extern* d = reinterpret_cast<Extern*>(dest);
Extern* s = reinterpret_cast<Extern*>(src);
d->functor_ = s->functor_;
// no need to set s->functor_=nullptr because parent will not destruct src after move
}
static void destruct(void *ptr)
{
Extern* self = reinterpret_cast<Extern<T>*>(ptr);
Extern* self = reinterpret_cast<Extern*>(ptr);
delete self->functor_;
}
@@ -220,7 +250,7 @@ namespace openvpn {
};
const Methods* methods;
void* data[N];
mutable void* data[N];
};
}
+1 -1
View File
@@ -461,7 +461,7 @@ namespace openvpn {
* of the input value. The result will always contain only
* two characters.
*/
std::string render_hex_number(unsigned char uc, const bool caps=false)
inline std::string render_hex_number(unsigned char uc, const bool caps=false)
{
RenderHexByte b(uc, caps);
return std::string(b.str2(), 2);
+57
View File
@@ -0,0 +1,57 @@
// 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 <fcntl.h> // Definition of AT_* constants */
#include <sys/stat.h>
#include <cstdint> // for std::uint64_t
#include <cerrno>
#include <string>
namespace openvpn {
inline int update_file_mod_time_nanoseconds(const std::string& filename,
const std::uint64_t nanoseconds_since_epooch)
{
struct timespec times[2];
times[0].tv_sec = nanoseconds_since_epooch / std::uint64_t(1000000000);
times[0].tv_nsec = nanoseconds_since_epooch % std::uint64_t(1000000000);
times[1] = times[0];
if (::utimensat(AT_FDCWD, filename.c_str(), times, 0) == -1)
return errno;
return 0;
}
inline int update_file_mod_time_nanoseconds(const int fd,
const std::uint64_t nanoseconds_since_epooch)
{
struct timespec times[2];
times[0].tv_sec = nanoseconds_since_epooch / std::uint64_t(1000000000);
times[0].tv_nsec = nanoseconds_since_epooch % std::uint64_t(1000000000);
times[1] = times[0];
if (::futimens(fd, times) == -1)
return errno;
return 0;
}
}
+30
View File
@@ -0,0 +1,30 @@
// 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 <openvpn/common/exception.hpp>
namespace openvpn {
OPENVPN_EXCEPTION(option_error);
}
+11 -3
View File
@@ -57,7 +57,6 @@
#include <cstdint> // for std::uint64_t
#include <openvpn/common/rc.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/size.hpp>
#include <openvpn/common/number.hpp>
#include <openvpn/common/hexstr.hpp>
@@ -65,11 +64,10 @@
#include <openvpn/common/split.hpp>
#include <openvpn/common/splitlines.hpp>
#include <openvpn/common/unicode.hpp>
#include <openvpn/common/option_error.hpp>
namespace openvpn {
OPENVPN_EXCEPTION(option_error);
class Option
{
public:
@@ -1173,6 +1171,16 @@ namespace openvpn {
}
}
// Return raw C string to option data or nullptr if option doesn't exist.
const char *get_c_str(const std::string& name, size_t index, const size_t max_len) const
{
const Option* o = get_ptr(name);
if (o)
return o->get(index, max_len).c_str();
else
return nullptr;
}
// Convenience method that gets a particular argument index within an option,
// while returning a default string if option doesn't exist, and raising an
// exception if argument index is out-of-bounds.
+2
View File
@@ -25,6 +25,8 @@
#include <string.h>
#include <string>
#include <errno.h>
namespace openvpn {
inline std::string strerror_str(const int errnum)
{
+14 -1
View File
@@ -223,7 +223,7 @@ namespace openvpn {
}
// return the first line (without newline) of a multi-line string
std::string first_line(const std::string& str)
inline std::string first_line(const std::string& str)
{
const size_t pos = str.find_first_of('\n');
if (pos != std::string::npos)
@@ -310,6 +310,19 @@ namespace openvpn {
return false;
}
// remove all spaces in string
inline std::string remove_spaces(const std::string& str)
{
std::string ret;
for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
{
char c = *i;
if (!is_space(c))
ret += c;
}
return ret;
}
// replace all spaces in string with rep
inline std::string replace_spaces(const std::string& str, const char rep)
{
+2 -2
View File
@@ -36,13 +36,13 @@ namespace openvpn {
// Check if a byte is an HTTP character.
inline bool is_char(const unsigned char c)
{
return c >= 0 && c <= 127;
return c <= 127;
}
// Check if a byte is an HTTP control character.
inline bool is_ctl(const unsigned char c)
{
return (c >= 0 && c <= 31) || (c == 127);
return (c <= 31)|| (c == 127);
}
// Check if a byte is defined as an HTTP tspecial character.
+1
View File
@@ -93,6 +93,7 @@ namespace openvpn {
public:
enum status {
undefined,
pending,
fail,
success,
+2 -1
View File
@@ -30,6 +30,7 @@
#include <openvpn/common/size.hpp>
#include <openvpn/common/arraysize.hpp>
#include <openvpn/common/core.hpp>
#include <openvpn/kovpn/kovpn.hpp>
namespace openvpn {
@@ -57,7 +58,7 @@ namespace openvpn {
void output_percpu(std::ostream& os) const
{
std::unique_ptr<struct ovpn_percpu_stats> pcs;
unsigned int stats_cap = 16;
unsigned int stats_cap = std::max(16, n_cores());
for (int i = 0; i < 2; ++i)
{
const size_t pcs_size = sizeof(struct ovpn_percpu_stats) +
+5 -3
View File
@@ -24,10 +24,12 @@
#ifndef OPENVPN_KOVPN_KOVPN_HPP
#define OPENVPN_KOVPN_KOVPN_HPP
// Not including this file causes redefinition errors
// when the sys/ and linux/ headers below are included
// before Asio.
#include <openvpn/io/io.hpp>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/in.h>
#include <linux/in6.h>
extern "C" {
#include <kovpn/kovpn.h>
+4 -7
View File
@@ -93,14 +93,14 @@ namespace openvpn {
size_t olen = 0;
int ret;
ret = mbedtls_pem_write_buffer(begin_cert.c_str(), end_cert.c_str(), der,
ret = mbedtls_pem_write_buffer(begin_cert, end_cert, der,
der_size, NULL, 0, &olen);
if (ret != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL)
throw MbedTLSException("X509Cert::extract: can't calculate PEM size");
BufferAllocated buff(olen, 0);
ret = mbedtls_pem_write_buffer(begin_cert.c_str(), end_cert.c_str(), der,
ret = mbedtls_pem_write_buffer(begin_cert, end_cert, der,
der_size, buff.data(), buff.max_size(), &olen);
if (ret)
throw MbedTLSException("X509Cert::extract: can't write PEM buffer");
@@ -158,12 +158,9 @@ namespace openvpn {
}
}
static const std::string begin_cert;
static const std::string end_cert;
constexpr static const char* begin_cert = "-----BEGIN CERTIFICATE-----\n";;
constexpr static const char* end_cert = "-----END CERTIFICATE-----\n";;
};
const std::string X509Cert::begin_cert = "-----BEGIN CERTIFICATE-----\n";
const std::string X509Cert::end_cert = "-----END CERTIFICATE-----\n";
}
}
+2
View File
@@ -268,6 +268,8 @@ namespace openvpn {
{
if (!defined())
return "UNDEF-TIME";
if (is_infinite())
return "INF";
const double df = delta_float(t);
std::string ret;
if (df >= 0.0)
+45 -4
View File
@@ -25,13 +25,15 @@
#define OPENVPN_TIME_TIMESTR_H
#include <string>
#include <cstring> // for std::strlen
#include <cstring> // for std::strlen and std::memset
#include <time.h>
#include <stdio.h>
#include <ctype.h>
#include <cstdint> // for std::uint64_t
#include <openvpn/common/platform.hpp>
#include <openvpn/common/size.hpp>
#include <openvpn/common/string.hpp>
#if defined(OPENVPN_PLATFORM_WIN)
#include <windows.h>
@@ -72,6 +74,7 @@ namespace openvpn {
struct tm lt;
char buf[64];
std::memset(&lt, 0, sizeof(lt));
if (!localtime_r(&t, &lt))
return "LOCALTIME_ERROR";
if (!asctime_r(&lt, buf))
@@ -82,6 +85,22 @@ namespace openvpn {
return std::string(buf);
}
inline std::string date_time_utc(const time_t t)
{
struct tm lt;
char buf[64];
std::memset(&lt, 0, sizeof(lt));
if (!gmtime_r(&t, &lt))
return "GMTIME_ERROR";
if (!asctime_r(&lt, buf))
return "ASCTIME_ERROR";
const size_t len = std::strlen(buf);
if (len > 0 && buf[len-1] == '\n')
buf[len-1] = '\0';
return std::string(buf);
}
// msecs == false : Tue Feb 17 01:24:30 2015
// msecs == true : Tue Feb 17 01:24:30.123 2015
inline std::string date_time(const struct timeval *tv, const bool msecs)
@@ -93,9 +112,9 @@ namespace openvpn {
const size_t pos = dt.find_last_of(':');
if (pos != std::string::npos
&& pos + 3 < dt.length()
&& isdigit(dt[pos+1])
&& isdigit(dt[pos+2])
&& isspace(dt[pos+3]))
&& string::is_digit(dt[pos+1])
&& string::is_digit(dt[pos+2])
&& string::is_space(dt[pos+3]))
{
char ms[5];
::snprintf(ms, sizeof(ms), ".%03u", static_cast<unsigned int>(tv->tv_usec / 1000));
@@ -105,6 +124,28 @@ namespace openvpn {
return dt;
}
inline std::string nanosec_time_to_string(const std::uint64_t ns_time)
{
const std::uint64_t sec = ns_time / std::uint64_t(1000000000);
const std::uint64_t ns = ns_time % std::uint64_t(1000000000);
const std::string dt = date_time_utc(sec);
// find correct position in string to insert nanoseconds
const size_t pos = dt.find_last_of(':');
if (pos != std::string::npos
&& pos + 3 < dt.length()
&& string::is_digit(dt[pos+1])
&& string::is_digit(dt[pos+2])
&& string::is_space(dt[pos+3]))
{
char ms[11];
::snprintf(ms, sizeof(ms), ".%09u", (unsigned int)ns);
return dt.substr(0, pos+3) + ms + dt.substr(pos+3);
}
return dt;
}
inline std::string date_time()
{
struct timeval tv;
+1 -1
View File
@@ -26,7 +26,7 @@
#include <cstdint> // for std::uint32_t, etc.
#include <openvpn/common/exception.hpp>
#include <openvpn/common/options.hpp>
#include <openvpn/common/option_error.hpp>
#include <openvpn/common/string.hpp>
#include <openvpn/addr/ip.hpp>
+6 -1
View File
@@ -41,6 +41,8 @@
#include <openvpn/tun/mac/utun.hpp>
#include <openvpn/tun/mac/macgw.hpp>
#include <openvpn/tun/mac/macdns_watchdog.hpp>
#include <openvpn/tun/proxy.hpp>
#include <openvpn/tun/mac/macproxy.hpp>
#include <openvpn/tun/builder/rgwflags.hpp>
#include <openvpn/tun/builder/setup.hpp>
@@ -317,7 +319,7 @@ namespace openvpn {
cmd->argv.push_back("/sbin/ifconfig");
cmd->argv.push_back(iface_name);
cmd->argv.push_back(local4->address);
cmd->argv.push_back(local4->address);
cmd->argv.push_back(local4->gateway);
cmd->argv.push_back("netmask");
cmd->argv.push_back(netmask.to_string());
cmd->argv.push_back("mtu");
@@ -463,6 +465,9 @@ namespace openvpn {
create,
destroy);
}
if (pull.proxy_auto_config_url.defined())
ProxySettings::add_actions<MacProxySettings>(pull, create, destroy);
}
ActionList::Ptr remove_cmds;
+184
View File
@@ -0,0 +1,184 @@
// 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
namespace openvpn {
class DSDict {
public:
OPENVPN_EXCEPTION(dsdict_error);
DSDict(CF::DynamicStore& sc_arg, const std::string& sname_arg, const std::string& dskey_arg)
: sc(sc_arg),
sname(sname_arg),
dskey(dskey_arg),
dict(CF::DynamicStoreCopyDict(sc_arg, dskey)) { }
bool dirty() const
{
return mod.defined() ? !CFEqual(dict(), mod()) : false;
}
bool push_to_store()
{
if (dirty())
{
const CF::String keystr = CF::string(dskey);
if (SCDynamicStoreSetValue(sc(), keystr(), mod()))
{
OPENVPN_LOG("DSDict: updated " << dskey);
return true;
}
else
OPENVPN_LOG("DSDict: ERROR updating " << dskey);
}
return false;
}
bool remove_from_store()
{
if (dirty())
throw dsdict_error("internal error: remove_from_store called on modified dict");
const CF::String keystr = CF::string(dskey);
if (SCDynamicStoreRemoveValue(sc(), keystr()))
{
OPENVPN_LOG("DSDict: removed " << dskey);
return true;
}
else
{
OPENVPN_LOG("DSDict: ERROR removing " << dskey);
return false;
}
}
void will_modify()
{
if (!mod.defined())
mod = CF::mutable_dict_copy(dict);
}
void mod_reset()
{
mod = CF::mutable_dict();
}
void backup_orig(const std::string& key, const bool wipe_orig=true)
{
const CF::String k = CF::string(key);
const CF::String orig = orig_key(key);
if (!CFDictionaryContainsKey(dict(), orig()))
{
const CF::String delval = delete_value();
CFTypeRef v = CFDictionaryGetValue(dict(), k());
if (!v)
v = delval();
will_modify();
CFDictionarySetValue(mod(), orig(), v);
}
if (wipe_orig)
{
will_modify();
CFDictionaryRemoveValue(mod(), k());
}
}
void restore_orig()
{
const CFIndex size = CFDictionaryGetCount(dict());
std::unique_ptr<const void *[]> keys(new const void *[size]);
std::unique_ptr<const void *[]> values(new const void *[size]);
CFDictionaryGetKeysAndValues(dict(), keys.get(), values.get());
const CF::String orig_prefix = orig_key("");
const CFIndex orig_prefix_len = CFStringGetLength(orig_prefix());
const CF::String delval = delete_value();
for (CFIndex i = 0; i < size; ++i)
{
const CF::String key = CF::string_cast(keys[i]);
if (CFStringHasPrefix(key(), orig_prefix()))
{
const CFIndex key_len = CFStringGetLength(key());
if (key_len > orig_prefix_len)
{
const CFRange r = CFRangeMake(orig_prefix_len, key_len - orig_prefix_len);
const CF::String k(CFStringCreateWithSubstring(kCFAllocatorDefault, key(), r));
const CFTypeRef v = values[i];
const CF::String vstr = CF::string_cast(v);
will_modify();
if (vstr.defined() && CFStringCompare(vstr(), delval(), 0) == kCFCompareEqualTo)
CFDictionaryRemoveValue(mod(), k());
else
CFDictionaryReplaceValue(mod(), k(), v);
CFDictionaryRemoveValue(mod(), key());
}
}
}
}
std::string to_string() const
{
std::ostringstream os;
os << "*** DSDict " << dskey << std::endl;
std::string orig = CF::description(dict());
string::trim_crlf(orig);
os << "ORIG " << orig << std::endl;
if (dirty())
{
std::string modstr = CF::description(mod());
string::trim_crlf(modstr);
os << "MODIFIED " << modstr << std::endl;
}
return os.str();
}
static CF::DynamicStore ds_create(const std::string& sname)
{
CF::String sn = CF::string(sname);
return CF::DynamicStore(SCDynamicStoreCreate(kCFAllocatorDefault, sn(), nullptr, nullptr));
}
static bool signal_network_reconfiguration(const std::string& sname)
{
const char *key = "Setup:/Network/Global/IPv4";
CF::DynamicStore sc = ds_create(sname);
const CF::String cfkey = CF::string(key);
OPENVPN_LOG("DSDict: SCDynamicStoreNotifyValue " << key);
return bool(SCDynamicStoreNotifyValue(sc(), cfkey()));
}
CF::DynamicStore sc;
const std::string sname;
const std::string dskey;
const CF::Dict dict;
CF::MutableDict mod;
private:
CF::String orig_key(const std::string& key) const
{
return CF::string(sname + "Orig" + key);
}
CF::String delete_value() const
{
return CF::string(sname + "DeleteValue");
}
};
}
+4 -153
View File
@@ -36,6 +36,7 @@
#include <openvpn/apple/scdynstore.hpp>
#include <openvpn/apple/cf/cfhelper.hpp>
#include <openvpn/tun/builder/capture.hpp>
#include <openvpn/tun/mac/dsdict.hpp>
namespace openvpn {
class MacDNS : public RC<thread_unsafe_refcount>
@@ -141,11 +142,7 @@ namespace openvpn {
bool signal_network_reconfiguration()
{
const char *key = "Setup:/Network/Global/IPv4";
CF::DynamicStore sc = ds_create();
const CF::String cfkey = CF::string(key);
OPENVPN_LOG("MacDNS: SCDynamicStoreNotifyValue " << key);
return bool(SCDynamicStoreNotifyValue(sc(), cfkey()));
return DSDict::signal_network_reconfiguration(sname);
}
bool setdns(const Config& config)
@@ -317,152 +314,7 @@ namespace openvpn {
}
return mod;
}
class DSDict {
public:
DSDict(CF::DynamicStore& sc_arg, const std::string& sname_arg, const std::string& dskey_arg)
: sc(sc_arg),
sname(sname_arg),
dskey(dskey_arg),
dict(CF::DynamicStoreCopyDict(sc_arg, dskey))
{
}
bool dirty() const
{
return mod.defined() ? !CFEqual(dict(), mod()) : false;
}
bool push_to_store()
{
if (dirty())
{
const CF::String keystr = CF::string(dskey);
if (SCDynamicStoreSetValue(sc(), keystr(), mod()))
{
OPENVPN_LOG("MacDNS: updated " << dskey);
return true;
}
else
OPENVPN_LOG("MacDNS: ERROR updating " << dskey);
}
return false;
}
bool remove_from_store()
{
if (dirty())
throw macdns_error("internal error: remove_from_store called on modified dict");
const CF::String keystr = CF::string(dskey);
if (SCDynamicStoreRemoveValue(sc(), keystr()))
{
OPENVPN_LOG("MacDNS: removed " << dskey);
return true;
}
else
{
OPENVPN_LOG("MacDNS: ERROR removing " << dskey);
return false;
}
}
void will_modify()
{
if (!mod.defined())
mod = CF::mutable_dict_copy(dict);
}
void mod_reset()
{
mod = CF::mutable_dict();
}
void backup_orig(const std::string& key, const bool wipe_orig=true)
{
const CF::String k = CF::string(key);
const CF::String orig = orig_key(key);
if (!CFDictionaryContainsKey(dict(), orig()))
{
const CF::String delval = delete_value();
CFTypeRef v = CFDictionaryGetValue(dict(), k());
if (!v)
v = delval();
will_modify();
CFDictionarySetValue(mod(), orig(), v);
}
if (wipe_orig)
{
will_modify();
CFDictionaryRemoveValue(mod(), k());
}
}
void restore_orig()
{
const CFIndex size = CFDictionaryGetCount(dict());
std::unique_ptr<const void *[]> keys(new const void *[size]);
std::unique_ptr<const void *[]> values(new const void *[size]);
CFDictionaryGetKeysAndValues(dict(), keys.get(), values.get());
const CF::String orig_prefix = orig_key("");
const CFIndex orig_prefix_len = CFStringGetLength(orig_prefix());
const CF::String delval = delete_value();
for (CFIndex i = 0; i < size; ++i)
{
const CF::String key = CF::string_cast(keys[i]);
if (CFStringHasPrefix(key(), orig_prefix()))
{
const CFIndex key_len = CFStringGetLength(key());
if (key_len > orig_prefix_len)
{
const CFRange r = CFRangeMake(orig_prefix_len, key_len - orig_prefix_len);
const CF::String k(CFStringCreateWithSubstring(kCFAllocatorDefault, key(), r));
const CFTypeRef v = values[i];
const CF::String vstr = CF::string_cast(v);
will_modify();
if (vstr.defined() && CFStringCompare(vstr(), delval(), 0) == kCFCompareEqualTo)
CFDictionaryRemoveValue(mod(), k());
else
CFDictionaryReplaceValue(mod(), k(), v);
CFDictionaryRemoveValue(mod(), key());
}
}
}
}
std::string to_string() const
{
std::ostringstream os;
os << "*** DSDict " << dskey << std::endl;
std::string orig = CF::description(dict());
string::trim_crlf(orig);
os << "ORIG " << orig << std::endl;
if (dirty())
{
std::string modstr = CF::description(mod());
string::trim_crlf(modstr);
os << "MODIFIED " << modstr << std::endl;
}
return os.str();
}
CF::DynamicStore sc;
const std::string sname;
const std::string dskey;
const CF::Dict dict;
CF::MutableDict mod;
private:
CF::String orig_key(const std::string& key) const
{
return CF::string(sname + "Orig" + key);
}
CF::String delete_value() const
{
return CF::string(sname + "DeleteValue");
}
};
class Info : public RC<thread_unsafe_refcount>
{
public:
@@ -510,8 +362,7 @@ namespace openvpn {
CF::DynamicStore ds_create() const
{
CF::String sn = CF::string(sname);
return CF::DynamicStore(SCDynamicStoreCreate(kCFAllocatorDefault, sn(), nullptr, nullptr));
return DSDict::ds_create(sname);
}
const std::string sname;
+99
View File
@@ -0,0 +1,99 @@
// 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 <openvpn/tun/proxy.hpp>
#include <openvpn/tun/mac/dsdict.hpp>
namespace openvpn {
class MacProxySettings : public ProxySettings
{
public:
OPENVPN_EXCEPTION(macproxy_error);
typedef RCPtr<MacProxySettings> Ptr;
class Info : public RC<thread_unsafe_refcount>
{
public:
typedef RCPtr<Info> Ptr;
Info(CF::DynamicStore& sc, const std::string& sname)
: ipv4(sc, sname, "State:/Network/Global/IPv4"),
info(sc, sname, "State:/Network/Service/" + sname + "/Info"),
proxy(sc, sname, proxies(ipv4.dict, info.dict)) { }
std::string to_string() const
{
std::ostringstream os;
os << ipv4.to_string();
os << info.to_string();
os << proxy.to_string();
return os.str();
}
DSDict ipv4;
DSDict info;
DSDict proxy;
private:
static std::string proxies(const CF::Dict& ipv4, const CF::Dict& info)
{
std::string serv = CF::dict_get_str(ipv4, "PrimaryService");
if (serv.empty())
serv = CF::dict_get_str(info, "PrimaryService");
if (serv.empty())
throw macproxy_error("no primary service");
return "Setup:/Network/Service/" + serv + "/Proxies";
}
};
MacProxySettings(const TunBuilderCapture::ProxyAutoConfigURL& config_arg)
: ProxySettings(config_arg) { }
void set_proxy(bool del) override
{
if (!config.defined())
return;
CF::DynamicStore sc = DSDict::ds_create(sname);
Info::Ptr info(new Info(sc, sname));
info->proxy.will_modify();
if (!del)
{
info->proxy.backup_orig("ProxyAutoConfigEnable");
CF::dict_set_int(info->proxy.mod, "ProxyAutoConfigEnable", 1);
info->proxy.backup_orig("ProxyAutoConfigURLString");
CF::dict_set_str(info->proxy.mod, "ProxyAutoConfigURLString", config.to_string());
}
else
info->proxy.restore_orig();
info->proxy.push_to_store();
OPENVPN_LOG("MacProxy: set_proxy " << info->to_string());
}
};
}
+84
View File
@@ -0,0 +1,84 @@
// 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 <openvpn/common/action.hpp>
#include <openvpn/tun/builder/capture.hpp>
namespace openvpn {
class ProxySettings : public RC<thread_unsafe_refcount>
{
public:
OPENVPN_EXCEPTION(proxy_error);
typedef RCPtr<ProxySettings> Ptr;
class ProxyAction : public Action
{
public:
typedef RCPtr<ProxyAction> Ptr;
ProxyAction(ProxySettings::Ptr parent_arg, bool del_arg)
: parent(parent_arg), del(del_arg) { }
virtual void execute(std::ostream& os) override
{
os << to_string() << std::endl;
if (parent)
parent->set_proxy(del);
}
virtual std::string to_string() const override
{
std::ostringstream os;
if (parent && parent->config.defined())
os << "ProxyAction: auto config: " << parent->config.to_string();
return os.str();
}
private:
const ProxySettings::Ptr parent;
bool del;
};
ProxySettings(const TunBuilderCapture::ProxyAutoConfigURL& config_arg)
: config(config_arg) { }
virtual void set_proxy(bool del) = 0;
template<class T>
static void add_actions(const TunBuilderCapture& settings,
ActionList& create,
ActionList& destroy)
{
ProxySettings::Ptr proxy(new T(settings.proxy_auto_config_url));
ProxyAction::Ptr create_action(new ProxyAction(proxy, false));
ProxyAction::Ptr destroy_action(new ProxyAction(proxy, true));
create.add(create_action);
destroy.add(destroy_action);
}
const std::string sname = "OpenVPNConnect";
TunBuilderCapture::ProxyAutoConfigURL config;
};
}
+10 -4
View File
@@ -4,7 +4,7 @@
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
// 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
@@ -37,12 +37,14 @@
#include <openvpn/common/string.hpp>
#include <openvpn/common/size.hpp>
#include <openvpn/common/arraysize.hpp>
#include <openvpn/time/time.hpp>
#include <openvpn/error/excode.hpp>
#include <openvpn/time/time.hpp>
#include <openvpn/tun/proxy.hpp>
#include <openvpn/tun/win/tunutil.hpp>
#include <openvpn/tun/win/winproxy.hpp>
#include <openvpn/tun/win/client/setupbase.hpp>
#include <openvpn/win/scoped_handle.hpp>
#include <openvpn/win/cmd.hpp>
#include <openvpn/tun/win/tunutil.hpp>
#include <openvpn/tun/win/client/setupbase.hpp>
#if _WIN32_WINNT >= 0x0600 // Vista+
#include <openvpn/tun/win/nrpt.hpp>
@@ -603,6 +605,10 @@ namespace openvpn {
}
}
OPENVPN_LOG("proxy_auto_config_url " << pull.proxy_auto_config_url.url);
if (pull.proxy_auto_config_url.defined())
ProxySettings::add_actions<WinProxySettings>(pull, create, destroy);
// flush DNS cache
create.add(new WinCmd("ipconfig /flushdns"));
destroy.add(new WinCmd("ipconfig /flushdns"));
+6 -26
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
@@ -58,11 +58,7 @@ namespace openvpn {
auto key_name = ss.str();
const LONG status = ::RegCreateKeyA(HKEY_LOCAL_MACHINE, key_name.c_str(), key.ref());
if (status != ERROR_SUCCESS)
{
const Win::Error err(status);
OPENVPN_THROW(nrpt_error, "cannot open/create registry key " << key_name << " : " << err.message());
}
check_reg_error<nrpt_error>(status, key_name);
}
// Name
@@ -75,11 +71,7 @@ namespace openvpn {
REG_MULTI_SZ,
(const BYTE *)name.c_str(),
(name.length()+1)*2);
if (status != ERROR_SUCCESS)
{
const Win::Error err(status);
OPENVPN_THROW(nrpt_error, "cannot set registry value for 'Name' : " << err.message());
}
check_reg_error<nrpt_error>(status, "Name");
}
// GenericDNSServers
@@ -91,11 +83,7 @@ namespace openvpn {
REG_SZ,
(const BYTE *)dns_servers_joined.c_str(),
(dns_servers_joined.length()+1)*2);
if (status != ERROR_SUCCESS)
{
const Win::Error err(status);
OPENVPN_THROW(nrpt_error, "cannot set registry value for 'GenericDNSServers' : " << err.message());
}
check_reg_error<nrpt_error>(status, "GenericDNSServers");
}
// ConfigOptions
@@ -107,11 +95,7 @@ namespace openvpn {
REG_DWORD,
(const BYTE *)&value,
sizeof(value));
if (status != ERROR_SUCCESS)
{
const Win::Error err(status);
OPENVPN_THROW(nrpt_error, "cannot set registry value for 'ConfigOptions' : " << err.message());
}
check_reg_error<nrpt_error>(status, "ConfigOptions");
}
// Version
@@ -123,11 +107,7 @@ namespace openvpn {
REG_DWORD,
(const BYTE *)&value,
sizeof(value));
if (status != ERROR_SUCCESS)
{
const Win::Error err(status);
OPENVPN_THROW(nrpt_error, "cannot set registry value for 'Version' : " << err.message());
}
check_reg_error<nrpt_error>(status, "Version");
}
}
}
+182
View File
@@ -0,0 +1,182 @@
// 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/>.
//
// proxy settings for Windows
#pragma once
#include <WinInet.h>
#include <openvpn\win\impersonate.hpp>
#include <openvpn\tun\proxy.hpp>
#include <openvpn\win\reg.hpp>
using namespace openvpn::Win;
namespace openvpn {
namespace TunWin {
class WinProxySettings : public ProxySettings {
public:
typedef RCPtr<WinProxySettings> Ptr;
WinProxySettings(const TunBuilderCapture::ProxyAutoConfigURL& config_arg)
: ProxySettings(config_arg) { }
void set_proxy(bool del) override
{
ImpersonateAsUser imp;
LONG status;
RegKey hkcu;
RegKey key;
status = ::RegOpenCurrentUser(KEY_QUERY_VALUE | KEY_SET_VALUE, hkcu.ref());
check_reg_error<proxy_error>(status, "RegOpenCurrentUser");
status = ::RegCreateKeyExA(hkcu(), key_name, 0, NULL, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, key.ref(), NULL);
check_reg_error<proxy_error>(status, key_name);
if (!del)
{
save_key(key, "AutoConfigURL", config.url, true);
save_key(key, "ProxyEnable", "0", false);
}
else
{
restore_key(key, "AutoConfigURL", true);
restore_key(key, "ProxyEnable", false);
}
// WinInet API cannot be called from service, even via impersonation
if (!imp.is_local_system())
{
OPENVPN_LOG("Refresh proxy settings");
InternetSetOptionA(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0);
InternetSetOptionA(NULL, INTERNET_OPTION_REFRESH, NULL, 0);
}
}
private:
void restore_key(Win::RegKey& regkey, const std::string& key, bool str)
{
LONG status;
char prev_val_str[1024] = { 0 }; // should be enough to fit proxy URL
DWORD prev_val_dword;
DWORD prev_buf_size = str ? sizeof(prev_val_str) : sizeof(prev_val_dword);
bool del = false;
Win::RegKey hkcu;
status = ::RegOpenCurrentUser(KEY_QUERY_VALUE | KEY_SET_VALUE, hkcu.ref());
check_reg_error<proxy_error>(status, "RegOpenCurrentUser");
// get previous value
std::string prev_key_name = sname + key;
status = ::RegGetValueA(hkcu(),
key_name,
prev_key_name.c_str(),
str ? RRF_RT_REG_SZ : RRF_RT_REG_DWORD,
NULL,
str ? (PVOID)prev_val_str : (PVOID)&prev_val_dword,
&prev_buf_size);
check_reg_error<proxy_error>(status, prev_key_name);
RegDeleteValueA(regkey(), prev_key_name.c_str());
// check if previous value needs to be deleted
if (str)
del = strcmp(delete_value_str, prev_val_str) == 0;
else
del = prev_val_dword == delete_value_dword;
if (del)
::RegDeleteValueA(regkey(), key.c_str());
else
::RegSetValueExA(regkey(),
key.c_str(),
0,
str ? REG_SZ : REG_DWORD,
str ? (const BYTE *)prev_val_str : (CONST BYTE *)&prev_val_dword,
str ? strlen(prev_val_str) + 1 : sizeof(prev_val_dword));
}
void save_key(Win::RegKey& regkey, const std::string& key, const std::string& value, bool str)
{
LONG status;
char prev_val_str[1024] = { 0 }; // should be enought to fit proxy URL
DWORD prev_val_dword;
DWORD prev_buf_size = str ? sizeof(prev_val_str) : sizeof(prev_val_dword);
Win::RegKey hkcu;
status = ::RegOpenCurrentUser(KEY_QUERY_VALUE | KEY_SET_VALUE, hkcu.ref());
check_reg_error<proxy_error>(status, "RegOpenCurrentUser");
// get original value
status = ::RegGetValueA(hkcu(),
key_name,
key.c_str(),
str ? RRF_RT_REG_SZ : RRF_RT_REG_DWORD,
NULL,
str ? (PVOID)prev_val_str : (PVOID)&prev_val_dword,
&prev_buf_size);
switch (status)
{
case ERROR_FILE_NOT_FOUND:
// mark that original value doesn't exist
strcpy(prev_val_str, delete_value_str);
prev_val_dword = delete_value_dword;
case ERROR_SUCCESS:
break;
default:
check_reg_error<proxy_error>(status, key);
break;
}
// save original value
std::string prev_key_name = sname + key;
status = ::RegSetValueExA(regkey(),
prev_key_name.c_str(),
0,
str ? REG_SZ : REG_DWORD,
str ? (const BYTE *)prev_val_str : (CONST BYTE *)&prev_val_dword,
str ? strlen(prev_val_str) + 1 : sizeof(DWORD));
check_reg_error<proxy_error>(status, prev_key_name);
// save new value
DWORD val_dword = 0;
if (!str)
val_dword = std::atol(value.c_str());
status = ::RegSetValueExA(regkey(),
key.c_str(),
0,
str ? REG_SZ : REG_DWORD,
str ? (const BYTE *)value.c_str() : (CONST BYTE *)&val_dword,
str ? value.length() + 1 : sizeof(val_dword));
check_reg_error<proxy_error>(status, key);
}
const char* key_name = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
const char* delete_value_str = "DeleteValue";
const DWORD delete_value_dword = 0xCAFEBABE;
};
}
}
+136
View File
@@ -0,0 +1,136 @@
// 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 <Windows.h>
#include <Lmcons.h>
#include <wtsapi32.h>
#include <openvpn/win/winerr.hpp>
namespace openvpn {
namespace Win {
class ImpersonateAsUser {
public:
ImpersonateAsUser() : local_system(is_local_system_())
{
if (local_system)
OPENVPN_LOG("ImpersonateAsUser: running under SYSTEM account, need to impersonate");
else
{
OPENVPN_LOG("ImpersonateAsUser: running under user account, no need to impersonate");
return;
}
DWORD sessId = WTSGetActiveConsoleSessionId();
if (sessId == 0xFFFFFFFF)
{
const Win::LastError err;
OPENVPN_LOG("ImpersonateAsUser: WTSGetActiveConsoleSessionId() failed: " << err.message());
return;
}
HANDLE hToken;
if (!WTSQueryUserToken(sessId, &hToken))
{
const Win::LastError err;
OPENVPN_LOG("ImpersonateAsUser: WTSQueryUserToken() failed: " << err.message());
return;
}
if (!ImpersonateLoggedOnUser(hToken))
{
CloseHandle(hToken);
const Win::LastError err;
OPENVPN_LOG("ImpersonateAsUser: ImpersonateLoggedOnUser() failed: " << err.message());
return;
}
CloseHandle(hToken);
impersonated = true;
char uname[UNLEN + 1];
DWORD len = UNLEN + 1;
GetUserNameA(uname, &len);
OPENVPN_LOG("ImpersonateAsUser: impersonated as " << uname);
}
~ImpersonateAsUser() {
if (impersonated)
{
if (!RevertToSelf())
{
const Win::LastError err;
OPENVPN_LOG("ImpersonateAsUser: RevertToSelf() failed: " << err.message());
}
}
}
bool is_local_system() const
{
return local_system;
}
private:
// https://stackoverflow.com/a/4024388/227024
BOOL is_local_system_() const
{
HANDLE hToken;
UCHAR bTokenUser[sizeof(TOKEN_USER) + 8 + 4 * SID_MAX_SUB_AUTHORITIES];
PTOKEN_USER pTokenUser = (PTOKEN_USER)bTokenUser;
ULONG cbTokenUser;
SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY;
PSID pSystemSid;
BOOL bSystem;
// open process token
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
return FALSE;
// retrieve user SID
if (!GetTokenInformation(hToken, TokenUser, pTokenUser, sizeof(bTokenUser), &cbTokenUser))
{
CloseHandle(hToken);
return FALSE;
}
CloseHandle(hToken);
// allocate LocalSystem well-known SID
if (!AllocateAndInitializeSid(&siaNT, 1, SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0, &pSystemSid)) return FALSE;
// compare the user SID from the token with the LocalSystem SID
bSystem = EqualSid(pTokenUser->User.Sid, pSystemSid);
FreeSid(pSystemSid);
return bSystem;
}
bool impersonated = false;
bool local_system = false;
};
}
}
+117 -106
View File
@@ -1,106 +1,117 @@
// 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/>.
// registry utilities for Windows
#ifndef OPENVPN_WIN_REG_H
#define OPENVPN_WIN_REG_H
#include <windows.h>
#include <openvpn/common/size.hpp>
namespace openvpn {
namespace Win {
// HKEY wrapper
class RegKey
{
RegKey(const RegKey&) = delete;
RegKey& operator=(const RegKey&) = delete;
public:
RegKey() : key(nullptr) {}
bool defined() const { return key != nullptr; }
HKEY* ref() { return &key; }
HKEY operator()() { return key; }
~RegKey()
{
if (defined())
::RegCloseKey(key);
}
private:
HKEY key;
};
class RegKeyEnumerator : public std::vector<std::string>
{
public:
RegKeyEnumerator(HKEY hkey, const std::string& path)
{
RegKey regKey;
auto status = ::RegOpenKeyExA(hkey,
path.c_str(),
0,
KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
regKey.ref());
if (status != ERROR_SUCCESS)
return;
DWORD subkeys_num;
status = ::RegQueryInfoKeyA(regKey(),
nullptr,
nullptr,
NULL,
&subkeys_num,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr);
if (status != ERROR_SUCCESS)
return;
const int MAX_KEY_LENGTH = 255;
for (auto i = 0; i < subkeys_num; ++ i)
{
DWORD subkey_size = MAX_KEY_LENGTH;
char subkey[MAX_KEY_LENGTH];
status = ::RegEnumKeyExA(regKey(),
i,
subkey,
&subkey_size,
nullptr,
nullptr,
nullptr,
nullptr);
if (status == ERROR_SUCCESS)
push_back(subkey);
}
}
};
}
}
#endif
// 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/>.
// registry utilities for Windows
#ifndef OPENVPN_WIN_REG_H
#define OPENVPN_WIN_REG_H
#include <windows.h>
#include <openvpn/win/winerr.hpp>
#include <openvpn/common/size.hpp>
namespace openvpn {
namespace Win {
template<typename E>
static void check_reg_error(DWORD status, const std::string& key)
{
if (status != ERROR_SUCCESS)
{
const Win::Error err(status);
OPENVPN_THROW(E, "registry key " << key << " error: " << err.message());
}
}
// HKEY wrapper
class RegKey
{
RegKey(const RegKey&) = delete;
RegKey& operator=(const RegKey&) = delete;
public:
RegKey() : key(nullptr) {}
bool defined() const { return key != nullptr; }
HKEY* ref() { return &key; }
HKEY operator()() { return key; }
~RegKey()
{
if (defined())
::RegCloseKey(key);
}
private:
HKEY key;
};
class RegKeyEnumerator : public std::vector<std::string>
{
public:
RegKeyEnumerator(HKEY hkey, const std::string& path)
{
RegKey regKey;
auto status = ::RegOpenKeyExA(hkey,
path.c_str(),
0,
KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
regKey.ref());
if (status != ERROR_SUCCESS)
return;
DWORD subkeys_num;
status = ::RegQueryInfoKeyA(regKey(),
nullptr,
nullptr,
NULL,
&subkeys_num,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr);
if (status != ERROR_SUCCESS)
return;
const int MAX_KEY_LENGTH = 255;
for (auto i = 0; i < subkeys_num; ++ i)
{
DWORD subkey_size = MAX_KEY_LENGTH;
char subkey[MAX_KEY_LENGTH];
status = ::RegEnumKeyExA(regKey(),
i,
subkey,
&subkey_size,
nullptr,
nullptr,
nullptr,
nullptr);
if (status == ERROR_SUCCESS)
push_back(subkey);
}
}
};
}
}
#endif