Added support for "noise" over I1P/Tor to mask Tx transmission.
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <boost/archive/portable_binary_oarchive.hpp>
|
||||
#include <boost/archive/portable_binary_iarchive.hpp>
|
||||
@@ -36,13 +37,22 @@
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/range/adaptor/sliced.hpp>
|
||||
#include <boost/range/combine.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/uuid/nil_generator.hpp>
|
||||
#include <boost/uuid/random_generator.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <gtest/gtest.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "net/dandelionpp.h"
|
||||
#include "net/error.h"
|
||||
#include "net/net_utils_base.h"
|
||||
#include "net/socks.h"
|
||||
@@ -857,3 +867,389 @@ TEST(socks_connector, timeout)
|
||||
EXPECT_THROW(sock.get().is_open(), boost::system::system_error);
|
||||
}
|
||||
|
||||
TEST(dandelionpp_map, traits)
|
||||
{
|
||||
EXPECT_TRUE(std::is_default_constructible<net::dandelionpp::connection_map>());
|
||||
EXPECT_TRUE(std::is_move_constructible<net::dandelionpp::connection_map>());
|
||||
EXPECT_TRUE(std::is_move_assignable<net::dandelionpp::connection_map>());
|
||||
EXPECT_FALSE(std::is_copy_constructible<net::dandelionpp::connection_map>());
|
||||
EXPECT_FALSE(std::is_copy_assignable<net::dandelionpp::connection_map>());
|
||||
}
|
||||
|
||||
TEST(dandelionpp_map, empty)
|
||||
{
|
||||
const net::dandelionpp::connection_map mapper{};
|
||||
|
||||
EXPECT_EQ(mapper.begin(), mapper.end());
|
||||
EXPECT_EQ(0u, mapper.size());
|
||||
|
||||
const net::dandelionpp::connection_map cloned = mapper.clone();
|
||||
EXPECT_EQ(cloned.begin(), cloned.end());
|
||||
EXPECT_EQ(0u, cloned.size());
|
||||
}
|
||||
|
||||
TEST(dandelionpp_map, zero_stems)
|
||||
{
|
||||
std::vector<boost::uuids::uuid> connections{6};
|
||||
std::generate(connections.begin(), connections.end(), boost::uuids::random_generator{});
|
||||
|
||||
net::dandelionpp::connection_map mapper{connections, 0};
|
||||
EXPECT_EQ(mapper.begin(), mapper.end());
|
||||
EXPECT_EQ(0u, mapper.size());
|
||||
|
||||
for (const boost::uuids::uuid& connection : connections)
|
||||
EXPECT_TRUE(mapper.get_stem(connection).is_nil());
|
||||
|
||||
EXPECT_FALSE(mapper.update(connections));
|
||||
EXPECT_EQ(mapper.begin(), mapper.end());
|
||||
EXPECT_EQ(0u, mapper.size());
|
||||
|
||||
for (const boost::uuids::uuid& connection : connections)
|
||||
EXPECT_TRUE(mapper.get_stem(connection).is_nil());
|
||||
|
||||
const net::dandelionpp::connection_map cloned = mapper.clone();
|
||||
EXPECT_EQ(cloned.end(), cloned.begin());
|
||||
EXPECT_EQ(0u, cloned.size());
|
||||
}
|
||||
|
||||
TEST(dandelionpp_map, dropped_connection)
|
||||
{
|
||||
std::vector<boost::uuids::uuid> connections{6};
|
||||
std::generate(connections.begin(), connections.end(), boost::uuids::random_generator{});
|
||||
std::sort(connections.begin(), connections.end());
|
||||
|
||||
// select 3 of 6 outgoing connections
|
||||
net::dandelionpp::connection_map mapper{connections, 3};
|
||||
EXPECT_EQ(3u, mapper.size());
|
||||
EXPECT_EQ(3, mapper.end() - mapper.begin());
|
||||
{
|
||||
std::set<boost::uuids::uuid> used;
|
||||
for (const boost::uuids::uuid& connection : mapper)
|
||||
{
|
||||
EXPECT_TRUE(used.insert(connection).second);
|
||||
EXPECT_TRUE(std::binary_search(connections.begin(), connections.end(), connection));
|
||||
}
|
||||
}
|
||||
{
|
||||
const net::dandelionpp::connection_map cloned = mapper.clone();
|
||||
EXPECT_EQ(3u, cloned.size());
|
||||
ASSERT_EQ(mapper.end() - mapper.begin(), cloned.end() - cloned.begin());
|
||||
for (auto elem : boost::combine(mapper, cloned))
|
||||
EXPECT_EQ(boost::get<0>(elem), boost::get<1>(elem));
|
||||
}
|
||||
EXPECT_FALSE(mapper.update(connections));
|
||||
EXPECT_EQ(3u, mapper.size());
|
||||
ASSERT_EQ(3, mapper.end() - mapper.begin());
|
||||
{
|
||||
std::set<boost::uuids::uuid> used;
|
||||
for (const boost::uuids::uuid& connection : mapper)
|
||||
{
|
||||
EXPECT_FALSE(connection.is_nil());
|
||||
EXPECT_TRUE(used.insert(connection).second);
|
||||
EXPECT_TRUE(std::binary_search(connections.begin(), connections.end(), connection));
|
||||
}
|
||||
}
|
||||
std::map<boost::uuids::uuid, boost::uuids::uuid> mapping;
|
||||
std::vector<boost::uuids::uuid> in_connections{9};
|
||||
std::generate(in_connections.begin(), in_connections.end(), boost::uuids::random_generator{});
|
||||
{
|
||||
std::map<boost::uuids::uuid, std::size_t> used;
|
||||
std::multimap<boost::uuids::uuid, boost::uuids::uuid> inverse_mapping;
|
||||
for (const boost::uuids::uuid& connection : in_connections)
|
||||
{
|
||||
const boost::uuids::uuid out = mapper.get_stem(connection);
|
||||
EXPECT_FALSE(out.is_nil());
|
||||
EXPECT_TRUE(mapping.emplace(connection, out).second);
|
||||
inverse_mapping.emplace(out, connection);
|
||||
used[out]++;
|
||||
}
|
||||
|
||||
EXPECT_EQ(3u, used.size());
|
||||
for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
|
||||
EXPECT_EQ(3u, entry.second);
|
||||
|
||||
for (const boost::uuids::uuid& connection : in_connections)
|
||||
EXPECT_EQ(mapping[connection], mapper.get_stem(connection));
|
||||
|
||||
// drop 1 connection, and select replacement from 1 of unused 3.
|
||||
const boost::uuids::uuid lost_connection = *(++mapper.begin());
|
||||
const auto elem = std::lower_bound(connections.begin(), connections.end(), lost_connection);
|
||||
ASSERT_NE(connections.end(), elem);
|
||||
ASSERT_EQ(lost_connection, *elem);
|
||||
connections.erase(elem);
|
||||
|
||||
EXPECT_TRUE(mapper.update(connections));
|
||||
EXPECT_EQ(3u, mapper.size());
|
||||
ASSERT_EQ(3, mapper.end() - mapper.begin());
|
||||
|
||||
for (const boost::uuids::uuid& connection : mapper)
|
||||
{
|
||||
EXPECT_FALSE(connection.is_nil());
|
||||
EXPECT_NE(lost_connection, connection);
|
||||
}
|
||||
|
||||
const boost::uuids::uuid newly_mapped = *(++mapper.begin());
|
||||
EXPECT_FALSE(newly_mapped.is_nil());
|
||||
EXPECT_NE(lost_connection, newly_mapped);
|
||||
|
||||
for (auto elems = inverse_mapping.equal_range(lost_connection); elems.first != elems.second; ++elems.first)
|
||||
mapping[elems.first->second] = newly_mapped;
|
||||
}
|
||||
{
|
||||
const net::dandelionpp::connection_map cloned = mapper.clone();
|
||||
EXPECT_EQ(3u, cloned.size());
|
||||
ASSERT_EQ(mapper.end() - mapper.begin(), cloned.end() - cloned.begin());
|
||||
for (auto elem : boost::combine(mapper, cloned))
|
||||
EXPECT_EQ(boost::get<0>(elem), boost::get<1>(elem));
|
||||
}
|
||||
// mappings should remain evenly distributed amongst 2, with 3 sitting in waiting
|
||||
{
|
||||
std::set<boost::uuids::uuid> used;
|
||||
for (const boost::uuids::uuid& connection : mapper)
|
||||
{
|
||||
EXPECT_FALSE(connection.is_nil());
|
||||
EXPECT_TRUE(used.insert(connection).second);
|
||||
EXPECT_TRUE(std::binary_search(connections.begin(), connections.end(), connection));
|
||||
}
|
||||
}
|
||||
{
|
||||
std::map<boost::uuids::uuid, std::size_t> used;
|
||||
for (const boost::uuids::uuid& connection : in_connections)
|
||||
{
|
||||
const boost::uuids::uuid& out = mapper.get_stem(connection);
|
||||
EXPECT_FALSE(out.is_nil());
|
||||
EXPECT_EQ(mapping[connection], out);
|
||||
used[out]++;
|
||||
}
|
||||
|
||||
EXPECT_EQ(3u, used.size());
|
||||
for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
|
||||
EXPECT_EQ(3u, entry.second);
|
||||
}
|
||||
{
|
||||
const net::dandelionpp::connection_map cloned = mapper.clone();
|
||||
EXPECT_EQ(3u, cloned.size());
|
||||
ASSERT_EQ(mapper.end() - mapper.begin(), cloned.end() - cloned.begin());
|
||||
for (auto elem : boost::combine(mapper, cloned))
|
||||
EXPECT_EQ(boost::get<0>(elem), boost::get<1>(elem));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(dandelionpp_map, dropped_connection_remapped)
|
||||
{
|
||||
boost::uuids::random_generator random_uuid{};
|
||||
|
||||
std::vector<boost::uuids::uuid> connections{3};
|
||||
std::generate(connections.begin(), connections.end(), random_uuid);
|
||||
std::sort(connections.begin(), connections.end());
|
||||
|
||||
// select 3 of 3 outgoing connections
|
||||
net::dandelionpp::connection_map mapper{connections, 3};
|
||||
EXPECT_EQ(3u, mapper.size());
|
||||
EXPECT_EQ(3, mapper.end() - mapper.begin());
|
||||
{
|
||||
std::set<boost::uuids::uuid> used;
|
||||
for (const boost::uuids::uuid& connection : mapper)
|
||||
{
|
||||
EXPECT_FALSE(connection.is_nil());
|
||||
EXPECT_TRUE(used.insert(connection).second);
|
||||
EXPECT_TRUE(std::binary_search(connections.begin(), connections.end(), connection));
|
||||
}
|
||||
}
|
||||
EXPECT_FALSE(mapper.update(connections));
|
||||
EXPECT_EQ(3u, mapper.size());
|
||||
ASSERT_EQ(3, mapper.end() - mapper.begin());
|
||||
{
|
||||
std::set<boost::uuids::uuid> used;
|
||||
for (const boost::uuids::uuid& connection : mapper)
|
||||
{
|
||||
EXPECT_FALSE(connection.is_nil());
|
||||
EXPECT_TRUE(used.insert(connection).second);
|
||||
EXPECT_TRUE(std::binary_search(connections.begin(), connections.end(), connection));
|
||||
}
|
||||
}
|
||||
std::map<boost::uuids::uuid, boost::uuids::uuid> mapping;
|
||||
std::vector<boost::uuids::uuid> in_connections{9};
|
||||
std::generate(in_connections.begin(), in_connections.end(), random_uuid);
|
||||
{
|
||||
std::map<boost::uuids::uuid, std::size_t> used;
|
||||
std::multimap<boost::uuids::uuid, boost::uuids::uuid> inverse_mapping;
|
||||
for (const boost::uuids::uuid& connection : in_connections)
|
||||
{
|
||||
const boost::uuids::uuid out = mapper.get_stem(connection);
|
||||
EXPECT_FALSE(out.is_nil());
|
||||
EXPECT_TRUE(mapping.emplace(connection, out).second);
|
||||
inverse_mapping.emplace(out, connection);
|
||||
used[out]++;
|
||||
}
|
||||
|
||||
EXPECT_EQ(3u, used.size());
|
||||
for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
|
||||
EXPECT_EQ(3u, entry.second);
|
||||
|
||||
for (const boost::uuids::uuid& connection : in_connections)
|
||||
EXPECT_EQ(mapping[connection], mapper.get_stem(connection));
|
||||
|
||||
// drop 1 connection leaving "hole"
|
||||
const boost::uuids::uuid lost_connection = *(++mapper.begin());
|
||||
const auto elem = std::lower_bound(connections.begin(), connections.end(), lost_connection);
|
||||
ASSERT_NE(connections.end(), elem);
|
||||
ASSERT_EQ(lost_connection, *elem);
|
||||
connections.erase(elem);
|
||||
|
||||
EXPECT_TRUE(mapper.update(connections));
|
||||
EXPECT_EQ(2u, mapper.size());
|
||||
EXPECT_EQ(3, mapper.end() - mapper.begin());
|
||||
|
||||
for (auto elems = inverse_mapping.equal_range(lost_connection); elems.first != elems.second; ++elems.first)
|
||||
mapping[elems.first->second] = boost::uuids::nil_uuid();
|
||||
}
|
||||
// remap 3 connections and map 1 new connection to 2 remaining out connections
|
||||
in_connections.resize(10);
|
||||
in_connections[9] = random_uuid();
|
||||
{
|
||||
std::map<boost::uuids::uuid, std::size_t> used;
|
||||
for (const boost::uuids::uuid& connection : in_connections)
|
||||
{
|
||||
const boost::uuids::uuid& out = mapper.get_stem(connection);
|
||||
EXPECT_FALSE(out.is_nil());
|
||||
used[out]++;
|
||||
|
||||
boost::uuids::uuid& expected = mapping[connection];
|
||||
if (!expected.is_nil())
|
||||
EXPECT_EQ(expected, out);
|
||||
else
|
||||
expected = out;
|
||||
}
|
||||
|
||||
EXPECT_EQ(2u, used.size());
|
||||
for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
|
||||
EXPECT_EQ(5u, entry.second);
|
||||
}
|
||||
// select 3 of 3 connections but do not remap existing links
|
||||
connections.resize(3);
|
||||
connections[2] = random_uuid();
|
||||
EXPECT_TRUE(mapper.update(connections));
|
||||
EXPECT_EQ(3u, mapper.size());
|
||||
EXPECT_EQ(3, mapper.end() - mapper.begin());
|
||||
{
|
||||
std::map<boost::uuids::uuid, std::size_t> used;
|
||||
for (const boost::uuids::uuid& connection : in_connections)
|
||||
{
|
||||
const boost::uuids::uuid& out = mapper.get_stem(connection);
|
||||
EXPECT_FALSE(out.is_nil());
|
||||
used[out]++;
|
||||
|
||||
EXPECT_EQ(mapping[connection], out);
|
||||
}
|
||||
|
||||
EXPECT_EQ(2u, used.size());
|
||||
for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
|
||||
EXPECT_EQ(5u, entry.second);
|
||||
}
|
||||
// map 8 new incoming connections across 3 outgoing links
|
||||
in_connections.resize(18);
|
||||
std::generate(in_connections.begin() + 10, in_connections.end(), random_uuid);
|
||||
{
|
||||
std::map<boost::uuids::uuid, std::size_t> used;
|
||||
for (const boost::uuids::uuid& connection : in_connections)
|
||||
{
|
||||
const boost::uuids::uuid& out = mapper.get_stem(connection);
|
||||
EXPECT_FALSE(out.is_nil());
|
||||
used[out]++;
|
||||
|
||||
boost::uuids::uuid& expected = mapping[connection];
|
||||
if (!expected.is_nil())
|
||||
EXPECT_EQ(expected, out);
|
||||
else
|
||||
expected = out;
|
||||
}
|
||||
|
||||
EXPECT_EQ(3u, used.size());
|
||||
for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
|
||||
EXPECT_EQ(6u, entry.second);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(dandelionpp_map, dropped_all_connections)
|
||||
{
|
||||
boost::uuids::random_generator random_uuid{};
|
||||
|
||||
std::vector<boost::uuids::uuid> connections{8};
|
||||
std::generate(connections.begin(), connections.end(), random_uuid);
|
||||
std::sort(connections.begin(), connections.end());
|
||||
|
||||
// select 3 of 8 outgoing connections
|
||||
net::dandelionpp::connection_map mapper{connections, 3};
|
||||
EXPECT_EQ(3u, mapper.size());
|
||||
EXPECT_EQ(3, mapper.end() - mapper.begin());
|
||||
{
|
||||
std::set<boost::uuids::uuid> used;
|
||||
for (const boost::uuids::uuid& connection : mapper)
|
||||
{
|
||||
EXPECT_FALSE(connection.is_nil());
|
||||
EXPECT_TRUE(used.insert(connection).second);
|
||||
EXPECT_TRUE(std::binary_search(connections.begin(), connections.end(), connection));
|
||||
}
|
||||
}
|
||||
EXPECT_FALSE(mapper.update(connections));
|
||||
EXPECT_EQ(3u, mapper.size());
|
||||
ASSERT_EQ(3, mapper.end() - mapper.begin());
|
||||
{
|
||||
std::set<boost::uuids::uuid> used;
|
||||
for (const boost::uuids::uuid& connection : mapper)
|
||||
{
|
||||
EXPECT_FALSE(connection.is_nil());
|
||||
EXPECT_TRUE(used.insert(connection).second);
|
||||
EXPECT_TRUE(std::binary_search(connections.begin(), connections.end(), connection));
|
||||
}
|
||||
}
|
||||
std::vector<boost::uuids::uuid> in_connections{9};
|
||||
std::generate(in_connections.begin(), in_connections.end(), random_uuid);
|
||||
{
|
||||
std::map<boost::uuids::uuid, std::size_t> used;
|
||||
std::map<boost::uuids::uuid, boost::uuids::uuid> mapping;
|
||||
for (const boost::uuids::uuid& connection : in_connections)
|
||||
{
|
||||
const boost::uuids::uuid out = mapper.get_stem(connection);
|
||||
EXPECT_FALSE(out.is_nil());
|
||||
EXPECT_TRUE(mapping.emplace(connection, out).second);
|
||||
used[out]++;
|
||||
}
|
||||
|
||||
EXPECT_EQ(3u, used.size());
|
||||
for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
|
||||
EXPECT_EQ(3u, entry.second);
|
||||
|
||||
for (const boost::uuids::uuid& connection : in_connections)
|
||||
EXPECT_EQ(mapping[connection], mapper.get_stem(connection));
|
||||
|
||||
// drop all connections
|
||||
connections.clear();
|
||||
|
||||
EXPECT_TRUE(mapper.update(connections));
|
||||
EXPECT_EQ(0u, mapper.size());
|
||||
EXPECT_EQ(3, mapper.end() - mapper.begin());
|
||||
}
|
||||
// remap 7 connections to nothing
|
||||
for (const boost::uuids::uuid& connection : boost::adaptors::slice(in_connections, 0, 7))
|
||||
EXPECT_TRUE(mapper.get_stem(connection).is_nil());
|
||||
|
||||
// select 3 of 30 connections, only 7 should be remapped to new indexes (but all to new uuids)
|
||||
connections.resize(30);
|
||||
std::generate(connections.begin(), connections.end(), random_uuid);
|
||||
EXPECT_TRUE(mapper.update(connections));
|
||||
{
|
||||
std::map<boost::uuids::uuid, std::size_t> used;
|
||||
for (const boost::uuids::uuid& connection : in_connections)
|
||||
{
|
||||
const boost::uuids::uuid& out = mapper.get_stem(connection);
|
||||
EXPECT_FALSE(out.is_nil());
|
||||
used[out]++;
|
||||
}
|
||||
|
||||
EXPECT_EQ(3u, used.size());
|
||||
for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
|
||||
EXPECT_EQ(3u, entry.second);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user