tests: require value fragments to fit the IPv6 minimum MTU

This commit is contained in:
Adrien Beraud committed 2026-10-29 23:28:48 -04:00
1 parent f29c77cadf
commit ed8131a3c6
2 files changed
+53 -6

No files matched your search

+51 -6
View File
@@ -942,11 +942,12 @@ NetworkEngineTester::testFindNodeRequestReuse()
/* A NetworkEngine with its own socket, delivering its packets to other engines */
struct TransportTestNode
{
TransportTestNode(const char* ip, TransportConfig transport, uint64_t seed)
TransportTestNode(const char* ip, TransportConfig transport, uint64_t seed, NetId network = 0)
: rd(seed)
, addr(makeIPv4(ip, 4222))
{
net::NetworkConfig config {};
config.network = network;
config.max_req_per_sec = -1;
config.max_peer_req_per_sec = -1;
if (transport.enabled and not transport.key)
@@ -1925,8 +1926,10 @@ NetworkEngineTester::testTransportInitialSenderConfirmsAfterSessionEnvelope()
/* a requests a value from b that b answers in a header and two encrypted fragments, kept in `reply` */
struct FragmentedReply
{
static constexpr size_t FRAGMENT {net::NetworkEngine::ENCRYPTED_FRAGMENT_SIZE};
FragmentedReply(TransportTestNode& a, TransportTestNode& b)
: data(2000, 'x')
: data(FRAGMENT + FRAGMENT / 2, 'x')
{
b.values = {std::make_shared<Value>((const uint8_t*) data.data(), data.size())};
request = a.get(a.node(b), got);
@@ -1956,13 +1959,13 @@ NetworkEngineTester::testTransportEncryptedFragmentsIgnorePlaintextParts()
establishSession(a, b);
FragmentedReply r(a, b);
const auto tid = r.request->getTid();
const Blob forged(1081, 'z');
const Blob forged(r.FRAGMENT, 'z');
// Plaintext fragments spoofed from b's address, before and after the header, must not be merged
auto early = makeValueDataPacketBlob(tid, 0, 0, forged);
a.engine->processMessage(early.data(), early.size(), b.addr);
r.deliver(a, b.addr, 0);
auto late = makeValueDataPacketBlob(tid, 0, 1081, Blob(919, 'z'));
auto late = makeValueDataPacketBlob(tid, 0, r.FRAGMENT, Blob(r.data.size() - r.FRAGMENT, 'z'));
a.engine->processMessage(late.data(), late.size(), b.addr);
r.deliver(a, b.addr, 1);
r.deliver(a, b.addr, 2);
@@ -1979,7 +1982,7 @@ NetworkEngineTester::testTransportEncryptedFragmentsIgnorePlaintextHeader()
const auto tid = r.request->getTid();
// A plaintext header spoofed from b's address must not claim the transaction
auto header = makeReplyHeaderPacketBlob(b.id, tid, {2000});
auto header = makeReplyHeaderPacketBlob(b.id, tid, {r.data.size()});
a.engine->processMessage(header.data(), header.size(), b.addr);
for (size_t i = 0; i < 3; i++)
r.deliver(a, b.addr, i);
@@ -1998,7 +2001,7 @@ NetworkEngineTester::testTransportEncryptedFragmentsRequireSenderKey()
// A fragment under another key, in an Initial envelope spoofed from b's address, must not be merged
auto sender = transport::KeyPair::generate();
auto ephemeral = transport::KeyPair::generate();
auto fragment = makeValueDataPacketBlob(tid, 0, 0, Blob(1081, 'z'));
auto fragment = makeValueDataPacketBlob(tid, 0, 0, Blob(r.FRAGMENT, 'z'));
auto initial = transport::seal(*transport::initialSendKey(sender, ephemeral, a.key.pub, 0),
transport::EnvelopeType::Initial,
sender.pub,
@@ -2012,6 +2015,48 @@ NetworkEngineTester::testTransportEncryptedFragmentsRequireSenderKey()
CPPUNIT_ASSERT(r.received());
}
/* every packet of a fragmented value fits the IPv6 minimum MTU, less the IPv6 and UDP headers */
static void
checkFragmentsFitMinimumMtu(TransportTestNode& a, TransportTestNode& b)
{
constexpr size_t MAX_PAYLOAD {1280 - 40 - 8};
const Blob data(5000, 'x');
b.values = {std::make_shared<Value>(data.data(), data.size())};
std::optional<std::vector<Sp<Value>>> got;
a.get(a.node(b), got);
a.deliverTo(b);
auto reply = b.takeSent();
CPPUNIT_ASSERT(reply.size() > 2);
for (const auto& p : reply)
CPPUNIT_ASSERT_LESSEQUAL(MAX_PAYLOAD, p.data.size());
for (const auto& p : reply)
a.engine->processMessage(p.data.data(), p.data.size(), b.addr);
CPPUNIT_ASSERT(got and got->size() == 1 and (*got)[0]->data == data);
}
void
NetworkEngineTester::testValueFragmentsFitMinimumMtu()
{
constexpr NetId network = 0x7fffffff;
{
TransportTestNode a("127.0.0.2", legacyTransport(), 1, network);
TransportTestNode b("127.0.0.3", legacyTransport(), 2, network);
checkFragmentsFitMinimumMtu(a, b);
}
{
// Largest overhead: Session envelopes with a credential, until a confirms b's session
auto authority = transport::Authority::generate();
TransportTestNode a("127.0.0.2", privateTransport(authority), 1, network);
TransportTestNode b("127.0.0.3", privateTransport(authority), 2, network);
bool done = false;
a.ping(b.addr, done);
a.deliverTo(b);
b.deliverTo(a);
CPPUNIT_ASSERT(done);
checkFragmentsFitMinimumMtu(a, b);
}
}
void
NetworkEngineTester::testTransportPlaintextCannotPoisonSessionCache()
{
+2
View File
@@ -51,6 +51,7 @@ class NetworkEngineTester : public CppUnit::TestFixture
CPPUNIT_TEST(testTransportEncryptedFragmentsIgnorePlaintextParts);
CPPUNIT_TEST(testTransportEncryptedFragmentsIgnorePlaintextHeader);
CPPUNIT_TEST(testTransportEncryptedFragmentsRequireSenderKey);
CPPUNIT_TEST(testValueFragmentsFitMinimumMtu);
CPPUNIT_TEST(testTransportPlaintextCannotPoisonSessionCache);
CPPUNIT_TEST(testTransportPlaintextCannotUpdateKeyedNode);
CPPUNIT_TEST(testTransportPlaintextCannotCompleteEncryptedRequest);
@@ -105,6 +106,7 @@ public:
void testTransportEncryptedFragmentsIgnorePlaintextParts();
void testTransportEncryptedFragmentsIgnorePlaintextHeader();
void testTransportEncryptedFragmentsRequireSenderKey();
void testValueFragmentsFitMinimumMtu();
void testTransportPlaintextCannotPoisonSessionCache();
void testTransportPlaintextCannotUpdateKeyedNode();
void testTransportPlaintextCannotCompleteEncryptedRequest();