0
0
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:
James Yonan 2012-05-06 00:39:39 +00:00
parent 3c99b8976b
commit 452b19b787
8 changed files with 559 additions and 9 deletions

297
openvpn/addr/cidrmap.hpp Normal file
View 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

View File

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

View File

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

View File

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

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

View File

@ -19,7 +19,7 @@ namespace openvpn {
OPENVPN_SIMPLE_EXCEPTION(type_exception);
template <typename T> struct types {};
template <typename T> struct types;
} // namespace openvpn

View 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