mirror of https://github.com/oxen-io/lokinet
more work
parent
593e2ddac6
commit
e88c39b9e2
@ -0,0 +1,90 @@
|
||||
Wire Protocol (version ½)
|
||||
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in RFC 2119 [RFC2119].
|
||||
|
||||
LLARP supports by default an authenticated and framed transport over UTP [1]
|
||||
|
||||
Handshake:
|
||||
|
||||
Alice establishes a UTP "connection" with Bob.
|
||||
|
||||
Alice sends a LIM a_L encrpyted with the initial b_K key
|
||||
|
||||
if Bob accepts Alice's router, Bob replies with a LIM b_L encrpyted with the
|
||||
b_K key.
|
||||
|
||||
next the session keys are generated via:
|
||||
|
||||
a_h = HS(a_K + a_L.n)
|
||||
b_h = HS(b_K + b_L.n)
|
||||
a_K = TKE(A.p, B_a.e, sk, a_h)
|
||||
b_K = TKE(A.p, B_a.e, sk, b_h)
|
||||
|
||||
A.tx_K = b_K
|
||||
A.rx_K = a_K
|
||||
B.tx_K = a_K
|
||||
B.rx_K = B_K
|
||||
|
||||
the initial value of a_K is HS(A.k) and b_K is HS(B.k)
|
||||
|
||||
1120 byte fragments are sent over UTP in an ordered fashion.
|
||||
|
||||
The each fragment F has the following structure:
|
||||
|
||||
[ 32 bytes blake2 keyed hash of the following 1088 bytes (h)]
|
||||
[ 32 bytes random nonce (n)]
|
||||
[ 1056 bytes encrypted payload (p)]
|
||||
|
||||
the recipiant verifies F.h == MDS(F.n + F.p, rx_K) and the UTP session
|
||||
is reset if verification fails.
|
||||
|
||||
the decrypted payload P has the following structure:
|
||||
|
||||
[ 24 bytes random (A) ]
|
||||
[ big endian unsigned 32 bit message id (I) ]
|
||||
[ big endian unsigned 16 bit fragment length (N) ]
|
||||
[ big endian unsigned 16 bit fragment remaining bytes (R) ]
|
||||
[ N bytes of plaintext payload (X) ]
|
||||
[ trailing bytes discarded ]
|
||||
|
||||
link layer messages fragmented and delievered in any order the sender chooses.
|
||||
|
||||
recipaint ensures a buffer for message number P.I exists, allocating one if it
|
||||
does not exist.
|
||||
|
||||
recipiant appends P.X to the end of the buffer for message P.I
|
||||
|
||||
if P.R is zero then message number P.I is completed and processed as a link
|
||||
layer messages. otherwise the recipiant expects P.R additional bytes.
|
||||
P.R's value MUST decrease by P.N in the next fragment sent.
|
||||
|
||||
message size MUST NOT exceed 8192 bytes.
|
||||
|
||||
if a message is not received in 2 seconds it is discarded and any further
|
||||
fragments for the message are also discarded.
|
||||
|
||||
P.I MUST have the initial value 0
|
||||
P.I MUST be incremeneted by 1 for each new messsage transmitted
|
||||
P.I MAY wrap around back to 0
|
||||
|
||||
|
||||
after every fragment F the session key K is mutated via:
|
||||
|
||||
K = HS(K + P.A)
|
||||
|
||||
Periodically the connection initiator MUST renegotiate the session key by
|
||||
sending a LIM after L.p milliseconds have elapsed.
|
||||
|
||||
If the local RC changes while a connection is established they MUST
|
||||
renegotioate the session keys by sending a LIM to ensure the new RC is sent.
|
||||
|
||||
|
||||
references:
|
||||
|
||||
[1] http://www.bittorrent.org/beps/bep_0029.html
|
||||
|
||||
|
||||
|
@ -1,90 +1,166 @@
|
||||
Wire Protocol (version ½)
|
||||
Wire Protocol (version 1)
|
||||
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in RFC 2119 [RFC2119].
|
||||
|
||||
LLARP supports by default an authenticated and framed transport over UTP [1]
|
||||
LLARP supports by default an authenticated message transport over a
|
||||
datagram based network layer.
|
||||
|
||||
Handshake:
|
||||
|
||||
Alice establishes a UTP "connection" with Bob.
|
||||
outer message format:
|
||||
|
||||
Alice sends a LIM a_L encrpyted with the initial b_K key
|
||||
{
|
||||
A: command,
|
||||
B: <16 bytes flow id>,
|
||||
C: <optional 32 bytes cookie>,
|
||||
X: <N bytes payload>
|
||||
}
|
||||
|
||||
if Bob accepts Alice's router, Bob replies with a LIM b_L encrpyted with the
|
||||
b_K key.
|
||||
comamnds:
|
||||
|
||||
next the session keys are generated via:
|
||||
A - get handshake cookie
|
||||
|
||||
a_h = HS(a_K + a_L.n)
|
||||
b_h = HS(b_K + b_L.n)
|
||||
a_K = TKE(A.p, B_a.e, sk, a_h)
|
||||
b_K = TKE(A.p, B_a.e, sk, b_h)
|
||||
obtain a handshake cookie
|
||||
|
||||
A.tx_K = b_K
|
||||
A.rx_K = a_K
|
||||
B.tx_K = a_K
|
||||
B.rx_K = B_K
|
||||
B is randomized
|
||||
X MUST contain the user agent string of the requester.
|
||||
|
||||
the initial value of a_K is HS(A.k) and b_K is HS(B.k)
|
||||
the if the network id differs from the current network's id a reject message is
|
||||
sent:
|
||||
|
||||
1120 byte fragments are sent over UTP in an ordered fashion.
|
||||
{
|
||||
A: R,
|
||||
B: msg.B,
|
||||
X: "<reply line>"
|
||||
}
|
||||
|
||||
The each fragment F has the following structure:
|
||||
MUST be replied to with a message rejected or a give handshake cookie
|
||||
|
||||
[ 32 bytes blake2 keyed hash of the following 1088 bytes (h)]
|
||||
[ 32 bytes random nonce (n)]
|
||||
[ 1056 bytes encrypted payload (p)]
|
||||
C - give handshake cookie
|
||||
|
||||
the recipiant verifies F.h == MDS(F.n + F.p, rx_K) and the UTP session
|
||||
is reset if verification fails.
|
||||
give a handshake cookie to a remote endpoint that asks for one
|
||||
|
||||
the decrypted payload P has the following structure:
|
||||
B is the B value from the get handshake cookie message
|
||||
X is a 32 byte handshake cookie, calcuated via:
|
||||
|
||||
[ 24 bytes random (A) ]
|
||||
[ big endian unsigned 32 bit message id (I) ]
|
||||
[ big endian unsigned 16 bit fragment length (N) ]
|
||||
[ big endian unsigned 16 bit fragment remaining bytes (R) ]
|
||||
[ N bytes of plaintext payload (X) ]
|
||||
[ trailing bytes discarded ]
|
||||
r = RAND(32)
|
||||
a = "<ascii representation of ip>" + " " + "<port number>"
|
||||
X = HS(a + B + r)
|
||||
|
||||
link layer messages fragmented and delievered in any order the sender chooses.
|
||||
R - message rejected
|
||||
|
||||
recipaint ensures a buffer for message number P.I exists, allocating one if it
|
||||
does not exist.
|
||||
B is the flow id from the recipiant
|
||||
X is a reply line
|
||||
|
||||
recipiant appends P.X to the end of the buffer for message P.I
|
||||
reject a message with flow id B
|
||||
|
||||
if P.R is zero then message number P.I is completed and processed as a link
|
||||
layer messages. otherwise the recipiant expects P.R additional bytes.
|
||||
P.R's value MUST decrease by P.N in the next fragment sent.
|
||||
S - session negotiation
|
||||
|
||||
message size MUST NOT exceed 8192 bytes.
|
||||
negotiate encrypted session
|
||||
|
||||
if a message is not received in 2 seconds it is discarded and any further
|
||||
fragments for the message are also discarded.
|
||||
B is the flow id from the recipiant
|
||||
C is the handshake cookie
|
||||
X is encrypted session negotiation data
|
||||
|
||||
P.I MUST have the initial value 0
|
||||
P.I MUST be incremeneted by 1 for each new messsage transmitted
|
||||
P.I MAY wrap around back to 0
|
||||
D - encrypted data transmission
|
||||
|
||||
transmit encrypted data on session
|
||||
|
||||
after every fragment F the session key K is mutated via:
|
||||
B is the flow id from the recipiant
|
||||
X is authenticated and encrypted data
|
||||
|
||||
K = HS(K + P.A)
|
||||
BNF:
|
||||
|
||||
Periodically the connection initiator MUST renegotiate the session key by
|
||||
sending a LIM after L.p milliseconds have elapsed.
|
||||
<reply-line> ::= <status-code> <space> <method> <space> <message>
|
||||
|
||||
If the local RC changes while a connection is established they MUST
|
||||
renegotioate the session keys by sending a LIM to ensure the new RC is sent.
|
||||
<status-code> ::= <integer> <digit> <digit>
|
||||
|
||||
<word> ::= <letter>+
|
||||
|
||||
references:
|
||||
<message> ::= <word> <space> <word>* | <word>
|
||||
|
||||
[1] http://www.bittorrent.org/beps/bep_0029.html
|
||||
<method> ::= "COOKIE" | "HANDSHAKE"
|
||||
|
||||
<user-agent> ::= <net-id> <space> <protocol-version> <space> <agent-version>
|
||||
|
||||
<net-id> ::= "lokinet" | "testnet"
|
||||
|
||||
<space> ::= " "
|
||||
|
||||
<zero> ::= "0"
|
||||
|
||||
<integer> ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||
|
||||
<digit> ::= <zero> | <integer>
|
||||
|
||||
<number> ::= <zero> | <integer> <digit>*
|
||||
|
||||
<agent-version> ::= <number> "." <number> "." <number>
|
||||
|
||||
<protocol-version> ::= <number>
|
||||
|
||||
|
||||
session negotiation:
|
||||
|
||||
The session starts out with each side having 2 session keys rx_K and tx_K for
|
||||
decrypting inbound messages and encrypting outbound messages respectively.
|
||||
|
||||
The initiator (alice) and the recipiant (bob) start out with static session keys
|
||||
|
||||
k_a = HS(a.k)
|
||||
k_b = HS(b.k)
|
||||
|
||||
a.rx_K = k_a
|
||||
b.rx_K = k_b
|
||||
|
||||
a.tx_K = k_b
|
||||
b.tx_K = k_a
|
||||
|
||||
|
||||
inner message format:
|
||||
|
||||
<32 bytes blake2s keyed hash of following data>
|
||||
<24 bytes nounce>
|
||||
<remaining bytes encrypted payload>
|
||||
|
||||
decryption is done via:
|
||||
|
||||
SD(remaining, rx_K, nounce)
|
||||
|
||||
encrypted payload is bencoded LIM (see proto_v0.txt)
|
||||
|
||||
the initiator starts out by sending a LIM a_LIM to the recipiant.
|
||||
|
||||
the recipiant replies with a LIM b_LIM to the initiator.
|
||||
|
||||
when the initiator gets a valid LIM from the recipiant the session keys for data
|
||||
transmission are set to:
|
||||
|
||||
k_a = TKE(a.k, b.k, a.sk, a_LIM.n)
|
||||
k_b = TKE(b.k, a.k, b.sk, b_LIM.n)
|
||||
|
||||
a.rx_K = k_a
|
||||
b.rx_K = k_b
|
||||
|
||||
a.tx_K = k_b
|
||||
b.tx_K = k_a
|
||||
|
||||
afterwards data transmission may happen
|
||||
|
||||
data tranmission:
|
||||
|
||||
message format:
|
||||
|
||||
<10 byte header>
|
||||
<remaining data payload>
|
||||
|
||||
header format:
|
||||
|
||||
<1 byte proto version>
|
||||
<1 byte command>
|
||||
<1 byte flags>
|
||||
<1 byte fragno>
|
||||
<2 bytes fraglen>
|
||||
<4 bytes seqno>
|
||||
|
@ -1 +0,0 @@
|
||||
#include <iwp.hpp>
|
@ -1,23 +0,0 @@
|
||||
#ifndef LLARP_IWP_HPP
|
||||
#define LLARP_IWP_HPP
|
||||
|
||||
#include <crypto.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
class Logic;
|
||||
struct Router;
|
||||
} // namespace llarp
|
||||
|
||||
struct llarp_iwp_args
|
||||
{
|
||||
struct llarp::Crypto* crypto;
|
||||
llarp::Logic* logic;
|
||||
struct llarp_threadpool* cryptoworker;
|
||||
struct llarp::Router* router;
|
||||
bool permitInbound;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,319 +0,0 @@
|
||||
#include <link/dtls_internal.hpp>
|
||||
#include <crypto.hpp>
|
||||
#include <router.hpp>
|
||||
#include <endian.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dtls
|
||||
{
|
||||
const mbedtls_ecp_group_id LinkLayer::AllowedCurve[2] = {
|
||||
MBEDTLS_ECP_DP_CURVE25519, MBEDTLS_ECP_DP_NONE};
|
||||
const int LinkLayer::AllowedHash[2] = {MBEDTLS_MD_SHA256, MBEDTLS_MD_NONE};
|
||||
|
||||
const int LinkLayer::CipherSuite[2] = {
|
||||
MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 0};
|
||||
|
||||
const mbedtls_x509_crt_profile LinkLayer::X509Profile = {
|
||||
MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256),
|
||||
MBEDTLS_X509_ID_FLAG(MBEDTLS_PK_ECDSA),
|
||||
MBEDTLS_X509_ID_FLAG(MBEDTLS_ECP_DP_CURVE25519), 0};
|
||||
|
||||
static int
|
||||
Random(void *ctx, unsigned char *buf, size_t sz)
|
||||
{
|
||||
static_cast< llarp::Crypto * >(ctx)->randbytes(buf, sz);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
WriteCookie(void *ctx, unsigned char **p, unsigned char *,
|
||||
const unsigned char *info, size_t ilen)
|
||||
{
|
||||
Session *self = static_cast< Session * >(ctx);
|
||||
if(!self->crypto->hmac(*p, llarp::InitBuffer(info, ilen),
|
||||
self->m_Parent->CookieSec()))
|
||||
return -1;
|
||||
*p += 32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
VerifyCookie(void *ctx, const unsigned char *cookie, size_t clen,
|
||||
const unsigned char *info, size_t ilen)
|
||||
{
|
||||
if(clen != 32)
|
||||
return -1;
|
||||
Session *self = static_cast< Session * >(ctx);
|
||||
ShortHash check;
|
||||
if(!self->crypto->hmac(check.data(), llarp::InitBuffer(info, ilen),
|
||||
self->m_Parent->CookieSec()))
|
||||
return -1;
|
||||
if(memcmp(check.data(), cookie, clen) == 0)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
InboundVerifyCert(void *, mbedtls_x509_crt *, int, unsigned int *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
OutboundVerifyCert(void *, mbedtls_x509_crt *, int, unsigned int *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Session::Session(LinkLayer *parent) : ILinkSession(), crypto(parent->crypto)
|
||||
{
|
||||
m_Parent = parent;
|
||||
mbedtls_ssl_config_init(&m_config);
|
||||
mbedtls_ssl_conf_transport(&m_config, MBEDTLS_SSL_TRANSPORT_DATAGRAM);
|
||||
mbedtls_ssl_conf_authmode(&m_config, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
mbedtls_ssl_conf_sig_hashes(&m_config, LinkLayer::AllowedHash);
|
||||
m_config.p_vrfy = this;
|
||||
m_config.key_cert = &m_Parent->ourKeys;
|
||||
m_config.p_cookie = this;
|
||||
m_config.f_cookie_write = &WriteCookie;
|
||||
m_config.f_cookie_check = &VerifyCookie;
|
||||
}
|
||||
|
||||
Session::Session(LinkLayer *parent, const llarp::Addr &from)
|
||||
: Session(parent)
|
||||
{
|
||||
remoteAddr = from;
|
||||
m_config.f_vrfy = &InboundVerifyCert;
|
||||
byte_t buf[20] = {0};
|
||||
parent->crypto->randbytes(buf, sizeof(buf));
|
||||
htobe16buf(buf, from.port());
|
||||
memcpy(buf + 2, from.addr6()->s6_addr, 16);
|
||||
mbedtls_ssl_set_client_transport_id(&m_ctx, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
Session::Session(LinkLayer *parent, const RouterContact &rc,
|
||||
const AddressInfo &ai)
|
||||
: Session(parent)
|
||||
{
|
||||
remoteRC = rc;
|
||||
remoteAddr = ai;
|
||||
m_config.f_vrfy = &OutboundVerifyCert;
|
||||
}
|
||||
|
||||
Session::~Session()
|
||||
{
|
||||
mbedtls_ssl_session_free(&m_session);
|
||||
mbedtls_ssl_free(&m_ctx);
|
||||
mbedtls_ssl_config_free(&m_config);
|
||||
}
|
||||
|
||||
void
|
||||
Session::Connect()
|
||||
{
|
||||
mbedtls_ssl_conf_endpoint(&m_config, MBEDTLS_SSL_IS_CLIENT);
|
||||
Configure();
|
||||
}
|
||||
|
||||
void
|
||||
Session::Accept()
|
||||
{
|
||||
mbedtls_ssl_conf_endpoint(&m_config, MBEDTLS_SSL_IS_SERVER);
|
||||
Configure();
|
||||
}
|
||||
|
||||
void
|
||||
Session::Configure()
|
||||
{
|
||||
m_config.ciphersuite_list[0] = LinkLayer::CipherSuite;
|
||||
m_config.ciphersuite_list[1] = LinkLayer::CipherSuite;
|
||||
m_config.ciphersuite_list[2] = LinkLayer::CipherSuite;
|
||||
m_config.ciphersuite_list[3] = LinkLayer::CipherSuite;
|
||||
m_config.p_dbg = nullptr;
|
||||
m_config.f_dbg = &Session::Debug;
|
||||
m_config.p_rng = m_Parent->crypto;
|
||||
m_config.f_rng = &Random;
|
||||
|
||||
const auto *conf = &m_config;
|
||||
mbedtls_ssl_setup(&m_ctx, conf);
|
||||
}
|
||||
|
||||
void
|
||||
Session::Recv_ll(const void *buf, size_t sz)
|
||||
{
|
||||
ll_recv.emplace_back(sz);
|
||||
auto &back = ll_recv.back();
|
||||
memcpy(back.data(), buf, sz);
|
||||
}
|
||||
|
||||
void
|
||||
Session::PumpIO()
|
||||
{
|
||||
llarp_time_t now = m_Parent->Now();
|
||||
if(m_ctx.state == MBEDTLS_SSL_HANDSHAKE_OVER)
|
||||
{
|
||||
// pump inbound acks
|
||||
{
|
||||
auto itr = m_Inbound.begin();
|
||||
while(itr != m_Inbound.end())
|
||||
{
|
||||
if(!itr->second.IsExpired(now))
|
||||
{
|
||||
if(itr->second.IsDone())
|
||||
{
|
||||
m_Parent->HandleMessage(this, itr->second.msg.as_buffer());
|
||||
itr = m_Inbound.erase(itr);
|
||||
continue;
|
||||
}
|
||||
else if(itr->second.ShouldRetransmit(now))
|
||||
{
|
||||
itr->second.TransmitAcks(&m_ctx, itr->first);
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
else
|
||||
itr = m_Inbound.erase(itr);
|
||||
}
|
||||
}
|
||||
// pump outbound fragments
|
||||
{
|
||||
auto itr = m_Outbound.begin();
|
||||
while(itr != m_Outbound.end())
|
||||
{
|
||||
if(itr->second.IsExpired(now) || itr->second.IsDone())
|
||||
{
|
||||
itr = m_Outbound.erase(itr);
|
||||
continue;
|
||||
}
|
||||
else if(itr->second.ShouldRetransmit(now))
|
||||
itr->second.TransmitUnacked(&m_ctx, itr->first);
|
||||
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/// step the handshake
|
||||
int res = mbedtls_ssl_handshake_step(&m_ctx);
|
||||
switch(res)
|
||||
{
|
||||
case MBEDTLS_ERR_SSL_WANT_READ:
|
||||
case MBEDTLS_ERR_SSL_WANT_WRITE:
|
||||
case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
|
||||
case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
|
||||
break;
|
||||
default:
|
||||
// drop send queue
|
||||
ll_send.clear();
|
||||
// drop recv queue
|
||||
ll_recv.clear();
|
||||
// reset session
|
||||
mbedtls_ssl_session_reset(&m_ctx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// low level sendto
|
||||
while(ll_send.size())
|
||||
{
|
||||
m_Parent->SendTo_LL(remoteAddr, llarp::ConstBuffer(ll_send.front()));
|
||||
ll_send.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Session::Debug(void *, int, const char *fname, int lineno, const char *msg)
|
||||
{
|
||||
llarp::_Log(llarp::eLogInfo, fname, lineno, msg);
|
||||
}
|
||||
|
||||
LinkLayer::LinkLayer(llarp::Crypto *c, const SecretKey &encryptionSecretKey,
|
||||
const SecretKey &identitySecretKey,
|
||||
llarp::GetRCFunc getrc, llarp::LinkMessageHandler h,
|
||||
llarp::SignBufferFunc sign,
|
||||
llarp::SessionEstablishedHandler established,
|
||||
llarp::SessionRenegotiateHandler reneg,
|
||||
llarp::TimeoutHandler timeout,
|
||||
llarp::SessionClosedHandler closed)
|
||||
: llarp::ILinkLayer(encryptionSecretKey, getrc, h, sign, established,
|
||||
reneg, timeout, closed)
|
||||
, crypto(c)
|
||||
, m_IdentityKey(identitySecretKey)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
LinkLayer::Start(llarp::Logic *l)
|
||||
{
|
||||
if(!ILinkLayer::Start(l))
|
||||
return false;
|
||||
return crypto->shorthash(m_CookieSec, llarp::ConstBuffer(m_IdentityKey));
|
||||
}
|
||||
|
||||
void
|
||||
LinkLayer::RecvFrom(const llarp::Addr &from, const void *buf, size_t sz)
|
||||
{
|
||||
auto itr = m_Pending.find(from);
|
||||
if(itr == m_Pending.end())
|
||||
{
|
||||
itr = m_Pending.insert(std::make_pair(from, new Session(this, from)))
|
||||
.first;
|
||||
itr->second->Start();
|
||||
}
|
||||
static_cast< Session * >(itr->second.get())->Recv_ll(buf, sz);
|
||||
}
|
||||
|
||||
ILinkSession *
|
||||
LinkLayer::NewOutboundSession(const llarp::RouterContact &rc,
|
||||
const llarp::AddressInfo &ai)
|
||||
{
|
||||
return new Session(this, rc, ai);
|
||||
}
|
||||
|
||||
void
|
||||
LinkLayer::Pump()
|
||||
{
|
||||
std::set< RouterID > sessions;
|
||||
{
|
||||
Lock l(m_AuthedLinksMutex);
|
||||
auto itr = m_AuthedLinks.begin();
|
||||
while(itr != m_AuthedLinks.end())
|
||||
{
|
||||
sessions.insert(itr->first);
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
ILinkLayer::Pump();
|
||||
{
|
||||
Lock l(m_AuthedLinksMutex);
|
||||
for(const auto &pk : sessions)
|
||||
{
|
||||
if(m_AuthedLinks.count(pk) == 0)
|
||||
{
|
||||
// all sessions were removed
|
||||
SessionClosed(pk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr< ILinkLayer >
|
||||
NewServerFromRouter(llarp::Router *r)
|
||||
{
|
||||
return std::unique_ptr< LinkLayer >(new LinkLayer(
|
||||
&r->crypto, r->encryption, r->identity,
|
||||
std::bind(&llarp::Router::rc, r),
|
||||
std::bind(&llarp::Router::HandleRecvLinkMessageBuffer, r,
|
||||
std::placeholders::_1, std::placeholders::_2),
|
||||
std::bind(&llarp::Router::Sign, r, std::placeholders::_1,
|
||||
std::placeholders::_2),
|
||||
std::bind(&llarp::Router::OnSessionEstablished, r,
|
||||
std::placeholders::_1),
|
||||
std::bind(&llarp::Router::CheckRenegotiateValid, r,
|
||||
std::placeholders::_1, std::placeholders::_2),
|
||||
std::bind(&llarp::Router::OnConnectTimeout, r, std::placeholders::_1),
|
||||
std::bind(&llarp::Router::SessionClosed, r, std::placeholders::_1)));
|
||||
}
|
||||
|
||||
} // namespace dtls
|
||||
} // namespace llarp
|
@ -1,18 +0,0 @@
|
||||
#ifndef LLARP_LINK_DTLS_HPP
|
||||
#define LLARP_LINK_DTLS_HPP
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
struct ILinkLayer;
|
||||
struct Router;
|
||||
|
||||
namespace dtls
|
||||
{
|
||||
std::unique_ptr< ILinkLayer >
|
||||
NewServerFromRouter(llarp::Router* r);
|
||||
}
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,24 @@
|
||||
#include <link/iwp_internal.hpp>
|
||||
#include <router.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace iwp
|
||||
{
|
||||
std::unique_ptr< ILinkLayer >
|
||||
NewServerFromRouter(llarp::Router*)
|
||||
{
|
||||
// TODO: implement me
|
||||
return nullptr;
|
||||
}
|
||||
std::unique_ptr< ILinkLayer >
|
||||
NewServer(llarp::Crypto*, const SecretKey&, llarp::GetRCFunc,
|
||||
llarp::LinkMessageHandler, llarp::SessionEstablishedHandler,
|
||||
llarp::SessionRenegotiateHandler, llarp::SignBufferFunc,
|
||||
llarp::TimeoutHandler, llarp::SessionClosedHandler)
|
||||
{
|
||||
// TODO: implement me
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace iwp
|
||||
} // namespace llarp
|
@ -0,0 +1,25 @@
|
||||
#ifndef LLARP_LINK_IWP_HPP
|
||||
#define LLARP_LINK_IWP_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <link/server.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace iwp
|
||||
{
|
||||
std::unique_ptr< ILinkLayer >
|
||||
NewServer(llarp::Crypto* crypto, const SecretKey& routerEncSecret,
|
||||
llarp::GetRCFunc getrc, llarp::LinkMessageHandler h,
|
||||
llarp::SessionEstablishedHandler est,
|
||||
llarp::SessionRenegotiateHandler reneg,
|
||||
llarp::SignBufferFunc sign, llarp::TimeoutHandler timeout,
|
||||
llarp::SessionClosedHandler closed);
|
||||
|
||||
std::unique_ptr< ILinkLayer >
|
||||
NewServerFromRouter(llarp::Router* r);
|
||||
|
||||
} // namespace iwp
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -0,0 +1,338 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <link/dtls.hpp>
|
||||
#include <messages/link_intro.hpp>
|
||||
#include <messages/discard.hpp>
|
||||
#include <ev.h>
|
||||
|
||||
struct DTLSTest : public ::testing::Test
|
||||
{
|
||||
static constexpr uint16_t AlicePort = 5000;
|
||||
static constexpr uint16_t BobPort = 6000;
|
||||
|
||||
struct Context
|
||||
{
|
||||
Context(llarp::Crypto& c)
|
||||
{
|
||||
crypto = &c;
|
||||
crypto->identity_keygen(signingKey);
|
||||
crypto->encryption_keygen(encryptionKey);
|
||||
rc.pubkey = llarp::seckey_topublic(signingKey);
|
||||
rc.enckey = llarp::seckey_topublic(encryptionKey);
|
||||
}
|
||||
|
||||
llarp::SecretKey signingKey;
|
||||
llarp::SecretKey encryptionKey;
|
||||
|
||||
llarp::RouterContact rc;
|
||||
|
||||
llarp::Crypto* crypto;
|
||||
|
||||
bool gotLIM = false;
|
||||
|
||||
const llarp::RouterContact&
|
||||
GetRC() const
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
llarp::RouterID
|
||||
GetRouterID() const
|
||||
{
|
||||
return rc.pubkey;
|
||||
}
|
||||
|
||||
/// regenerate rc and rotate onion key
|
||||
bool
|
||||
Regen()
|
||||
{
|
||||
crypto->encryption_keygen(encryptionKey);
|
||||
rc.enckey = llarp::seckey_topublic(encryptionKey);
|
||||
return rc.Sign(crypto, signingKey);
|
||||
}
|
||||
|
||||
std::unique_ptr< llarp::ILinkLayer > link;
|
||||
|
||||
static std::string
|
||||
localLoopBack()
|
||||
{
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|
||||
|| (__APPLE__ && __MACH__)
|
||||
return "lo0";
|
||||
#else
|
||||
return "lo";
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
Start(llarp::Logic* logic, llarp_ev_loop* loop, uint16_t port)
|
||||
{
|
||||
if(!link->Configure(loop, localLoopBack(), AF_INET, port))
|
||||
return false;
|
||||
if(!link->GenEphemeralKeys())
|
||||
return false;
|
||||
rc.addrs.emplace_back();
|
||||
if(!link->GetOurAddressInfo(rc.addrs[0]))
|
||||
return false;
|
||||
if(!rc.Sign(crypto, signingKey))
|
||||
return false;
|
||||
return link->Start(logic);
|
||||
}
|
||||
|
||||
void
|
||||
Stop()
|
||||
{
|
||||
link->Stop();
|
||||
}
|
||||
|
||||
void
|
||||
TearDown()
|
||||
{
|
||||
Stop();
|
||||
link.reset();
|
||||
}
|
||||
};
|
||||
|
||||
llarp::Crypto crypto;
|
||||
|
||||
Context Alice;
|
||||
Context Bob;
|
||||
|
||||
bool success = false;
|
||||
|
||||
llarp_ev_loop* netLoop;
|
||||
std::unique_ptr< llarp::Logic > logic;
|
||||
|
||||
llarp_time_t oldRCLifetime;
|
||||
|
||||
DTLSTest()
|
||||
: crypto(llarp::Crypto::sodium{})
|
||||
, Alice(crypto)
|
||||
, Bob(crypto)
|
||||
, netLoop(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SetUp()
|
||||
{
|
||||
oldRCLifetime = llarp::RouterContact::Lifetime;
|
||||
llarp::RouterContact::IgnoreBogons = true;
|
||||
llarp::RouterContact::Lifetime = 500;
|
||||
llarp_ev_loop_alloc(&netLoop);
|
||||
logic.reset(new llarp::Logic());
|
||||
}
|
||||
|
||||
void
|
||||
TearDown()
|
||||
{
|
||||
Alice.TearDown();
|
||||
Bob.TearDown();
|
||||
logic.reset();
|
||||
llarp_ev_loop_free(&netLoop);
|
||||
llarp::RouterContact::IgnoreBogons = false;
|
||||
llarp::RouterContact::Lifetime = oldRCLifetime;
|
||||
}
|
||||
|
||||
static void
|
||||
OnTimeout(void* u, uint64_t, uint64_t left)
|
||||
{
|
||||
if(left)
|
||||
return;
|
||||
static_cast< DTLSTest* >(u)->Stop();
|
||||
}
|
||||
|
||||
void
|
||||
RunMainloop()
|
||||
{
|
||||
logic->call_later({5000, this, &OnTimeout});
|
||||
llarp_ev_loop_run_single_process(netLoop, logic->thread, logic.get());
|
||||
}
|
||||
|
||||
void
|
||||
Stop()
|
||||
{
|
||||
llarp_ev_loop_stop(netLoop);
|
||||
}
|
||||
|
||||
bool AliceGotMessage(llarp_buffer_t)
|
||||
{
|
||||
success = true;
|
||||
Stop();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(DTLSTest, TestAliceRenegWithBob)
|
||||
{
|
||||
Alice.link = llarp::dtls::NewServer(
|
||||
&crypto, Alice.encryptionKey, Alice.signingKey,
|
||||
[&]() -> const llarp::RouterContact& { return Alice.GetRC(); },
|
||||
[&](llarp::ILinkSession* s, llarp_buffer_t buf) -> bool {
|
||||
if(Alice.gotLIM)
|
||||
{
|
||||
Alice.Regen();
|
||||
return s->RenegotiateSession();
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LinkIntroMessage msg;
|
||||
if(!msg.BDecode(&buf))
|
||||
return false;
|
||||
if(!s->GotLIM(&msg))
|
||||
return false;
|
||||
Alice.gotLIM = true;
|
||||
return true;
|
||||
}
|
||||
},
|
||||
[&](llarp::RouterContact rc) {
|
||||
ASSERT_EQ(rc, Bob.GetRC());
|
||||
llarp::LogInfo("alice established with bob");
|
||||
},
|
||||
[&](llarp::RouterContact, llarp::RouterContact) -> bool { return true; },
|
||||
[&](llarp::Signature& sig, llarp_buffer_t buf) -> bool {
|
||||
return crypto.sign(sig, Alice.signingKey, buf);
|
||||
},
|
||||
[&](llarp::ILinkSession* session) {
|
||||
ASSERT_FALSE(session->IsEstablished());
|
||||
Stop();
|
||||
},
|
||||
[&](llarp::RouterID router) { ASSERT_EQ(router, Bob.GetRouterID()); });
|
||||
|
||||
auto sendDiscardMessage = [](llarp::ILinkSession* s) -> bool {
|
||||
// send discard message in reply to complete unit test
|
||||
byte_t tmp[32] = {0};
|
||||
auto otherBuf = llarp::StackBuffer< decltype(tmp) >(tmp);
|
||||
llarp::DiscardMessage discard;
|
||||
if(!discard.BEncode(&otherBuf))
|
||||
return false;
|
||||
otherBuf.sz = otherBuf.cur - otherBuf.base;
|
||||
otherBuf.cur = otherBuf.base;
|
||||
return s->SendMessageBuffer(otherBuf);
|
||||
};
|
||||
|
||||
Bob.link = llarp::dtls::NewServer(
|
||||
&crypto, Bob.encryptionKey, Bob.signingKey,
|
||||
[&]() -> const llarp::RouterContact& { return Bob.GetRC(); },
|
||||
[&](llarp::ILinkSession* s, llarp_buffer_t buf) -> bool {
|
||||
llarp::LinkIntroMessage msg;
|
||||
if(!msg.BDecode(&buf))
|
||||
return false;
|
||||
if(!s->GotLIM(&msg))
|
||||
return false;
|
||||
Bob.gotLIM = true;
|
||||
return sendDiscardMessage(s);
|
||||
},
|
||||
[&](llarp::RouterContact rc) {
|
||||
ASSERT_EQ(rc, Alice.GetRC());
|
||||
llarp::LogInfo("bob established with alice");
|
||||
Bob.link->VisitSessionByPubkey(Alice.GetRC().pubkey.as_array(),
|
||||
sendDiscardMessage);
|
||||
},
|
||||
[&](llarp::RouterContact newrc, llarp::RouterContact oldrc) -> bool {
|
||||
success = newrc.pubkey == oldrc.pubkey;
|
||||
return true;
|
||||
},
|
||||
[&](llarp::Signature& sig, llarp_buffer_t buf) -> bool {
|
||||
return crypto.sign(sig, Bob.signingKey, buf);
|
||||
},
|
||||
[&](llarp::ILinkSession* session) {
|
||||
ASSERT_FALSE(session->IsEstablished());
|
||||
},
|
||||
[&](llarp::RouterID router) { ASSERT_EQ(router, Alice.GetRouterID()); });
|
||||
|
||||
ASSERT_TRUE(Alice.Start(logic.get(), netLoop, AlicePort));
|
||||
ASSERT_TRUE(Bob.Start(logic.get(), netLoop, BobPort));
|
||||
|
||||
ASSERT_TRUE(Alice.link->TryEstablishTo(Bob.GetRC()));
|
||||
|
||||
RunMainloop();
|
||||
ASSERT_TRUE(Alice.gotLIM);
|
||||
ASSERT_TRUE(Bob.gotLIM);
|
||||
ASSERT_TRUE(success);
|
||||
}
|
||||
|
||||
TEST_F(DTLSTest, TestAliceConnectToBob)
|
||||
{
|
||||
Alice.link = llarp::dtls::NewServer(
|
||||
&crypto, Alice.encryptionKey, Alice.signingKey,
|
||||
[&]() -> const llarp::RouterContact& { return Alice.GetRC(); },
|
||||
[&](llarp::ILinkSession* s, llarp_buffer_t buf) -> bool {
|
||||
if(Alice.gotLIM)
|
||||
{
|
||||
return AliceGotMessage(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LinkIntroMessage msg;
|
||||
if(!msg.BDecode(&buf))
|
||||
return false;
|
||||
if(!s->GotLIM(&msg))
|
||||
return false;
|
||||
Alice.gotLIM = true;
|
||||
return true;
|
||||
}
|
||||
},
|
||||
[&](llarp::RouterContact rc) {
|
||||
ASSERT_EQ(rc, Bob.GetRC());
|
||||
llarp::LogInfo("alice established with bob");
|
||||
},
|
||||
[&](llarp::RouterContact, llarp::RouterContact) -> bool { return true; },
|
||||
[&](llarp::Signature& sig, llarp_buffer_t buf) -> bool {
|
||||
return crypto.sign(sig, Alice.signingKey, buf);
|
||||
},
|
||||
[&](llarp::ILinkSession* session) {
|
||||
ASSERT_FALSE(session->IsEstablished());
|
||||
Stop();
|
||||
},
|
||||
[&](llarp::RouterID router) { ASSERT_EQ(router, Bob.GetRouterID()); });
|
||||
|
||||
auto sendDiscardMessage = [](llarp::ILinkSession* s) -> bool {
|
||||
// send discard message in reply to complete unit test
|
||||
byte_t tmp[32] = {0};
|
||||
auto otherBuf = llarp::StackBuffer< decltype(tmp) >(tmp);
|
||||
llarp::DiscardMessage discard;
|
||||
if(!discard.BEncode(&otherBuf))
|
||||
return false;
|
||||
otherBuf.sz = otherBuf.cur - otherBuf.base;
|
||||
otherBuf.cur = otherBuf.base;
|
||||
return s->SendMessageBuffer(otherBuf);
|
||||
};
|
||||
|
||||
Bob.link = llarp::dtls::NewServer(
|
||||
&crypto, Bob.encryptionKey, Bob.signingKey,
|
||||
[&]() -> const llarp::RouterContact& { return Bob.GetRC(); },
|
||||
[&](llarp::ILinkSession* s, llarp_buffer_t buf) -> bool {
|
||||
llarp::LinkIntroMessage msg;
|
||||
if(!msg.BDecode(&buf))
|
||||
return false;
|
||||
if(!s->GotLIM(&msg))
|
||||
return false;
|
||||
Bob.gotLIM = true;
|
||||
return true;
|
||||
},
|
||||
[&](llarp::RouterContact rc) {
|
||||
ASSERT_EQ(rc, Alice.GetRC());
|
||||
llarp::LogInfo("bob established with alice");
|
||||
Bob.link->VisitSessionByPubkey(Alice.GetRC().pubkey.as_array(),
|
||||
sendDiscardMessage);
|
||||
},
|
||||
[&](llarp::RouterContact, llarp::RouterContact) -> bool { return true; },
|
||||
[&](llarp::Signature& sig, llarp_buffer_t buf) -> bool {
|
||||
return crypto.sign(sig, Bob.signingKey, buf);
|
||||
},
|
||||
|
||||
[&](llarp::ILinkSession* session) {
|
||||
ASSERT_FALSE(session->IsEstablished());
|
||||
},
|
||||
[&](llarp::RouterID router) { ASSERT_EQ(router, Alice.GetRouterID()); });
|
||||
|
||||
ASSERT_TRUE(Alice.Start(logic.get(), netLoop, AlicePort));
|
||||
ASSERT_TRUE(Bob.Start(logic.get(), netLoop, BobPort));
|
||||
|
||||
ASSERT_TRUE(Alice.link->TryEstablishTo(Bob.GetRC()));
|
||||
|
||||
RunMainloop();
|
||||
ASSERT_TRUE(Alice.gotLIM);
|
||||
ASSERT_TRUE(Bob.gotLIM);
|
||||
ASSERT_TRUE(success);
|
||||
}
|
@ -0,0 +1,426 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <link/utp.hpp>
|
||||
#include <link/iwp.hpp>
|
||||
#include <messages/link_intro.hpp>
|
||||
#include <messages/discard.hpp>
|
||||
#include <ev.h>
|
||||
|
||||
struct LinkLayerTest : public ::testing::Test
|
||||
{
|
||||
static constexpr uint16_t AlicePort = 5000;
|
||||
static constexpr uint16_t BobPort = 6000;
|
||||
|
||||
struct Context
|
||||
{
|
||||
Context(llarp::Crypto& c)
|
||||
{
|
||||
crypto = &c;
|
||||
crypto->identity_keygen(signingKey);
|
||||
crypto->encryption_keygen(encryptionKey);
|
||||
rc.pubkey = llarp::seckey_topublic(signingKey);
|
||||
rc.enckey = llarp::seckey_topublic(encryptionKey);
|
||||
}
|
||||
|
||||
llarp::SecretKey signingKey;
|
||||
llarp::SecretKey encryptionKey;
|
||||
|
||||
llarp::RouterContact rc;
|
||||
|
||||
llarp::Crypto* crypto;
|
||||
|
||||
bool gotLIM = false;
|
||||
|
||||
const llarp::RouterContact&
|
||||
GetRC() const
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
llarp::RouterID
|
||||
GetRouterID() const
|
||||
{
|
||||
return rc.pubkey;
|
||||
}
|
||||
|
||||
/// regenerate rc and rotate onion key
|
||||
bool
|
||||
Regen()
|
||||
{
|
||||
crypto->encryption_keygen(encryptionKey);
|
||||
rc.enckey = llarp::seckey_topublic(encryptionKey);
|
||||
return rc.Sign(crypto, signingKey);
|
||||
}
|
||||
|
||||
std::unique_ptr< llarp::ILinkLayer > link;
|
||||
|
||||
static std::string
|
||||
localLoopBack()
|
||||
{
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|
||||
|| (__APPLE__ && __MACH__)
|
||||
return "lo0";
|
||||
#else
|
||||
return "lo";
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
Start(llarp::Logic* logic, llarp_ev_loop* loop, uint16_t port)
|
||||
{
|
||||
if(!link)
|
||||
return false;
|
||||
if(!link->Configure(loop, localLoopBack(), AF_INET, port))
|
||||
return false;
|
||||
if(!link->GenEphemeralKeys())
|
||||
return false;
|
||||
rc.addrs.emplace_back();
|
||||
if(!link->GetOurAddressInfo(rc.addrs[0]))
|
||||
return false;
|
||||
if(!rc.Sign(crypto, signingKey))
|
||||
return false;
|
||||
return link->Start(logic);
|
||||
}
|
||||
|
||||
void
|
||||
Stop()
|
||||
{
|
||||
if(link)
|
||||
link->Stop();
|
||||
}
|
||||
|
||||
void
|
||||
TearDown()
|
||||
{
|
||||
Stop();
|
||||
link.reset();
|
||||
}
|
||||
};
|
||||
|
||||
llarp::Crypto crypto;
|
||||
|
||||
Context Alice;
|
||||
Context Bob;
|
||||
|
||||
bool success = false;
|
||||
|
||||
llarp_ev_loop* netLoop;
|
||||
std::unique_ptr< llarp::Logic > logic;
|
||||
|
||||
llarp_time_t oldRCLifetime;
|
||||
|
||||
LinkLayerTest()
|
||||
: crypto(llarp::Crypto::sodium{})
|
||||
, Alice(crypto)
|
||||
, Bob(crypto)
|
||||
, netLoop(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SetUp()
|
||||
{
|
||||
oldRCLifetime = llarp::RouterContact::Lifetime;
|
||||
llarp::RouterContact::IgnoreBogons = true;
|
||||
llarp::RouterContact::Lifetime = 500;
|
||||
llarp_ev_loop_alloc(&netLoop);
|
||||
logic.reset(new llarp::Logic());
|
||||
}
|
||||
|
||||
void
|
||||
TearDown()
|
||||
{
|
||||
Alice.TearDown();
|
||||
Bob.TearDown();
|
||||
logic.reset();
|
||||
llarp_ev_loop_free(&netLoop);
|
||||
llarp::RouterContact::IgnoreBogons = false;
|
||||
llarp::RouterContact::Lifetime = oldRCLifetime;
|
||||
}
|
||||
|
||||
static void
|
||||
OnTimeout(void* u, uint64_t, uint64_t left)
|
||||
{
|
||||
if(left)
|
||||
return;
|
||||
static_cast< LinkLayerTest* >(u)->Stop();
|
||||
}
|
||||
|
||||
void
|
||||
RunMainloop()
|
||||
{
|
||||
logic->call_later({5000, this, &OnTimeout});
|
||||
llarp_ev_loop_run_single_process(netLoop, logic->thread, logic.get());
|
||||
}
|
||||
|
||||
void
|
||||
Stop()
|
||||
{
|
||||
llarp_ev_loop_stop(netLoop);
|
||||
}
|
||||
|
||||
bool AliceGotMessage(llarp_buffer_t)
|
||||
{
|
||||
success = true;
|
||||
Stop();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(LinkLayerTest, TestUTPAliceRenegWithBob)
|
||||
{
|
||||
Alice.link = llarp::utp::NewServer(
|
||||
&crypto, Alice.encryptionKey,
|
||||
[&]() -> const llarp::RouterContact& { return Alice.GetRC(); },
|
||||
[&](llarp::ILinkSession* s, llarp_buffer_t buf) -> bool {
|
||||
if(Alice.gotLIM)
|
||||
{
|
||||
Alice.Regen();
|
||||
return s->RenegotiateSession();
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LinkIntroMessage msg;
|
||||
if(!msg.BDecode(&buf))
|
||||
return false;
|
||||
if(!s->GotLIM(&msg))
|
||||
return false;
|
||||
Alice.gotLIM = true;
|
||||
return true;
|
||||
}
|
||||
},
|
||||
[&](llarp::RouterContact rc) {
|
||||
ASSERT_EQ(rc, Bob.GetRC());
|
||||
llarp::LogInfo("alice established with bob");
|
||||
},
|
||||
[&](llarp::RouterContact, llarp::RouterContact) -> bool { return true; },
|
||||
[&](llarp::Signature& sig, llarp_buffer_t buf) -> bool {
|
||||
return crypto.sign(sig, Alice.signingKey, buf);
|
||||
},
|
||||
[&](llarp::ILinkSession* session) {
|
||||
ASSERT_FALSE(session->IsEstablished());
|
||||
Stop();
|
||||
},
|
||||
[&](llarp::RouterID router) { ASSERT_EQ(router, Bob.GetRouterID()); });
|
||||
|
||||
auto sendDiscardMessage = [](llarp::ILinkSession* s) -> bool {
|
||||
// send discard message in reply to complete unit test
|
||||
byte_t tmp[32] = {0};
|
||||
auto otherBuf = llarp::StackBuffer< decltype(tmp) >(tmp);
|
||||
llarp::DiscardMessage discard;
|
||||
if(!discard.BEncode(&otherBuf))
|
||||
return false;
|
||||
otherBuf.sz = otherBuf.cur - otherBuf.base;
|
||||
otherBuf.cur = otherBuf.base;
|
||||
return s->SendMessageBuffer(otherBuf);
|
||||
};
|
||||
|
||||
Bob.link = llarp::utp::NewServer(
|
||||
&crypto, Bob.encryptionKey,
|
||||
[&]() -> const llarp::RouterContact& { return Bob.GetRC(); },
|
||||
[&](llarp::ILinkSession* s, llarp_buffer_t buf) -> bool {
|
||||
llarp::LinkIntroMessage msg;
|
||||
if(!msg.BDecode(&buf))
|
||||
return false;
|
||||
if(!s->GotLIM(&msg))
|
||||
return false;
|
||||
Bob.gotLIM = true;
|
||||
return sendDiscardMessage(s);
|
||||
},
|
||||
[&](llarp::RouterContact rc) {
|
||||
ASSERT_EQ(rc, Alice.GetRC());
|
||||
llarp::LogInfo("bob established with alice");
|
||||
Bob.link->VisitSessionByPubkey(Alice.GetRC().pubkey.as_array(),
|
||||
sendDiscardMessage);
|
||||
},
|
||||
[&](llarp::RouterContact newrc, llarp::RouterContact oldrc) -> bool {
|
||||
success = newrc.pubkey == oldrc.pubkey;
|
||||
return true;
|
||||
},
|
||||
[&](llarp::Signature& sig, llarp_buffer_t buf) -> bool {
|
||||
return crypto.sign(sig, Bob.signingKey, buf);
|
||||
},
|
||||
[&](llarp::ILinkSession* session) {
|
||||
ASSERT_FALSE(session->IsEstablished());
|
||||
},
|
||||
[&](llarp::RouterID router) { ASSERT_EQ(router, Alice.GetRouterID()); });
|
||||
|
||||
ASSERT_TRUE(Alice.Start(logic.get(), netLoop, AlicePort));
|
||||
ASSERT_TRUE(Bob.Start(logic.get(), netLoop, BobPort));
|
||||
|
||||
ASSERT_TRUE(Alice.link->TryEstablishTo(Bob.GetRC()));
|
||||
|
||||
RunMainloop();
|
||||
ASSERT_TRUE(Alice.gotLIM);
|
||||
ASSERT_TRUE(Bob.gotLIM);
|
||||
ASSERT_TRUE(success);
|
||||
}
|
||||
|
||||
TEST_F(LinkLayerTest, TestUTPAliceConnectToBob)
|
||||
{
|
||||
Alice.link = llarp::utp::NewServer(
|
||||
&crypto, Alice.encryptionKey,
|
||||
[&]() -> const llarp::RouterContact& { return Alice.GetRC(); },
|
||||
[&](llarp::ILinkSession* s, llarp_buffer_t buf) -> bool {
|
||||
if(Alice.gotLIM)
|
||||
{
|
||||
return AliceGotMessage(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LinkIntroMessage msg;
|
||||
if(!msg.BDecode(&buf))
|
||||
return false;
|
||||
if(!s->GotLIM(&msg))
|
||||
return false;
|
||||
Alice.gotLIM = true;
|
||||
return true;
|
||||
}
|
||||
},
|
||||
[&](llarp::RouterContact rc) {
|
||||
ASSERT_EQ(rc, Bob.GetRC());
|
||||
llarp::LogInfo("alice established with bob");
|
||||
},
|
||||
[&](llarp::RouterContact, llarp::RouterContact) -> bool { return true; },
|
||||
[&](llarp::Signature& sig, llarp_buffer_t buf) -> bool {
|
||||
return crypto.sign(sig, Alice.signingKey, buf);
|
||||
},
|
||||
[&](llarp::ILinkSession* session) {
|
||||
ASSERT_FALSE(session->IsEstablished());
|
||||
Stop();
|
||||
},
|
||||
[&](llarp::RouterID router) { ASSERT_EQ(router, Bob.GetRouterID()); });
|
||||
|
||||
auto sendDiscardMessage = [](llarp::ILinkSession* s) -> bool {
|
||||
// send discard message in reply to complete unit test
|
||||
byte_t tmp[32] = {0};
|
||||
auto otherBuf = llarp::StackBuffer< decltype(tmp) >(tmp);
|
||||
llarp::DiscardMessage discard;
|
||||
if(!discard.BEncode(&otherBuf))
|
||||
return false;
|
||||
otherBuf.sz = otherBuf.cur - otherBuf.base;
|
||||
otherBuf.cur = otherBuf.base;
|
||||
return s->SendMessageBuffer(otherBuf);
|
||||
};
|
||||
|
||||
Bob.link = llarp::utp::NewServer(
|
||||
&crypto, Bob.encryptionKey,
|
||||
[&]() -> const llarp::RouterContact& { return Bob.GetRC(); },
|
||||
[&](llarp::ILinkSession* s, llarp_buffer_t buf) -> bool {
|
||||
llarp::LinkIntroMessage msg;
|
||||
if(!msg.BDecode(&buf))
|
||||
return false;
|
||||
if(!s->GotLIM(&msg))
|
||||
return false;
|
||||
Bob.gotLIM = true;
|
||||
return true;
|
||||
},
|
||||
[&](llarp::RouterContact rc) {
|
||||
ASSERT_EQ(rc, Alice.GetRC());
|
||||
llarp::LogInfo("bob established with alice");
|
||||
Bob.link->VisitSessionByPubkey(Alice.GetRC().pubkey.as_array(),
|
||||
sendDiscardMessage);
|
||||
},
|
||||
[&](llarp::RouterContact, llarp::RouterContact) -> bool { return true; },
|
||||
[&](llarp::Signature& sig, llarp_buffer_t buf) -> bool {
|
||||
return crypto.sign(sig, Bob.signingKey, buf);
|
||||
},
|
||||
[&](llarp::ILinkSession* session) {
|
||||
ASSERT_FALSE(session->IsEstablished());
|
||||
},
|
||||
[&](llarp::RouterID router) { ASSERT_EQ(router, Alice.GetRouterID()); });
|
||||
|
||||
ASSERT_TRUE(Alice.Start(logic.get(), netLoop, AlicePort));
|
||||
ASSERT_TRUE(Bob.Start(logic.get(), netLoop, BobPort));
|
||||
|
||||
ASSERT_TRUE(Alice.link->TryEstablishTo(Bob.GetRC()));
|
||||
|
||||
RunMainloop();
|
||||
ASSERT_TRUE(Alice.gotLIM);
|
||||
ASSERT_TRUE(Bob.gotLIM);
|
||||
ASSERT_TRUE(success);
|
||||
}
|
||||
|
||||
TEST_F(LinkLayerTest, TestIWPAliceConnectToBob)
|
||||
{
|
||||
Alice.link = llarp::iwp::NewServer(
|
||||
&crypto, Alice.encryptionKey,
|
||||
[&]() -> const llarp::RouterContact& { return Alice.GetRC(); },
|
||||
[&](llarp::ILinkSession* s, llarp_buffer_t buf) -> bool {
|
||||
if(Alice.gotLIM)
|
||||
{
|
||||
return AliceGotMessage(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LinkIntroMessage msg;
|
||||
if(!msg.BDecode(&buf))
|
||||
return false;
|
||||
if(!s->GotLIM(&msg))
|
||||
return false;
|
||||
Alice.gotLIM = true;
|
||||
return true;
|
||||
}
|
||||
},
|
||||
[&](llarp::RouterContact rc) {
|
||||
ASSERT_EQ(rc, Bob.GetRC());
|
||||
llarp::LogInfo("alice established with bob");
|
||||
},
|
||||
[&](llarp::RouterContact, llarp::RouterContact) -> bool { return true; },
|
||||
[&](llarp::Signature& sig, llarp_buffer_t buf) -> bool {
|
||||
return crypto.sign(sig, Alice.signingKey, buf);
|
||||
},
|
||||
[&](llarp::ILinkSession* session) {
|
||||
ASSERT_FALSE(session->IsEstablished());
|
||||
Stop();
|
||||
},
|
||||
[&](llarp::RouterID router) { ASSERT_EQ(router, Bob.GetRouterID()); });
|
||||
|
||||
auto sendDiscardMessage = [](llarp::ILinkSession* s) -> bool {
|
||||
// send discard message in reply to complete unit test
|
||||
byte_t tmp[32] = {0};
|
||||
auto otherBuf = llarp::StackBuffer< decltype(tmp) >(tmp);
|
||||
llarp::DiscardMessage discard;
|
||||
if(!discard.BEncode(&otherBuf))
|
||||
return false;
|
||||
otherBuf.sz = otherBuf.cur - otherBuf.base;
|
||||
otherBuf.cur = otherBuf.base;
|
||||
return s->SendMessageBuffer(otherBuf);
|
||||
};
|
||||
|
||||
Bob.link = llarp::iwp::NewServer(
|
||||
&crypto, Bob.encryptionKey,
|
||||
[&]() -> const llarp::RouterContact& { return Bob.GetRC(); },
|
||||
[&](llarp::ILinkSession* s, llarp_buffer_t buf) -> bool {
|
||||
llarp::LinkIntroMessage msg;
|
||||
if(!msg.BDecode(&buf))
|
||||
return false;
|
||||
if(!s->GotLIM(&msg))
|
||||
return false;
|
||||
Bob.gotLIM = true;
|
||||
return true;
|
||||
},
|
||||
[&](llarp::RouterContact rc) {
|
||||
ASSERT_EQ(rc, Alice.GetRC());
|
||||
llarp::LogInfo("bob established with alice");
|
||||
Bob.link->VisitSessionByPubkey(Alice.GetRC().pubkey.as_array(),
|
||||
sendDiscardMessage);
|
||||
},
|
||||
[&](llarp::RouterContact, llarp::RouterContact) -> bool { return true; },
|
||||
[&](llarp::Signature& sig, llarp_buffer_t buf) -> bool {
|
||||
return crypto.sign(sig, Bob.signingKey, buf);
|
||||
},
|
||||
[&](llarp::ILinkSession* session) {
|
||||
ASSERT_FALSE(session->IsEstablished());
|
||||
},
|
||||
[&](llarp::RouterID router) { ASSERT_EQ(router, Alice.GetRouterID()); });
|
||||
|
||||
ASSERT_TRUE(Alice.Start(logic.get(), netLoop, AlicePort));
|
||||
ASSERT_TRUE(Bob.Start(logic.get(), netLoop, BobPort));
|
||||
|
||||
ASSERT_TRUE(Alice.link->TryEstablishTo(Bob.GetRC()));
|
||||
|
||||
RunMainloop();
|
||||
ASSERT_TRUE(Alice.gotLIM);
|
||||
ASSERT_TRUE(Bob.gotLIM);
|
||||
ASSERT_TRUE(success);
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
struct DTLSTest : public ::testing::Test
|
||||
{
|
||||
};
|
||||
|
||||
TEST_F(DTLSTest, TestAliceConnectToBob)
|
||||
{
|
||||
}
|
Loading…
Reference in New Issue