mirror of https://github.com/oxen-io/lokinet
more work
This commit is contained in:
parent
593e2ddac6
commit
e88c39b9e2
|
@ -177,6 +177,7 @@ if(JEMALLOC)
|
|||
set(MALLOC_LIB jemalloc)
|
||||
endif(JEMALLOC)
|
||||
|
||||
|
||||
# FS_LIB should resolve to nothing on all other platforms
|
||||
# it is only required on win32 -rick
|
||||
set(LIBS ${LIBS} ${MALLOC_LIB} ${FS_LIB})
|
||||
|
@ -517,10 +518,9 @@ set(LIB_SRC
|
|||
llarp/handlers/tun.cpp
|
||||
llarp/ini.cpp
|
||||
llarp/ip.cpp
|
||||
llarp/iwp.cpp
|
||||
llarp/link/curvecp.cpp
|
||||
llarp/link/dtls.cpp
|
||||
llarp/link/encoder.cpp
|
||||
llarp/link/iwp.cpp
|
||||
llarp/link/server.cpp
|
||||
llarp/link/session.cpp
|
||||
llarp/link/utp.cpp
|
||||
|
@ -613,7 +613,7 @@ set(TEST_SRC
|
|||
test/obtain_exit_unittest.cpp
|
||||
test/pq_unittest.cpp
|
||||
test/net_unittest.cpp
|
||||
test/utp_unittest.cpp
|
||||
test/link_layer_unittest.cpp
|
||||
test/test_dns_unit.cpp
|
||||
test/test_dnsc_unit.cpp
|
||||
test/test_dnsd_unit.cpp
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -300,6 +300,7 @@ the RC.a matching the ipv6 address it originated from.
|
|||
|
||||
{
|
||||
a: "i",
|
||||
e: "<32 bytes ephemeral public encryption key>",
|
||||
n: "<32 bytes nonce for key exhcange>",
|
||||
p: uint64_milliseconds_session_period,
|
||||
r: RC,
|
||||
|
|
|
@ -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]
|
||||
|
||||
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
|
||||
LLARP supports by default an authenticated message transport over a
|
||||
datagram based network layer.
|
||||
|
||||
|
||||
after every fragment F the session key K is mutated via:
|
||||
outer message format:
|
||||
|
||||
K = HS(K + P.A)
|
||||
{
|
||||
A: command,
|
||||
B: <16 bytes flow id>,
|
||||
C: <optional 32 bytes cookie>,
|
||||
X: <N bytes payload>
|
||||
}
|
||||
|
||||
Periodically the connection initiator MUST renegotiate the session key by
|
||||
sending a LIM after L.p milliseconds have elapsed.
|
||||
comamnds:
|
||||
|
||||
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.
|
||||
A - get handshake cookie
|
||||
|
||||
obtain a handshake cookie
|
||||
|
||||
B is randomized
|
||||
X MUST contain the user agent string of the requester.
|
||||
|
||||
the if the network id differs from the current network's id a reject message is
|
||||
sent:
|
||||
|
||||
{
|
||||
A: R,
|
||||
B: msg.B,
|
||||
X: "<reply line>"
|
||||
}
|
||||
|
||||
MUST be replied to with a message rejected or a give handshake cookie
|
||||
|
||||
C - give handshake cookie
|
||||
|
||||
give a handshake cookie to a remote endpoint that asks for one
|
||||
|
||||
B is the B value from the get handshake cookie message
|
||||
X is a 32 byte handshake cookie, calcuated via:
|
||||
|
||||
r = RAND(32)
|
||||
a = "<ascii representation of ip>" + " " + "<port number>"
|
||||
X = HS(a + B + r)
|
||||
|
||||
R - message rejected
|
||||
|
||||
B is the flow id from the recipiant
|
||||
X is a reply line
|
||||
|
||||
reject a message with flow id B
|
||||
|
||||
S - session negotiation
|
||||
|
||||
negotiate encrypted session
|
||||
|
||||
B is the flow id from the recipiant
|
||||
C is the handshake cookie
|
||||
X is encrypted session negotiation data
|
||||
|
||||
D - encrypted data transmission
|
||||
|
||||
transmit encrypted data on session
|
||||
|
||||
B is the flow id from the recipiant
|
||||
X is authenticated and encrypted data
|
||||
|
||||
BNF:
|
||||
|
||||
<reply-line> ::= <status-code> <space> <method> <space> <message>
|
||||
|
||||
<status-code> ::= <integer> <digit> <digit>
|
||||
|
||||
<word> ::= <letter>+
|
||||
|
||||
<message> ::= <word> <space> <word>* | <word>
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
references:
|
||||
session negotiation:
|
||||
|
||||
[1] http://www.bittorrent.org/beps/bep_0029.html
|
||||
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
|
|
@ -1,20 +1,15 @@
|
|||
#ifndef LLARP_LINK_DTLS_INTERNAL_HPP
|
||||
#define LLARP_LINK_DTLS_INTERNAL_HPP
|
||||
#ifndef LLARP_LINK_IWP_INTERNAL_HPP
|
||||
#define LLARP_LINK_IWP_INTERNAL_HPP
|
||||
#include <link/server.hpp>
|
||||
#include <link/session.hpp>
|
||||
#include <link_layer.hpp>
|
||||
|
||||
#include <mbedtls/ssl_internal.h>
|
||||
#include <mbedtls/ecp.h>
|
||||
#include <mbedtls/md.h>
|
||||
#include <mbedtls/x509.h>
|
||||
|
||||
#include <bitset>
|
||||
#include <deque>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dtls
|
||||
namespace iwp
|
||||
{
|
||||
struct LinkLayer;
|
||||
|
||||
|
@ -33,10 +28,15 @@ namespace llarp
|
|||
PumpIO();
|
||||
|
||||
void
|
||||
TickIO();
|
||||
TickIO(llarp_time_t now);
|
||||
|
||||
bool
|
||||
QueueBuffer(llarp_buffer_t buf);
|
||||
QueueMessageBuffer(llarp_buffer_t buf);
|
||||
|
||||
/// return true if the session is established and handshaked and all that
|
||||
/// jazz
|
||||
bool
|
||||
SessionIsEstablished();
|
||||
|
||||
/// inbound start
|
||||
void
|
||||
|
@ -53,22 +53,16 @@ namespace llarp
|
|||
void
|
||||
Configure();
|
||||
|
||||
/// ll recv
|
||||
/// low level recv
|
||||
void
|
||||
Recv_ll(const void *buf, size_t sz);
|
||||
|
||||
static int
|
||||
ssl_recv(void *ctx, unsigned char *buf, size_t sz);
|
||||
/// verify a lim
|
||||
bool
|
||||
VerfiyLIM(const llarp::LinkIntroMessage *msg);
|
||||
|
||||
static int
|
||||
ssl_send(void *ctx, const unsigned char *buf, size_t sz);
|
||||
|
||||
static void
|
||||
Debug(void *ctx, int lvl, const char *fname, int lineno, const char *msg);
|
||||
|
||||
mbedtls_ssl_config m_config;
|
||||
mbedtls_ssl_context m_ctx;
|
||||
mbedtls_ssl_session m_session;
|
||||
SharedSecret m_TXKey;
|
||||
SharedSecret m_RXKey;
|
||||
LinkLayer *m_Parent;
|
||||
llarp::Crypto *const crypto;
|
||||
llarp::RouterContact remoteRC;
|
||||
|
@ -227,9 +221,11 @@ namespace llarp
|
|||
return now > lastActiveAt && now - lastActiveAt > 500;
|
||||
}
|
||||
|
||||
template < typename write_pkt_func >
|
||||
bool
|
||||
TransmitUnacked(mbedtls_ssl_context *ctx, Seqno_t seqno) const
|
||||
TransmitUnacked(write_pkt_func write_pkt, Seqno_t seqno) const
|
||||
{
|
||||
static FragLen_t maxfragsize = fragsize;
|
||||
FragmentHeader hdr;
|
||||
hdr.seqno = seqno;
|
||||
hdr.cmd = XMIT;
|
||||
|
@ -240,7 +236,7 @@ namespace llarp
|
|||
FragLen_t len = sz;
|
||||
while(idx < maxfrags)
|
||||
{
|
||||
const FragLen_t l = std::min(len, fragsize);
|
||||
const FragLen_t l = std::min(len, maxfragsize);
|
||||
if(!acks.test(idx))
|
||||
{
|
||||
hdr.fragno = idx;
|
||||
|
@ -250,7 +246,7 @@ namespace llarp
|
|||
buf.sz = buf.cur - buf.base;
|
||||
buf.cur = buf.base;
|
||||
len -= l;
|
||||
if(mbedtls_ssl_write(ctx, buf.base, buf.sz) != int(buf.sz))
|
||||
if(write_pkt(buf.base, buf.sz) != int(buf.sz))
|
||||
return false;
|
||||
}
|
||||
ptr += l;
|
||||
|
@ -263,8 +259,9 @@ namespace llarp
|
|||
return true;
|
||||
}
|
||||
|
||||
template < typename write_pkt_func >
|
||||
bool
|
||||
TransmitAcks(mbedtls_ssl_context *ctx, Seqno_t seqno)
|
||||
TransmitAcks(write_pkt_func write_pkt, Seqno_t seqno)
|
||||
{
|
||||
FragmentHeader hdr;
|
||||
hdr.seqno = seqno;
|
||||
|
@ -283,7 +280,7 @@ namespace llarp
|
|||
auto buf = frag.as_buffer();
|
||||
if(!hdr.Encode(&buf, llarp::InitBuffer(nullptr, 0)))
|
||||
return false;
|
||||
return mbedtls_ssl_write(ctx, buf.base, buf.sz) == int(buf.sz);
|
||||
return write_pkt(buf.base, buf.sz) == int(buf.sz);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -312,11 +309,6 @@ namespace llarp
|
|||
~LinkLayer();
|
||||
llarp::Crypto *const crypto;
|
||||
|
||||
static const mbedtls_ecp_group_id AllowedCurve[2];
|
||||
static const int AllowedHash[2];
|
||||
static const int CipherSuite[2];
|
||||
static const mbedtls_x509_crt_profile X509Profile;
|
||||
|
||||
bool
|
||||
Start(llarp::Logic *l) override;
|
||||
|
||||
|
@ -336,8 +328,6 @@ namespace llarp
|
|||
uint16_t
|
||||
Rank() const override;
|
||||
|
||||
mbedtls_ssl_key_cert ourKeys;
|
||||
|
||||
const byte_t *
|
||||
IndentityKey() const
|
||||
{
|
||||
|
@ -350,6 +340,12 @@ namespace llarp
|
|||
return m_CookieSec;
|
||||
}
|
||||
|
||||
RouterID
|
||||
GetRouterID() const
|
||||
{
|
||||
return m_IdentityKey.toPublic();
|
||||
}
|
||||
|
||||
private:
|
||||
bool
|
||||
SignBuffer(llarp::Signature &sig, llarp_buffer_t buf) const
|
||||
|
@ -363,7 +359,7 @@ namespace llarp
|
|||
void
|
||||
RecvFrom(const llarp::Addr &from, const void *buf, size_t sz) override;
|
||||
};
|
||||
} // namespace dtls
|
||||
} // namespace iwp
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
|
@ -155,6 +155,16 @@ namespace llarp
|
|||
const SecretKey&
|
||||
TransportSecretKey() const;
|
||||
|
||||
bool
|
||||
IsCompatable(const llarp::RouterContact& other) const
|
||||
{
|
||||
const std::string us = Name();
|
||||
for(const auto& ai : other.addrs)
|
||||
if(ai.dialect == us)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
EnsureKeys(const char* fpath);
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace llarp
|
|||
std::function< bool(llarp_time_t) > TimedOut;
|
||||
|
||||
/// get remote public identity key
|
||||
std::function< const PubKey &(void) > GetPubKey;
|
||||
std::function< PubKey(void) > GetPubKey;
|
||||
|
||||
/// get remote address
|
||||
std::function< Addr(void) > GetRemoteEndpoint;
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace llarp
|
|||
namespace utp
|
||||
{
|
||||
std::unique_ptr< ILinkLayer >
|
||||
NewServer(llarp::Crypto* crypto, const byte_t* routerEncSecret,
|
||||
NewServer(llarp::Crypto* crypto, const SecretKey& routerEncSecret,
|
||||
llarp::GetRCFunc getrc, llarp::LinkMessageHandler h,
|
||||
llarp::SessionEstablishedHandler est,
|
||||
llarp::SessionRenegotiateHandler reneg,
|
||||
|
|
229
llarp/router.cpp
229
llarp/router.cpp
|
@ -1,8 +1,8 @@
|
|||
#include <buffer.hpp>
|
||||
#include <encode.hpp>
|
||||
#include <iwp.hpp>
|
||||
#include <link/server.hpp>
|
||||
#include <link/utp.hpp>
|
||||
#include <link/iwp.hpp>
|
||||
#include <link_message.hpp>
|
||||
#include <logger.hpp>
|
||||
#include <net.hpp>
|
||||
|
@ -98,28 +98,6 @@ on_try_connecting(void *u)
|
|||
j->Attempt();
|
||||
}
|
||||
|
||||
bool
|
||||
llarp_router_try_connect(llarp::Router *router,
|
||||
const llarp::RouterContact &remote,
|
||||
uint16_t numretries)
|
||||
{
|
||||
// do we already have a pending job for this remote?
|
||||
if(router->HasPendingConnectJob(remote.pubkey))
|
||||
{
|
||||
llarp::LogDebug("We have pending connect jobs to ", remote.pubkey);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto link = router->outboundLink.get();
|
||||
auto itr = router->pendingEstablishJobs.emplace(
|
||||
remote.pubkey,
|
||||
std::make_unique< TryConnectJob >(remote, link, numretries, router));
|
||||
TryConnectJob *job = itr.first->second.get();
|
||||
// try establishing async
|
||||
router->logic->queue_job({job, &on_try_connecting});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
llarp_findOrCreateIdentity(llarp::Crypto *crypto, const char *fpath,
|
||||
llarp::SecretKey &secretkey)
|
||||
|
@ -182,6 +160,32 @@ llarp_findOrCreateEncryption(llarp::Crypto *crypto, const char *fpath,
|
|||
|
||||
namespace llarp
|
||||
{
|
||||
bool
|
||||
Router::TryConnectAsync(llarp::RouterContact remote, uint16_t numretries)
|
||||
{
|
||||
// do we already have a pending job for this remote?
|
||||
if(HasPendingConnectJob(remote.pubkey))
|
||||
{
|
||||
llarp::LogDebug("We have pending connect jobs to ", remote.pubkey);
|
||||
return false;
|
||||
}
|
||||
|
||||
for(auto &link : outboundLinks)
|
||||
{
|
||||
if(!link->IsCompatable(remote))
|
||||
continue;
|
||||
auto itr = pendingEstablishJobs.emplace(
|
||||
remote.pubkey,
|
||||
std::make_unique< TryConnectJob >(remote, link.get(), numretries,
|
||||
this));
|
||||
TryConnectJob *job = itr.first->second.get();
|
||||
// try establishing async
|
||||
logic->queue_job({job, &on_try_connecting});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Router::OnSessionEstablished(llarp::RouterContact rc)
|
||||
{
|
||||
|
@ -270,12 +274,14 @@ namespace llarp
|
|||
return true;
|
||||
}
|
||||
}
|
||||
if(outboundLink && outboundLink->HasSessionTo(remote))
|
||||
for(const auto &link : outboundLinks)
|
||||
{
|
||||
SendTo(remote, msg, outboundLink.get());
|
||||
return true;
|
||||
if(link->HasSessionTo(remote))
|
||||
{
|
||||
SendTo(remote, msg, link.get());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// no link available
|
||||
|
||||
// this will create an entry in the obmq if it's not already there
|
||||
|
@ -308,7 +314,7 @@ namespace llarp
|
|||
if(nodedb->Get(remote, remoteRC))
|
||||
{
|
||||
// try connecting directly as the rc is loaded from disk
|
||||
llarp_router_try_connect(this, remoteRC, 10);
|
||||
TryConnectAsync(remoteRC, 10);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -334,7 +340,7 @@ namespace llarp
|
|||
if(results[0].Verify(&crypto, Now()))
|
||||
{
|
||||
nodedb->Insert(results[0]);
|
||||
llarp_router_try_connect(this, results[0], 10);
|
||||
TryConnectAsync(results[0], 10);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -345,8 +351,11 @@ namespace llarp
|
|||
Router::ForEachPeer(
|
||||
std::function< void(const llarp::ILinkSession *, bool) > visit) const
|
||||
{
|
||||
outboundLink->ForEachSession(
|
||||
[visit](const llarp::ILinkSession *peer) { visit(peer, true); });
|
||||
for(const auto &link : outboundLinks)
|
||||
{
|
||||
link->ForEachSession(
|
||||
[visit](const llarp::ILinkSession *peer) { visit(peer, true); });
|
||||
}
|
||||
for(const auto &link : inboundLinks)
|
||||
{
|
||||
link->ForEachSession(
|
||||
|
@ -357,8 +366,10 @@ namespace llarp
|
|||
void
|
||||
Router::ForEachPeer(std::function< void(llarp::ILinkSession *) > visit)
|
||||
{
|
||||
outboundLink->ForEachSession(
|
||||
[visit](llarp::ILinkSession *peer) { visit(peer); });
|
||||
for(const auto &link : inboundLinks)
|
||||
{
|
||||
link->ForEachSession([visit](llarp::ILinkSession *peer) { visit(peer); });
|
||||
}
|
||||
for(const auto &link : inboundLinks)
|
||||
{
|
||||
link->ForEachSession([visit](llarp::ILinkSession *peer) { visit(peer); });
|
||||
|
@ -382,7 +393,7 @@ namespace llarp
|
|||
{
|
||||
llarp::LogWarn("failed to store");
|
||||
}
|
||||
if(!llarp_router_try_connect(this, remote, 10))
|
||||
if(!TryConnectAsync(remote, 10))
|
||||
{
|
||||
// or error?
|
||||
llarp::LogWarn("session already made");
|
||||
|
@ -411,7 +422,7 @@ namespace llarp
|
|||
void
|
||||
Router::AddInboundLink(std::unique_ptr< llarp::ILinkLayer > &link)
|
||||
{
|
||||
inboundLinks.push_back(std::move(link));
|
||||
inboundLinks.insert(std::move(link));
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -421,7 +432,7 @@ namespace llarp
|
|||
iter.user = this;
|
||||
iter.visit = llarp::router_iter_config;
|
||||
llarp_config_iter(conf, &iter);
|
||||
if(!InitOutboundLink())
|
||||
if(!InitOutboundLinks())
|
||||
return false;
|
||||
if(!Ready())
|
||||
{
|
||||
|
@ -433,7 +444,7 @@ namespace llarp
|
|||
bool
|
||||
Router::Ready()
|
||||
{
|
||||
return outboundLink != nullptr;
|
||||
return outboundLinks.size() > 0;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -461,7 +472,7 @@ namespace llarp
|
|||
llarp::LogInfo("closing router");
|
||||
llarp_ev_loop_stop(netloop);
|
||||
inboundLinks.clear();
|
||||
outboundLink.reset(nullptr);
|
||||
outboundLinks.clear();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -590,7 +601,7 @@ namespace llarp
|
|||
if(nodedb->Get(remote, rc))
|
||||
{
|
||||
// try connecting async
|
||||
llarp_router_try_connect(this, rc, 5);
|
||||
TryConnectAsync(rc, 5);
|
||||
}
|
||||
else if(IsServiceNode() || !routerProfiling.IsBad(remote))
|
||||
{
|
||||
|
@ -635,7 +646,7 @@ namespace llarp
|
|||
&& lokinetRouters.find(result.pubkey) == lokinetRouters.end())
|
||||
continue;
|
||||
nodedb->Insert(result);
|
||||
llarp_router_try_connect(this, result, 10);
|
||||
TryConnectAsync(result, 10);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -771,7 +782,7 @@ namespace llarp
|
|||
{
|
||||
for(const auto &rc : bootstrapRCList)
|
||||
{
|
||||
llarp_router_try_connect(this, rc, 4);
|
||||
TryConnectAsync(rc, 4);
|
||||
dht->impl.ExploreNetworkVia(dht::Key_t{rc.pubkey});
|
||||
}
|
||||
}
|
||||
|
@ -821,19 +832,17 @@ namespace llarp
|
|||
if(selected->SendTo(remote, buf))
|
||||
return;
|
||||
}
|
||||
bool sent = outboundLink->SendTo(remote, buf);
|
||||
if(!sent)
|
||||
for(const auto &link : outboundLinks)
|
||||
{
|
||||
for(const auto &link : inboundLinks)
|
||||
{
|
||||
if(!sent)
|
||||
{
|
||||
sent = link->SendTo(remote, buf);
|
||||
}
|
||||
}
|
||||
if(link->SendTo(remote, buf))
|
||||
return;
|
||||
}
|
||||
if(!sent)
|
||||
llarp::LogWarn("message to ", remote, " was dropped");
|
||||
for(const auto &link : inboundLinks)
|
||||
{
|
||||
if(link->SendTo(remote, buf))
|
||||
return;
|
||||
}
|
||||
llarp::LogWarn("message to ", remote, " was dropped");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -854,8 +863,11 @@ namespace llarp
|
|||
llarp::ILinkLayer *
|
||||
Router::GetLinkWithSessionByPubkey(const llarp::RouterID &pubkey)
|
||||
{
|
||||
if(outboundLink && outboundLink->HasSessionTo(pubkey))
|
||||
return outboundLink.get();
|
||||
for(const auto &link : outboundLinks)
|
||||
{
|
||||
if(link->HasSessionTo(pubkey))
|
||||
return link.get();
|
||||
}
|
||||
for(const auto &link : inboundLinks)
|
||||
{
|
||||
if(link->HasSessionTo(pubkey))
|
||||
|
@ -995,52 +1007,21 @@ namespace llarp
|
|||
}
|
||||
|
||||
llarp::LogInfo("You have ", inboundLinks.size(), " inbound links");
|
||||
|
||||
llarp::AddressInfo ai;
|
||||
for(const auto &link : inboundLinks)
|
||||
{
|
||||
llarp::AddressInfo addr;
|
||||
if(!link->GetOurAddressInfo(addr))
|
||||
continue;
|
||||
llarp::Addr a(addr);
|
||||
if(this->publicOverride && a.sameAddr(publicAddr))
|
||||
{
|
||||
llarp::LogInfo("Found adapter for public address");
|
||||
}
|
||||
if(!llarp::IsBogon(*a.addr6()))
|
||||
{
|
||||
llarp::LogInfo("Loading Addr: ", a, " into our RC");
|
||||
_rc.addrs.push_back(addr);
|
||||
}
|
||||
};
|
||||
if(this->publicOverride)
|
||||
{
|
||||
llarp::ILinkLayer *link = nullptr;
|
||||
// llarp::LogWarn("Need to load our public IP into RC!");
|
||||
if(inboundLinks.size() == 1)
|
||||
{
|
||||
link = inboundLinks[0].get();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(inboundLinks.size())
|
||||
{
|
||||
link = inboundLinks[0].get();
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"No need to set public ipv4 and port if no external interface "
|
||||
"binds, turning off public override");
|
||||
this->publicOverride = false;
|
||||
link = nullptr;
|
||||
}
|
||||
}
|
||||
if(link && link->GetOurAddressInfo(this->addrInfo))
|
||||
if(link->GetOurAddressInfo(ai))
|
||||
{
|
||||
// override ip and port
|
||||
this->addrInfo.ip = *publicAddr.addr6();
|
||||
this->addrInfo.port = publicAddr.port();
|
||||
llarp::LogInfo("Loaded our public ", publicAddr, " override into RC!");
|
||||
_rc.addrs.push_back(this->addrInfo);
|
||||
if(this->publicOverride)
|
||||
{
|
||||
ai.ip = *publicAddr.addr6();
|
||||
ai.port = publicAddr.port();
|
||||
}
|
||||
if(llarp::IsBogon(ai.ip))
|
||||
continue;
|
||||
_rc.addrs.push_back(ai);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1074,11 +1055,14 @@ namespace llarp
|
|||
|
||||
llarp::LogInfo("have ", nodedb->num_loaded(), " routers");
|
||||
|
||||
llarp::LogDebug("starting outbound link");
|
||||
if(!outboundLink->Start(logic))
|
||||
llarp::LogDebug("starting outbound links");
|
||||
for(const auto &link : outboundLinks)
|
||||
{
|
||||
llarp::LogWarn("outbound link failed to start");
|
||||
return false;
|
||||
if(link->Start(logic))
|
||||
{
|
||||
llarp::LogWarn("outbound link failed to start");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int IBLinksStarted = 0;
|
||||
|
@ -1159,8 +1143,9 @@ namespace llarp
|
|||
Router::StopLinks()
|
||||
{
|
||||
llarp::LogInfo("stopping links");
|
||||
outboundLink->Stop();
|
||||
for(auto &link : inboundLinks)
|
||||
for(const auto &link : outboundLinks)
|
||||
link->Stop();
|
||||
for(const auto &link : inboundLinks)
|
||||
link->Stop();
|
||||
}
|
||||
|
||||
|
@ -1204,7 +1189,7 @@ namespace llarp
|
|||
&& !(self->HasSessionTo(other.pubkey)
|
||||
|| self->HasPendingConnectJob(other.pubkey)))
|
||||
{
|
||||
llarp_router_try_connect(self, other, 5);
|
||||
self->TryConnectAsync(other, 5);
|
||||
--want;
|
||||
}
|
||||
return want > 0;
|
||||
|
@ -1291,31 +1276,35 @@ namespace llarp
|
|||
}
|
||||
|
||||
bool
|
||||
Router::InitOutboundLink()
|
||||
Router::InitOutboundLinks()
|
||||
{
|
||||
if(outboundLink)
|
||||
if(outboundLinks.size() > 0)
|
||||
return true;
|
||||
|
||||
auto link = llarp::utp::NewServerFromRouter(this);
|
||||
static std::list<
|
||||
std::function< std::unique_ptr< ILinkLayer >(llarp::Router *) > >
|
||||
linkFactories = {llarp::utp::NewServerFromRouter,
|
||||
llarp::iwp::NewServerFromRouter};
|
||||
|
||||
if(!link->EnsureKeys(transport_keyfile.string().c_str()))
|
||||
for(const auto &factory : linkFactories)
|
||||
{
|
||||
llarp::LogError("failed to load ", transport_keyfile);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto afs = {AF_INET, AF_INET6};
|
||||
|
||||
for(auto af : afs)
|
||||
{
|
||||
if(link->Configure(netloop, "*", af, 0))
|
||||
auto link = factory(this);
|
||||
if(!link->EnsureKeys(transport_keyfile.string().c_str()))
|
||||
{
|
||||
outboundLink = std::move(link);
|
||||
llarp::LogInfo("outbound link ready");
|
||||
return true;
|
||||
llarp::LogError("failed to load ", transport_keyfile);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto afs = {AF_INET, AF_INET6};
|
||||
|
||||
for(auto af : afs)
|
||||
{
|
||||
if(!link->Configure(netloop, "*", af, 0))
|
||||
continue;
|
||||
outboundLinks.insert(std::move(link));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return outboundLinks.size() > 0;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <map>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
|
||||
bool
|
||||
llarp_findOrCreateEncryption(llarp::Crypto *crypto, const char *fpath,
|
||||
|
@ -44,6 +45,19 @@ struct TryConnectJob;
|
|||
|
||||
namespace llarp
|
||||
{
|
||||
template < typename T >
|
||||
struct CompareLinks
|
||||
{
|
||||
bool
|
||||
operator()(const std::unique_ptr< T > &left,
|
||||
const std::unique_ptr< T > &right) const
|
||||
{
|
||||
const std::string leftName = left->Name();
|
||||
const std::string rightName = right->Name();
|
||||
return left->Rank() < right->Rank() || leftName < rightName;
|
||||
}
|
||||
};
|
||||
|
||||
struct Router
|
||||
{
|
||||
bool ready;
|
||||
|
@ -150,8 +164,12 @@ namespace llarp
|
|||
std::unique_ptr< llarp::rpc::Caller > rpcCaller;
|
||||
std::string lokidRPCAddr = DefaultLokidRPCAddr;
|
||||
|
||||
std::unique_ptr< llarp::ILinkLayer > outboundLink;
|
||||
std::vector< std::unique_ptr< llarp::ILinkLayer > > inboundLinks;
|
||||
std::set< std::unique_ptr< llarp::ILinkLayer >,
|
||||
CompareLinks< llarp::ILinkLayer > >
|
||||
outboundLinks;
|
||||
std::set< std::unique_ptr< llarp::ILinkLayer >,
|
||||
CompareLinks< llarp::ILinkLayer > >
|
||||
inboundLinks;
|
||||
|
||||
llarp::Profiling routerProfiling;
|
||||
std::string routerProfilesFile = "profiles.dat";
|
||||
|
@ -201,7 +219,7 @@ namespace llarp
|
|||
AddInboundLink(std::unique_ptr< llarp::ILinkLayer > &link);
|
||||
|
||||
bool
|
||||
InitOutboundLink();
|
||||
InitOutboundLinks();
|
||||
|
||||
bool
|
||||
GetRandomGoodRouter(RouterID &r);
|
||||
|
@ -370,6 +388,9 @@ namespace llarp
|
|||
size_t
|
||||
NumberOfConnectedRouters() const;
|
||||
|
||||
bool
|
||||
TryConnectAsync(llarp::RouterContact rc, uint16_t tries);
|
||||
|
||||
bool
|
||||
GetRandomConnectedRouter(llarp::RouterContact &result) const;
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
|
@ -52,7 +52,7 @@ struct UTPTest : public ::testing::Test
|
|||
return rc.Sign(crypto, signingKey);
|
||||
}
|
||||
|
||||
std::unique_ptr< Link_t > link;
|
||||
std::unique_ptr< ILinkLayer > link;
|
||||
|
||||
static std::string
|
||||
localLoopBack()
|
||||
|
|
Loading…
Reference in New Issue