Merge branch 'datagram' into staging

pull/209/head
Jeff Becker 5 years ago
commit 6206fb2a41
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -183,6 +183,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})
@ -523,9 +524,9 @@ set(LIB_SRC
llarp/handlers/tun.cpp
llarp/ini.cpp
llarp/ip.cpp
llarp/iwp.cpp
llarp/link/curvecp.cpp
llarp/link/encoder.cpp
llarp/link/iwp.cpp
llarp/link/server.cpp
llarp/link/session.cpp
llarp/link/utp.cpp
@ -618,7 +619,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]
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,8 +1,7 @@
#include <crypto.hpp>
#include <buffer.hpp>
#include <fstream>
#include <iterator>
#include <buffer.hpp>
namespace llarp
{

@ -89,6 +89,16 @@ namespace llarp
struct SecretKey final : public AlignedBuffer< SECKEYSIZE >
{
SecretKey() : AlignedBuffer< SECKEYSIZE >(){};
explicit SecretKey(const SecretKey &k) : AlignedBuffer< SECKEYSIZE >(k)
{
}
explicit SecretKey(const byte_t *ptr) : AlignedBuffer< SECKEYSIZE >(ptr)
{
}
friend std::ostream &
operator<<(std::ostream &out, const SecretKey &)
{

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

@ -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,365 @@
#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 <bitset>
#include <deque>
namespace llarp
{
namespace iwp
{
struct LinkLayer;
struct Session final : public llarp::ILinkSession
{
/// base
Session(LinkLayer *parent);
/// inbound
Session(LinkLayer *parent, const llarp::Addr &from);
/// outbound
Session(LinkLayer *parent, const RouterContact &rc,
const AddressInfo &ai);
~Session();
void
PumpIO();
void
TickIO(llarp_time_t now);
bool
QueueMessageBuffer(llarp_buffer_t buf);
/// return true if the session is established and handshaked and all that
/// jazz
bool
SessionIsEstablished();
/// inbound start
void
Accept();
/// sendclose
void
Close();
void
Connect();
// set tls config
void
Configure();
/// low level recv
void
Recv_ll(const void *buf, size_t sz);
/// verify a lim
bool
VerfiyLIM(const llarp::LinkIntroMessage *msg);
SharedSecret m_TXKey;
SharedSecret m_RXKey;
LinkLayer *m_Parent;
llarp::Crypto *const crypto;
llarp::RouterContact remoteRC;
llarp::Addr remoteAddr;
using MessageBuffer_t = llarp::AlignedBuffer< MAX_LINK_MSG_SIZE >;
using Seqno_t = uint32_t;
using Proto_t = uint8_t;
using FragLen_t = uint16_t;
using Flags_t = uint8_t;
using Fragno_t = uint8_t;
using Cmd_t = uint8_t;
static constexpr size_t fragoverhead = sizeof(Proto_t) + sizeof(Cmd_t)
+ sizeof(Flags_t) + sizeof(Fragno_t) + sizeof(FragLen_t)
+ sizeof(Seqno_t);
/// keepalive command
static constexpr Cmd_t PING = 0;
/// transmit fragment command
static constexpr Cmd_t XMIT = 1;
/// fragment ack command
static constexpr Cmd_t FACK = 2;
/// maximum number of fragments
static constexpr uint8_t maxfrags = 8;
/// maximum fragment size
static constexpr FragLen_t fragsize = MAX_LINK_MSG_SIZE / maxfrags;
struct FragmentHeader
{
/// protocol version, always LLARP_PROTO_VERSION
Proto_t version = LLARP_PROTO_VERSION;
/// fragment command type
Cmd_t cmd = 0;
/// if cmd is XMIT this is the number of additional fragments this
/// message has
/// if cmd is FACK this is the fragment bitfield of the
/// messages acked otherwise 0
Flags_t flags = 0;
/// if cmd is XMIT this is the fragment index
/// if cmd is FACK this is set to 0xff to indicate message drop
/// otherwise set to 0
/// any other cmd it is set to 0
Fragno_t fragno = 0;
/// if cmd is XMIT then this is the size of the current fragment
/// if cmd is FACK then this MUST be set to 0
FragLen_t fraglen = 0;
/// if cmd is XMIT or FACK this is the sequence number of the message
/// otherwise it's 0
Seqno_t seqno = 0;
bool
Decode(llarp_buffer_t *buf)
{
if(llarp_buffer_size_left(*buf) < fragoverhead)
return false;
version = *buf->cur;
if(version != LLARP_PROTO_VERSION)
return false;
buf->cur++;
cmd = *buf->cur;
buf->cur++;
flags = *buf->cur;
buf->cur++;
fragno = *buf->cur;
buf->cur++;
llarp_buffer_read_uint16(buf, &fraglen);
llarp_buffer_read_uint32(buf, &seqno);
return fraglen <= fragsize;
}
bool
Encode(llarp_buffer_t *buf, llarp_buffer_t body)
{
if(body.sz > fragsize)
return false;
fraglen = body.sz;
if(llarp_buffer_size_left(*buf) < (fragoverhead + fraglen))
return false;
*buf->cur = LLARP_PROTO_VERSION;
buf->cur++;
*buf->cur = cmd;
buf->cur++;
*buf->cur = flags;
buf->cur++;
*buf->cur = fragno;
buf->cur++;
llarp_buffer_put_uint16(buf, fraglen);
llarp_buffer_put_uint32(buf, seqno);
if(fraglen)
memcpy(buf->cur, body.base, fraglen);
buf->cur += fraglen;
return true;
}
};
struct MessageState
{
/// default
MessageState(){};
/// inbound
MessageState(Flags_t numfrags)
{
acks.set();
if(numfrags <= maxfrags)
{
while(numfrags)
acks.reset(maxfrags - (numfrags--));
}
else // invalid value
return;
}
/// outbound
MessageState(llarp_buffer_t buf)
{
sz = std::min(buf.sz, MAX_LINK_MSG_SIZE);
memcpy(msg.data(), buf.base, sz);
size_t idx = 0;
acks.set();
while(idx * fragsize < sz)
acks.reset(idx++);
};
/// which fragments have we got
std::bitset< maxfrags > acks;
/// the message buffer
MessageBuffer_t msg;
/// the message's size
FragLen_t sz;
/// the last activity we have had
llarp_time_t lastActiveAt;
/// return true if this message is to be removed
/// because of inactivity
bool
IsExpired(llarp_time_t now) const
{
return now > lastActiveAt && now - lastActiveAt > 2000;
}
bool
IsDone() const
{
return acks.all();
}
bool
ShouldRetransmit(llarp_time_t now) const
{
if(IsDone())
return false;
return now > lastActiveAt && now - lastActiveAt > 500;
}
template < typename write_pkt_func >
bool
TransmitUnacked(write_pkt_func write_pkt, Seqno_t seqno) const
{
static FragLen_t maxfragsize = fragsize;
FragmentHeader hdr;
hdr.seqno = seqno;
hdr.cmd = XMIT;
AlignedBuffer< fragoverhead + fragsize > frag;
auto buf = frag.as_buffer();
const byte_t *ptr = msg.data();
Fragno_t idx = 0;
FragLen_t len = sz;
while(idx < maxfrags)
{
const FragLen_t l = std::min(len, maxfragsize);
if(!acks.test(idx))
{
hdr.fragno = idx;
hdr.fraglen = l;
if(!hdr.Encode(&buf, llarp::InitBuffer(ptr, l)))
return false;
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
len -= l;
if(write_pkt(buf.base, buf.sz) != int(buf.sz))
return false;
}
ptr += l;
len -= l;
if(l >= fragsize)
++idx;
else
break;
}
return true;
}
template < typename write_pkt_func >
bool
TransmitAcks(write_pkt_func write_pkt, Seqno_t seqno)
{
FragmentHeader hdr;
hdr.seqno = seqno;
hdr.cmd = FACK;
hdr.flags = 0;
byte_t idx = 0;
while(idx < maxfrags)
{
if(acks.test(idx))
hdr.flags |= 1 << idx;
++idx;
}
hdr.fraglen = 0;
hdr.fragno = 0;
AlignedBuffer< fragoverhead > frag;
auto buf = frag.as_buffer();
if(!hdr.Encode(&buf, llarp::InitBuffer(nullptr, 0)))
return false;
return write_pkt(buf.base, buf.sz) == int(buf.sz);
}
};
using MessageHolder_t = std::unordered_map< Seqno_t, MessageState >;
MessageHolder_t m_Inbound;
MessageHolder_t m_Outbound;
using Buf_t = std::vector< byte_t >;
using IOQueue_t = std::deque< Buf_t >;
IOQueue_t ll_recv;
IOQueue_t ll_send;
};
struct LinkLayer final : public llarp::ILinkLayer
{
LinkLayer(llarp::Crypto *crypto, 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);
~LinkLayer();
llarp::Crypto *const crypto;
bool
Start(llarp::Logic *l) override;
ILinkSession *
NewOutboundSession(const llarp::RouterContact &rc,
const llarp::AddressInfo &ai) override;
void
Pump() override;
bool
KeyGen(SecretKey &k) override;
const char *
Name() const override;
uint16_t
Rank() const override;
const byte_t *
IndentityKey() const
{
return m_IdentityKey.data();
}
const AlignedBuffer< 32 > &
CookieSec() const
{
return m_CookieSec;
}
RouterID
GetRouterID() const
{
return m_IdentityKey.toPublic();
}
private:
bool
SignBuffer(llarp::Signature &sig, llarp_buffer_t buf) const
{
return crypto->sign(sig, m_IdentityKey, buf);
}
const llarp::SecretKey m_IdentityKey;
AlignedBuffer< 32 > m_CookieSec;
/// handle ll recv
void
RecvFrom(const llarp::Addr &from, const void *buf, size_t sz) override;
};
} // namespace iwp
} // namespace llarp
#endif

@ -129,21 +129,20 @@ namespace llarp
static constexpr size_t MaxSessionsPerKey = 16;
Lock l_authed(m_AuthedLinksMutex);
Lock l_pending(m_PendingMutex);
auto itr = m_Pending.find(s->GetRemoteEndpoint());
if(itr == m_Pending.end())
{
// this should never happen
return false;
}
if(m_AuthedLinks.count(pk) >= MaxSessionsPerKey)
llarp::Addr addr = s->GetRemoteEndpoint();
auto itr = m_Pending.find(addr);
if(itr != m_Pending.end())
{
s->SendClose();
m_Pending.erase(itr);
return false;
if(m_AuthedLinks.count(pk) > MaxSessionsPerKey)
{
s->SendClose();
return false;
}
m_AuthedLinks.emplace(pk, std::move(itr->second));
itr = m_Pending.erase(itr);
return true;
}
m_AuthedLinks.emplace(pk, std::move(itr->second));
itr = m_Pending.erase(itr);
return true;
return false;
}
bool

@ -87,6 +87,12 @@ namespace llarp
static_cast< ILinkLayer* >(udp->user)->RecvFrom(*from, buf.base, buf.sz);
}
void
SendTo_LL(const llarp::Addr& to, llarp_buffer_t pkt)
{
llarp_ev_udp_sendto(&m_udp, to, pkt);
}
bool
Configure(llarp_ev_loop* loop, const std::string& ifname, int af,
uint16_t port);
@ -106,7 +112,7 @@ namespace llarp
bool
TryEstablishTo(RouterContact rc);
bool
virtual bool
Start(llarp::Logic* l);
void
@ -149,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);
@ -211,7 +227,9 @@ namespace llarp
RouterID::Hash >
m_AuthedLinks;
Mutex m_PendingMutex;
std::unordered_map<llarp::Addr, std::unique_ptr< ILinkSession >, llarp::Addr::Hash > m_Pending;
std::unordered_map< llarp::Addr, std::unique_ptr< ILinkSession >,
llarp::Addr::Hash >
m_Pending;
};
} // namespace llarp

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

@ -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>
@ -103,29 +103,7 @@ on_try_connecting(void *u)
}
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 fs::path &path,
llarp_findOrCreateIdentity(llarp::Crypto *crypto, const char *fpath,
llarp::SecretKey &secretkey)
{
llarp::LogDebug("find or create ", path);
@ -184,6 +162,32 @@ llarp_findOrCreateEncryption(llarp::Crypto *crypto, const fs::path &path,
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)
{
@ -272,12 +276,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
@ -310,7 +316,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;
}
@ -336,7 +342,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;
}
}
@ -347,8 +353,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(
@ -359,8 +368,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); });
@ -384,7 +395,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");
@ -412,7 +423,7 @@ namespace llarp
void
Router::AddInboundLink(std::unique_ptr< llarp::ILinkLayer > &link)
{
inboundLinks.push_back(std::move(link));
inboundLinks.insert(std::move(link));
}
bool
@ -422,7 +433,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())
{
@ -434,7 +445,7 @@ namespace llarp
bool
Router::Ready()
{
return outboundLink != nullptr;
return outboundLinks.size() > 0;
}
bool
@ -463,7 +474,7 @@ namespace llarp
llarp::LogInfo("closing router");
llarp_ev_loop_stop(netloop);
inboundLinks.clear();
outboundLink.reset(nullptr);
outboundLinks.clear();
}
void
@ -592,7 +603,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))
{
@ -637,7 +648,7 @@ namespace llarp
&& lokinetRouters.find(result.pubkey) == lokinetRouters.end())
continue;
nodedb->Insert(result);
llarp_router_try_connect(this, result, 10);
TryConnectAsync(result, 10);
}
}
@ -773,7 +784,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});
}
}
@ -823,19 +834,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;
}
for(const auto &link : inboundLinks)
{
if(link->SendTo(remote, buf))
return;
}
if(!sent)
llarp::LogWarn("message to ", remote, " was dropped");
llarp::LogWarn("message to ", remote, " was dropped");
}
void
@ -856,8 +865,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))
@ -997,52 +1009,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()))
if(link->GetOurAddressInfo(ai))
{
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
// override ip and port
if(this->publicOverride)
{
llarp::LogWarn(
"No need to set public ipv4 and port if no external interface "
"binds, turning off public override");
this->publicOverride = false;
link = nullptr;
ai.ip = *publicAddr.addr6();
ai.port = publicAddr.port();
}
}
if(link && link->GetOurAddressInfo(this->addrInfo))
{
// 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(llarp::IsBogon(ai.ip))
continue;
_rc.addrs.push_back(ai);
}
}
@ -1076,11 +1057,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;
@ -1161,8 +1145,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();
}
@ -1206,7 +1191,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;
@ -1293,31 +1278,37 @@ 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 link = factory(this);
if(!link)
continue;
if(!link->EnsureKeys(transport_keyfile.string().c_str()))
{
llarp::LogError("failed to load ", transport_keyfile);
continue;
}
auto afs = {AF_INET, AF_INET6};
auto afs = {AF_INET, AF_INET6};
for(auto af : afs)
{
if(link->Configure(netloop, "*", af, 0))
for(auto af : afs)
{
outboundLink = std::move(link);
llarp::LogInfo("outbound link ready");
return true;
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 fs::path &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,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()

@ -45,8 +45,7 @@
#define UTUN_OPT_IFNAME 2
static int
fucky_tuntap_sys_start(struct device *dev, __attribute__((unused)) int mode,
int tun)
tuntap_sys_start(struct device *dev, int, int)
{
uint32_t namesz = IFNAMSIZ;
char name[IFNAMSIZ + 1];
@ -57,8 +56,6 @@ fucky_tuntap_sys_start(struct device *dev, __attribute__((unused)) int mode,
if(fd == -1)
return fd;
snprintf(name, sizeof(name), "utun%i", tun);
struct ctl_info info;
memset(&info, 0, sizeof(info));
strncpy(info.ctl_name, APPLE_UTUN, strlen(APPLE_UTUN));
@ -77,7 +74,7 @@ fucky_tuntap_sys_start(struct device *dev, __attribute__((unused)) int mode,
addr.sc_len = sizeof(addr);
addr.sc_family = AF_SYSTEM;
addr.ss_sysaddr = AF_SYS_CONTROL;
addr.sc_unit = tun + 1;
addr.sc_unit = 0;
if(connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
@ -95,24 +92,6 @@ fucky_tuntap_sys_start(struct device *dev, __attribute__((unused)) int mode,
return fd;
}
int
tuntap_sys_start(struct device *dev, int mode, int tun)
{
int fd = -1;
while(tun < 128)
{
// yes linear complexity here
// sue me but I blame apple
fd = fucky_tuntap_sys_start(dev, mode, tun);
if(fd != -1)
{
return fd;
}
++tun;
}
return -1;
}
void
tuntap_sys_destroy(struct device *dev)
{

Loading…
Cancel
Save