mirror of
https://github.com/OpenVPN/openvpn3.git
synced 2024-09-20 12:12:15 +02:00
Checkpoint for new core server implementation
(not yet complete).
This commit is contained in:
parent
3c99b8976b
commit
452b19b787
297
openvpn/addr/cidrmap.hpp
Normal file
297
openvpn/addr/cidrmap.hpp
Normal file
@ -0,0 +1,297 @@
|
||||
#ifndef OPENVPN_ADDR_CIDRMAP_H
|
||||
#define OPENVPN_ADDR_CIDRMAP_H
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include <openvpn/common/types.hpp>
|
||||
#include <openvpn/common/exception.hpp>
|
||||
#include <openvpn/common/hash.hpp>
|
||||
#include <openvpn/addr/ip.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace CIDRMap {
|
||||
|
||||
// Keep track of a set of route prefix lengths
|
||||
template <size_t N>
|
||||
class PrefixSet {
|
||||
public:
|
||||
OPENVPN_SIMPLE_EXCEPTION(cidr_index);
|
||||
|
||||
PrefixSet()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
size = 0;
|
||||
std::memset(sparse, 0, sizeof(sparse));
|
||||
}
|
||||
|
||||
void set(unsigned int i, const bool recompile_on_mod)
|
||||
{
|
||||
if (i > N)
|
||||
throw cidr_index();
|
||||
if (!sparse[i])
|
||||
{
|
||||
sparse[i] = 1;
|
||||
if (recompile_on_mod)
|
||||
compile();
|
||||
}
|
||||
}
|
||||
|
||||
size_t n_prefixes() const { return size; }
|
||||
unsigned int get_prefix(const size_t i) const
|
||||
{
|
||||
if (i >= size)
|
||||
throw cidr_index();
|
||||
return list[i];
|
||||
}
|
||||
|
||||
void compile()
|
||||
{
|
||||
size = 0;
|
||||
for (int i = N; i >= 0; --i)
|
||||
{
|
||||
if (sparse[i])
|
||||
list[size++] = (unsigned char)i;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
size_t size; // size of list
|
||||
unsigned char list[N+1]; // list of active prefixes in descending order
|
||||
unsigned char sparse[N+1]; // data indexed by prefix
|
||||
};
|
||||
|
||||
// Basic route object
|
||||
template <typename ADDR>
|
||||
struct Route
|
||||
{
|
||||
typedef ADDR Addr;
|
||||
|
||||
ADDR addr;
|
||||
unsigned int prefix_len;
|
||||
|
||||
bool operator==(const Route& other) const
|
||||
{
|
||||
return prefix_len == other.prefix_len && addr == other.addr;
|
||||
}
|
||||
};
|
||||
|
||||
// Compute hash value of Route
|
||||
template <typename ADDR>
|
||||
inline std::size_t hash_value(const Route<ADDR>& route)
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
boost::hash_combine(seed, route.addr);
|
||||
boost::hash_combine(seed, route.prefix_len);
|
||||
return seed;
|
||||
}
|
||||
|
||||
// Set of route prefix_lengths with iterator
|
||||
template <typename ROUTE>
|
||||
class RoutePrefixSet
|
||||
{
|
||||
public:
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Iterator(const RoutePrefixSet& parent_arg, const typename ROUTE::Addr& addr_arg)
|
||||
: ps(parent_arg.ps), addr(addr_arg), index(0) {}
|
||||
|
||||
bool next(ROUTE& r)
|
||||
{
|
||||
if (index < ps.n_prefixes())
|
||||
{
|
||||
r.prefix_len = ps.get_prefix(index++);
|
||||
r.addr = addr.network_addr(r.prefix_len);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
const PrefixSet<ROUTE::Addr::SIZE>& ps;
|
||||
const typename ROUTE::Addr& addr;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
void reset()
|
||||
{
|
||||
ps.reset();
|
||||
}
|
||||
|
||||
void add(const ROUTE& r, const bool recompile_on_mod)
|
||||
{
|
||||
ps.set(r.prefix_len, recompile_on_mod);
|
||||
}
|
||||
|
||||
void compile()
|
||||
{
|
||||
ps.compile();
|
||||
}
|
||||
|
||||
private:
|
||||
PrefixSet<ROUTE::Addr::SIZE> ps;
|
||||
};
|
||||
|
||||
// Template specialization for RoutePrefixSet when IP::Addr is used
|
||||
// as the underlying type.
|
||||
// Since IP::Addr is run-time polymorphic (underlying address can be IPv4
|
||||
// or IPv6), we need some special handling here.
|
||||
template <>
|
||||
class RoutePrefixSet<Route<IP::Addr> >
|
||||
{
|
||||
typedef Route<IP::Addr> ROUTE;
|
||||
|
||||
public:
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Iterator(const RoutePrefixSet& parent_arg, const typename ROUTE::Addr& addr_arg)
|
||||
: parent(parent_arg), addr(addr_arg), index(0) {}
|
||||
|
||||
bool next(ROUTE& r)
|
||||
{
|
||||
if (addr.version() == IP::Addr::V4)
|
||||
{
|
||||
if (index < parent.ps_v4.n_prefixes())
|
||||
{
|
||||
r.prefix_len = parent.ps_v4.get_prefix(index++);
|
||||
r.addr = addr.network_addr(r.prefix_len);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (addr.version() == IP::Addr::V6)
|
||||
{
|
||||
if (index < parent.ps_v6.n_prefixes())
|
||||
{
|
||||
r.prefix_len = parent.ps_v6.get_prefix(index++);
|
||||
r.addr = addr.network_addr(r.prefix_len);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
const RoutePrefixSet& parent;
|
||||
const typename ROUTE::Addr& addr;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
RoutePrefixSet() : v4(false), v6(false) {}
|
||||
|
||||
void reset()
|
||||
{
|
||||
if (v4)
|
||||
ps_v4.reset();
|
||||
if (v6)
|
||||
ps_v6.reset();
|
||||
v4 = v6 = false;
|
||||
}
|
||||
|
||||
void add(const ROUTE& r, const bool recompile_on_mod)
|
||||
{
|
||||
if (r.addr.version() == IP::Addr::V4)
|
||||
{
|
||||
v4 = true;
|
||||
ps_v4.set(r.prefix_len, recompile_on_mod);
|
||||
}
|
||||
else if (r.addr.version() == IP::Addr::V6)
|
||||
{
|
||||
v6 = true;
|
||||
ps_v6.set(r.prefix_len, recompile_on_mod);
|
||||
}
|
||||
}
|
||||
|
||||
void compile()
|
||||
{
|
||||
if (v4)
|
||||
ps_v4.compile();
|
||||
if (v6)
|
||||
ps_v6.compile();
|
||||
}
|
||||
|
||||
private:
|
||||
bool v4, v6;
|
||||
PrefixSet<IPv4::Addr::SIZE> ps_v4;
|
||||
PrefixSet<IPv6::Addr::SIZE> ps_v6;
|
||||
};
|
||||
|
||||
template <typename ROUTE, typename VALUE>
|
||||
class RoutingTable
|
||||
{
|
||||
typedef boost::unordered_map<ROUTE, typename VALUE::Ptr, HashInitialSeed<ROUTE> > map_type;
|
||||
|
||||
public:
|
||||
enum {
|
||||
INITIAL_BUCKETS = 2048,
|
||||
REAP_TRIGGER = 1024,
|
||||
};
|
||||
|
||||
RoutingTable(const std::size_t initial_seed)
|
||||
: insertions_since_reap(0),
|
||||
seed(initial_seed),
|
||||
map(INITIAL_BUCKETS, seed)
|
||||
{
|
||||
}
|
||||
|
||||
void add(const ROUTE& r, const typename VALUE::Ptr& vp)
|
||||
{
|
||||
if (++insertions_since_reap > REAP_TRIGGER)
|
||||
reap();
|
||||
map[r] = vp;
|
||||
prefix_set.add(r, true);
|
||||
}
|
||||
|
||||
bool match(const typename ROUTE::Addr& addr, typename VALUE::Ptr& vp)
|
||||
{
|
||||
ROUTE r;
|
||||
typename RoutePrefixSet<ROUTE>::Iterator ri(prefix_set, addr);
|
||||
while (ri.next(r))
|
||||
{
|
||||
typename map_type::const_iterator i = map.find(r);
|
||||
if (i != map.end() && i->second->defined())
|
||||
{
|
||||
vp = i->second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void reap()
|
||||
{
|
||||
insertions_since_reap = 0;
|
||||
prefix_set.reset();
|
||||
typename map_type::const_iterator i = map.begin();
|
||||
while (i != map.end())
|
||||
{
|
||||
if (i->second->defined())
|
||||
{
|
||||
prefix_set.add(i->first, false);
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
map.erase(i++);
|
||||
}
|
||||
}
|
||||
prefix_set.compile();
|
||||
}
|
||||
|
||||
private:
|
||||
size_t insertions_since_reap;
|
||||
RoutePrefixSet<ROUTE> prefix_set;
|
||||
HashInitialSeed<ROUTE> seed;
|
||||
map_type map;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -29,6 +29,38 @@ namespace openvpn {
|
||||
ver = UNSPEC;
|
||||
}
|
||||
|
||||
Addr(const Addr& other)
|
||||
: ver(other.ver)
|
||||
{
|
||||
switch (ver)
|
||||
{
|
||||
case V4:
|
||||
u.v4 = other.u.v4;
|
||||
break;
|
||||
case V6:
|
||||
u.v6 = other.u.v6;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Addr& operator=(const Addr& other)
|
||||
{
|
||||
switch (ver = other.ver)
|
||||
{
|
||||
case V4:
|
||||
u.v4 = other.u.v4;
|
||||
break;
|
||||
case V6:
|
||||
u.v6 = other.u.v6;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
static std::string validate(const std::string& ipstr, const char *title = NULL)
|
||||
{
|
||||
Addr a = from_string(ipstr, title);
|
||||
@ -190,6 +222,28 @@ namespace openvpn {
|
||||
}
|
||||
}
|
||||
|
||||
Addr network_addr(const unsigned int prefix_len) const {
|
||||
switch (ver)
|
||||
{
|
||||
case V4:
|
||||
{
|
||||
Addr ret;
|
||||
ret.ver = V4;
|
||||
ret.u.v4 = u.v4.network_addr(prefix_len);
|
||||
return ret;
|
||||
}
|
||||
case V6:
|
||||
{
|
||||
Addr ret;
|
||||
ret.ver = V6;
|
||||
ret.u.v6 = u.v6.network_addr(prefix_len);
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
throw ip_addr_unspecified();
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const Addr& other) const
|
||||
{
|
||||
switch (ver)
|
||||
@ -292,15 +346,21 @@ namespace openvpn {
|
||||
|
||||
inline std::size_t hash_value(const Addr& addr)
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
switch (addr.ver)
|
||||
{
|
||||
case Addr::V4:
|
||||
return hash_value(addr.u.v4);
|
||||
boost::hash_combine(seed, 4);
|
||||
boost::hash_combine(seed, addr.u.v4);
|
||||
break;
|
||||
case Addr::V6:
|
||||
return hash_value(addr.u.v6);
|
||||
boost::hash_combine(seed, 6);
|
||||
boost::hash_combine(seed, addr.u.v6);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
} // namespace openvpn
|
||||
|
@ -28,6 +28,8 @@ namespace openvpn {
|
||||
friend class IP::Addr;
|
||||
|
||||
public:
|
||||
enum { SIZE=32 };
|
||||
|
||||
typedef boost::uint32_t base_type;
|
||||
|
||||
static Addr from_uint32(const base_type addr)
|
||||
@ -114,6 +116,14 @@ namespace openvpn {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// return the network that contains the current address
|
||||
Addr network_addr(const unsigned int prefix_len) const
|
||||
{
|
||||
Addr ret;
|
||||
ret.u.addr = u.addr & prefix_len_to_netmask(prefix_len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool operator==(const Addr& other) const
|
||||
{
|
||||
return u.addr == other.u.addr;
|
||||
@ -128,7 +138,11 @@ namespace openvpn {
|
||||
// throws ipv4_malformed_netmask if addr is not a netmask
|
||||
unsigned int prefix_len() const
|
||||
{
|
||||
if (u.addr != ~0)
|
||||
if (u.addr == ~0)
|
||||
return 32;
|
||||
else if (u.addr == 0)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
unsigned int high = 32;
|
||||
unsigned int low = 1;
|
||||
@ -145,8 +159,6 @@ namespace openvpn {
|
||||
}
|
||||
throw ipv4_malformed_netmask();
|
||||
}
|
||||
else
|
||||
return 32;
|
||||
}
|
||||
|
||||
void negate()
|
||||
@ -170,12 +182,15 @@ namespace openvpn {
|
||||
|
||||
static base_type prefix_len_to_netmask_unchecked(const unsigned int prefix_len)
|
||||
{
|
||||
return ~((1 << (32 - prefix_len)) - 1);
|
||||
if (prefix_len)
|
||||
return ~((1 << (32 - prefix_len)) - 1);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static base_type prefix_len_to_netmask(const unsigned int prefix_len)
|
||||
{
|
||||
if (prefix_len >= 1 && prefix_len <= 32)
|
||||
if (prefix_len <= 32)
|
||||
return prefix_len_to_netmask_unchecked(prefix_len);
|
||||
else
|
||||
throw ipv4_bad_prefix_len();
|
||||
|
@ -27,6 +27,8 @@ namespace openvpn {
|
||||
friend class IP::Addr;
|
||||
|
||||
public:
|
||||
enum { SIZE=128 };
|
||||
|
||||
static Addr from_string(const std::string& ipstr, const char *title = NULL)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
@ -62,6 +64,7 @@ namespace openvpn {
|
||||
static Addr from_zero()
|
||||
{
|
||||
Addr ret;
|
||||
ret.scope_id_ = 0;
|
||||
ret.zero();
|
||||
return ret;
|
||||
}
|
||||
@ -69,6 +72,7 @@ namespace openvpn {
|
||||
static Addr from_zero_complement()
|
||||
{
|
||||
Addr ret;
|
||||
ret.scope_id_ = 0;
|
||||
ret.zero();
|
||||
ret.negate();
|
||||
return ret;
|
||||
@ -103,6 +107,12 @@ namespace openvpn {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// return the network that contains the current address
|
||||
Addr network_addr(const unsigned int prefix_len) const
|
||||
{
|
||||
throw ipv6_not_implemented(); // fixme for ipv6
|
||||
}
|
||||
|
||||
bool operator==(const Addr& other) const
|
||||
{
|
||||
return u.u64[0] == other.u.u64[0] && u.u64[1] == other.u.u64[1];
|
||||
|
53
openvpn/common/backref.hpp
Normal file
53
openvpn/common/backref.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef OPENVPN_COMMON_BACKREF_H
|
||||
#define OPENVPN_COMMON_BACKREF_H
|
||||
|
||||
namespace openvpn {
|
||||
|
||||
template <typename REF>
|
||||
class BackRef {
|
||||
public:
|
||||
BackRef() { reset(); }
|
||||
|
||||
bool defined() const
|
||||
{
|
||||
return ref_ != NULL;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
ref_ = NULL;
|
||||
value_ = NULL;
|
||||
}
|
||||
|
||||
void set(REF* ref, void* value)
|
||||
{
|
||||
ref_ = ref;
|
||||
value_ = value;
|
||||
}
|
||||
|
||||
void set_ref(REF* ref)
|
||||
{
|
||||
ref_ = ref;
|
||||
}
|
||||
|
||||
void set_value(void* value)
|
||||
{
|
||||
value_ = value;
|
||||
}
|
||||
|
||||
template <typename VALUE>
|
||||
VALUE* value() const
|
||||
{
|
||||
return (VALUE*)value_;
|
||||
}
|
||||
|
||||
REF* ref() const { return ref_; }
|
||||
|
||||
private:
|
||||
REF* ref_;
|
||||
void* value_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
26
openvpn/common/hash.hpp
Normal file
26
openvpn/common/hash.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef OPENVPN_COMMON_HASH_H
|
||||
#define OPENVPN_COMMON_HASH_H
|
||||
|
||||
#include <openvpn/common/types.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
|
||||
template <typename T>
|
||||
class HashInitialSeed
|
||||
{
|
||||
public:
|
||||
HashInitialSeed(std::size_t seed) : seed_(seed) {}
|
||||
|
||||
std::size_t operator()(const T& obj) const
|
||||
{
|
||||
std::size_t seed = seed_;
|
||||
boost::hash_combine(seed, obj);
|
||||
return seed;
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t seed_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -19,7 +19,7 @@ namespace openvpn {
|
||||
|
||||
OPENVPN_SIMPLE_EXCEPTION(type_exception);
|
||||
|
||||
template <typename T> struct types {};
|
||||
template <typename T> struct types;
|
||||
|
||||
} // namespace openvpn
|
||||
|
||||
|
89
openvpn/transport/transmap.hpp
Normal file
89
openvpn/transport/transmap.hpp
Normal file
@ -0,0 +1,89 @@
|
||||
#ifndef OPENVPN_TRANSPORT_TRANSMAP_H
|
||||
#define OPENVPN_TRANSPORT_TRANSMAP_H
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include <openvpn/common/types.hpp>
|
||||
#include <openvpn/common/exception.hpp>
|
||||
#include <openvpn/common/hash.hpp>
|
||||
#include <openvpn/addr/ip.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace TransportMap {
|
||||
|
||||
// Basic transport endpoint object, for example might be used
|
||||
// on server to record the address of a remote UDP client.
|
||||
template <typename ADDR>
|
||||
struct Endpoint
|
||||
{
|
||||
typedef ADDR Addr;
|
||||
|
||||
ADDR addr;
|
||||
unsigned short port;
|
||||
|
||||
bool operator==(const Endpoint& other) const
|
||||
{
|
||||
return port == other.port && addr == other.addr;
|
||||
}
|
||||
};
|
||||
|
||||
// Compute hash value of Endpoint
|
||||
template <typename ADDR>
|
||||
inline std::size_t hash_value(const Endpoint<ADDR>& endpoint)
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
boost::hash_combine(seed, endpoint.addr);
|
||||
boost::hash_combine(seed, endpoint.port);
|
||||
return seed;
|
||||
}
|
||||
|
||||
template <typename ENDPOINT, typename VALUE>
|
||||
class Map
|
||||
{
|
||||
typedef boost::unordered_map<ENDPOINT, typename VALUE::Ptr, HashInitialSeed<ENDPOINT> > map_type;
|
||||
|
||||
public:
|
||||
enum {
|
||||
INITIAL_BUCKETS = 2048,
|
||||
REAP_TRIGGER = 1024,
|
||||
};
|
||||
|
||||
Map(const std::size_t initial_seed)
|
||||
: insertions_since_reap(0),
|
||||
seed(initial_seed),
|
||||
map(INITIAL_BUCKETS, seed)
|
||||
{
|
||||
}
|
||||
|
||||
void add(const ENDPOINT& r, const typename VALUE::Ptr& vp)
|
||||
{
|
||||
if (++insertions_since_reap > REAP_TRIGGER)
|
||||
reap();
|
||||
map[r] = vp;
|
||||
}
|
||||
|
||||
void reap()
|
||||
{
|
||||
insertions_since_reap = 0;
|
||||
typename map_type::const_iterator i = map.begin();
|
||||
while (i != map.end())
|
||||
{
|
||||
if (i->second->defined())
|
||||
++i;
|
||||
else
|
||||
map.erase(i++);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
size_t insertions_since_reap;
|
||||
HashInitialSeed<ENDPOINT> seed;
|
||||
map_type map;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user