mirror of https://github.com/oxen-io/lokinet
Merge branch 'master' of https://github.com/loki-project/loki-network
This commit is contained in:
commit
f283923cb7
|
@ -11,9 +11,9 @@ build:linux:
|
|||
- linux
|
||||
stage: build
|
||||
before_script:
|
||||
- apk add --update g++ make cmake automake libtool autoconf linux-headers libsodium
|
||||
- apk add --update g++ make cmake linux-headers libsodium-dev ninja
|
||||
script:
|
||||
- make clean test
|
||||
- make
|
||||
artifacts:
|
||||
paths:
|
||||
- "lokinet"
|
||||
|
|
|
@ -49,10 +49,6 @@ else()
|
|||
set(THREAD_LIB pthread)
|
||||
endif()
|
||||
|
||||
if (NOT MSVC)
|
||||
add_cflags("-march=native")
|
||||
add_cxxflags("-march=native")
|
||||
endif(NOT MSVC)
|
||||
|
||||
if(STATIC_LINK)
|
||||
add_cflags("-static -Wl,--whole-archive -lpthread -Wl,--no-whole-archive")
|
||||
|
@ -358,6 +354,7 @@ set(LIB_SRC
|
|||
llarp/path.cpp
|
||||
llarp/pathbuilder.cpp
|
||||
llarp/pathset.cpp
|
||||
llarp/profiling.cpp
|
||||
llarp/proofofwork.cpp
|
||||
llarp/relay_commit.cpp
|
||||
llarp/relay_up_down.cpp
|
||||
|
|
10
Makefile
10
Makefile
|
@ -5,6 +5,8 @@ SIGN = gpg --sign --detach
|
|||
|
||||
REPO := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
|
||||
CC ?= cc
|
||||
CXX ?= c++
|
||||
|
||||
|
@ -97,7 +99,7 @@ shared: shared-configure
|
|||
testnet:
|
||||
cp $(EXE) $(TESTNET_EXE)
|
||||
mkdir -p $(TESTNET_ROOT)
|
||||
python3 contrib/testnet/genconf.py --bin=$(TESTNET_EXE) --svc=$(TESTNET_SERVERS) --clients=$(TESTNET_CLIENTS) --dir=$(TESTNET_ROOT) --out $(TESTNET_CONF)
|
||||
python3 contrib/testnet/genconf.py --bin=$(TESTNET_EXE) --svc=$(TESTNET_SERVERS) --clients=$(TESTNET_CLIENTS) --dir=$(TESTNET_ROOT) --out $(TESTNET_CONF) --connect=3
|
||||
LLARP_DEBUG=$(TESTNET_DEBUG) supervisord -n -d $(TESTNET_ROOT) -l $(TESTNET_LOG) -c $(TESTNET_CONF)
|
||||
|
||||
test: debug
|
||||
|
@ -105,3 +107,9 @@ test: debug
|
|||
|
||||
format:
|
||||
clang-format -i $$(find daemon llarp include | grep -E '\.[h,c](pp)?$$')
|
||||
|
||||
install:
|
||||
rm -f $(PREFIX)/bin/lokinet
|
||||
cp $(EXE) $(PREFIX)/bin/lokinet
|
||||
chmod 755 $(PREFIX)/bin/lokinet
|
||||
setcap cap_net_admin=+eip $(PREFIX)/bin/lokinet
|
||||
|
|
|
@ -36,6 +36,9 @@ main(int argc, char *argv[])
|
|||
if(ctx)
|
||||
{
|
||||
signal(SIGINT, handle_signal);
|
||||
#ifndef _WIN32
|
||||
signal(SIGHUP, handle_signal);
|
||||
#endif
|
||||
code = llarp_main_run(ctx);
|
||||
llarp_main_free(ctx);
|
||||
}
|
||||
|
|
225
doc/iwp_v0.txt
225
doc/iwp_v0.txt
|
@ -1,225 +0,0 @@
|
|||
|
||||
invisible wire protocol version 0:
|
||||
|
||||
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].
|
||||
|
||||
cryptography:
|
||||
|
||||
see crypto_v0.txt
|
||||
|
||||
|
||||
wire decryption:
|
||||
|
||||
the first 32 bytes are message authentication bytes, h
|
||||
the next 32 bytes are nouce for cipher, n
|
||||
the remaining bytes are interpreted as ciphertext, x
|
||||
|
||||
a shared secret S is generated in the session start message
|
||||
next the integrity of the ciphertext is done by checking MDS(n + x, S) == h
|
||||
if the ciphertext is valid then the frame is decrypted via SD(S, x, n)
|
||||
|
||||
wire encryption:
|
||||
|
||||
given variadic sized payload p, 32 byte nounce n and public encryption keys A
|
||||
and B
|
||||
|
||||
x = SE(S, p, n[0:24])
|
||||
h = MDS(n + x, S)
|
||||
|
||||
the resulting data is:
|
||||
|
||||
h + n + x
|
||||
|
||||
|
||||
handshake:
|
||||
|
||||
0) intro
|
||||
|
||||
32 bytes hmac, h
|
||||
32 bytes nounce, n
|
||||
32 bytes encrypted alice's transport public encryption key e
|
||||
variadic bytes padding, w0
|
||||
|
||||
Alice transmits ( h + n + e + w0 ) to Bob from the transport address matching
|
||||
his public transport encryption key (b.k).
|
||||
|
||||
w0 = "[insert variable length random padding here]"
|
||||
n = RAND(32)
|
||||
e = SE(a.k, HS(b.k + n), n[0:24])
|
||||
S = TKE(a.k, b.k, n)
|
||||
h = MDS(n + e + w0, S)
|
||||
|
||||
Bob recieves ( s + n + e + w0 )
|
||||
|
||||
1) intro ack
|
||||
|
||||
sent in reply to an intro, bob sends an intro ack encrypted to Alice using
|
||||
|
||||
32 bytes hmac, h
|
||||
32 bytes nounce, n
|
||||
32 bytes ciphertext, x
|
||||
variadic bytes padding, w1
|
||||
|
||||
w1 = "[insert variable length random padding here]"
|
||||
token = RAND(32)
|
||||
S = TKE(a.k, b.k, n)
|
||||
x = SE(k, token, n[0:24])
|
||||
h = MDS(n + x + w1, S)
|
||||
|
||||
Bob transmits ( s + n + x + w1 ), r is ignored and discarded
|
||||
Alice recieves ( s + n + x + w1 ) and verifies the signature silently
|
||||
dropping if it does not match.
|
||||
|
||||
2) session start
|
||||
|
||||
Alice uses the token from the previous message to start the wire session
|
||||
|
||||
32 bytes hmac, h
|
||||
32 bytes nounce, n
|
||||
32 bytes ciphertext, x
|
||||
variadic byttes padding, w2
|
||||
|
||||
w2 = "[insert variable length random padding here]"
|
||||
e_K = TKE(a.k, b.k, n)
|
||||
x = SE(e_K, token, n[0:24])
|
||||
h = MDS(n + x + w2, e_K)
|
||||
T = HS(token + n)
|
||||
K = TKE(a.k, b.k, T)
|
||||
|
||||
Alice transmits ( h + n + x + w2 )
|
||||
Bob recieves ( h + n + x + w2) and verifies that h == MDS(n + x, k) silently
|
||||
drops if not matching
|
||||
|
||||
the session is now established with session key K,
|
||||
Bob replies by transmitting a LIM
|
||||
|
||||
IWP payload format:
|
||||
|
||||
ciphertext:
|
||||
32 bytes hmac, h
|
||||
32 bytes nounce, n
|
||||
N bytes of ciphertext, x
|
||||
|
||||
plaintext header, H
|
||||
8 bits protocol version, v (currently 0)
|
||||
8 bits message type, t
|
||||
16 bits payload size, s
|
||||
8 bits reserved, r (currently 0)
|
||||
8 bits flags, f
|
||||
|
||||
plaintext payload: P
|
||||
s bytes of data
|
||||
N bytes remaining data is discarded
|
||||
|
||||
Encryption:
|
||||
|
||||
D = H + P
|
||||
x = SE(D, S, n)
|
||||
h = MDS(n + x, S)
|
||||
|
||||
Alice transmits h + n + x
|
||||
|
||||
Bob recieves recieve h + n + x
|
||||
|
||||
Bob checks hmac by verifying h == MDS(n + x, S)
|
||||
|
||||
if the hmac fails the data is silently dropped
|
||||
|
||||
Decryption:
|
||||
|
||||
verify h == MDS(n + x, S)
|
||||
D = SD(x, S, n)
|
||||
H = D[0:6]
|
||||
P = D[6:6+H.s]
|
||||
|
||||
message types:
|
||||
|
||||
ALIV = 0x00
|
||||
|
||||
keepalive message
|
||||
|
||||
XMIT = 0x01
|
||||
|
||||
begin link layer message transmission
|
||||
|
||||
ACKS = 0x02
|
||||
|
||||
acknolege link layer message fragment
|
||||
|
||||
FRAG = 0x03
|
||||
|
||||
transmit link layer message fragment
|
||||
|
||||
flags:
|
||||
|
||||
SESSION_INVALIDATED = 1 << 0
|
||||
|
||||
this session is now invalidated and a new session is required
|
||||
|
||||
HIGH_PACKET_DROP = 1 << 1
|
||||
|
||||
high packet drop detected
|
||||
|
||||
HIGH_MTU_DETECTED = 1 << 2
|
||||
|
||||
the network uses an mtu greater than 1488 bytes
|
||||
|
||||
PROTOCOL_UPGRADE = 1 << 3
|
||||
|
||||
indicates we want to do protocol upgrade (future use)
|
||||
|
||||
XMIT payload:
|
||||
|
||||
start transmiting a link layer message
|
||||
|
||||
msg_bytes = BE(msg)
|
||||
|
||||
32 bytes hash of message computed by HS(msg_bytes)
|
||||
64 bits unsigned int message id
|
||||
16 bits unsigned int fragment size bytes, S
|
||||
16 bits size of last fragment in bytes, L
|
||||
16 bits reserved for future, currently zero
|
||||
8 bits unsigned int nonzero number of fragments, n
|
||||
8 bits reserved flags, f
|
||||
if f LSB is set then last fragment is included and is l bytes long
|
||||
|
||||
f's LSB MUST be set as of protocol version 0.
|
||||
|
||||
msg_bytes is S * (n - 1) + L bytes long
|
||||
|
||||
FRAG payload:
|
||||
|
||||
transmit a link layer message fragment
|
||||
|
||||
64 bits message id
|
||||
8 bits unsigned int fragment number
|
||||
S bytes of payload fragment data
|
||||
remaining bytes discarded
|
||||
|
||||
ACKS payload:
|
||||
|
||||
indicates we which chunks we have recieved
|
||||
|
||||
64 bits message id
|
||||
32 bits bitmask of chunks we have received
|
||||
remaining bytes discarded
|
||||
|
||||
|
||||
control flow:
|
||||
|
||||
To transmit link message over an established session the transmitter sends an
|
||||
XMIT frame.
|
||||
In reply to an XMIT frame the recipiant MUST send an ACKS frame with an emtpy
|
||||
bitmask.
|
||||
After the transmitter recieves the first ACKS frame it is allowed to start
|
||||
sending FRAG messages.
|
||||
When all fragmenets are obtained by the recipiant, the recipiant sends an ACKS
|
||||
frame with a full bitfield (0xFFFF), to indicate the link message was recieved.
|
||||
In the event of packet drop the sender decides when to retransmit FRAG frames
|
||||
with expontential backoff.
|
||||
|
||||
In the event of packet loss greater than 50% over 10 second the session is
|
||||
invalidated and must be renegotiated with a new handshake.
|
||||
|
|
@ -266,14 +266,18 @@ identifies the sender as having the RC contained in r. The recipiant MUST
|
|||
validate the RC's signature and ensure that the public key in use is listed in
|
||||
the RC.a matching the ipv6 address it originated from.
|
||||
|
||||
if r is not present in sessions made by clients.
|
||||
|
||||
{
|
||||
a: "i",
|
||||
n: "<32 bytes nonce for key exhcange>",
|
||||
p: uint64_milliseconds_session_period,
|
||||
r: RC,
|
||||
v: 0
|
||||
v: 0,
|
||||
z: "<64 bytes signature of entire message by r.k>"
|
||||
}
|
||||
|
||||
the link session will be kept open for p milliseconds after which
|
||||
the session MUST be renegotiated.
|
||||
|
||||
link relay commit message (LRCM)
|
||||
|
||||
request a commit to relay traffic to another node.
|
||||
|
@ -452,7 +456,8 @@ always the first message sent
|
|||
|
||||
path latency message (PLM)
|
||||
|
||||
a latency measurement message, reply with a PLM response if we are the far end of a path.
|
||||
a latency measurement message, reply with a PLM response if we are the far end
|
||||
of a path.
|
||||
|
||||
variant 1, request, generated by the path creator:
|
||||
|
||||
|
@ -467,7 +472,7 @@ variant 2, response, generated by the endpoint that recieved the request.
|
|||
{
|
||||
A: "L",
|
||||
S: uint64_sequence_number,
|
||||
T: uint64_timestamp_sent,
|
||||
T: uint64_timestamp_recieved,
|
||||
V: 0
|
||||
}
|
||||
|
||||
|
@ -530,6 +535,18 @@ B is set to a backoff value.
|
|||
R contains additional metadata text describing why the exit was rejected.
|
||||
|
||||
|
||||
discarded data fragment message (DDFM)
|
||||
|
||||
sent in reply to TDFM when we don't have a path locally or are doing network
|
||||
congestion control. indcates a TDFM was discarded.
|
||||
|
||||
{
|
||||
A: "D",
|
||||
P: "<16 bytes path id>",
|
||||
S: uint64_sequence_number_of_fragment_dropped,
|
||||
V: 0
|
||||
}
|
||||
|
||||
transfer data fragment message (TDFM)
|
||||
|
||||
transfer data between paths.
|
||||
|
@ -538,13 +555,14 @@ transfer data between paths.
|
|||
A: "T",
|
||||
P: "<16 bytes path id>",
|
||||
S: uint64_sequence_number,
|
||||
T: message_transfered_between_paths,
|
||||
T: hidden_service_frame,
|
||||
V: 0
|
||||
}
|
||||
|
||||
transfer data to another path with id P on the local router place a random 32 byte and T values
|
||||
into y and z values into a LRDM message (respectively) and send it in the
|
||||
downstream direction.
|
||||
transfer data to another path with id P on the local router place a random 32
|
||||
byte and T values into y and z values into a LRDM message (respectively) and
|
||||
send it in the downstream direction. if this path does not exist on the router
|
||||
it is replied to with a DDFM.
|
||||
|
||||
|
||||
|
||||
|
@ -622,7 +640,7 @@ M = {
|
|||
D: D,
|
||||
N: N,
|
||||
V: 0,
|
||||
Z: "\x00" * 32
|
||||
Z: "\x00" * 64
|
||||
},
|
||||
V: 0
|
||||
}
|
||||
|
@ -680,12 +698,12 @@ transfer ip traffic for exit
|
|||
A: "E",
|
||||
S: uint64_sequence_number,
|
||||
V: 0,
|
||||
X: "<N bytes ipv6 packet>",
|
||||
X: "<N bytes ip packet>",
|
||||
Y: "<16 bytes nounce>",
|
||||
Z: "<64 bytes signature using previously provided signing key>"
|
||||
}
|
||||
|
||||
X is parsed as an IPv6 packet and the source addresss is extracted.
|
||||
X is parsed as an IP packet and the source addresss is extracted.
|
||||
Next we find the corrisponding signing key for a previously granted exit address
|
||||
and use it to validate the siganture of the entire message. If the signing key
|
||||
cannot be found or the signature is invalid this message is dropped, otherwise
|
||||
|
@ -734,4 +752,4 @@ wrapper message for sending many dht messages down a path.
|
|||
M: [many, dht, messages, here],
|
||||
S: uint64_sequence_number,
|
||||
V: 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
Wire Protocol (version 0)
|
||||
|
||||
|
||||
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]
|
||||
|
||||
1088 byte fragments are sent over UTP in an ordered fashion.
|
||||
|
||||
The each fragment has the following structure:
|
||||
|
||||
[ 32 bytes blake2 keyed hash of the following 1056 bytes ]
|
||||
[ 24 bytes random nonce ]
|
||||
[ 1032 bytes encrypted payload ]
|
||||
|
||||
the decrypted payload has the following structure:
|
||||
|
||||
[ big endian unsigned 32 bit flags (F) ]
|
||||
[ big endian unsigned 32 bit fragment length (N) ]
|
||||
[ N bytes of plaintext payload ]
|
||||
|
||||
if F is non zero then more fragments for the current message being transmitted
|
||||
are expected. If F is zero then this fragment is the last in the sequence.
|
||||
|
||||
On each fragment append the N bytes of payload to an internal buffer.
|
||||
This internal buffer MUST NOT exceed 8192 bytes, the maximum size of an inter
|
||||
node message.
|
||||
|
||||
When the last fragment in the sequence is reached the internal buffer is
|
||||
processed as a link layer message (see proto_v0.txt)
|
||||
|
||||
Handshake phase:
|
||||
|
||||
Before data flows a protocol handshake must happen.
|
||||
|
||||
The first message sent is a LIM (L) (see proto_v0.txt) by the connection initiator, Alice.
|
||||
|
||||
The receiving end MUST verify the signatures of the LIM and RC.
|
||||
If any verification fails at any phase the underlying UTP session MUST be reset.
|
||||
|
||||
Each side re-computes the session key.
|
||||
|
||||
the session key kdf for K is:
|
||||
|
||||
t_h = HS(K + L.n)
|
||||
K = TKE(A.p, B_a.e, sk, t_h)
|
||||
|
||||
the initial value of K is HS(B.k)
|
||||
|
||||
Periodically the connection initiator MUST renegotiate the session key by
|
||||
sending a LIM after L.p milliseconds have elapsed.
|
||||
|
||||
If either party's RC changes while a connection is established they MUST
|
||||
renegotioate the session keys to ensure the new RC is sent.
|
||||
|
||||
|
||||
references:
|
||||
|
||||
[1] http://www.bittorrent.org/beps/bep_0029.html
|
||||
|
||||
|
||||
|
|
@ -24,8 +24,7 @@ namespace llarp
|
|||
llarp_config *config = nullptr;
|
||||
llarp_nodedb *nodedb = nullptr;
|
||||
llarp_ev_loop *mainloop = nullptr;
|
||||
char nodedb_dir[256] = {0};
|
||||
char conatctFile[256] = "router.signed";
|
||||
std::string nodedb_dir;
|
||||
|
||||
bool
|
||||
LoadConfig(const std::string &fname);
|
||||
|
|
|
@ -224,11 +224,22 @@ namespace llarp
|
|||
{
|
||||
virtual ~IBEncodeMessage(){};
|
||||
|
||||
virtual bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val) = 0;
|
||||
IBEncodeMessage(uint64_t v = LLARP_PROTO_VERSION)
|
||||
{
|
||||
version = v;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
BEncode(llarp_buffer_t* buf) const = 0;
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
BDecode(llarp_buffer_t* buf)
|
||||
|
@ -240,7 +251,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
// TODO: check for shadowed values elsewhere
|
||||
uint64_t version = LLARP_PROTO_VERSION;
|
||||
uint64_t version = 0;
|
||||
|
||||
static bool
|
||||
OnKey(dict_reader* r, llarp_buffer_t* k)
|
||||
|
|
|
@ -18,6 +18,12 @@ namespace llarp
|
|||
|
||||
Bucket(const Key_t& us) : nodes(XorMetric(us)){};
|
||||
|
||||
size_t
|
||||
Size() const
|
||||
{
|
||||
return nodes.size();
|
||||
}
|
||||
|
||||
bool
|
||||
GetRandomNodeExcluding(Key_t& result,
|
||||
const std::set< Key_t >& exclude) const
|
||||
|
@ -120,7 +126,7 @@ namespace llarp
|
|||
void
|
||||
PutNode(const Val_t& val)
|
||||
{
|
||||
nodes.insert(std::make_pair(val.ID, val));
|
||||
nodes[val.ID] = val;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -69,11 +69,15 @@ namespace llarp
|
|||
std::vector< V > valuesFound;
|
||||
TXOwner whoasked;
|
||||
|
||||
virtual bool
|
||||
Validate(const V& value) const = 0;
|
||||
|
||||
void
|
||||
OnFound(const Key_t& askedPeer, const V& value)
|
||||
{
|
||||
peersAsked.insert(askedPeer);
|
||||
valuesFound.push_back(value);
|
||||
if(Validate(value))
|
||||
valuesFound.push_back(value);
|
||||
}
|
||||
|
||||
virtual void
|
||||
|
@ -116,6 +120,9 @@ namespace llarp
|
|||
Context();
|
||||
~Context();
|
||||
|
||||
llarp_crypto*
|
||||
Crypto();
|
||||
|
||||
/// on behalf of whoasked request introset for target from dht router with
|
||||
/// key askpeer
|
||||
void
|
||||
|
@ -147,6 +154,12 @@ namespace llarp
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HasRouterLookup(const RouterID& target) const
|
||||
{
|
||||
return pendingRouterLookups.HasLookupFor(target);
|
||||
}
|
||||
|
||||
/// on behalf of whoasked request introsets with tag from dht router with
|
||||
/// key askpeer with Recursion depth R
|
||||
void
|
||||
|
@ -257,22 +270,34 @@ namespace llarp
|
|||
return itr->second.get();
|
||||
}
|
||||
|
||||
bool
|
||||
HasLookupFor(const K& target) const
|
||||
{
|
||||
return timeouts.find(target) != timeouts.end();
|
||||
}
|
||||
|
||||
bool
|
||||
HasPendingLookupFrom(const TXOwner& owner) const
|
||||
{
|
||||
return GetPendingLookupFrom(owner) != nullptr;
|
||||
}
|
||||
|
||||
TX< K, V >*
|
||||
NewTX(const TXOwner& owner, const K& k, TX< K, V >* t)
|
||||
void
|
||||
NewTX(const TXOwner& owner, const K& k, TX< K, V >* t,
|
||||
bool forceStart = true)
|
||||
{
|
||||
tx.emplace(owner, std::unique_ptr< TX< K, V > >(t));
|
||||
auto n = waiting.count(k);
|
||||
waiting.insert(std::make_pair(k, owner));
|
||||
|
||||
auto itr = timeouts.find(k);
|
||||
if(itr == timeouts.end())
|
||||
{
|
||||
timeouts.insert(
|
||||
std::make_pair(k, llarp_time_now_ms() + requestTimeoutMS));
|
||||
return t;
|
||||
}
|
||||
if(forceStart || n == 0)
|
||||
t->Start(owner);
|
||||
}
|
||||
|
||||
/// mark tx as not fond
|
||||
|
|
|
@ -25,6 +25,12 @@ namespace llarp
|
|||
rc = other;
|
||||
ID = other.pubkey.data();
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(const RCNode& other) const
|
||||
{
|
||||
return rc.OtherIsNewer(other.rc);
|
||||
}
|
||||
};
|
||||
|
||||
struct ISNode
|
||||
|
@ -42,7 +48,12 @@ namespace llarp
|
|||
{
|
||||
introset = other;
|
||||
introset.A.CalculateAddress(ID);
|
||||
llarp::LogInfo("make ISNode with topic ", introset.topic.ToString());
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(const ISNode& other) const
|
||||
{
|
||||
return introset.OtherIsNewer(other.introset);
|
||||
}
|
||||
};
|
||||
} // namespace dht
|
||||
|
|
|
@ -27,6 +27,18 @@ namespace llarp
|
|||
return bencode_write_bytestring(buf, _data, _sz);
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const Encrypted& other) const
|
||||
{
|
||||
return _sz == other._sz && memcmp(_data, other._data, _sz) == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
operator!=(const Encrypted& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
Encrypted&
|
||||
operator=(const Encrypted& other)
|
||||
{
|
||||
|
|
|
@ -45,8 +45,8 @@ namespace llarp
|
|||
|
||||
/// overrides Endpoint
|
||||
/// handle inbound traffic
|
||||
void
|
||||
HandleDataMessage(service::ProtocolMessage* msg);
|
||||
bool
|
||||
ProcessDataMessage(service::ProtocolMessage* msg);
|
||||
|
||||
#ifndef _MINGW32_NO_THREADS
|
||||
/// overrides Endpount
|
||||
|
@ -97,6 +97,10 @@ namespace llarp
|
|||
void
|
||||
MarkIPActive(uint32_t ip);
|
||||
|
||||
/// mark this address as active forever
|
||||
void
|
||||
MarkIPActiveForever(uint32_t ip);
|
||||
|
||||
void
|
||||
FlushSend();
|
||||
|
||||
|
|
|
@ -51,9 +51,27 @@ typedef struct ip_hdr
|
|||
#define check ip_sum
|
||||
#define ihl ip_hl
|
||||
#endif
|
||||
#if defined(__linux__)
|
||||
#define ip_version version
|
||||
struct ip_header
|
||||
{
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
unsigned int ihl:4;
|
||||
unsigned int version:4;
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
unsigned int version:4;
|
||||
unsigned int ihl:4;
|
||||
#else
|
||||
# error "Please fix <bits/endian.h>"
|
||||
#endif
|
||||
uint8_t tos;
|
||||
uint16_t tot_len;
|
||||
uint16_t id;
|
||||
uint16_t frag_off;
|
||||
uint8_t ttl;
|
||||
uint8_t protocol;
|
||||
uint16_t check;
|
||||
uint32_t saddr;
|
||||
uint32_t daddr;
|
||||
};
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
|
@ -99,40 +117,40 @@ namespace llarp
|
|||
}
|
||||
};
|
||||
|
||||
iphdr*
|
||||
ip_header*
|
||||
Header()
|
||||
{
|
||||
return (iphdr*)&buf[0];
|
||||
return (ip_header*)&buf[0];
|
||||
}
|
||||
|
||||
const iphdr*
|
||||
const ip_header*
|
||||
Header() const
|
||||
{
|
||||
return (iphdr*)&buf[0];
|
||||
return (ip_header*)&buf[0];
|
||||
}
|
||||
|
||||
uint32_t
|
||||
src()
|
||||
{
|
||||
return Header()->saddr;
|
||||
return ntohl(Header()->saddr);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
dst()
|
||||
{
|
||||
return Header()->daddr;
|
||||
return ntohl(Header()->daddr);
|
||||
}
|
||||
|
||||
void
|
||||
src(uint32_t ip)
|
||||
{
|
||||
Header()->saddr = htons(ip);
|
||||
Header()->saddr = htonl(ip);
|
||||
}
|
||||
|
||||
void
|
||||
dst(uint32_t ip)
|
||||
{
|
||||
Header()->daddr = htons(ip);
|
||||
Header()->daddr = htonl(ip);
|
||||
}
|
||||
|
||||
// update ip packet checksum
|
||||
|
|
|
@ -77,9 +77,6 @@ namespace llarp
|
|||
bool
|
||||
GetOurAddressInfo(AddressInfo& addr) const;
|
||||
|
||||
void
|
||||
RemoveSessionVia(const Addr& addr);
|
||||
|
||||
virtual uint16_t
|
||||
Rank() const = 0;
|
||||
|
||||
|
@ -122,19 +119,22 @@ namespace llarp
|
|||
uint32_t tick_id;
|
||||
|
||||
protected:
|
||||
typedef util::NullLock Lock;
|
||||
typedef util::NullMutex Mutex;
|
||||
|
||||
void
|
||||
PutSession(const Addr& addr, ILinkSession* s);
|
||||
PutSession(ILinkSession* s);
|
||||
|
||||
llarp_logic* m_Logic = nullptr;
|
||||
Addr m_ourAddr;
|
||||
llarp_udp_io m_udp;
|
||||
SecretKey m_SecretKey;
|
||||
|
||||
util::Mutex m_AuthedLinksMutex;
|
||||
Mutex m_AuthedLinksMutex;
|
||||
std::unordered_multimap< PubKey, std::unique_ptr< ILinkSession >,
|
||||
PubKey::Hash >
|
||||
m_AuthedLinks;
|
||||
util::Mutex m_PendingMutex;
|
||||
Mutex m_PendingMutex;
|
||||
std::list< std::unique_ptr< ILinkSession > > m_Pending;
|
||||
};
|
||||
} // namespace llarp
|
||||
|
|
|
@ -43,6 +43,12 @@ namespace llarp
|
|||
std::function< const PubKey &(void) > GetPubKey;
|
||||
/// get remote address
|
||||
std::function< const Addr &(void) > GetRemoteEndpoint;
|
||||
|
||||
/// handle a valid LIM
|
||||
std::function< bool(const LinkIntroMessage *msg) > GotLIM;
|
||||
|
||||
/// send queue current blacklog
|
||||
std::function< size_t(void) > SendQueueBacklog;
|
||||
};
|
||||
} // namespace llarp
|
||||
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
#define LLARP_LINK_LAYER_HPP
|
||||
#include <llarp/link/server.hpp>
|
||||
#include <llarp/link/session.hpp>
|
||||
constexpr size_t MAX_LINK_MSG_SIZE = 8192;
|
||||
constexpr size_t MAX_LINK_MSG_SIZE = 8192;
|
||||
constexpr llarp_time_t DefaultLinkSessionLifetime = 10 * 1000;
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
#ifndef LLARP_MESSAGES_DISCARD_HPP
|
||||
#define LLARP_MESSAGES_DISCARD_HPP
|
||||
#include <llarp/link_message.hpp>
|
||||
#include <llarp/routing/message.hpp>
|
||||
#include <llarp/bencode.hpp>
|
||||
#include <llarp/routing/handler.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
struct DiscardMessage : public ILinkMessage
|
||||
|
@ -44,6 +47,62 @@ namespace llarp
|
|||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
namespace routing
|
||||
{
|
||||
struct DataDiscardMessage : public IMessage
|
||||
{
|
||||
PathID_t P;
|
||||
|
||||
DataDiscardMessage() : IMessage()
|
||||
{
|
||||
}
|
||||
|
||||
DataDiscardMessage(const PathID_t& dst, uint64_t s) : P(dst)
|
||||
{
|
||||
S = s;
|
||||
version = LLARP_PROTO_VERSION;
|
||||
}
|
||||
|
||||
bool
|
||||
HandleMessage(IMessageHandler* h, llarp_router* r) const
|
||||
{
|
||||
return h->HandleDataDiscardMessage(this, r);
|
||||
}
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t k, llarp_buffer_t* buf)
|
||||
{
|
||||
bool read = false;
|
||||
if(!BEncodeMaybeReadDictEntry("P", P, read, k, buf))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictInt("S", S, read, k, buf))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictInt("V", version, read, k, buf))
|
||||
return false;
|
||||
return read;
|
||||
}
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
|
||||
if(!BEncodeWriteDictMsgType(buf, "A", "D"))
|
||||
return false;
|
||||
if(!BEncodeWriteDictEntry("P", P, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("S", S, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("V", version, buf))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
};
|
||||
} // namespace routing
|
||||
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,6 +8,8 @@ namespace llarp
|
|||
|
||||
struct LinkIntroMessage : public ILinkMessage
|
||||
{
|
||||
static constexpr size_t MaxSize = MAX_RC_SIZE + 256;
|
||||
|
||||
LinkIntroMessage() : ILinkMessage()
|
||||
{
|
||||
}
|
||||
|
@ -19,8 +21,12 @@ namespace llarp
|
|||
~LinkIntroMessage();
|
||||
|
||||
RouterContact rc;
|
||||
|
||||
KeyExchangeNonce N;
|
||||
Signature Z;
|
||||
uint64_t P;
|
||||
|
||||
LinkIntroMessage&
|
||||
operator=(const LinkIntroMessage& msg);
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
|
||||
|
@ -30,6 +36,12 @@ namespace llarp
|
|||
|
||||
bool
|
||||
HandleMessage(llarp_router* router) const;
|
||||
|
||||
bool
|
||||
Sign(llarp_crypto* c, const SecretKey& signKeySecret);
|
||||
|
||||
bool
|
||||
Verify(llarp_crypto* c) const;
|
||||
};
|
||||
} // namespace llarp
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ namespace llarp
|
|||
{
|
||||
PathID_t P;
|
||||
service::ProtocolFrame T;
|
||||
uint64_t V = 0;
|
||||
TunnelNonce Y;
|
||||
|
||||
PathTransferMessage();
|
||||
|
@ -38,4 +37,4 @@ namespace llarp
|
|||
} // namespace routing
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include <llarp/link_message.hpp>
|
||||
#include <llarp/path_types.hpp>
|
||||
#include <llarp/pow.hpp>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
|
|
|
@ -49,6 +49,13 @@ struct llarp_nodedb_iter
|
|||
int
|
||||
llarp_nodedb_iterate_all(struct llarp_nodedb *n, struct llarp_nodedb_iter i);
|
||||
|
||||
/// visit all loaded rc
|
||||
/// stop iteration if visit return false
|
||||
void
|
||||
llarp_nodedb_visit_loaded(
|
||||
struct llarp_nodedb *n,
|
||||
std::function< bool(const llarp::RouterContact &) > visit);
|
||||
|
||||
/// return number of RC loaded
|
||||
size_t
|
||||
llarp_nodedb_num_loaded(struct llarp_nodedb *n);
|
||||
|
@ -66,6 +73,13 @@ bool
|
|||
llarp_nodedb_get_rc(struct llarp_nodedb *n, const llarp::RouterID &pk,
|
||||
llarp::RouterContact &result);
|
||||
|
||||
/**
|
||||
remove rc by public key from nodedb
|
||||
returns true if removed
|
||||
*/
|
||||
bool
|
||||
llarp_nodedb_del_rc(struct llarp_nodedb *n, const llarp::RouterID &pk);
|
||||
|
||||
/// struct for async rc verification
|
||||
struct llarp_async_verify_rc;
|
||||
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
|
||||
#define MAXHOPS (8)
|
||||
#define DEFAULT_PATH_LIFETIME (10 * 60 * 1000)
|
||||
#define PATH_BUILD_TIMEOUT (10 * 1000)
|
||||
#define MESSAGE_PAD_SIZE (1024)
|
||||
#define PATH_BUILD_TIMEOUT (15 * 1000)
|
||||
#define MESSAGE_PAD_SIZE (512)
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
|
@ -159,6 +159,10 @@ namespace llarp
|
|||
HandleRoutingMessage(const llarp::routing::IMessage* msg,
|
||||
llarp_router* r);
|
||||
|
||||
bool
|
||||
HandleDataDiscardMessage(const llarp::routing::DataDiscardMessage* msg,
|
||||
llarp_router* r);
|
||||
|
||||
bool
|
||||
HandlePathConfirmMessage(const llarp::routing::PathConfirmMessage* msg,
|
||||
llarp_router* r);
|
||||
|
@ -220,8 +224,11 @@ namespace llarp
|
|||
struct Path : public IHopHandler, public llarp::routing::IMessageHandler
|
||||
{
|
||||
typedef std::function< void(Path*) > BuildResultHookFunc;
|
||||
typedef std::function< bool(Path*, llarp_time_t) > CheckForDeadFunc;
|
||||
typedef std::function< bool(Path*, const PathID_t&, uint64_t) >
|
||||
DropHandlerFunc;
|
||||
typedef std::vector< PathHopConfig > HopList;
|
||||
typedef std::function< bool(const service::ProtocolFrame*) >
|
||||
typedef std::function< bool(Path*, const service::ProtocolFrame*) >
|
||||
DataHandlerFunc;
|
||||
|
||||
HopList hops;
|
||||
|
@ -229,7 +236,7 @@ namespace llarp
|
|||
llarp::service::Introduction intro;
|
||||
|
||||
llarp_time_t buildStarted;
|
||||
PathStatus status;
|
||||
PathStatus _status;
|
||||
|
||||
Path(const std::vector< RouterContact >& routers);
|
||||
|
||||
|
@ -242,6 +249,21 @@ namespace llarp
|
|||
m_DataHandler = func;
|
||||
}
|
||||
|
||||
void
|
||||
SetDropHandler(DropHandlerFunc func)
|
||||
{
|
||||
m_DropHandler = func;
|
||||
}
|
||||
|
||||
void
|
||||
SetDeadChecker(CheckForDeadFunc func)
|
||||
{
|
||||
m_CheckForDead = func;
|
||||
}
|
||||
|
||||
void
|
||||
EnterState(PathStatus st);
|
||||
|
||||
llarp_time_t
|
||||
ExpireTime() const
|
||||
{
|
||||
|
@ -257,6 +279,10 @@ namespace llarp
|
|||
bool
|
||||
SendRoutingMessage(llarp::routing::IMessage* msg, llarp_router* r);
|
||||
|
||||
bool
|
||||
HandleDataDiscardMessage(const llarp::routing::DataDiscardMessage* msg,
|
||||
llarp_router* r);
|
||||
|
||||
bool
|
||||
HandlePathConfirmMessage(const llarp::routing::PathConfirmMessage* msg,
|
||||
llarp_router* r);
|
||||
|
@ -306,12 +332,17 @@ namespace llarp
|
|||
RouterID
|
||||
Upstream() const;
|
||||
|
||||
std::string
|
||||
Name() const;
|
||||
|
||||
protected:
|
||||
llarp::routing::InboundMessageParser m_InboundMessageParser;
|
||||
|
||||
private:
|
||||
BuildResultHookFunc m_BuiltHook;
|
||||
DataHandlerFunc m_DataHandler;
|
||||
DropHandlerFunc m_DropHandler;
|
||||
CheckForDeadFunc m_CheckForDead;
|
||||
llarp_time_t m_LastLatencyTestTime = 0;
|
||||
uint64_t m_LastLatencyTestID = 0;
|
||||
};
|
||||
|
|
|
@ -101,6 +101,9 @@ namespace llarp
|
|||
Path*
|
||||
GetPathByRouter(const RouterID& router) const;
|
||||
|
||||
Path*
|
||||
GetNewestPathByRouter(const RouterID& router) const;
|
||||
|
||||
Path*
|
||||
GetPathByID(const PathID_t& id) const;
|
||||
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
#ifndef LLARP_PROFILING_HPP
|
||||
#define LLARP_PROFILING_HPP
|
||||
#include <llarp/bencode.hpp>
|
||||
#include <llarp/threading.hpp>
|
||||
#include <llarp/router_id.hpp>
|
||||
#include <llarp/path.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
struct RouterProfile : public IBEncodeMessage
|
||||
{
|
||||
static constexpr size_t MaxSize = 256;
|
||||
uint64_t connectTimeoutCount = 0;
|
||||
uint64_t connectGoodCount = 0;
|
||||
uint64_t pathSuccessCount = 0;
|
||||
uint64_t pathFailCount = 0;
|
||||
|
||||
RouterProfile() : IBEncodeMessage(){};
|
||||
~RouterProfile(){};
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t k, llarp_buffer_t* buf);
|
||||
|
||||
bool
|
||||
IsGood(uint64_t chances) const;
|
||||
};
|
||||
|
||||
struct Profiling : public IBEncodeMessage
|
||||
{
|
||||
Profiling() : IBEncodeMessage(){};
|
||||
~Profiling()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
IsBad(const RouterID& r, uint64_t chances = 8);
|
||||
|
||||
void
|
||||
MarkSuccess(const RouterID& r);
|
||||
|
||||
void
|
||||
MarkTimeout(const RouterID& r);
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t* buf) const;
|
||||
|
||||
bool
|
||||
DecodeKey(llarp_buffer_t k, llarp_buffer_t* buf);
|
||||
|
||||
bool
|
||||
Load(const char* fname);
|
||||
|
||||
bool
|
||||
Save(const char* fname);
|
||||
|
||||
void
|
||||
MarkPathFail(path::Path* p);
|
||||
|
||||
void
|
||||
MarkPathSuccess(path::Path* p);
|
||||
|
||||
private:
|
||||
typedef llarp::util::Lock lock_t;
|
||||
typedef llarp::util::Mutex mtx_t;
|
||||
mtx_t m_ProfilesMutex;
|
||||
std::map< RouterID, RouterProfile > m_Profiles;
|
||||
};
|
||||
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
|
@ -33,13 +33,13 @@ namespace llarp
|
|||
}
|
||||
|
||||
// advertised addresses
|
||||
std::vector< AddressInfo > addrs = {};
|
||||
std::vector< AddressInfo > addrs;
|
||||
// public encryption public key
|
||||
llarp::PubKey enckey;
|
||||
// public signing public key
|
||||
llarp::PubKey pubkey;
|
||||
// advertised exits
|
||||
std::vector< ExitInfo > exits = {};
|
||||
std::vector< ExitInfo > exits;
|
||||
// signature
|
||||
llarp::Signature signature;
|
||||
/// node nickname, yw kee
|
||||
|
@ -84,6 +84,12 @@ namespace llarp
|
|||
bool
|
||||
Sign(llarp_crypto *crypto, const llarp::SecretKey &secret);
|
||||
|
||||
bool
|
||||
OtherIsNewer(const RouterContact &other) const
|
||||
{
|
||||
return last_updated < other.last_updated;
|
||||
}
|
||||
|
||||
bool
|
||||
Read(const char *fname);
|
||||
|
||||
|
|
|
@ -7,15 +7,22 @@
|
|||
|
||||
#include <llarp/messages/path_confirm.hpp>
|
||||
#include <llarp/messages/path_latency.hpp>
|
||||
|
||||
#include <llarp/messages/path_transfer.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace routing
|
||||
{
|
||||
struct DataDiscardMessage;
|
||||
|
||||
// handles messages on the routing level
|
||||
struct IMessageHandler
|
||||
{
|
||||
virtual bool
|
||||
HandleDataDiscardMessage(const DataDiscardMessage *msg,
|
||||
llarp_router *r) = 0;
|
||||
|
||||
virtual bool
|
||||
HandlePathTransferMessage(const PathTransferMessage *msg,
|
||||
llarp_router *r) = 0;
|
||||
|
@ -36,4 +43,4 @@ namespace llarp
|
|||
} // namespace routing
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -16,6 +16,13 @@ namespace llarp
|
|||
{
|
||||
llarp::PathID_t from;
|
||||
uint64_t S = 0;
|
||||
|
||||
IMessage() : llarp::IBEncodeMessage()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~IMessage(){};
|
||||
|
||||
virtual bool
|
||||
HandleMessage(IMessageHandler* h, llarp_router* r) const = 0;
|
||||
};
|
||||
|
@ -38,4 +45,4 @@ namespace llarp
|
|||
} // namespace routing
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -85,6 +85,7 @@ namespace llarp
|
|||
signkey = other.signkey;
|
||||
version = other.version;
|
||||
vanity = other.vanity;
|
||||
version = other.version;
|
||||
UpdateAddr();
|
||||
return *this;
|
||||
};
|
||||
|
|
|
@ -28,6 +28,20 @@ namespace llarp
|
|||
expiresAt = other.expiresAt;
|
||||
}
|
||||
|
||||
bool
|
||||
IsExpired(llarp_time_t now) const
|
||||
{
|
||||
return now >= expiresAt;
|
||||
}
|
||||
|
||||
bool
|
||||
ExpiresSoon(llarp_time_t now, llarp_time_t dlt = 5000) const
|
||||
{
|
||||
if(dlt)
|
||||
return now >= (expiresAt - (llarp_randint() % dlt));
|
||||
return IsExpired(now);
|
||||
}
|
||||
|
||||
~Introduction();
|
||||
|
||||
friend std::ostream&
|
||||
|
@ -51,8 +65,22 @@ namespace llarp
|
|||
{
|
||||
return expiresAt < other.expiresAt || pathID < other.pathID;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const Introduction& other) const
|
||||
{
|
||||
return expiresAt == other.expiresAt && version == other.version
|
||||
&& pathID == other.pathID && router == other.router
|
||||
&& latency == other.latency;
|
||||
}
|
||||
|
||||
bool
|
||||
operator!=(const Introduction& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
} // namespace service
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace llarp
|
|||
|
||||
IntroSet() = default;
|
||||
|
||||
IntroSet(const IntroSet&& other)
|
||||
IntroSet(IntroSet&& other)
|
||||
{
|
||||
A = std::move(other.A);
|
||||
I = std::move(other.I);
|
||||
|
@ -75,6 +75,12 @@ namespace llarp
|
|||
return A < other.A;
|
||||
}
|
||||
|
||||
bool
|
||||
OtherIsNewer(const IntroSet& other) const
|
||||
{
|
||||
return GetNewestIntroExpiration() < other.GetNewestIntroExpiration();
|
||||
}
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& out, const IntroSet& i)
|
||||
{
|
||||
|
@ -101,21 +107,13 @@ namespace llarp
|
|||
return out << " V=" << i.version << " Z=" << i.Z;
|
||||
}
|
||||
|
||||
bool
|
||||
IsNewerThan(const IntroSet& other) const
|
||||
llarp_time_t
|
||||
GetNewestIntroExpiration() const
|
||||
{
|
||||
return GetNewestIntro().expiresAt > other.GetNewestIntro().expiresAt;
|
||||
}
|
||||
|
||||
Introduction
|
||||
GetNewestIntro() const
|
||||
{
|
||||
Introduction i;
|
||||
i.expiresAt = 0;
|
||||
llarp_time_t t = 0;
|
||||
for(const auto& intro : I)
|
||||
if(intro.expiresAt > i.expiresAt)
|
||||
i = intro;
|
||||
return i;
|
||||
t = std::max(intro.expiresAt, t);
|
||||
return t;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -136,4 +134,4 @@ namespace llarp
|
|||
} // namespace service
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -7,10 +7,18 @@
|
|||
#include <llarp/service/protocol.hpp>
|
||||
#include <llarp/path.hpp>
|
||||
|
||||
// minimum time between interoset shifts
|
||||
#ifndef MIN_SHIFT_INTERVAL
|
||||
#define MIN_SHIFT_INTERVAL (5 * 1000)
|
||||
#endif
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace service
|
||||
{
|
||||
// foward declare
|
||||
struct AsyncKeyExchange;
|
||||
|
||||
struct Endpoint : public path::Builder,
|
||||
public ILookupHolder,
|
||||
public IDataHandler
|
||||
|
@ -73,9 +81,15 @@ namespace llarp
|
|||
bool
|
||||
ShouldPublishDescriptors(llarp_time_t now) const;
|
||||
|
||||
void
|
||||
EnsureReplyPath(const ServiceInfo& addr);
|
||||
|
||||
bool
|
||||
PublishIntroSet(llarp_router* r);
|
||||
|
||||
bool
|
||||
PublishIntroSetVia(llarp_router* r, path::Path* p);
|
||||
|
||||
bool
|
||||
HandleGotIntroMessage(const llarp::dht::GotIntroMessage* msg);
|
||||
|
||||
|
@ -83,7 +97,8 @@ namespace llarp
|
|||
HandleGotRouterMessage(const llarp::dht::GotRouterMessage* msg);
|
||||
|
||||
bool
|
||||
HandleHiddenServiceFrame(const llarp::service::ProtocolFrame* msg);
|
||||
HandleHiddenServiceFrame(path::Path* p,
|
||||
const llarp::service::ProtocolFrame* msg);
|
||||
|
||||
/// return true if we have an established path to a hidden service
|
||||
bool
|
||||
|
@ -99,10 +114,13 @@ namespace llarp
|
|||
bool
|
||||
ForgetPathToService(const Address& remote);
|
||||
|
||||
virtual void
|
||||
HandleDataMessage(ProtocolMessage* msg)
|
||||
bool
|
||||
HandleDataMessage(const PathID_t&, ProtocolMessage* msg);
|
||||
|
||||
virtual bool
|
||||
ProcessDataMessage(ProtocolMessage* msg)
|
||||
{
|
||||
// override me in subclass
|
||||
return true;
|
||||
}
|
||||
|
||||
/// ensure that we know a router, looks up if it doesn't
|
||||
|
@ -143,31 +161,82 @@ namespace llarp
|
|||
}
|
||||
};
|
||||
|
||||
bool
|
||||
HandleDataDrop(path::Path* p, const PathID_t& dst, uint64_t s);
|
||||
|
||||
bool
|
||||
CheckPathIsDead(path::Path* p, llarp_time_t latency);
|
||||
|
||||
typedef std::queue< PendingBuffer > PendingBufferQueue;
|
||||
|
||||
struct SendContext
|
||||
{
|
||||
SendContext(const ServiceInfo& ident, const Introduction& intro,
|
||||
PathSet* send, Endpoint* ep);
|
||||
|
||||
void
|
||||
AsyncEncryptAndSendTo(llarp_buffer_t payload, ProtocolType t);
|
||||
|
||||
/// send a fully encrypted hidden service frame
|
||||
/// via a path on our pathset with path id p
|
||||
void
|
||||
Send(ProtocolFrame& f);
|
||||
|
||||
llarp::SharedSecret sharedKey;
|
||||
ServiceInfo remoteIdent;
|
||||
Introduction remoteIntro;
|
||||
PathSet* m_PathSet;
|
||||
IDataHandler* m_DataHandler;
|
||||
Endpoint* m_Endpoint;
|
||||
uint64_t sequenceNo = 0;
|
||||
|
||||
virtual void
|
||||
ShiftIntroduction(){};
|
||||
virtual void
|
||||
UpdateIntroSet(){};
|
||||
virtual void
|
||||
MarkCurrentIntroBad(){};
|
||||
|
||||
private:
|
||||
void
|
||||
EncryptAndSendTo(llarp_buffer_t payload, ProtocolType t);
|
||||
|
||||
virtual void
|
||||
AsyncGenIntro(llarp_buffer_t payload, ProtocolType t)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
HandlePathDead(void*);
|
||||
|
||||
/// context needed to initiate an outbound hidden service session
|
||||
struct OutboundContext : public path::Builder
|
||||
struct OutboundContext : public path::Builder, public SendContext
|
||||
{
|
||||
OutboundContext(const IntroSet& introSet, Endpoint* parent);
|
||||
~OutboundContext();
|
||||
|
||||
/// the remote hidden service's curren intro set
|
||||
IntroSet currentIntroSet;
|
||||
/// the current selected intro
|
||||
Introduction selectedIntro;
|
||||
bool
|
||||
HandleDataDrop(path::Path* p, const PathID_t& dst, uint64_t s);
|
||||
|
||||
/// set to true if we are updating the remote introset right now
|
||||
bool updatingIntroSet;
|
||||
|
||||
/// update the current selected intro to be a new best introduction
|
||||
void
|
||||
ShiftIntroduction();
|
||||
|
||||
/// mark the current remote intro as bad
|
||||
void
|
||||
MarkCurrentIntroBad();
|
||||
|
||||
/// tick internal state
|
||||
/// return true to remove otherwise don't remove
|
||||
bool
|
||||
Tick(llarp_time_t now);
|
||||
|
||||
/// encrypt asynchronously and send to remote endpoint from us
|
||||
void
|
||||
AsyncEncryptAndSendTo(llarp_buffer_t D, ProtocolType protocol);
|
||||
AsyncGenIntro(llarp_buffer_t payload, ProtocolType t);
|
||||
|
||||
/// issues a lookup to find the current intro set of the remote service
|
||||
void
|
||||
|
@ -181,29 +250,22 @@ namespace llarp
|
|||
RouterContact& cur, size_t hop);
|
||||
|
||||
bool
|
||||
HandleHiddenServiceFrame(const ProtocolFrame* frame);
|
||||
HandleHiddenServiceFrame(path::Path* p, const ProtocolFrame* frame);
|
||||
|
||||
std::string
|
||||
Name() const;
|
||||
|
||||
private:
|
||||
void
|
||||
OnGeneratedIntroFrame(AsyncKeyExchange* k, PathID_t p);
|
||||
|
||||
bool
|
||||
OnIntroSetUpdate(const IntroSet* i);
|
||||
OnIntroSetUpdate(const Address& addr, const IntroSet* i);
|
||||
|
||||
void
|
||||
EncryptAndSendTo(path::Path* p, llarp_buffer_t payload, ProtocolType t);
|
||||
|
||||
void
|
||||
AsyncGenIntro(path::Path* p, llarp_buffer_t payload, ProtocolType t);
|
||||
|
||||
/// send a fully encrypted hidden service frame
|
||||
void
|
||||
Send(ProtocolFrame& f);
|
||||
|
||||
uint64_t sequenceNo = 0;
|
||||
llarp::SharedSecret sharedKey;
|
||||
Endpoint* m_Parent;
|
||||
// uint64_t m_UpdateIntrosetTX = 0;
|
||||
uint64_t m_UpdateIntrosetTX = 0;
|
||||
IntroSet currentIntroSet;
|
||||
std::set< Introduction > m_BadIntros;
|
||||
llarp_time_t lastShift = 0;
|
||||
};
|
||||
|
||||
// passed a sendto context when we have a path established otherwise
|
||||
|
@ -249,12 +311,15 @@ namespace llarp
|
|||
void
|
||||
PutNewOutboundContext(const IntroSet& introset);
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
IntroSetPublishFail();
|
||||
virtual void
|
||||
IntroSetPublished();
|
||||
|
||||
protected:
|
||||
void
|
||||
RegenAndPublishIntroSet(llarp_time_t now);
|
||||
|
||||
IServiceLookup*
|
||||
GenerateLookupByTag(const Tag& tag);
|
||||
|
||||
|
@ -275,7 +340,7 @@ namespace llarp
|
|||
|
||||
private:
|
||||
bool
|
||||
OnOutboundLookup(const IntroSet* i); /* */
|
||||
OnOutboundLookup(const Address&, const IntroSet* i); /* */
|
||||
|
||||
static bool
|
||||
SetupIsolatedNetwork(void* user, bool success);
|
||||
|
@ -319,6 +384,10 @@ namespace llarp
|
|||
std::unordered_map< Address, std::unique_ptr< OutboundContext >,
|
||||
Address::Hash >
|
||||
m_RemoteSessions;
|
||||
|
||||
std::unordered_map< Address, ServiceInfo, Address::Hash >
|
||||
m_AddressToService;
|
||||
|
||||
std::unordered_map< Address, PathEnsureHook, Address::Hash >
|
||||
m_PendingServiceLookups;
|
||||
|
||||
|
@ -348,6 +417,7 @@ namespace llarp
|
|||
uint64_t m_CurrentPublishTX = 0;
|
||||
llarp_time_t m_LastPublish = 0;
|
||||
llarp_time_t m_LastPublishAttempt = 0;
|
||||
llarp_time_t m_MinPathLatency = 10000;
|
||||
/// our introset
|
||||
service::IntroSet m_IntroSet;
|
||||
/// pending remote service lookups by id
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#include <llarp/aligned.hpp>
|
||||
#include <llarp/crypto.hpp>
|
||||
#include <llarp/service/IntroSet.hpp>
|
||||
#include <llarp/path_types.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace service
|
||||
|
@ -12,8 +14,8 @@ namespace llarp
|
|||
struct ProtocolMessage;
|
||||
struct IDataHandler
|
||||
{
|
||||
virtual void
|
||||
HandleDataMessage(ProtocolMessage* msg) = 0;
|
||||
virtual bool
|
||||
HandleDataMessage(const PathID_t&, ProtocolMessage* msg) = 0;
|
||||
|
||||
virtual bool
|
||||
GetCachedSessionKeyFor(const ConvoTag& remote,
|
||||
|
@ -41,4 +43,4 @@ namespace llarp
|
|||
} // namespace service
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -28,12 +28,14 @@ namespace llarp
|
|||
ProtocolMessage(const ConvoTag& tag);
|
||||
ProtocolMessage();
|
||||
~ProtocolMessage();
|
||||
ProtocolType proto = eProtocolText;
|
||||
ProtocolType proto = eProtocolTraffic;
|
||||
llarp_time_t queued = 0;
|
||||
std::vector< byte_t > payload;
|
||||
Introduction introReply;
|
||||
ServiceInfo sender;
|
||||
IDataHandler* handler = nullptr;
|
||||
/// local path we got this message from
|
||||
PathID_t srcPath;
|
||||
ConvoTag tag;
|
||||
|
||||
bool
|
||||
|
@ -58,10 +60,33 @@ namespace llarp
|
|||
llarp::Signature Z;
|
||||
llarp::service::ConvoTag T;
|
||||
|
||||
ProtocolFrame();
|
||||
ProtocolFrame(const ProtocolFrame& other)
|
||||
: llarp::routing::IMessage()
|
||||
, C(other.C)
|
||||
, D(other.D)
|
||||
, N(other.N)
|
||||
, Z(other.Z)
|
||||
, T(other.T)
|
||||
{
|
||||
S = other.S;
|
||||
version = other.version;
|
||||
}
|
||||
|
||||
ProtocolFrame() : llarp::routing::IMessage()
|
||||
{
|
||||
}
|
||||
|
||||
~ProtocolFrame();
|
||||
|
||||
bool
|
||||
operator==(const ProtocolFrame& other) const;
|
||||
|
||||
bool
|
||||
operator!=(const ProtocolFrame& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
ProtocolFrame&
|
||||
operator=(const ProtocolFrame& other);
|
||||
|
||||
|
@ -71,7 +96,7 @@ namespace llarp
|
|||
|
||||
bool
|
||||
AsyncDecryptAndVerify(llarp_logic* logic, llarp_crypto* c,
|
||||
llarp_threadpool* worker,
|
||||
const PathID_t& srcpath, llarp_threadpool* worker,
|
||||
const Identity& localIdent,
|
||||
IDataHandler* handler) const;
|
||||
|
||||
|
@ -94,4 +119,4 @@ namespace llarp
|
|||
} // namespace service
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
#endif
|
||||
|
||||
#ifndef LLARP_VERSION_MIN
|
||||
#define LLARP_VERSION_MIN "1"
|
||||
#define LLARP_VERSION_MIN "2"
|
||||
#endif
|
||||
|
||||
#ifndef LLARP_VERSION_PATCH
|
||||
#define LLARP_VERSION_PATCH "0"
|
||||
#define LLARP_VERSION_PATCH "2"
|
||||
#endif
|
||||
|
||||
#ifndef LLARP_VERSION_NUM
|
||||
|
|
|
@ -75,14 +75,7 @@ namespace llarp
|
|||
// encryption public key
|
||||
if(llarp_buffer_eq(key, "e"))
|
||||
{
|
||||
if(!bencode_read_string(buf, &strbuf))
|
||||
return false;
|
||||
|
||||
if(strbuf.sz != PUBKEYSIZE)
|
||||
return false;
|
||||
|
||||
pubkey = strbuf.base;
|
||||
return true;
|
||||
return pubkey.BDecode(buf);
|
||||
}
|
||||
|
||||
// ip address
|
||||
|
|
|
@ -34,7 +34,6 @@ namespace llarp
|
|||
dns = find_section(top, "dns", section_t{});
|
||||
iwp_links = find_section(top, "bind", section_t{});
|
||||
services = find_section(top, "services", section_t{});
|
||||
dns = find_section(top, "dns", section_t{});
|
||||
system = find_section(top, "system", section_t{});
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -53,8 +53,7 @@ namespace llarp
|
|||
iter.user = this;
|
||||
iter.visit = &iter_config;
|
||||
llarp_config_iter(config, &iter);
|
||||
llarp::LogInfo("config [", configfile, "] loaded");
|
||||
return true;
|
||||
return router->ReloadConfig(config);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -72,10 +71,6 @@ namespace llarp
|
|||
ctx->worker = llarp_init_threadpool(workers, "llarp-worker");
|
||||
}
|
||||
}
|
||||
else if(!strcmp(key, "contact-file"))
|
||||
{
|
||||
strncpy(ctx->conatctFile, val, fmin(255, strlen(val)));
|
||||
}
|
||||
else if(!strcmp(key, "net-threads"))
|
||||
{
|
||||
ctx->num_nethreads = atoi(val);
|
||||
|
@ -89,7 +84,7 @@ namespace llarp
|
|||
{
|
||||
if(!strcmp(key, "dir"))
|
||||
{
|
||||
strncpy(ctx->nodedb_dir, val, sizeof(ctx->nodedb_dir));
|
||||
ctx->nodedb_dir = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -99,20 +94,14 @@ namespace llarp
|
|||
{
|
||||
llarp_crypto_init(&crypto);
|
||||
nodedb = llarp_nodedb_new(&crypto);
|
||||
if(!nodedb_dir[0])
|
||||
{
|
||||
llarp::LogError("no nodedb_dir configured");
|
||||
return 0;
|
||||
}
|
||||
|
||||
nodedb_dir[sizeof(nodedb_dir) - 1] = 0;
|
||||
if(!llarp_nodedb_ensure_dir(nodedb_dir))
|
||||
if(!llarp_nodedb_ensure_dir(nodedb_dir.c_str()))
|
||||
{
|
||||
llarp::LogError("nodedb_dir is incorrect");
|
||||
return 0;
|
||||
}
|
||||
// llarp::LogInfo("nodedb_dir [", nodedb_dir, "] configured!");
|
||||
ssize_t loaded = llarp_nodedb_load_dir(nodedb, nodedb_dir);
|
||||
ssize_t loaded = llarp_nodedb_load_dir(nodedb, nodedb_dir.c_str());
|
||||
llarp::LogInfo("nodedb_dir loaded ", loaded, " RCs from [", nodedb_dir,
|
||||
"]");
|
||||
if(loaded < 0)
|
||||
|
@ -151,7 +140,8 @@ namespace llarp
|
|||
{
|
||||
llarp::LogInfo(LLARP_VERSION, " ", LLARP_RELEASE_MOTTO);
|
||||
llarp::LogInfo("starting up");
|
||||
this->LoadDatabase();
|
||||
if(!this->LoadDatabase())
|
||||
return -1;
|
||||
llarp_ev_loop_alloc(&mainloop);
|
||||
|
||||
// ensure worker thread pool
|
||||
|
@ -412,7 +402,7 @@ llarp_main_getDatabase(struct llarp_main *ptr, byte_t *pk)
|
|||
//llarp_rc *rc = new llarp_rc;
|
||||
llarp::RouterContact *rc = new llarp::RouterContact;
|
||||
//llarp_rc_new(rc);
|
||||
llarp::LogInfo("FIXME: Loading ", ptr->ctx->conatctFile);
|
||||
//llarp::LogInfo("FIXME: Loading ", ptr->ctx->conatctFile);
|
||||
// FIXME
|
||||
/*
|
||||
if(llarp_rc_read(ptr->ctx->conatctFile, rc))
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace llarp
|
|||
Context::Explore(size_t N)
|
||||
{
|
||||
// ask N random peers for new routers
|
||||
llarp::LogInfo("Exploring network");
|
||||
llarp::LogInfo("Exploring network via ", N, " peers");
|
||||
std::set< Key_t > peers;
|
||||
|
||||
if(nodes->GetManyRandom(peers, N))
|
||||
|
@ -46,6 +46,13 @@ namespace llarp
|
|||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Validate(const RouterID &) const
|
||||
{
|
||||
// TODO: check with lokid
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Start(const TXOwner &peer)
|
||||
{
|
||||
|
@ -70,13 +77,9 @@ namespace llarp
|
|||
llarp::LogInfo("got ", valuesFound.size(), " routers from exploration");
|
||||
for(const auto &pk : valuesFound)
|
||||
{
|
||||
RouterContact rc;
|
||||
if(!llarp_nodedb_get_rc(parent->router->nodedb, pk, rc))
|
||||
{
|
||||
// try connecting to it we don't know it
|
||||
// this triggers a dht lookup
|
||||
parent->router->TryEstablishTo(pk);
|
||||
}
|
||||
// try connecting to it we don't know it
|
||||
// this triggers a dht lookup
|
||||
parent->router->TryEstablishTo(pk);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -85,9 +88,8 @@ namespace llarp
|
|||
Context::ExploreNetworkVia(const Key_t &askpeer)
|
||||
{
|
||||
TXOwner peer(askpeer, ++ids);
|
||||
auto tx = pendingExploreLookups.NewTX(
|
||||
peer, askpeer, new ExploreNetworkJob(askpeer, this));
|
||||
tx->Start(peer);
|
||||
pendingExploreLookups.NewTX(peer, askpeer,
|
||||
new ExploreNetworkJob(askpeer, this));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -96,7 +98,7 @@ namespace llarp
|
|||
if(left)
|
||||
return;
|
||||
Context *ctx = static_cast< Context * >(u);
|
||||
ctx->Explore();
|
||||
ctx->Explore(1);
|
||||
llarp_logic_call_later(ctx->router->logic,
|
||||
{orig, ctx, &handle_explore_timer});
|
||||
}
|
||||
|
@ -120,7 +122,7 @@ namespace llarp
|
|||
{
|
||||
if(itr->second.introset.IsExpired(now))
|
||||
{
|
||||
llarp::LogInfo("introset expired ", itr->second.introset.A.Addr());
|
||||
llarp::LogDebug("introset expired ", itr->second.introset.A.Addr());
|
||||
itr = nodes.erase(itr);
|
||||
}
|
||||
else
|
||||
|
@ -192,7 +194,7 @@ namespace llarp
|
|||
{
|
||||
// we are the target, give them our RC
|
||||
replies.emplace_back(
|
||||
new GotRouterMessage(requester, txid, {router->rc}, false));
|
||||
new GotRouterMessage(requester, txid, {router->rc()}, false));
|
||||
return;
|
||||
}
|
||||
Key_t next;
|
||||
|
@ -322,6 +324,23 @@ namespace llarp
|
|||
peersAsked.insert(ctx->OurKey());
|
||||
}
|
||||
|
||||
bool
|
||||
Validate(const service::IntroSet &value) const
|
||||
{
|
||||
if(!value.VerifySignature(parent->Crypto()))
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"Got introset with invalid signature from service lookup");
|
||||
return false;
|
||||
}
|
||||
if(value.A.Addr() != target)
|
||||
{
|
||||
llarp::LogWarn("got introset with wrong target from service lookup");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DoNextRequest(const Key_t &nextPeer)
|
||||
{
|
||||
|
@ -422,10 +441,9 @@ namespace llarp
|
|||
{
|
||||
TXOwner asker(OurKey(), txid);
|
||||
TXOwner peer(askpeer, ++ids);
|
||||
auto tx = pendingIntrosetLookups.NewTX(
|
||||
pendingIntrosetLookups.NewTX(
|
||||
peer, addr,
|
||||
new LocalServiceAddressLookup(path, txid, addr, this, askpeer));
|
||||
tx->Start(peer);
|
||||
}
|
||||
|
||||
struct PublishServiceJob : public TX< service::Address, service::IntroSet >
|
||||
|
@ -444,6 +462,18 @@ namespace llarp
|
|||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Validate(const service::IntroSet &introset) const
|
||||
{
|
||||
if(I.A != introset.A)
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"publish introset acknoledgement acked a different service");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Start(const TXOwner &peer)
|
||||
{
|
||||
|
@ -481,10 +511,9 @@ namespace llarp
|
|||
TXOwner asker(from, txid);
|
||||
TXOwner peer(tellpeer, ++ids);
|
||||
service::Address addr = introset.A.Addr();
|
||||
auto tx = pendingIntrosetLookups.NewTX(
|
||||
asker, addr,
|
||||
new PublishServiceJob(asker, introset, this, S, exclude));
|
||||
tx->Start(peer);
|
||||
pendingIntrosetLookups.NewTX(
|
||||
asker, addr, new PublishServiceJob(asker, introset, this, S, exclude),
|
||||
true);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -495,9 +524,8 @@ namespace llarp
|
|||
{
|
||||
TXOwner asker(whoasked, txid);
|
||||
TXOwner peer(askpeer, ++ids);
|
||||
auto tx = pendingIntrosetLookups.NewTX(
|
||||
pendingIntrosetLookups.NewTX(
|
||||
peer, addr, new ServiceAddressLookup(asker, addr, this, R, handler));
|
||||
tx->Start(peer);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -508,9 +536,8 @@ namespace llarp
|
|||
{
|
||||
TXOwner asker(whoasked, txid);
|
||||
TXOwner peer(askpeer, ++ids);
|
||||
auto tx = pendingIntrosetLookups.NewTX(
|
||||
pendingIntrosetLookups.NewTX(
|
||||
peer, addr, new ServiceAddressLookup(asker, addr, this, 0, handler));
|
||||
tx->Start(peer);
|
||||
}
|
||||
|
||||
struct TagLookup : public TX< service::Tag, service::IntroSet >
|
||||
|
@ -522,6 +549,22 @@ namespace llarp
|
|||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Validate(const service::IntroSet &introset) const
|
||||
{
|
||||
if(!introset.VerifySignature(parent->Crypto()))
|
||||
{
|
||||
llarp::LogWarn("got introset from tag lookup with invalid signature");
|
||||
return false;
|
||||
}
|
||||
if(introset.topic != target)
|
||||
{
|
||||
llarp::LogWarn("got introset with missmatched topic in tag lookup");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Start(const TXOwner &peer)
|
||||
{
|
||||
|
@ -573,9 +616,7 @@ namespace llarp
|
|||
{
|
||||
TXOwner asker(whoasked, whoaskedTX);
|
||||
TXOwner peer(askpeer, ++ids);
|
||||
auto tx = pendingTagLookups.NewTX(peer, tag,
|
||||
new TagLookup(asker, tag, this, R));
|
||||
tx->Start(peer);
|
||||
pendingTagLookups.NewTX(peer, tag, new TagLookup(asker, tag, this, R));
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -586,11 +627,22 @@ namespace llarp
|
|||
std::vector< RouterID > closer;
|
||||
Key_t t(target.data());
|
||||
std::set< Key_t > found;
|
||||
if(!nodes->GetManyNearExcluding(t, found, 4,
|
||||
// TODO: also load from nodedb
|
||||
size_t nodeCount = nodes->Size();
|
||||
if(nodeCount == 0)
|
||||
{
|
||||
llarp::LogError(
|
||||
"cannot handle exploritory router lookup, no dht peers");
|
||||
return false;
|
||||
}
|
||||
size_t want = std::min(size_t(4), nodeCount);
|
||||
if(!nodes->GetManyNearExcluding(t, found, want,
|
||||
std::set< Key_t >{ourKey, requester}))
|
||||
{
|
||||
llarp::LogError(
|
||||
"not enough dht nodes to handle exploritory router lookup");
|
||||
"not enough dht nodes to handle exploritory router lookup, "
|
||||
"need a minimum of ",
|
||||
want, " dht peers");
|
||||
return false;
|
||||
}
|
||||
for(const auto &f : found)
|
||||
|
@ -611,6 +663,17 @@ namespace llarp
|
|||
peersAsked.insert(ctx->OurKey());
|
||||
}
|
||||
|
||||
bool
|
||||
Validate(const RouterContact &rc) const
|
||||
{
|
||||
if(!rc.VerifySignature(parent->Crypto()))
|
||||
{
|
||||
llarp::LogWarn("rc has invalid signature from lookup result");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GetNextPeer(Key_t &next, const std::set< Key_t > &exclude)
|
||||
{
|
||||
|
@ -631,12 +694,6 @@ namespace llarp
|
|||
new FindRouterMessage(parent->OurKey(), target, peer.txid));
|
||||
}
|
||||
|
||||
void
|
||||
SendTo(const Key_t &peer, IMessage *msg) const
|
||||
{
|
||||
return parent->DHTSendTo(peer, msg);
|
||||
}
|
||||
|
||||
virtual void
|
||||
SendReply()
|
||||
{
|
||||
|
@ -698,9 +755,8 @@ namespace llarp
|
|||
|
||||
{
|
||||
TXOwner peer(askpeer, ++ids);
|
||||
auto tx = pendingRouterLookups.NewTX(
|
||||
pendingRouterLookups.NewTX(
|
||||
peer, target, new LocalRouterLookup(path, txid, target, this));
|
||||
tx->Start(peer);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -711,10 +767,18 @@ namespace llarp
|
|||
{
|
||||
TXOwner asker(whoasked, txid);
|
||||
TXOwner peer(askpeer, ++ids);
|
||||
auto tx = pendingRouterLookups.NewTX(
|
||||
peer, target,
|
||||
new RecursiveRouterLookup(asker, target, this, handler));
|
||||
tx->Start(peer);
|
||||
if(target != askpeer)
|
||||
{
|
||||
pendingRouterLookups.NewTX(
|
||||
peer, target,
|
||||
new RecursiveRouterLookup(asker, target, this, handler));
|
||||
}
|
||||
}
|
||||
|
||||
llarp_crypto *
|
||||
Context::Crypto()
|
||||
{
|
||||
return &router->crypto;
|
||||
}
|
||||
|
||||
} // namespace dht
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace llarp
|
|||
if(path)
|
||||
{
|
||||
replies.emplace_back(
|
||||
new GotRouterMessage(K.data(), txid, {dht.router->rc}, false));
|
||||
new GotRouterMessage(K.data(), txid, {dht.router->rc()}, false));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -30,6 +30,15 @@ namespace llarp
|
|||
|
||||
Key_t peer;
|
||||
Key_t k = K.data();
|
||||
// check if we know this in our nodedb first
|
||||
RouterContact found;
|
||||
if(llarp_nodedb_get_rc(dht.router->nodedb, K, found))
|
||||
{
|
||||
replies.emplace_back(
|
||||
new GotRouterMessage(K.data(), txid, {found}, false));
|
||||
return true;
|
||||
}
|
||||
// lookup if we don't have it in our nodedb
|
||||
if(dht.nodes->FindClosest(k, peer))
|
||||
dht.LookupRouterForPath(K, txid, pathID, peer);
|
||||
return true;
|
||||
|
@ -146,8 +155,15 @@ namespace llarp
|
|||
llarp::LogWarn("Duplicate FRM from ", From, " txid=", txid);
|
||||
return false;
|
||||
}
|
||||
RouterContact found;
|
||||
if(exploritory)
|
||||
return dht.HandleExploritoryRouterLookup(From, txid, K, replies);
|
||||
else if(llarp_nodedb_get_rc(dht.router->nodedb, K, found))
|
||||
{
|
||||
replies.emplace_back(
|
||||
new GotRouterMessage(K.data(), txid, {found}, false));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
dht.LookupRouterRelayed(From, txid, K.data(), !iterative, replies);
|
||||
return true;
|
||||
|
|
|
@ -36,6 +36,8 @@ namespace llarp
|
|||
From);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
dht.services->PutNode(introset);
|
||||
}
|
||||
TXOwner owner(From, T);
|
||||
auto tagLookup = dht.pendingTagLookups.GetPendingLookupFrom(owner);
|
||||
|
|
|
@ -43,12 +43,7 @@ namespace llarp
|
|||
bool
|
||||
queue_write(const void* data, size_t sz)
|
||||
{
|
||||
return m_writeq.EmplaceIf(
|
||||
[&](WriteBuffer& pkt) -> bool {
|
||||
return m_writeq.Size() < MAX_WRITE_QUEUE_SIZE
|
||||
&& sz <= sizeof(pkt.buf);
|
||||
},
|
||||
data, sz);
|
||||
return write(fd, data, sz) != -1;
|
||||
}
|
||||
|
||||
/// called in event loop when fd is ready for writing
|
||||
|
|
|
@ -143,21 +143,12 @@ namespace llarp
|
|||
struct llarp_epoll_loop : public llarp_ev_loop
|
||||
{
|
||||
int epollfd;
|
||||
int pipefds[2];
|
||||
llarp_epoll_loop() : epollfd(-1)
|
||||
{
|
||||
pipefds[0] = -1;
|
||||
pipefds[1] = -1;
|
||||
}
|
||||
|
||||
~llarp_epoll_loop()
|
||||
{
|
||||
if(pipefds[0] != -1)
|
||||
close(pipefds[0]);
|
||||
|
||||
if(pipefds[1] != -1)
|
||||
close(pipefds[1]);
|
||||
|
||||
if(epollfd != -1)
|
||||
close(epollfd);
|
||||
}
|
||||
|
@ -173,16 +164,6 @@ struct llarp_epoll_loop : public llarp_ev_loop
|
|||
{
|
||||
if(epollfd == -1)
|
||||
epollfd = epoll_create(1);
|
||||
if(epollfd != -1)
|
||||
{
|
||||
if(pipe(pipefds) == -1)
|
||||
return false;
|
||||
epoll_event sig_ev;
|
||||
|
||||
sig_ev.data.fd = pipefds[0];
|
||||
sig_ev.events = EPOLLIN;
|
||||
return epoll_ctl(epollfd, EPOLL_CTL_ADD, pipefds[0], &sig_ev) != -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -197,12 +178,6 @@ struct llarp_epoll_loop : public llarp_ev_loop
|
|||
int idx = 0;
|
||||
while(idx < result)
|
||||
{
|
||||
// handle signalfd
|
||||
if(events[idx].data.fd == pipefds[0])
|
||||
{
|
||||
llarp::LogDebug("exiting epoll loop");
|
||||
return 0;
|
||||
}
|
||||
llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].data.ptr);
|
||||
if(events[idx].events & EPOLLIN)
|
||||
{
|
||||
|
@ -211,7 +186,8 @@ struct llarp_epoll_loop : public llarp_ev_loop
|
|||
++idx;
|
||||
}
|
||||
}
|
||||
tick_listeners();
|
||||
if(result != -1)
|
||||
tick_listeners();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -228,12 +204,6 @@ struct llarp_epoll_loop : public llarp_ev_loop
|
|||
int idx = 0;
|
||||
while(idx < result)
|
||||
{
|
||||
// handle signalfd
|
||||
if(events[idx].data.fd == pipefds[0])
|
||||
{
|
||||
llarp::LogDebug("exiting epoll loop");
|
||||
return 0;
|
||||
}
|
||||
llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].data.ptr);
|
||||
if(events[idx].events & EPOLLIN)
|
||||
{
|
||||
|
@ -242,7 +212,8 @@ struct llarp_epoll_loop : public llarp_ev_loop
|
|||
++idx;
|
||||
}
|
||||
}
|
||||
tick_listeners();
|
||||
if(result != -1)
|
||||
tick_listeners();
|
||||
} while(epollfd != -1);
|
||||
return result;
|
||||
}
|
||||
|
@ -356,9 +327,9 @@ struct llarp_epoll_loop : public llarp_ev_loop
|
|||
void
|
||||
stop()
|
||||
{
|
||||
int i = 1;
|
||||
auto val = write(pipefds[1], &i, sizeof(i));
|
||||
(void)val;
|
||||
if(epollfd != -1)
|
||||
close(epollfd);
|
||||
epollfd = -1;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -195,7 +195,8 @@ struct llarp_kqueue_loop : public llarp_ev_loop
|
|||
++idx;
|
||||
}
|
||||
}
|
||||
tick_listeners();
|
||||
if(result != -1)
|
||||
tick_listeners();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -229,7 +230,8 @@ struct llarp_kqueue_loop : public llarp_ev_loop
|
|||
++idx;
|
||||
}
|
||||
}
|
||||
tick_listeners();
|
||||
if(result != -1)
|
||||
tick_listeners();
|
||||
} while(result != -1);
|
||||
return result;
|
||||
}
|
||||
|
|
37
llarp/fs.hpp
37
llarp/fs.hpp
|
@ -23,6 +23,7 @@ namespace fs = std::experimental::filesystem;
|
|||
// linux gcc 7.2 needs this
|
||||
namespace fs = cpp17::filesystem;
|
||||
#endif
|
||||
#include <dirent.h>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
|
@ -30,31 +31,25 @@ namespace llarp
|
|||
{
|
||||
typedef std::function< bool(const fs::path &) > PathVisitor;
|
||||
typedef std::function< void(const fs::path &, PathVisitor) > PathIter;
|
||||
#if defined(CPP17) && defined(USE_CXX17_FILESYSTEM)
|
||||
|
||||
static PathIter IterDir = [](const fs::path &path, PathVisitor visit) {
|
||||
fs::directory_iterator i(path);
|
||||
auto itr = fs::begin(i);
|
||||
while(itr != fs::end(i))
|
||||
DIR *d = opendir(path.string().c_str());
|
||||
if(d == nullptr)
|
||||
return;
|
||||
struct dirent *ent = nullptr;
|
||||
do
|
||||
{
|
||||
fs::path p = path / *itr;
|
||||
ent = readdir(d);
|
||||
if(!ent)
|
||||
break;
|
||||
if(ent->d_name[0] == '.')
|
||||
continue;
|
||||
fs::path p = path / fs::path(ent->d_name);
|
||||
if(!visit(p))
|
||||
return;
|
||||
++itr;
|
||||
}
|
||||
break;
|
||||
} while(ent);
|
||||
closedir(d);
|
||||
};
|
||||
#else
|
||||
static PathIter IterDir = [](const fs::path &path, PathVisitor visit) {
|
||||
fs::directory_iterator i(path);
|
||||
auto itr = i.begin();
|
||||
while(itr != itr.end())
|
||||
{
|
||||
fs::path p = path / *itr;
|
||||
if(!visit(p))
|
||||
return;
|
||||
++itr;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
} // namespace util
|
||||
} // namespace llarp
|
||||
#endif // end LLARP_FS_HPP
|
||||
|
|
|
@ -38,21 +38,22 @@ namespace llarp
|
|||
auto addr_str = v.substr(0, pos);
|
||||
if(!addr.FromString(addr_str))
|
||||
{
|
||||
llarp::LogError("cannot map invalid address ", addr_str);
|
||||
llarp::LogError(Name() + " cannot map invalid address ", addr_str);
|
||||
return false;
|
||||
}
|
||||
auto ip_str = v.substr(pos + 1);
|
||||
uint32_t ip;
|
||||
in_addr ip;
|
||||
if(inet_pton(AF_INET, ip_str.c_str(), &ip) != 1)
|
||||
{
|
||||
llarp::LogError("cannot map to invalid ip ", ip_str);
|
||||
return false;
|
||||
}
|
||||
return MapAddress(addr, ip);
|
||||
return MapAddress(addr, ntohl(ip.s_addr));
|
||||
}
|
||||
if(k == "ifname")
|
||||
{
|
||||
strncpy(tunif.ifname, v.c_str(), sizeof(tunif.ifname) - 1);
|
||||
llarp::LogInfo(Name() + " setting ifname to ", tunif.ifname);
|
||||
return true;
|
||||
}
|
||||
if(k == "ifaddr")
|
||||
|
@ -78,7 +79,8 @@ namespace llarp
|
|||
tunif.netmask = 32;
|
||||
addr = v;
|
||||
}
|
||||
llarp::LogInfo("set ifaddr to ", addr, " with netmask ", tunif.netmask);
|
||||
llarp::LogInfo(Name() + " set ifaddr to ", addr, " with netmask ",
|
||||
tunif.netmask);
|
||||
strncpy(tunif.ifaddr, addr.c_str(), sizeof(tunif.ifaddr) - 1);
|
||||
return true;
|
||||
}
|
||||
|
@ -88,19 +90,18 @@ namespace llarp
|
|||
bool
|
||||
TunEndpoint::MapAddress(const service::Address &addr, uint32_t ip)
|
||||
{
|
||||
char buf[32] = {0};
|
||||
inet_ntop(AF_INET, &ip, buf, sizeof(buf));
|
||||
auto itr = m_IPToAddr.find(ip);
|
||||
if(itr != m_IPToAddr.end())
|
||||
{
|
||||
llarp::LogWarn(buf, " already mapped to ", itr->second.ToString());
|
||||
llarp::LogWarn(inet_ntoa({ip}), " already mapped to ",
|
||||
itr->second.ToString());
|
||||
return false;
|
||||
}
|
||||
llarp::LogInfo("map ", addr.ToString(), " to ", buf);
|
||||
llarp::LogInfo(Name() + " map ", addr.ToString(), " to ",
|
||||
inet_ntoa({ip}));
|
||||
m_IPToAddr.insert(std::make_pair(ip, addr));
|
||||
m_AddrToIP.insert(std::make_pair(addr, ip));
|
||||
// TODO: make ip mapping persist forever
|
||||
MarkIPActive(ip);
|
||||
MarkIPActiveForever(ip);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -141,12 +142,12 @@ namespace llarp
|
|||
llarp::LogError(Name(), " failed to set up tun interface");
|
||||
return false;
|
||||
}
|
||||
m_OurIP = inet_addr(tunif.ifaddr);
|
||||
m_OurIP = ntohl(inet_addr(tunif.ifaddr));
|
||||
m_NextIP = m_OurIP;
|
||||
uint32_t mask = tunif.netmask;
|
||||
|
||||
uint32_t baseaddr = (ntohs(m_OurIP) & netmask_ipv4_bits(mask));
|
||||
m_MaxIP = (ntohs(baseaddr) | ~ntohs(netmask_ipv4_bits(mask)));
|
||||
uint32_t baseaddr = (htonl(m_OurIP) & netmask_ipv4_bits(mask));
|
||||
m_MaxIP = (htonl(baseaddr) | ~htonl(netmask_ipv4_bits(mask)));
|
||||
char buf[128] = {0};
|
||||
llarp::LogInfo(Name(), " set ", tunif.ifname, " to have address ",
|
||||
inet_ntop(AF_INET, &m_OurIP, buf, sizeof(buf)));
|
||||
|
@ -183,65 +184,68 @@ namespace llarp
|
|||
auto itr = m_IPToAddr.find(pkt.dst());
|
||||
if(itr == m_IPToAddr.end())
|
||||
{
|
||||
in_addr a;
|
||||
a.s_addr = pkt.dst();
|
||||
llarp::LogWarn("drop packet to ", inet_ntoa(a));
|
||||
llarp::DumpBuffer(pkt.Buffer());
|
||||
llarp::LogWarn(Name(), " has no endpoint for ",
|
||||
inet_ntoa({htonl(pkt.dst())}));
|
||||
return true;
|
||||
}
|
||||
return SendToOrQueue(itr->second, pkt.Buffer(),
|
||||
service::eProtocolTraffic);
|
||||
if(!SendToOrQueue(itr->second, pkt.Buffer(), service::eProtocolTraffic))
|
||||
{
|
||||
llarp::LogWarn(Name(), " did not flush packets");
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
TunEndpoint::HandleDataMessage(service::ProtocolMessage *msg)
|
||||
bool
|
||||
TunEndpoint::ProcessDataMessage(service::ProtocolMessage *msg)
|
||||
{
|
||||
if(msg->proto != service::eProtocolTraffic)
|
||||
{
|
||||
llarp::LogWarn("dropping unwarrented message, not ip traffic, proto=",
|
||||
msg->proto);
|
||||
return;
|
||||
}
|
||||
uint32_t themIP = ObtainIPForAddr(msg->sender.Addr());
|
||||
uint32_t usIP = m_OurIP;
|
||||
auto buf = llarp::Buffer(msg->payload);
|
||||
if(!m_NetworkToUserPktQueue.EmplaceIf(
|
||||
if(m_NetworkToUserPktQueue.EmplaceIf(
|
||||
[buf, themIP, usIP](net::IPv4Packet &pkt) -> bool {
|
||||
// do packet info rewrite here
|
||||
// TODO: don't truncate packet here
|
||||
memcpy(pkt.buf, buf.base, std::min(buf.sz, sizeof(pkt.buf)));
|
||||
pkt.sz = std::min(buf.sz, sizeof(pkt.buf));
|
||||
memcpy(pkt.buf, buf.base, pkt.sz);
|
||||
pkt.src(themIP);
|
||||
pkt.dst(usIP);
|
||||
pkt.UpdateChecksum();
|
||||
return true;
|
||||
}))
|
||||
{
|
||||
llarp::LogWarn("failed to parse buffer for ip traffic");
|
||||
llarp::DumpBuffer(buf);
|
||||
}
|
||||
|
||||
llarp::LogInfo(Name(), " handle data message ", msg->payload.size(),
|
||||
" bytes from ", inet_ntoa({htonl(themIP)}));
|
||||
else
|
||||
llarp::LogWarn(Name(), " dropped packet");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TunEndpoint::ObtainIPForAddr(const service::Address &addr)
|
||||
{
|
||||
llarp_time_t now = llarp_time_now_ms();
|
||||
uint32_t nextIP;
|
||||
uint32_t nextIP = 0;
|
||||
{
|
||||
// previously allocated address
|
||||
auto itr = m_AddrToIP.find(addr);
|
||||
if(itr != m_AddrToIP.end())
|
||||
{
|
||||
// mark ip active
|
||||
m_IPActivity[itr->second] = now;
|
||||
MarkIPActive(itr->second);
|
||||
return itr->second;
|
||||
}
|
||||
}
|
||||
// allocate new address
|
||||
if(m_NextIP < m_MaxIP)
|
||||
{
|
||||
nextIP = ++m_NextIP;
|
||||
m_AddrToIP.insert(std::make_pair(addr, nextIP));
|
||||
m_IPToAddr.insert(std::make_pair(nextIP, addr));
|
||||
llarp::LogInfo(Name(), " mapped ", addr, " to ",
|
||||
inet_ntoa({htonl(nextIP)}));
|
||||
MarkIPActive(nextIP);
|
||||
return nextIP;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -271,7 +275,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
// mark ip active
|
||||
m_IPActivity[nextIP] = now;
|
||||
m_IPActivity[nextIP] = std::max(m_IPActivity[nextIP], now);
|
||||
|
||||
return nextIP;
|
||||
}
|
||||
|
@ -285,7 +289,13 @@ namespace llarp
|
|||
void
|
||||
TunEndpoint::MarkIPActive(uint32_t ip)
|
||||
{
|
||||
m_IPActivity[ip] = llarp_time_now_ms();
|
||||
m_IPActivity[ip] = std::max(llarp_time_now_ms(), m_IPActivity[ip]);
|
||||
}
|
||||
|
||||
void
|
||||
TunEndpoint::MarkIPActiveForever(uint32_t ip)
|
||||
{
|
||||
m_IPActivity[ip] = std::numeric_limits< uint64_t >::max();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -331,9 +341,9 @@ namespace llarp
|
|||
if(!self->m_UserToNetworkPktQueue.EmplaceIf(
|
||||
[self, buf, sz](net::IPv4Packet &pkt) -> bool {
|
||||
return pkt.Load(llarp::InitBuffer(buf, sz))
|
||||
&& pkt.Header()->ip_version == 4;
|
||||
&& pkt.Header()->version == 4;
|
||||
}))
|
||||
llarp::LogError("Failed to parse ipv4 packet");
|
||||
llarp::LogDebug("Failed to parse ipv4 packet");
|
||||
}
|
||||
|
||||
TunEndpoint::~TunEndpoint()
|
||||
|
|
71
llarp/ip.cpp
71
llarp/ip.cpp
|
@ -3,6 +3,8 @@
|
|||
#include <llarp/ip.hpp>
|
||||
#include "llarp/buffer.hpp"
|
||||
#include "mem.hpp"
|
||||
#include <llarp/endian.h>
|
||||
#include <map>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
|
@ -26,30 +28,65 @@ namespace llarp
|
|||
return llarp::InitBuffer(buf, sz);
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
ipchksum(const byte_t *buf, size_t sz, uint32_t sum = 0)
|
||||
{
|
||||
while(sz > 1)
|
||||
{
|
||||
sum += *(const uint16_t *)buf;
|
||||
sz -= sizeof(uint16_t);
|
||||
buf += sizeof(uint16_t);
|
||||
}
|
||||
if(sz > 0)
|
||||
sum += *(const byte_t *)buf;
|
||||
|
||||
while(sum >> 16)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
|
||||
return ~sum;
|
||||
}
|
||||
|
||||
static std::map<
|
||||
byte_t, std::function< void(const ip_header *, byte_t *, size_t) > >
|
||||
protoCheckSummer = {
|
||||
/// ICMP
|
||||
{1,
|
||||
[](const ip_header *hdr, byte_t *buf, size_t sz) {
|
||||
auto len = hdr->ihl * 4;
|
||||
uint16_t *check = (uint16_t *)buf + len + 2;
|
||||
*check = 0;
|
||||
*check = ipchksum(buf, sz);
|
||||
}},
|
||||
/// TCP
|
||||
{6, [](const ip_header *hdr, byte_t *pkt, size_t sz) {
|
||||
byte_t pktbuf[1500];
|
||||
auto len = hdr->ihl * 4;
|
||||
size_t pktsz = sz - len;
|
||||
uint16_t *check = (uint16_t *)(pkt + len + 16);
|
||||
*check = 0;
|
||||
memcpy(pktbuf, &hdr->saddr, 4);
|
||||
memcpy(pktbuf + 4, &hdr->daddr, 4);
|
||||
pktbuf[8] = 0;
|
||||
pktbuf[9] = 6;
|
||||
// TODO: endian (?)
|
||||
pktbuf[10] = (pktsz & 0xff00) >> 8;
|
||||
pktbuf[11] = pktsz & 0x00ff;
|
||||
memcpy(pktbuf + 12, pkt + len, pktsz);
|
||||
*check = ipchksum(pktbuf, 12 + pktsz);
|
||||
}}};
|
||||
void
|
||||
IPv4Packet::UpdateChecksum()
|
||||
{
|
||||
auto hdr = Header();
|
||||
hdr->check = 0;
|
||||
|
||||
size_t count = hdr->ihl;
|
||||
uint32_t sum = 0;
|
||||
byte_t *addr = buf;
|
||||
|
||||
while(count > 1)
|
||||
auto len = hdr->ihl * 4;
|
||||
hdr->check = ipchksum(buf, len);
|
||||
auto proto = hdr->protocol;
|
||||
auto itr = protoCheckSummer.find(proto);
|
||||
if(itr != protoCheckSummer.end())
|
||||
{
|
||||
sum += ntohs(*(uint16_t *)addr);
|
||||
count -= sizeof(uint16_t);
|
||||
addr += sizeof(uint16_t);
|
||||
itr->second(hdr, buf, sz);
|
||||
}
|
||||
if(count > 0)
|
||||
sum += *(byte_t *)addr;
|
||||
|
||||
while(sum >> 16)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
|
||||
hdr->check = htons(~sum);
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace llarp
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace llarp
|
|||
bool
|
||||
ILinkLayer::HasSessionTo(const PubKey& pk)
|
||||
{
|
||||
util::Lock l(m_AuthedLinksMutex);
|
||||
Lock l(m_AuthedLinksMutex);
|
||||
return m_AuthedLinks.find(pk) != m_AuthedLinks.end();
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ namespace llarp
|
|||
{
|
||||
auto now = llarp_time_now_ms();
|
||||
{
|
||||
util::Lock lock(m_AuthedLinksMutex);
|
||||
Lock lock(m_AuthedLinksMutex);
|
||||
auto itr = m_AuthedLinks.begin();
|
||||
while(itr != m_AuthedLinks.end())
|
||||
{
|
||||
|
@ -51,7 +51,7 @@ namespace llarp
|
|||
}
|
||||
}
|
||||
{
|
||||
util::Lock lock(m_PendingMutex);
|
||||
Lock lock(m_PendingMutex);
|
||||
|
||||
auto itr = m_Pending.begin();
|
||||
while(itr != m_Pending.end())
|
||||
|
@ -70,8 +70,8 @@ namespace llarp
|
|||
void
|
||||
ILinkLayer::MapAddr(const PubKey& pk, ILinkSession* s)
|
||||
{
|
||||
util::Lock l_authed(m_AuthedLinksMutex);
|
||||
util::Lock l_pending(m_PendingMutex);
|
||||
Lock l_authed(m_AuthedLinksMutex);
|
||||
Lock l_pending(m_PendingMutex);
|
||||
auto itr = m_Pending.begin();
|
||||
while(itr != m_Pending.end())
|
||||
{
|
||||
|
@ -111,7 +111,7 @@ namespace llarp
|
|||
llarp::Addr addr(to);
|
||||
auto s = NewOutboundSession(rc, to);
|
||||
s->Start();
|
||||
PutSession(addr, s);
|
||||
PutSession(s);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -132,7 +132,7 @@ namespace llarp
|
|||
void
|
||||
ILinkLayer::CloseSessionTo(const PubKey& remote)
|
||||
{
|
||||
util::Lock l(m_AuthedLinksMutex);
|
||||
Lock l(m_AuthedLinksMutex);
|
||||
auto range = m_AuthedLinks.equal_range(remote);
|
||||
auto itr = range.first;
|
||||
while(itr != range.second)
|
||||
|
@ -145,7 +145,7 @@ namespace llarp
|
|||
void
|
||||
ILinkLayer::KeepAliveSessionTo(const PubKey& remote)
|
||||
{
|
||||
util::Lock l(m_AuthedLinksMutex);
|
||||
Lock l(m_AuthedLinksMutex);
|
||||
auto range = m_AuthedLinks.equal_range(remote);
|
||||
auto itr = range.first;
|
||||
while(itr != range.second)
|
||||
|
@ -158,17 +158,23 @@ namespace llarp
|
|||
bool
|
||||
ILinkLayer::SendTo(const PubKey& remote, llarp_buffer_t buf)
|
||||
{
|
||||
util::Lock l(m_AuthedLinksMutex);
|
||||
Lock l(m_AuthedLinksMutex);
|
||||
auto range = m_AuthedLinks.equal_range(remote);
|
||||
auto itr = range.first;
|
||||
// TODO: random selection
|
||||
// pick lowest backlog session
|
||||
size_t min = std::numeric_limits< size_t >::max();
|
||||
ILinkSession* s = nullptr;
|
||||
while(itr != range.second)
|
||||
{
|
||||
if(itr->second->SendMessageBuffer(buf))
|
||||
return true;
|
||||
auto backlog = itr->second->SendQueueBacklog();
|
||||
if(backlog < min)
|
||||
{
|
||||
s = itr->second.get();
|
||||
min = backlog;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
return false;
|
||||
return s && s->SendMessageBuffer(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -218,9 +224,9 @@ namespace llarp
|
|||
}
|
||||
|
||||
void
|
||||
ILinkLayer::PutSession(const Addr& addr, ILinkSession* s)
|
||||
ILinkLayer::PutSession(ILinkSession* s)
|
||||
{
|
||||
util::Lock lock(m_PendingMutex);
|
||||
Lock lock(m_PendingMutex);
|
||||
m_Pending.emplace_back(s);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,11 @@ namespace llarp
|
|||
FragmentOverheadSize + FragmentBodySize;
|
||||
typedef llarp::AlignedBuffer< FragmentBufferSize > FragmentBuffer;
|
||||
|
||||
constexpr size_t MaxSend = 64;
|
||||
|
||||
/// maximum size for send queue for a session before we drop
|
||||
constexpr size_t MaxSendQueueSize = 128;
|
||||
|
||||
typedef llarp::AlignedBuffer< MAX_LINK_MSG_SIZE > MessageBuffer;
|
||||
|
||||
struct LinkLayer;
|
||||
|
@ -47,8 +52,8 @@ namespace llarp
|
|||
llarp_time_t lastActive;
|
||||
const static llarp_time_t sessionTimeout = 30 * 1000;
|
||||
|
||||
std::deque< utp_iovec > vecq;
|
||||
std::deque< FragmentBuffer > sendq;
|
||||
size_t sendBufOffset;
|
||||
|
||||
FragmentBuffer recvBuf;
|
||||
size_t recvBufOffset;
|
||||
|
@ -60,14 +65,14 @@ namespace llarp
|
|||
Alive();
|
||||
|
||||
/// base
|
||||
BaseSession(llarp_router* r);
|
||||
BaseSession(LinkLayer* p);
|
||||
|
||||
/// outbound
|
||||
BaseSession(llarp_router* r, utp_socket* s, const RouterContact& rc,
|
||||
BaseSession(LinkLayer* p, utp_socket* s, const RouterContact& rc,
|
||||
const AddressInfo& addr);
|
||||
|
||||
/// inbound
|
||||
BaseSession(llarp_router* r, utp_socket* s, const Addr& remote);
|
||||
BaseSession(LinkLayer* p, utp_socket* s, const Addr& remote);
|
||||
|
||||
enum State
|
||||
{
|
||||
|
@ -96,16 +101,46 @@ namespace llarp
|
|||
EnterState(State st);
|
||||
|
||||
BaseSession();
|
||||
virtual ~BaseSession();
|
||||
~BaseSession();
|
||||
|
||||
void
|
||||
PumpWrite()
|
||||
{
|
||||
if(!sock)
|
||||
return;
|
||||
ssize_t expect = 0;
|
||||
std::vector< utp_iovec > vecs;
|
||||
for(const auto& vec : vecq)
|
||||
{
|
||||
expect += vec.iov_len;
|
||||
vecs.push_back(vec);
|
||||
}
|
||||
if(expect)
|
||||
{
|
||||
ssize_t s = utp_writev(sock, vecs.data(), vecs.size());
|
||||
llarp::LogDebug("utp_writev wrote=", s, " expect=", expect,
|
||||
" to=", remoteAddr);
|
||||
|
||||
while(s > vecq.front().iov_len)
|
||||
{
|
||||
s -= vecq.front().iov_len;
|
||||
vecq.pop_front();
|
||||
sendq.pop_front();
|
||||
}
|
||||
if(vecq.size())
|
||||
{
|
||||
auto& front = vecq.front();
|
||||
front.iov_len -= s;
|
||||
front.iov_base = ((byte_t*)front.iov_base) + s;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
while(sendq.size() > 0 && !stalled)
|
||||
{
|
||||
ssize_t expect = FragmentBufferSize - sendBufOffset;
|
||||
ssize_t s = write_ll(sendq.front().data() + sendBufOffset, expect);
|
||||
if(s != expect)
|
||||
ssize_t s = write_ll(sendq.front().data() + sendBufOffset,
|
||||
expect); if(s != expect)
|
||||
{
|
||||
llarp::LogDebug("stalled at offset=", sendBufOffset, " sz=", s,
|
||||
" to ", remoteAddr);
|
||||
|
@ -118,6 +153,7 @@ namespace llarp
|
|||
sendq.pop_front();
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
ssize_t
|
||||
|
@ -142,15 +178,10 @@ namespace llarp
|
|||
bool
|
||||
QueueWriteBuffers(llarp_buffer_t buf)
|
||||
{
|
||||
llarp::LogDebug("write ", buf.sz, " bytes to ", remoteAddr);
|
||||
if(state != eSessionReady)
|
||||
{
|
||||
llarp::LogWarn("failed to send ", buf.sz,
|
||||
" bytes on non ready session state=", state);
|
||||
if(sendq.size() >= MaxSendQueueSize)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
lastActive = llarp_time_now_ms();
|
||||
llarp::LogDebug("write ", buf.sz, " bytes to ", remoteAddr);
|
||||
lastActive = llarp_time_now_ms();
|
||||
size_t sz = buf.sz;
|
||||
byte_t* ptr = buf.base;
|
||||
while(sz)
|
||||
|
@ -174,59 +205,36 @@ namespace llarp
|
|||
OutboundLinkEstablished(LinkLayer* p)
|
||||
{
|
||||
OnLinkEstablished(p);
|
||||
KeyExchangeNonce nonce;
|
||||
nonce.Randomize();
|
||||
gotLIM = true;
|
||||
if(DoKeyExchange(Router()->crypto.transport_dh_client, nonce,
|
||||
remoteTransportPubKey, Router()->encryption))
|
||||
{
|
||||
SendHandshake(nonce);
|
||||
EnterState(eSessionReady);
|
||||
SendKeepAlive();
|
||||
}
|
||||
OutboundHandshake();
|
||||
}
|
||||
|
||||
// send our RC to the remote
|
||||
// send first message
|
||||
void
|
||||
SendHandshake(const KeyExchangeNonce& n)
|
||||
{
|
||||
FragmentBuffer tmp;
|
||||
auto buf = InitBuffer(tmp.data(), tmp.size());
|
||||
// fastforward buffer for handshake to fit before
|
||||
buf.cur += sizeof(uint32_t) * 2;
|
||||
byte_t* begin = buf.cur;
|
||||
LinkIntroMessage msg;
|
||||
msg.rc = Router()->rc;
|
||||
msg.N = n;
|
||||
if(!msg.BEncode(&buf))
|
||||
{
|
||||
llarp::LogError("failed to encode our RC for handshake");
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t sz = buf.cur - begin;
|
||||
llarp::LogDebug("handshake is of size ", sz, " bytes");
|
||||
// write handshake header
|
||||
buf.cur = buf.base;
|
||||
llarp_buffer_put_uint32(&buf, LLARP_PROTO_VERSION);
|
||||
llarp_buffer_put_uint32(&buf, sz);
|
||||
// send it
|
||||
write_ll(tmp.data(), sz + (sizeof(uint32_t) * 2));
|
||||
}
|
||||
OutboundHandshake();
|
||||
|
||||
// mix keys
|
||||
bool
|
||||
DoKeyExchange(llarp_transport_dh_func dh, const KeyExchangeNonce& n,
|
||||
const PubKey& other, const SecretKey& secret)
|
||||
{
|
||||
PubKey us = llarp::seckey_topublic(secret);
|
||||
llarp::LogDebug("DH us=", us, " them=", other, " n=", n);
|
||||
if(!dh(sessionKey, other, secret, n))
|
||||
ShortHash t_h;
|
||||
AlignedBuffer< 64 > tmp;
|
||||
memcpy(tmp.data(), sessionKey, sessionKey.size());
|
||||
memcpy(tmp.data() + sessionKey.size(), n, n.size());
|
||||
// t_h = HS(K + L.n)
|
||||
if(!Router()->crypto.shorthash(t_h, ConstBuffer(tmp)))
|
||||
{
|
||||
llarp::LogError("key exchange with ", other, " failed");
|
||||
Close();
|
||||
llarp::LogError("failed to mix key to ", remoteAddr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// K = TKE(a.p, B_a.e, sk, t_h)
|
||||
if(!dh(sessionKey, other, secret, t_h))
|
||||
{
|
||||
llarp::LogError("key exchange with ", other, " failed");
|
||||
return false;
|
||||
}
|
||||
llarp::LogDebug("keys mixed with session to ", remoteAddr);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -238,19 +246,11 @@ namespace llarp
|
|||
void
|
||||
Close();
|
||||
|
||||
bool
|
||||
RecvHandshake(const void* buf, size_t bufsz, LinkLayer* p);
|
||||
|
||||
bool
|
||||
Recv(const void* buf, size_t sz)
|
||||
{
|
||||
if(state != eSessionReady)
|
||||
{
|
||||
llarp::LogWarn("session not ready via ", remoteAddr);
|
||||
return false;
|
||||
}
|
||||
Alive();
|
||||
byte_t* ptr = (const byte_t*)buf;
|
||||
byte_t* ptr = (byte_t*)buf;
|
||||
llarp::LogDebug("utp read ", sz, " from ", remoteAddr);
|
||||
size_t s = sz;
|
||||
// process leftovers
|
||||
|
@ -290,9 +290,17 @@ namespace llarp
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
InboundLIM(const LinkIntroMessage* msg);
|
||||
|
||||
bool
|
||||
OutboundLIM(const LinkIntroMessage* msg);
|
||||
|
||||
bool
|
||||
IsTimedOut(llarp_time_t now) const
|
||||
{
|
||||
if(state == eClose)
|
||||
return true;
|
||||
if(now < lastActive)
|
||||
return false;
|
||||
auto dlt = now - lastActive;
|
||||
|
@ -346,7 +354,18 @@ namespace llarp
|
|||
static uint64
|
||||
OnError(utp_callback_arguments* arg)
|
||||
{
|
||||
llarp::LogError(utp_error_code_names[arg->error_code]);
|
||||
BaseSession* session =
|
||||
static_cast< BaseSession* >(utp_get_userdata(arg->socket));
|
||||
if(session)
|
||||
{
|
||||
if(arg->error_code == UTP_ETIMEDOUT)
|
||||
{
|
||||
session->Router()->OnConnectTimeout(session->GetPubKey());
|
||||
}
|
||||
llarp::LogError(utp_error_code_names[arg->error_code], " via ",
|
||||
session->remoteAddr);
|
||||
session->Close();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -481,7 +500,28 @@ namespace llarp
|
|||
#ifdef __linux__
|
||||
ProcessICMP();
|
||||
#endif
|
||||
std::set< PubKey > 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.find(pk) == m_AuthedLinks.end())
|
||||
{
|
||||
// all sessions were removed
|
||||
router->SessionClosed(pk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void
|
||||
Stop()
|
||||
|
@ -527,13 +567,16 @@ namespace llarp
|
|||
return std::unique_ptr< LinkLayer >(new LinkLayer(r));
|
||||
}
|
||||
|
||||
BaseSession::BaseSession(llarp_router* r)
|
||||
BaseSession::BaseSession(LinkLayer* p)
|
||||
{
|
||||
parent = p;
|
||||
remoteTransportPubKey.Zero();
|
||||
parent = nullptr;
|
||||
recvMsgOffset = 0;
|
||||
|
||||
SendQueueBacklog = [&]() -> size_t { return sendq.size(); };
|
||||
|
||||
SendKeepAlive = [&]() -> bool {
|
||||
if(false && sendq.size() == 0)
|
||||
if(sendq.size() == 0 && state == eSessionReady)
|
||||
{
|
||||
DiscardMessage msg;
|
||||
byte_t tmp[128] = {0};
|
||||
|
@ -547,14 +590,15 @@ namespace llarp
|
|||
}
|
||||
return true;
|
||||
};
|
||||
sendBufOffset = 0;
|
||||
gotLIM = false;
|
||||
recvBufOffset = 0;
|
||||
TimedOut = [&](llarp_time_t now) -> bool {
|
||||
return this->IsTimedOut(now) || this->state == eClose;
|
||||
};
|
||||
GetPubKey = std::bind(&BaseSession::RemotePubKey, this);
|
||||
lastActive = llarp_time_now_ms();
|
||||
Pump = std::bind(&BaseSession::PumpWrite, this);
|
||||
// Pump = []() {};
|
||||
Pump = std::bind(&BaseSession::PumpWrite, this);
|
||||
Tick = std::bind(&BaseSession::TickImpl, this, std::placeholders::_1);
|
||||
SendMessageBuffer = std::bind(&BaseSession::QueueWriteBuffers, this,
|
||||
std::placeholders::_1);
|
||||
|
@ -567,9 +611,9 @@ namespace llarp
|
|||
GetRemoteEndpoint = std::bind(&BaseSession::RemoteEndpoint, this);
|
||||
}
|
||||
|
||||
BaseSession::BaseSession(llarp_router* r, utp_socket* s,
|
||||
BaseSession::BaseSession(LinkLayer* p, utp_socket* s,
|
||||
const RouterContact& rc, const AddressInfo& addr)
|
||||
: BaseSession(r)
|
||||
: BaseSession(p)
|
||||
{
|
||||
remoteRC.Clear();
|
||||
remoteTransportPubKey = addr.pubkey;
|
||||
|
@ -579,17 +623,107 @@ namespace llarp
|
|||
assert(s == sock);
|
||||
remoteAddr = addr;
|
||||
Start = std::bind(&BaseSession::Connect, this);
|
||||
GotLIM =
|
||||
std::bind(&BaseSession::OutboundLIM, this, std::placeholders::_1);
|
||||
}
|
||||
|
||||
BaseSession::BaseSession(llarp_router* r, utp_socket* s, const Addr& addr)
|
||||
: BaseSession(r)
|
||||
BaseSession::BaseSession(LinkLayer* p, utp_socket* s, const Addr& addr)
|
||||
: BaseSession(p)
|
||||
{
|
||||
p->router->crypto.shorthash(sessionKey,
|
||||
InitBuffer(p->router->pubkey(), PUBKEYSIZE));
|
||||
remoteRC.Clear();
|
||||
sock = s;
|
||||
assert(s == sock);
|
||||
assert(utp_set_userdata(sock, this) == this);
|
||||
remoteAddr = addr;
|
||||
Start = []() {};
|
||||
GotLIM = std::bind(&BaseSession::InboundLIM, this, std::placeholders::_1);
|
||||
}
|
||||
|
||||
bool
|
||||
BaseSession::InboundLIM(const LinkIntroMessage* msg)
|
||||
{
|
||||
if(gotLIM && remoteRC.pubkey != msg->rc.pubkey)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
remoteRC = msg->rc;
|
||||
gotLIM = true;
|
||||
if(!DoKeyExchange(Router()->crypto.transport_dh_server, msg->N,
|
||||
remoteRC.enckey, parent->TransportSecretKey()))
|
||||
return false;
|
||||
EnterState(eSessionReady);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaseSession::OutboundLIM(const LinkIntroMessage* msg)
|
||||
{
|
||||
if(gotLIM && remoteRC.pubkey != msg->rc.pubkey)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
remoteRC = msg->rc;
|
||||
gotLIM = true;
|
||||
// TODO: update address info pubkey
|
||||
return DoKeyExchange(Router()->crypto.transport_dh_client, msg->N,
|
||||
remoteTransportPubKey, Router()->encryption);
|
||||
}
|
||||
|
||||
void
|
||||
BaseSession::OutboundHandshake()
|
||||
{
|
||||
// set session key
|
||||
Router()->crypto.shorthash(sessionKey, ConstBuffer(remoteRC.pubkey));
|
||||
|
||||
byte_t tmp[LinkIntroMessage::MaxSize];
|
||||
auto buf = StackBuffer< decltype(tmp) >(tmp);
|
||||
// build our RC
|
||||
LinkIntroMessage msg;
|
||||
msg.rc = Router()->rc();
|
||||
if(!msg.rc.VerifySignature(&Router()->crypto))
|
||||
{
|
||||
llarp::LogError("our RC is invalid? closing session to", remoteAddr);
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
msg.N.Randomize();
|
||||
msg.P = DefaultLinkSessionLifetime;
|
||||
if(!msg.Sign(&Router()->crypto, Router()->identity))
|
||||
{
|
||||
llarp::LogError("failed to sign LIM for outbound handshake to ",
|
||||
remoteAddr);
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
// encode
|
||||
if(!msg.BEncode(&buf))
|
||||
{
|
||||
llarp::LogError("failed to encode LIM for handshake to ", remoteAddr);
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
// rewind
|
||||
buf.sz = buf.cur - buf.base;
|
||||
buf.cur = buf.base;
|
||||
// send
|
||||
if(!SendMessageBuffer(buf))
|
||||
{
|
||||
llarp::LogError("failed to send handshake to ", remoteAddr);
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
// mix keys
|
||||
if(!DoKeyExchange(Router()->crypto.transport_dh_client, msg.N,
|
||||
remoteTransportPubKey, Router()->encryption))
|
||||
{
|
||||
llarp::LogError("failed to mix keys for outbound session to ",
|
||||
remoteAddr);
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
EnterState(eSessionReady);
|
||||
}
|
||||
|
||||
llarp_router*
|
||||
|
@ -611,14 +745,12 @@ namespace llarp
|
|||
LinkLayer::NewOutboundSession(const RouterContact& rc,
|
||||
const AddressInfo& addr)
|
||||
{
|
||||
return new BaseSession(router, utp_create_socket(_utp_ctx), rc, addr);
|
||||
return new BaseSession(this, utp_create_socket(_utp_ctx), rc, addr);
|
||||
}
|
||||
|
||||
uint64
|
||||
LinkLayer::OnRead(utp_callback_arguments* arg)
|
||||
{
|
||||
LinkLayer* parent =
|
||||
static_cast< LinkLayer* >(utp_context_get_userdata(arg->context));
|
||||
BaseSession* self =
|
||||
static_cast< BaseSession* >(utp_get_userdata(arg->socket));
|
||||
|
||||
|
@ -628,30 +760,18 @@ namespace llarp
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
else if(self->state == BaseSession::eSessionReady)
|
||||
if(!self->Recv(arg->buf, arg->len))
|
||||
{
|
||||
if(!self->Recv(arg->buf, arg->len))
|
||||
{
|
||||
llarp::LogDebug("recv fail for ", self->remoteAddr);
|
||||
self->Close();
|
||||
return 0;
|
||||
}
|
||||
utp_read_drained(arg->socket);
|
||||
}
|
||||
else if(self->state == BaseSession::eLinkEstablished)
|
||||
{
|
||||
if(!self->RecvHandshake(arg->buf, arg->len, parent))
|
||||
{
|
||||
llarp::LogDebug("recv handshake failed for ", self->remoteAddr);
|
||||
self->Close();
|
||||
return 0;
|
||||
}
|
||||
utp_read_drained(arg->socket);
|
||||
llarp::LogDebug("recv fail for ", self->remoteAddr);
|
||||
self->Close();
|
||||
return 0;
|
||||
}
|
||||
utp_read_drained(arg->socket);
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LogWarn("utp_socket got data with no underlying session");
|
||||
utp_close(arg->socket);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -675,12 +795,7 @@ namespace llarp
|
|||
}
|
||||
else if(arg->state == UTP_STATE_WRITABLE)
|
||||
{
|
||||
if(session->IsEstablished())
|
||||
{
|
||||
llarp::LogDebug("write resumed for ", session->remoteAddr);
|
||||
session->stalled = false;
|
||||
session->PumpWrite();
|
||||
}
|
||||
session->PumpWrite();
|
||||
}
|
||||
else if(arg->state == UTP_STATE_EOF)
|
||||
{
|
||||
|
@ -698,8 +813,8 @@ namespace llarp
|
|||
static_cast< LinkLayer* >(utp_context_get_userdata(arg->context));
|
||||
Addr remote(*arg->address);
|
||||
llarp::LogDebug("utp accepted from ", remote);
|
||||
BaseSession* session = new BaseSession(self->router, arg->socket, remote);
|
||||
self->PutSession(remote, session);
|
||||
BaseSession* session = new BaseSession(self, arg->socket, remote);
|
||||
self->PutSession(session);
|
||||
session->OnLinkEstablished(self);
|
||||
return 0;
|
||||
}
|
||||
|
@ -709,12 +824,12 @@ namespace llarp
|
|||
bool isLastFragment)
|
||||
|
||||
{
|
||||
if(state != eSessionReady)
|
||||
{
|
||||
llarp::LogWarn("tried to send to non ready session on ", remoteAddr);
|
||||
return;
|
||||
}
|
||||
FragmentBuffer buf;
|
||||
sendq.emplace_back();
|
||||
auto& buf = sendq.back();
|
||||
vecq.emplace_back();
|
||||
auto& vec = vecq.back();
|
||||
vec.iov_base = buf.data();
|
||||
vec.iov_len = FragmentBufferSize;
|
||||
llarp::LogDebug("encrypt then hash ", sz, " bytes last=", isLastFragment);
|
||||
buf.Randomize();
|
||||
byte_t* nonce = buf.data() + FragmentHashSize;
|
||||
|
@ -740,8 +855,6 @@ namespace llarp
|
|||
payload.sz = FragmentBufferSize - FragmentHashSize;
|
||||
// key'd hash
|
||||
Router()->crypto.hmac(buf.data(), payload, sessionKey);
|
||||
// push back
|
||||
sendq.push_back(std::move(buf));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -811,83 +924,6 @@ namespace llarp
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaseSession::RecvHandshake(const void* buf, size_t bufsz, LinkLayer* p)
|
||||
{
|
||||
size_t sz = bufsz;
|
||||
parent = p;
|
||||
|
||||
llarp::LogDebug("recv handshake ", sz, " from ", remoteAddr);
|
||||
if(sz <= 8)
|
||||
{
|
||||
llarp::LogDebug("handshake too small from ", remoteAddr);
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// process handshake header
|
||||
byte_t* ptr = (byte_t*)buf;
|
||||
uint32_t version = bufbe32toh(ptr);
|
||||
if(version != LLARP_PROTO_VERSION)
|
||||
{
|
||||
llarp::LogWarn("protocol version missmatch ", version,
|
||||
" != ", LLARP_PROTO_VERSION);
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
ptr += sizeof(uint32_t);
|
||||
sz -= sizeof(uint32_t);
|
||||
uint32_t limsz = bufbe32toh(ptr);
|
||||
ptr += sizeof(uint32_t);
|
||||
sz -= sizeof(uint32_t);
|
||||
if(limsz > sz)
|
||||
{
|
||||
// not enough data
|
||||
// TODO: don't bail here, continue reading
|
||||
llarp::LogDebug("not enough data for handshake, want ", limsz,
|
||||
" bytes but got ", sz);
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
llarp::LogDebug("from ", bufsz, " bytes reading ", limsz, " of ", sz,
|
||||
" bytes");
|
||||
|
||||
// process LIM
|
||||
auto mbuf = InitBuffer(ptr, limsz);
|
||||
LinkIntroMessage msg(this);
|
||||
if(!msg.BDecode(&mbuf))
|
||||
{
|
||||
llarp::LogError("Failed to parse LIM from ", remoteAddr);
|
||||
llarp::DumpBuffer(mbuf);
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
if(!msg.HandleMessage(Router()))
|
||||
{
|
||||
llarp::LogError("failed to verify signature of rc");
|
||||
return false;
|
||||
}
|
||||
gotLIM = true;
|
||||
sz -= limsz;
|
||||
remoteRC = msg.rc;
|
||||
if(!DoKeyExchange(Router()->crypto.transport_dh_server, msg.N,
|
||||
remoteRC.enckey, parent->TransportSecretKey()))
|
||||
return false;
|
||||
EnterState(eSessionReady);
|
||||
if(sz)
|
||||
{
|
||||
llarp::LogDebug("got ", sz, " leftover from handshake from ",
|
||||
remoteAddr);
|
||||
return Recv(ptr + limsz, sz);
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LogDebug("no leftovers in handshake from ", remoteAddr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
BaseSession::Close()
|
||||
{
|
||||
|
|
|
@ -29,6 +29,10 @@ namespace llarp
|
|||
llarp::LogWarn("failed to decode nonce in LIM");
|
||||
return false;
|
||||
}
|
||||
if(llarp_buffer_eq(key, "p"))
|
||||
{
|
||||
return bencode_read_integer(buf, &P);
|
||||
}
|
||||
if(llarp_buffer_eq(key, "r"))
|
||||
{
|
||||
if(rc.BDecode(buf))
|
||||
|
@ -50,6 +54,10 @@ namespace llarp
|
|||
llarp::LogDebug("LIM version ", version);
|
||||
return true;
|
||||
}
|
||||
else if(llarp_buffer_eq(key, "z"))
|
||||
{
|
||||
return Z.BDecode(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LogWarn("invalid LIM key: ", *key.cur);
|
||||
|
@ -73,6 +81,11 @@ namespace llarp
|
|||
if(!N.BEncode(buf))
|
||||
return false;
|
||||
|
||||
if(!bencode_write_bytestring(buf, "p", 1))
|
||||
return false;
|
||||
if(!bencode_write_uint64(buf, P))
|
||||
return false;
|
||||
|
||||
if(!bencode_write_bytestring(buf, "r", 1))
|
||||
return false;
|
||||
if(!rc.BEncode(buf))
|
||||
|
@ -81,12 +94,71 @@ namespace llarp
|
|||
if(!bencode_write_version_entry(buf))
|
||||
return false;
|
||||
|
||||
if(!bencode_write_bytestring(buf, "z", 1))
|
||||
return false;
|
||||
if(!Z.BEncode(buf))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
LinkIntroMessage&
|
||||
LinkIntroMessage::operator=(const LinkIntroMessage& msg)
|
||||
{
|
||||
version = msg.version;
|
||||
Z = msg.Z;
|
||||
rc = msg.rc;
|
||||
N = msg.N;
|
||||
P = msg.P;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
LinkIntroMessage::HandleMessage(llarp_router* router) const
|
||||
{
|
||||
return rc.VerifySignature(&router->crypto);
|
||||
if(!Verify(&router->crypto))
|
||||
return false;
|
||||
return session->GotLIM(this);
|
||||
}
|
||||
|
||||
bool
|
||||
LinkIntroMessage::Sign(llarp_crypto* c, const SecretKey& k)
|
||||
{
|
||||
Z.Zero();
|
||||
byte_t tmp[MaxSize] = {0};
|
||||
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
|
||||
if(!BEncode(&buf))
|
||||
return false;
|
||||
buf.sz = buf.cur - buf.base;
|
||||
buf.cur = buf.base;
|
||||
return c->sign(Z, k, buf);
|
||||
}
|
||||
|
||||
bool
|
||||
LinkIntroMessage::Verify(llarp_crypto* c) const
|
||||
{
|
||||
LinkIntroMessage copy;
|
||||
copy = *this;
|
||||
copy.Z.Zero();
|
||||
byte_t tmp[MaxSize] = {0};
|
||||
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
|
||||
if(!copy.BEncode(&buf))
|
||||
return false;
|
||||
buf.sz = buf.cur - buf.base;
|
||||
buf.cur = buf.base;
|
||||
// outer signature
|
||||
if(!c->verify(rc.pubkey, buf, Z))
|
||||
{
|
||||
llarp::LogError("outer signature failure");
|
||||
return false;
|
||||
}
|
||||
// rc signature
|
||||
if(!rc.VerifySignature(c))
|
||||
{
|
||||
llarp::LogError("inner signature failure");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace llarp
|
||||
|
|
|
@ -27,6 +27,18 @@ struct llarp_nodedb
|
|||
entries;
|
||||
fs::path nodePath;
|
||||
|
||||
bool
|
||||
Remove(const llarp::PubKey &pk)
|
||||
{
|
||||
llarp::util::Lock lock(access);
|
||||
auto itr = entries.find(pk);
|
||||
if(itr == entries.end())
|
||||
return false;
|
||||
entries.erase(itr);
|
||||
fs::remove(fs::path(getRCFilePath(pk)));
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Clear()
|
||||
{
|
||||
|
@ -139,7 +151,6 @@ struct llarp_nodedb
|
|||
if(fpath.extension() != RC_FILE_EXT)
|
||||
return false;
|
||||
llarp::RouterContact rc;
|
||||
|
||||
if(!rc.Read(fpath.string().c_str()))
|
||||
{
|
||||
llarp::LogError("failed to read file ", fpath);
|
||||
|
@ -157,6 +168,19 @@ struct llarp_nodedb
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
visit(std::function< bool(const llarp::RouterContact &) > visit)
|
||||
{
|
||||
llarp::util::Lock lock(access);
|
||||
auto itr = entries.begin();
|
||||
while(itr != entries.end())
|
||||
{
|
||||
if(!visit(itr->second))
|
||||
return;
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
iterate(struct llarp_nodedb_iter i)
|
||||
{
|
||||
|
@ -339,6 +363,14 @@ llarp_nodedb_iterate_all(struct llarp_nodedb *n, struct llarp_nodedb_iter i)
|
|||
return n->entries.size();
|
||||
}
|
||||
|
||||
void
|
||||
llarp_nodedb_visit_loaded(
|
||||
struct llarp_nodedb *n,
|
||||
std::function< bool(const llarp::RouterContact &) > visit)
|
||||
{
|
||||
return n->visit(visit);
|
||||
}
|
||||
|
||||
/// maybe rename to verify_and_set
|
||||
void
|
||||
llarp_nodedb_async_verify(struct llarp_async_verify_rc *job)
|
||||
|
@ -373,6 +405,12 @@ llarp_nodedb_num_loaded(struct llarp_nodedb *n)
|
|||
return n->entries.size();
|
||||
}
|
||||
|
||||
bool
|
||||
llarp_nodedb_del_rc(struct llarp_nodedb *n, const llarp::RouterID &pk)
|
||||
{
|
||||
return n->Remove(pk);
|
||||
}
|
||||
|
||||
bool
|
||||
llarp_nodedb_select_random_hop(struct llarp_nodedb *n,
|
||||
const llarp::RouterContact &prev,
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <llarp/path.hpp>
|
||||
#include <llarp/pathbuilder.hpp>
|
||||
#include <llarp/messages/dht.hpp>
|
||||
#include <llarp/messages/discard.hpp>
|
||||
#include "buffer.hpp"
|
||||
#include "router.hpp"
|
||||
|
||||
|
@ -341,6 +342,7 @@ namespace llarp
|
|||
intro.router = hops[hsz - 1].rc.pubkey;
|
||||
// TODO: or is it rxid ?
|
||||
intro.pathID = hops[hsz - 1].txID;
|
||||
EnterState(ePathBuilding);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -370,7 +372,7 @@ namespace llarp
|
|||
bool
|
||||
Path::IsReady() const
|
||||
{
|
||||
return intro.latency > 0 && status == ePathEstablished;
|
||||
return intro.latency > 0 && _status == ePathEstablished;
|
||||
}
|
||||
|
||||
RouterID
|
||||
|
@ -379,11 +381,40 @@ namespace llarp
|
|||
return hops[0].rc.pubkey;
|
||||
}
|
||||
|
||||
void
|
||||
Path::EnterState(PathStatus st)
|
||||
{
|
||||
if(st == ePathTimeout)
|
||||
{
|
||||
llarp::LogInfo("path ", Name(), " has timed out");
|
||||
}
|
||||
else if(st == ePathBuilding)
|
||||
{
|
||||
llarp::LogInfo("path ", Name(), " is building");
|
||||
buildStarted = llarp_time_now_ms();
|
||||
}
|
||||
_status = st;
|
||||
}
|
||||
|
||||
void
|
||||
Path::Tick(llarp_time_t now, llarp_router* r)
|
||||
{
|
||||
if(Expired(now))
|
||||
return;
|
||||
|
||||
if(_status == ePathBuilding)
|
||||
{
|
||||
if(now < buildStarted)
|
||||
return;
|
||||
auto dlt = now - buildStarted;
|
||||
if(dlt >= PATH_BUILD_TIMEOUT)
|
||||
{
|
||||
r->routerProfiling.MarkPathFail(this);
|
||||
EnterState(ePathTimeout);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(now < m_LastLatencyTestTime)
|
||||
return;
|
||||
auto dlt = now - m_LastLatencyTestTime;
|
||||
|
@ -395,6 +426,23 @@ namespace llarp
|
|||
m_LastLatencyTestTime = now;
|
||||
SendRoutingMessage(&latency, r);
|
||||
}
|
||||
// check to see if this path is dead
|
||||
if(_status == ePathEstablished)
|
||||
{
|
||||
if(m_CheckForDead)
|
||||
{
|
||||
if(m_CheckForDead(this, dlt))
|
||||
{
|
||||
r->routerProfiling.MarkPathFail(this);
|
||||
EnterState(ePathTimeout);
|
||||
}
|
||||
}
|
||||
else if(dlt >= 10000)
|
||||
{
|
||||
r->routerProfiling.MarkPathFail(this);
|
||||
EnterState(ePathTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -420,14 +468,22 @@ namespace llarp
|
|||
bool
|
||||
Path::Expired(llarp_time_t now) const
|
||||
{
|
||||
if(status == ePathEstablished)
|
||||
if(_status == ePathEstablished)
|
||||
return now - buildStarted > hops[0].lifetime;
|
||||
else if(status == ePathBuilding)
|
||||
return now - buildStarted > PATH_BUILD_TIMEOUT;
|
||||
else if(_status == ePathBuilding)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string
|
||||
Path::Name() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "TX=" << TXID() << " RX=" << RXID();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
bool
|
||||
Path::HandleDownstream(llarp_buffer_t buf, const TunnelNonce& Y,
|
||||
llarp_router* r)
|
||||
|
@ -488,21 +544,33 @@ namespace llarp
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::HandleDataDiscardMessage(
|
||||
const llarp::routing::DataDiscardMessage* msg, llarp_router* r)
|
||||
{
|
||||
if(m_DropHandler)
|
||||
return m_DropHandler(this, msg->P, msg->S);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Path::HandlePathConfirmMessage(
|
||||
const llarp::routing::PathConfirmMessage* msg, llarp_router* r)
|
||||
{
|
||||
if(status == ePathBuilding)
|
||||
if(_status == ePathBuilding)
|
||||
{
|
||||
// finish initializing introduction
|
||||
intro.expiresAt = buildStarted + hops[0].lifetime;
|
||||
// confirm that we build the path
|
||||
status = ePathEstablished;
|
||||
llarp::LogInfo("path is confirmed tx=", TXID(), " rx=", RXID());
|
||||
EnterState(ePathEstablished);
|
||||
llarp::LogInfo("path is confirmed tx=", TXID(), " rx=", RXID(),
|
||||
" took ", llarp_time_now_ms() - buildStarted, " ms");
|
||||
if(m_BuiltHook)
|
||||
m_BuiltHook(this);
|
||||
m_BuiltHook = nullptr;
|
||||
|
||||
r->routerProfiling.MarkPathSuccess(this);
|
||||
|
||||
// persist session with upstream router until the path is done
|
||||
r->PersistSessionUntil(Upstream(), intro.expiresAt);
|
||||
|
||||
|
@ -522,7 +590,7 @@ namespace llarp
|
|||
Path::HandleHiddenServiceFrame(const llarp::service::ProtocolFrame* frame)
|
||||
{
|
||||
if(m_DataHandler)
|
||||
return m_DataHandler(frame);
|
||||
return m_DataHandler(this, frame);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -530,11 +598,12 @@ namespace llarp
|
|||
Path::HandlePathLatencyMessage(
|
||||
const llarp::routing::PathLatencyMessage* msg, llarp_router* r)
|
||||
{
|
||||
if(msg->L == m_LastLatencyTestID && status == ePathEstablished)
|
||||
// TODO: reanimate dead paths if they get this message
|
||||
if(msg->L == m_LastLatencyTestID && _status == ePathEstablished)
|
||||
{
|
||||
intro.latency = llarp_time_now_ms() - m_LastLatencyTestTime;
|
||||
llarp::LogInfo("path latency is ", intro.latency, " ms for tx=", TXID(),
|
||||
" rx=", RXID());
|
||||
llarp::LogDebug("path latency is ", intro.latency,
|
||||
" ms for tx=", TXID(), " rx=", RXID());
|
||||
m_LastLatencyTestID = 0;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace llarp
|
|||
hop.nonce))
|
||||
{
|
||||
llarp::LogError("Failed to generate shared key for path build");
|
||||
abort();
|
||||
delete ctx;
|
||||
return;
|
||||
}
|
||||
// generate nonceXOR valueself->hop->pathKey
|
||||
|
@ -82,6 +82,7 @@ namespace llarp
|
|||
{
|
||||
// failed to encode?
|
||||
llarp::LogError("Failed to generate Commit Record");
|
||||
delete ctx;
|
||||
return;
|
||||
}
|
||||
// use ephameral keypair for frame
|
||||
|
@ -90,6 +91,7 @@ namespace llarp
|
|||
if(!frame.EncryptInPlace(framekey, hop.rc.enckey, ctx->crypto))
|
||||
{
|
||||
llarp::LogError("Failed to encrypt LRCR");
|
||||
delete ctx;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -137,15 +139,15 @@ namespace llarp
|
|||
if(!router->SendToOrQueue(remote, ctx->LRCM))
|
||||
{
|
||||
llarp::LogError("failed to send LRCM");
|
||||
delete ctx;
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->path->status = llarp::path::ePathBuilding;
|
||||
ctx->path->buildStarted = llarp_time_now_ms();
|
||||
// persist session with router until this path is done
|
||||
router->PersistSessionUntil(remote, ctx->path->ExpireTime());
|
||||
// add own path
|
||||
router->paths.AddOwnPath(ctx->pathset, ctx->path);
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
namespace path
|
||||
|
|
|
@ -22,10 +22,7 @@ namespace llarp
|
|||
{
|
||||
for(auto& item : m_Paths)
|
||||
{
|
||||
if(item.second->status == ePathEstablished)
|
||||
{
|
||||
item.second->Tick(now, r);
|
||||
}
|
||||
item.second->Tick(now, r);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,19 +65,47 @@ namespace llarp
|
|||
}
|
||||
|
||||
Path*
|
||||
PathSet::GetPathByRouter(const RouterID& id) const
|
||||
PathSet::GetNewestPathByRouter(const RouterID& id) const
|
||||
{
|
||||
auto itr = m_Paths.begin();
|
||||
Path* chosen = nullptr;
|
||||
auto itr = m_Paths.begin();
|
||||
while(itr != m_Paths.end())
|
||||
{
|
||||
if(itr->second->IsReady())
|
||||
{
|
||||
if(itr->second->Endpoint() == id)
|
||||
return itr->second;
|
||||
{
|
||||
if(chosen == nullptr)
|
||||
chosen = itr->second;
|
||||
else if(chosen->intro.expiresAt < itr->second->intro.expiresAt)
|
||||
chosen = itr->second;
|
||||
}
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
return nullptr;
|
||||
return chosen;
|
||||
}
|
||||
|
||||
Path*
|
||||
PathSet::GetPathByRouter(const RouterID& id) const
|
||||
{
|
||||
Path* chosen = nullptr;
|
||||
auto itr = m_Paths.begin();
|
||||
while(itr != m_Paths.end())
|
||||
{
|
||||
if(itr->second->IsReady())
|
||||
{
|
||||
if(itr->second->Endpoint() == id)
|
||||
{
|
||||
if(chosen == nullptr)
|
||||
chosen = itr->second;
|
||||
else if(chosen->intro.latency > itr->second->intro.latency)
|
||||
chosen = itr->second;
|
||||
}
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
return chosen;
|
||||
}
|
||||
|
||||
Path*
|
||||
|
@ -103,7 +128,7 @@ namespace llarp
|
|||
auto itr = m_Paths.begin();
|
||||
while(itr != m_Paths.end())
|
||||
{
|
||||
if(itr->second->status == st)
|
||||
if(itr->second->_status == st)
|
||||
++count;
|
||||
++itr;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
#include <llarp/profiling.hpp>
|
||||
#include <fstream>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
bool
|
||||
RouterProfile::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
|
||||
if(!BEncodeWriteDictInt("g", connectGoodCount, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("p", pathSuccessCount, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("s", pathFailCount, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("t", connectTimeoutCount, buf))
|
||||
return false;
|
||||
if(!BEncodeWriteDictInt("v", version, buf))
|
||||
return false;
|
||||
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
RouterProfile::DecodeKey(llarp_buffer_t k, llarp_buffer_t* buf)
|
||||
{
|
||||
bool read = false;
|
||||
if(!BEncodeMaybeReadDictInt("g", connectGoodCount, read, k, buf))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictInt("t", connectTimeoutCount, read, k, buf))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictInt("v", version, read, k, buf))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictInt("s", pathFailCount, read, k, buf))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictInt("p", pathSuccessCount, read, k, buf))
|
||||
return false;
|
||||
return read;
|
||||
}
|
||||
|
||||
bool
|
||||
RouterProfile::IsGood(uint64_t chances) const
|
||||
{
|
||||
return connectTimeoutCount <= connectGoodCount
|
||||
/// 4 hops + N chances
|
||||
&& (pathSuccessCount * 4 * chances) >= (pathFailCount / chances);
|
||||
}
|
||||
|
||||
bool
|
||||
Profiling::IsBad(const RouterID& r, uint64_t chances)
|
||||
{
|
||||
lock_t lock(m_ProfilesMutex);
|
||||
auto itr = m_Profiles.find(r);
|
||||
if(itr == m_Profiles.end())
|
||||
return false;
|
||||
return !itr->second.IsGood(chances);
|
||||
}
|
||||
|
||||
void
|
||||
Profiling::MarkTimeout(const RouterID& r)
|
||||
{
|
||||
lock_t lock(m_ProfilesMutex);
|
||||
m_Profiles[r].connectTimeoutCount += 1;
|
||||
}
|
||||
|
||||
void
|
||||
Profiling::MarkSuccess(const RouterID& r)
|
||||
{
|
||||
lock_t lock(m_ProfilesMutex);
|
||||
m_Profiles[r].connectGoodCount += 1;
|
||||
}
|
||||
|
||||
void
|
||||
Profiling::MarkPathFail(path::Path* p)
|
||||
{
|
||||
lock_t lock(m_ProfilesMutex);
|
||||
for(const auto& hop : p->hops)
|
||||
{
|
||||
// TODO: also mark bad?
|
||||
m_Profiles[hop.rc.pubkey].pathFailCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Profiling::MarkPathSuccess(path::Path* p)
|
||||
{
|
||||
lock_t lock(m_ProfilesMutex);
|
||||
for(const auto& hop : p->hops)
|
||||
{
|
||||
m_Profiles[hop.rc.pubkey].pathSuccessCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Profiling::Save(const char* fname)
|
||||
{
|
||||
lock_t lock(m_ProfilesMutex);
|
||||
size_t sz = (m_Profiles.size() * (RouterProfile::MaxSize + 32 + 8)) + 8;
|
||||
|
||||
byte_t* tmp = new byte_t[sz];
|
||||
auto buf = llarp::InitBuffer(tmp, sz);
|
||||
auto res = BEncode(&buf);
|
||||
if(res)
|
||||
{
|
||||
buf.sz = buf.cur - buf.base;
|
||||
std::ofstream f;
|
||||
f.open(fname);
|
||||
if(f.is_open())
|
||||
{
|
||||
f.write((char*)buf.base, buf.sz);
|
||||
}
|
||||
}
|
||||
delete[] tmp;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool
|
||||
Profiling::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if(!bencode_start_dict(buf))
|
||||
return false;
|
||||
auto itr = m_Profiles.begin();
|
||||
while(itr != m_Profiles.end())
|
||||
{
|
||||
if(!itr->first.BEncode(buf))
|
||||
return false;
|
||||
if(!itr->second.BEncode(buf))
|
||||
return false;
|
||||
++itr;
|
||||
}
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
Profiling::DecodeKey(llarp_buffer_t k, llarp_buffer_t* buf)
|
||||
{
|
||||
if(k.sz != 32)
|
||||
return false;
|
||||
RouterProfile profile;
|
||||
if(!profile.BDecode(buf))
|
||||
return false;
|
||||
RouterID pk = k.base;
|
||||
return m_Profiles.insert(std::make_pair(pk, profile)).second;
|
||||
}
|
||||
|
||||
bool
|
||||
Profiling::Load(const char* fname)
|
||||
{
|
||||
lock_t lock(m_ProfilesMutex);
|
||||
m_Profiles.clear();
|
||||
if(!BDecodeReadFile(fname, *this))
|
||||
{
|
||||
llarp::LogWarn("failed to load router profiles from ", fname);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace llarp
|
|
@ -119,6 +119,7 @@ namespace llarp
|
|||
{
|
||||
return path->HandleDownstream(X.Buffer(), Y, r);
|
||||
}
|
||||
llarp::LogWarn("unhandled downstream message");
|
||||
return false;
|
||||
}
|
||||
} // namespace llarp
|
||||
|
|
184
llarp/router.cpp
184
llarp/router.cpp
|
@ -52,12 +52,22 @@ struct TryConnectJob
|
|||
void
|
||||
AttemptTimedout()
|
||||
{
|
||||
router->routerProfiling.MarkTimeout(rc.pubkey);
|
||||
if(ShouldRetry())
|
||||
{
|
||||
Attempt();
|
||||
return;
|
||||
}
|
||||
if(router->routerProfiling.IsBad(rc.pubkey))
|
||||
llarp_nodedb_del_rc(router->nodedb, rc.pubkey);
|
||||
// delete this
|
||||
router->pendingEstablishJobs.erase(rc.pubkey);
|
||||
}
|
||||
|
||||
void
|
||||
Attempt()
|
||||
{
|
||||
--triesLeft;
|
||||
link->TryEstablishTo(rc);
|
||||
}
|
||||
|
||||
|
@ -93,7 +103,7 @@ llarp_router_try_connect(struct llarp_router *router,
|
|||
std::make_unique< TryConnectJob >(remote, link, numretries, router)));
|
||||
TryConnectJob *job = itr.first->second.get();
|
||||
// try establishing async
|
||||
job->Attempt();
|
||||
llarp_logic_queue_job(router->logic, {job, &on_try_connecting});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -142,6 +152,8 @@ llarp_router::PersistSessionUntil(const llarp::RouterID &remote,
|
|||
}
|
||||
}
|
||||
|
||||
constexpr size_t MaxPendingSendQueueSize = 8;
|
||||
|
||||
bool
|
||||
llarp_router::SendToOrQueue(const llarp::RouterID &remote,
|
||||
const llarp::ILinkMessage *msg)
|
||||
|
@ -171,15 +183,24 @@ llarp_router::SendToOrQueue(const llarp::RouterID &remote,
|
|||
return false;
|
||||
// queue buffer
|
||||
auto &q = outboundMessageQueue[remote];
|
||||
buf.sz = buf.cur - buf.base;
|
||||
|
||||
if(q.size() >= MaxPendingSendQueueSize)
|
||||
{
|
||||
llarp::LogWarn("tried to queue a message to ", remote,
|
||||
" but the queue is full so we drop it like it's hawt");
|
||||
return false;
|
||||
}
|
||||
|
||||
buf.sz = buf.cur - buf.base;
|
||||
q.emplace(buf.sz);
|
||||
memcpy(q.back().data(), buf.base, buf.sz);
|
||||
|
||||
llarp::RouterContact remoteRC;
|
||||
// we don't have an open session to that router right now
|
||||
if(llarp_nodedb_get_rc(nodedb, remote, rc))
|
||||
if(llarp_nodedb_get_rc(nodedb, remote, remoteRC))
|
||||
{
|
||||
// try connecting directly as the rc is loaded from disk
|
||||
llarp_router_try_connect(this, rc, 10);
|
||||
llarp_router_try_connect(this, remoteRC, 10);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -198,6 +219,7 @@ llarp_router::HandleDHTLookupForSendTo(
|
|||
{
|
||||
llarp_nodedb_put_rc(nodedb, results[0]);
|
||||
llarp_router_try_connect(this, results[0], 10);
|
||||
async_verify_RC(results[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -264,13 +286,13 @@ bool
|
|||
llarp_router::SaveRC()
|
||||
{
|
||||
llarp::LogDebug("verify RC signature");
|
||||
if(!rc.VerifySignature(&crypto))
|
||||
if(!rc().VerifySignature(&crypto))
|
||||
{
|
||||
rc.Dump< MAX_RC_SIZE >();
|
||||
rc().Dump< MAX_RC_SIZE >();
|
||||
llarp::LogError("RC has bad signature not saving");
|
||||
return false;
|
||||
}
|
||||
return rc.Write(our_rc_file.string().c_str());
|
||||
return rc().Write(our_rc_file.string().c_str());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -297,6 +319,9 @@ llarp_router::on_verify_client_rc(llarp_async_verify_rc *job)
|
|||
llarp::async_verify_context *ctx =
|
||||
static_cast< llarp::async_verify_context * >(job->user);
|
||||
ctx->router->pendingEstablishJobs.erase(job->rc.pubkey);
|
||||
auto router = ctx->router;
|
||||
llarp::PubKey pk(job->rc.pubkey);
|
||||
router->FlushOutboundFor(pk, router->GetLinkWithSessionByPubkey(pk));
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
|
@ -334,6 +359,9 @@ llarp_router::on_verify_server_rc(llarp_async_verify_rc *job)
|
|||
// track valid router in dht
|
||||
router->dht->impl.nodes->PutNode(rc);
|
||||
|
||||
// mark success in profile
|
||||
router->routerProfiling.MarkSuccess(pk);
|
||||
|
||||
// this was an outbound establish job
|
||||
if(ctx->establish_job)
|
||||
{
|
||||
|
@ -362,22 +390,43 @@ llarp_router::TryEstablishTo(const llarp::RouterID &remote)
|
|||
// try connecting async
|
||||
llarp_router_try_connect(this, rc, 5);
|
||||
}
|
||||
else
|
||||
else if(!routerProfiling.IsBad(remote))
|
||||
{
|
||||
if(dht->impl.HasRouterLookup(remote))
|
||||
return;
|
||||
llarp::LogInfo("looking up router ", remote);
|
||||
// dht lookup as we don't know it
|
||||
dht->impl.LookupRouter(
|
||||
remote,
|
||||
std::bind(&llarp_router::HandleDHTLookupForTryEstablishTo, this,
|
||||
std::bind(&llarp_router::HandleDHTLookupForTryEstablishTo, this, remote,
|
||||
std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
llarp_router::HandleDHTLookupForTryEstablishTo(
|
||||
const std::vector< llarp::RouterContact > &results)
|
||||
llarp_router::OnConnectTimeout(const llarp::RouterID &remote)
|
||||
{
|
||||
auto itr = pendingEstablishJobs.find(remote);
|
||||
if(itr != pendingEstablishJobs.end())
|
||||
{
|
||||
itr->second->AttemptTimedout();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
llarp_router::HandleDHTLookupForTryEstablishTo(
|
||||
llarp::RouterID remote, const std::vector< llarp::RouterContact > &results)
|
||||
{
|
||||
if(results.size() == 0)
|
||||
{
|
||||
routerProfiling.MarkTimeout(remote);
|
||||
}
|
||||
for(const auto &result : results)
|
||||
{
|
||||
llarp_nodedb_put_rc(nodedb, result);
|
||||
llarp_router_try_connect(this, result, 10);
|
||||
async_verify_RC(result);
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
|
@ -397,14 +446,7 @@ llarp_router::Tick()
|
|||
while(itr != m_PersistingSessions.end())
|
||||
{
|
||||
auto link = GetLinkWithSessionByPubkey(itr->first);
|
||||
if(now > itr->second)
|
||||
{
|
||||
// persisting ended
|
||||
if(link)
|
||||
link->CloseSessionTo(itr->first);
|
||||
itr = m_PersistingSessions.erase(itr);
|
||||
}
|
||||
else
|
||||
if(now < itr->second)
|
||||
{
|
||||
if(link)
|
||||
{
|
||||
|
@ -416,26 +458,28 @@ llarp_router::Tick()
|
|||
llarp::LogDebug("establish to ", itr->first);
|
||||
TryEstablishTo(itr->first);
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
if(inboundLinks.size() == 0)
|
||||
{
|
||||
auto N = llarp_nodedb_num_loaded(nodedb);
|
||||
if(N > 3)
|
||||
if(N < minRequiredRouters)
|
||||
{
|
||||
paths.BuildPaths();
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LogInfo(
|
||||
"We need more than 3 service nodes to build paths but we have ", N);
|
||||
dht->impl.Explore(N);
|
||||
llarp::LogInfo("We need at least ", minRequiredRouters,
|
||||
" service nodes to build paths but we have ", N);
|
||||
auto explore = std::max(NumberOfConnectedRouters(), size_t(1));
|
||||
dht->impl.Explore(explore);
|
||||
}
|
||||
paths.BuildPaths();
|
||||
hiddenServiceContext.Tick();
|
||||
}
|
||||
if(NumberOfConnectedRouters() < minConnectedRouters)
|
||||
{
|
||||
ConnectToRandomRouters(minConnectedRouters);
|
||||
}
|
||||
paths.TickPaths();
|
||||
}
|
||||
|
||||
|
@ -589,6 +633,7 @@ llarp_router::async_verify_RC(const llarp::RouterContact &rc)
|
|||
void
|
||||
llarp_router::Run()
|
||||
{
|
||||
routerProfiling.Load(routerProfilesFile.string().c_str());
|
||||
// zero out router contact
|
||||
sockaddr *dest = (sockaddr *)&this->ip4addr;
|
||||
llarp::Addr publicAddr(*dest);
|
||||
|
@ -614,7 +659,7 @@ llarp_router::Run()
|
|||
if(!a.isPrivate())
|
||||
{
|
||||
llarp::LogInfo("Loading Addr: ", a, " into our RC");
|
||||
rc.addrs.push_back(addr);
|
||||
_rc.addrs.push_back(addr);
|
||||
}
|
||||
};
|
||||
if(this->publicOverride)
|
||||
|
@ -640,19 +685,18 @@ llarp_router::Run()
|
|||
this->addrInfo.ip = *publicAddr.addr6();
|
||||
this->addrInfo.port = publicAddr.port();
|
||||
llarp::LogInfo("Loaded our public ", publicAddr, " override into RC!");
|
||||
// we need the link to set the pubkey
|
||||
rc.addrs.push_back(this->addrInfo);
|
||||
_rc.addrs.push_back(this->addrInfo);
|
||||
}
|
||||
}
|
||||
// set public encryption key
|
||||
rc.enckey = llarp::seckey_topublic(encryption);
|
||||
llarp::LogInfo("Your Encryption pubkey ", rc.enckey);
|
||||
_rc.enckey = llarp::seckey_topublic(encryption);
|
||||
llarp::LogInfo("Your Encryption pubkey ", rc().enckey);
|
||||
// set public signing key
|
||||
rc.pubkey = llarp::seckey_topublic(identity);
|
||||
llarp::LogInfo("Your Identity pubkey ", rc.pubkey);
|
||||
_rc.pubkey = llarp::seckey_topublic(identity);
|
||||
llarp::LogInfo("Your Identity pubkey ", rc().pubkey);
|
||||
|
||||
llarp::LogInfo("Signing rc...");
|
||||
if(!rc.Sign(&crypto, identity))
|
||||
if(!_rc.Sign(&crypto, identity))
|
||||
{
|
||||
llarp::LogError("failed to sign rc");
|
||||
return;
|
||||
|
@ -663,6 +707,8 @@ llarp_router::Run()
|
|||
return;
|
||||
}
|
||||
|
||||
llarp::LogInfo("have ", llarp_nodedb_num_loaded(nodedb), " routers");
|
||||
|
||||
llarp::LogDebug("starting outbound link");
|
||||
if(!outboundLink->Start(logic))
|
||||
{
|
||||
|
@ -693,6 +739,18 @@ llarp_router::Run()
|
|||
}
|
||||
else
|
||||
{
|
||||
// we are a client
|
||||
// regenerate keys and resign rc before everything else
|
||||
crypto.identity_keygen(identity);
|
||||
crypto.encryption_keygen(encryption);
|
||||
_rc.pubkey = llarp::seckey_topublic(identity);
|
||||
_rc.enckey = llarp::seckey_topublic(encryption);
|
||||
if(!_rc.Sign(&crypto, identity))
|
||||
{
|
||||
llarp::LogError("failed to regenerate keys and sign RC");
|
||||
return;
|
||||
}
|
||||
|
||||
// delayed connect all for clients
|
||||
uint64_t delay = ((llarp_randint() % 10) * 500) + 500;
|
||||
llarp_logic_call_later(logic, {delay, this, &ConnectAll});
|
||||
|
@ -719,12 +777,47 @@ llarp_router::ConnectAll(void *user, uint64_t orig, uint64_t left)
|
|||
if(left)
|
||||
return;
|
||||
llarp_router *self = static_cast< llarp_router * >(user);
|
||||
// connect to all explicit connections in connect block
|
||||
for(const auto &itr : self->connect)
|
||||
{
|
||||
llarp::LogInfo("connecting to node ", itr.first);
|
||||
self->try_connect(itr.second);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
llarp_router::HasSessionTo(const llarp::RouterID &remote) const
|
||||
{
|
||||
return validRouters.find(remote) != validRouters.end();
|
||||
}
|
||||
|
||||
void
|
||||
llarp_router::ConnectToRandomRouters(int want)
|
||||
{
|
||||
int wanted = want;
|
||||
llarp_router *self = this;
|
||||
llarp_nodedb_visit_loaded(
|
||||
self->nodedb, [self, &want](const llarp::RouterContact &other) -> bool {
|
||||
if(llarp_randint() % 2 == 0
|
||||
&& !(self->HasSessionTo(other.pubkey)
|
||||
|| self->HasPendingConnectJob(other.pubkey)))
|
||||
{
|
||||
llarp_router_try_connect(self, other, 5);
|
||||
--want;
|
||||
}
|
||||
return want > 0;
|
||||
});
|
||||
if(wanted != want)
|
||||
llarp::LogInfo("connecting to ", abs(want - wanted), " out of ", wanted,
|
||||
" random routers");
|
||||
}
|
||||
|
||||
bool
|
||||
llarp_router::ReloadConfig(const llarp_config *conf)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
llarp_router::InitOutboundLink()
|
||||
{
|
||||
|
@ -807,7 +900,10 @@ void
|
|||
llarp_stop_router(struct llarp_router *router)
|
||||
{
|
||||
if(router)
|
||||
{
|
||||
router->Close();
|
||||
router->routerProfiling.Save(router->routerProfilesFile.string().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -966,14 +1062,26 @@ namespace llarp
|
|||
}
|
||||
else if(StrEq(section, "network"))
|
||||
{
|
||||
if(StrEq(key, "profiles"))
|
||||
{
|
||||
self->routerProfilesFile = fs::path(val);
|
||||
}
|
||||
if(StrEq(key, "min-connected"))
|
||||
{
|
||||
self->minConnectedRouters = std::max(atoi(val), 0);
|
||||
}
|
||||
if(StrEq(key, "max-connected"))
|
||||
{
|
||||
self->maxConnectedRouters = std::max(atoi(val), 1);
|
||||
}
|
||||
}
|
||||
else if(StrEq(section, "router"))
|
||||
{
|
||||
if(StrEq(key, "nickname"))
|
||||
{
|
||||
self->rc.SetNick(val);
|
||||
self->_rc.SetNick(val);
|
||||
// set logger name here
|
||||
_glog.nodeName = self->rc.Nick();
|
||||
_glog.nodeName = self->rc().Nick();
|
||||
}
|
||||
if(StrEq(key, "encryption-privkey"))
|
||||
{
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <llarp/routing/handler.hpp>
|
||||
#include <llarp/service.hpp>
|
||||
#include <llarp/establish_job.hpp>
|
||||
#include <llarp/profiling.hpp>
|
||||
|
||||
#include "crypto.hpp"
|
||||
#include "fs.hpp"
|
||||
|
@ -47,7 +48,13 @@ struct llarp_router
|
|||
fs::path our_rc_file = "rc.signed";
|
||||
|
||||
// our router contact
|
||||
llarp::RouterContact rc;
|
||||
llarp::RouterContact _rc;
|
||||
|
||||
const llarp::RouterContact &
|
||||
rc() const
|
||||
{
|
||||
return _rc;
|
||||
}
|
||||
|
||||
// our ipv4 public setting
|
||||
bool publicOverride = false;
|
||||
|
@ -69,6 +76,13 @@ struct llarp_router
|
|||
// buffer for serializing link messages
|
||||
byte_t linkmsg_buffer[MAX_LINK_MSG_SIZE];
|
||||
|
||||
/// always maintain this many connections to other routers
|
||||
size_t minConnectedRouters = 5;
|
||||
/// hard upperbound limit on the number of router to router connections
|
||||
size_t maxConnectedRouters = 2000;
|
||||
|
||||
int minRequiredRouters = 4;
|
||||
|
||||
// should we be sending padded messages every interval?
|
||||
bool sendPadding = false;
|
||||
|
||||
|
@ -82,6 +96,9 @@ struct llarp_router
|
|||
std::unique_ptr< llarp::ILinkLayer > outboundLink;
|
||||
std::list< std::unique_ptr< llarp::ILinkLayer > > inboundLinks;
|
||||
|
||||
llarp::Profiling routerProfiling;
|
||||
fs::path routerProfilesFile = "profiles.dat";
|
||||
|
||||
typedef std::queue< std::vector< byte_t > > MessageQueue;
|
||||
|
||||
/// outbound message queue
|
||||
|
@ -156,12 +173,18 @@ struct llarp_router
|
|||
return llarp::seckey_topublic(identity);
|
||||
}
|
||||
|
||||
void
|
||||
OnConnectTimeout(const llarp::RouterID &remote);
|
||||
|
||||
bool
|
||||
HasPendingConnectJob(const llarp::RouterID &remote);
|
||||
|
||||
void
|
||||
try_connect(fs::path rcfile);
|
||||
|
||||
bool
|
||||
ReloadConfig(const llarp_config *conf);
|
||||
|
||||
/// send to remote router or queue for sending
|
||||
/// returns false on overflow
|
||||
/// returns true on successful queue
|
||||
|
@ -207,6 +230,9 @@ struct llarp_router
|
|||
llarp::ILinkLayer *
|
||||
GetLinkWithSessionByPubkey(const llarp::RouterID &remote);
|
||||
|
||||
void
|
||||
ConnectToRandomRouters(int N);
|
||||
|
||||
size_t
|
||||
NumberOfConnectedRouters() const;
|
||||
|
||||
|
@ -220,8 +246,12 @@ struct llarp_router
|
|||
HandleDHTLookupForSendTo(llarp::RouterID remote,
|
||||
const std::vector< llarp::RouterContact > &results);
|
||||
|
||||
bool
|
||||
HasSessionTo(const llarp::RouterID &remote) const;
|
||||
|
||||
void
|
||||
HandleDHTLookupForTryEstablishTo(
|
||||
llarp::RouterID remote,
|
||||
const std::vector< llarp::RouterContact > &results);
|
||||
|
||||
static void
|
||||
|
|
|
@ -223,13 +223,9 @@ namespace llarp
|
|||
RouterContact &
|
||||
RouterContact::operator=(const RouterContact &other)
|
||||
{
|
||||
addrs.clear();
|
||||
exits.clear();
|
||||
addrs = other.addrs;
|
||||
exits = other.exits;
|
||||
|
||||
signature = other.signature;
|
||||
|
||||
addrs = other.addrs;
|
||||
exits = other.exits;
|
||||
signature = other.signature;
|
||||
last_updated = other.last_updated;
|
||||
enckey = other.enckey;
|
||||
pubkey = other.pubkey;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <llarp/messages/path_confirm.hpp>
|
||||
#include <llarp/messages/path_latency.hpp>
|
||||
#include <llarp/messages/path_transfer.hpp>
|
||||
#include <llarp/messages/discard.hpp>
|
||||
#include <llarp/routing/message.hpp>
|
||||
#include "mem.hpp"
|
||||
|
||||
|
@ -41,6 +42,9 @@ namespace llarp
|
|||
self->key = *strbuf.cur;
|
||||
switch(self->key)
|
||||
{
|
||||
case 'D':
|
||||
self->msg = new DataDiscardMessage();
|
||||
break;
|
||||
case 'L':
|
||||
self->msg = new PathLatencyMessage();
|
||||
break;
|
||||
|
@ -93,4 +97,4 @@ namespace llarp
|
|||
return result;
|
||||
}
|
||||
} // namespace routing
|
||||
} // namespace llarp
|
||||
} // namespace llarp
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace llarp
|
|||
return false;
|
||||
if(!BEncodeMaybeReadDictEntry("T", T, read, key, val))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictInt("V", V, read, key, val))
|
||||
if(!BEncodeMaybeReadDictInt("V", version, read, key, val))
|
||||
return false;
|
||||
if(!BEncodeMaybeReadDictEntry("Y", Y, read, key, val))
|
||||
return false;
|
||||
|
|
|
@ -105,7 +105,7 @@ namespace llarp
|
|||
auto highest = now;
|
||||
for(const auto& i : I)
|
||||
highest = std::max(i.expiresAt, highest);
|
||||
return highest == now;
|
||||
return highest <= now;
|
||||
}
|
||||
|
||||
Introduction::~Introduction()
|
||||
|
@ -260,7 +260,12 @@ namespace llarp
|
|||
return false;
|
||||
// decode
|
||||
inf.read((char*)buf.base, sz);
|
||||
return BDecode(&buf);
|
||||
if(!BDecode(&buf))
|
||||
return false;
|
||||
// update pubkey
|
||||
pub.Update(llarp::seckey_topublic(enckey),
|
||||
llarp::seckey_topublic(signkey));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace llarp
|
|||
namespace service
|
||||
{
|
||||
Endpoint::Endpoint(const std::string& name, llarp_router* r)
|
||||
: path::Builder(r, r->dht, 2, 4), m_Router(r), m_Name(name)
|
||||
: path::Builder(r, r->dht, 4, 4), m_Router(r), m_Name(name)
|
||||
{
|
||||
m_Tag.Zero();
|
||||
}
|
||||
|
@ -43,6 +43,12 @@ namespace llarp
|
|||
m_NetNS = v;
|
||||
m_OnInit.push_back(std::bind(&Endpoint::IsolateNetwork, this));
|
||||
}
|
||||
if(k == "min-latency")
|
||||
{
|
||||
auto val = atoi(v.c_str());
|
||||
if(val > 0)
|
||||
m_MinPathLatency = val;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -84,41 +90,55 @@ namespace llarp
|
|||
!= m_PendingServiceLookups.end();
|
||||
}
|
||||
|
||||
void
|
||||
Endpoint::RegenAndPublishIntroSet(llarp_time_t now)
|
||||
{
|
||||
std::set< Introduction > I;
|
||||
if(!GetCurrentIntroductions(I))
|
||||
{
|
||||
llarp::LogWarn("could not publish descriptors for endpoint ", Name(),
|
||||
" because we couldn't get any introductions");
|
||||
if(ShouldBuildMore())
|
||||
ManualRebuild(1);
|
||||
return;
|
||||
}
|
||||
IntroSet introset = m_IntroSet;
|
||||
introset.I.clear();
|
||||
for(const auto& intro : I)
|
||||
{
|
||||
llarp::LogInfo(intro);
|
||||
if(!intro.ExpiresSoon(now))
|
||||
introset.I.push_back(intro);
|
||||
}
|
||||
if(introset.I.size() == 0)
|
||||
{
|
||||
llarp::LogWarn("not enough intros to publish introset for ", Name());
|
||||
return;
|
||||
}
|
||||
introset.topic = m_Tag;
|
||||
if(!m_Identity.SignIntroSet(introset, &m_Router->crypto))
|
||||
{
|
||||
llarp::LogWarn("failed to sign introset for endpoint ", Name());
|
||||
return;
|
||||
}
|
||||
m_IntroSet = introset;
|
||||
if(PublishIntroSet(m_Router))
|
||||
{
|
||||
llarp::LogInfo("(re)publishing introset for endpoint ", Name());
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LogWarn("failed to publish intro set for endpoint ", Name());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Endpoint::Tick(llarp_time_t now)
|
||||
{
|
||||
/// reset tx id for publish
|
||||
if(now - m_LastPublishAttempt >= INTROSET_PUBLISH_RETRY_INTERVAL)
|
||||
m_CurrentPublishTX = 0;
|
||||
// publish descriptors
|
||||
if(ShouldPublishDescriptors(now))
|
||||
{
|
||||
std::set< Introduction > I;
|
||||
if(!GetCurrentIntroductions(I))
|
||||
{
|
||||
llarp::LogWarn("could not publish descriptors for endpoint ", Name(),
|
||||
" because we couldn't get any introductions");
|
||||
if(ShouldBuildMore())
|
||||
ManualRebuild(1);
|
||||
return;
|
||||
}
|
||||
m_IntroSet.I.clear();
|
||||
for(const auto& intro : I)
|
||||
m_IntroSet.I.push_back(intro);
|
||||
m_IntroSet.topic = m_Tag;
|
||||
if(!m_Identity.SignIntroSet(m_IntroSet, &m_Router->crypto))
|
||||
{
|
||||
llarp::LogWarn("failed to sign introset for endpoint ", Name());
|
||||
return;
|
||||
}
|
||||
if(PublishIntroSet(m_Router))
|
||||
{
|
||||
llarp::LogInfo("publishing introset for endpoint ", Name());
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LogWarn("failed to publish intro set for endpoint ", Name());
|
||||
}
|
||||
RegenAndPublishIntroSet(now);
|
||||
}
|
||||
// expire pending tx
|
||||
{
|
||||
|
@ -346,6 +366,7 @@ namespace llarp
|
|||
{
|
||||
inserted |= tags.insert(itr->first).second;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
return inserted;
|
||||
}
|
||||
|
@ -451,46 +472,78 @@ namespace llarp
|
|||
bool
|
||||
Endpoint::PublishIntroSet(llarp_router* r)
|
||||
{
|
||||
auto path = GetEstablishedPathClosestTo(m_Identity.pub.Addr().ToRouter());
|
||||
if(path)
|
||||
auto path = GetEstablishedPathClosestTo(m_Identity.pub.Addr().data());
|
||||
if(path && PublishIntroSetVia(r, path))
|
||||
{
|
||||
m_CurrentPublishTX = llarp_randint();
|
||||
llarp::routing::DHTMessage msg;
|
||||
msg.M.emplace_back(new llarp::dht::PublishIntroMessage(
|
||||
m_IntroSet, m_CurrentPublishTX, 4));
|
||||
if(path->SendRoutingMessage(&msg, r))
|
||||
{
|
||||
m_LastPublishAttempt = llarp_time_now_ms();
|
||||
llarp::LogInfo(Name(), " publishing introset");
|
||||
return true;
|
||||
}
|
||||
path = PickRandomEstablishedPath();
|
||||
return path && PublishIntroSetVia(r, path);
|
||||
}
|
||||
llarp::LogWarn(Name(), " publish introset failed, no path");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct PublishIntroSetJob : public IServiceLookup
|
||||
{
|
||||
IntroSet m_IntroSet;
|
||||
Endpoint* m_Endpoint;
|
||||
PublishIntroSetJob(Endpoint* parent, uint64_t id,
|
||||
const IntroSet& introset)
|
||||
: IServiceLookup(parent, id, "PublishIntroSet")
|
||||
, m_IntroSet(introset)
|
||||
, m_Endpoint(parent)
|
||||
{
|
||||
}
|
||||
|
||||
llarp::routing::IMessage*
|
||||
BuildRequestMessage()
|
||||
{
|
||||
llarp::routing::DHTMessage* msg = new llarp::routing::DHTMessage();
|
||||
msg->M.emplace_back(
|
||||
new llarp::dht::PublishIntroMessage(m_IntroSet, txid, 4));
|
||||
return msg;
|
||||
}
|
||||
|
||||
bool
|
||||
HandleResponse(const std::set< IntroSet >& response)
|
||||
{
|
||||
if(response.size())
|
||||
m_Endpoint->IntroSetPublished();
|
||||
else
|
||||
m_Endpoint->IntroSetPublishFail();
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
Endpoint::IntroSetPublishFail()
|
||||
{
|
||||
llarp::LogWarn("failed to publish introset for ", Name());
|
||||
m_CurrentPublishTX = 0;
|
||||
// TODO: linear backoff
|
||||
}
|
||||
|
||||
bool
|
||||
Endpoint::PublishIntroSetVia(llarp_router* r, path::Path* path)
|
||||
{
|
||||
auto job = new PublishIntroSetJob(this, GenTXID(), m_IntroSet);
|
||||
if(job->SendRequestViaPath(path, r))
|
||||
{
|
||||
m_LastPublishAttempt = llarp_time_now_ms();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Endpoint::ShouldPublishDescriptors(llarp_time_t now) const
|
||||
{
|
||||
if(m_IntroSet.HasExpiredIntros(now))
|
||||
return m_CurrentPublishTX == 0
|
||||
&& now - m_LastPublishAttempt >= INTROSET_PUBLISH_RETRY_INTERVAL;
|
||||
return m_CurrentPublishTX == 0
|
||||
&& now - m_LastPublish >= INTROSET_PUBLISH_INTERVAL;
|
||||
return now - m_LastPublishAttempt >= INTROSET_PUBLISH_RETRY_INTERVAL;
|
||||
return now - m_LastPublishAttempt >= INTROSET_PUBLISH_INTERVAL;
|
||||
}
|
||||
|
||||
void
|
||||
Endpoint::IntroSetPublished()
|
||||
{
|
||||
m_CurrentPublishTX = 0;
|
||||
m_LastPublish = llarp_time_now_ms();
|
||||
m_LastPublish = llarp_time_now_ms();
|
||||
llarp::LogInfo(Name(), " IntroSet publish confirmed");
|
||||
}
|
||||
|
||||
|
@ -501,7 +554,8 @@ namespace llarp
|
|||
}
|
||||
|
||||
Address remote;
|
||||
typedef std::function< bool(const IntroSet*) > HandlerFunc;
|
||||
typedef std::function< bool(const Address&, const IntroSet*) >
|
||||
HandlerFunc;
|
||||
HandlerFunc handle;
|
||||
|
||||
HiddenServiceAddressLookup(Endpoint* p, HandlerFunc h,
|
||||
|
@ -514,19 +568,11 @@ namespace llarp
|
|||
HandleResponse(const std::set< IntroSet >& results)
|
||||
{
|
||||
llarp::LogInfo("found ", results.size(), " for ", remote.ToString());
|
||||
if(results.size() == 1)
|
||||
if(results.size() > 0)
|
||||
{
|
||||
llarp::LogInfo("hidden service lookup for ", remote.ToString(),
|
||||
" success");
|
||||
handle(&*results.begin());
|
||||
return handle(remote, &*results.begin());
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LogInfo("no response in hidden service lookup for ",
|
||||
remote.ToString());
|
||||
handle(nullptr);
|
||||
}
|
||||
return false;
|
||||
return handle(remote, nullptr);
|
||||
}
|
||||
|
||||
llarp::routing::IMessage*
|
||||
|
@ -638,14 +684,67 @@ namespace llarp
|
|||
Endpoint::HandlePathBuilt(path::Path* p)
|
||||
{
|
||||
p->SetDataHandler(std::bind(&Endpoint::HandleHiddenServiceFrame, this,
|
||||
std::placeholders::_1));
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
p->SetDropHandler(std::bind(&Endpoint::HandleDataDrop, this,
|
||||
std::placeholders::_1, std::placeholders::_2,
|
||||
std::placeholders::_3));
|
||||
p->SetDeadChecker(std::bind(&Endpoint::CheckPathIsDead, this,
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
RegenAndPublishIntroSet(llarp_time_now_ms());
|
||||
}
|
||||
|
||||
bool
|
||||
Endpoint::HandleHiddenServiceFrame(const ProtocolFrame* frame)
|
||||
Endpoint::HandleDataDrop(path::Path* p, const PathID_t& dst, uint64_t seq)
|
||||
{
|
||||
llarp::LogWarn(Name(), " message ", seq, " dropped by endpoint ",
|
||||
p->Endpoint(), " via ", dst);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Endpoint::OutboundContext::HandleDataDrop(path::Path* p,
|
||||
const PathID_t& dst, uint64_t seq)
|
||||
{
|
||||
llarp::LogWarn(Name(), " message ", seq, " dropped by endpoint ",
|
||||
p->Endpoint(), " via ", dst);
|
||||
// pick another intro
|
||||
if(dst == remoteIntro.pathID)
|
||||
{
|
||||
MarkCurrentIntroBad();
|
||||
ShiftIntroduction();
|
||||
}
|
||||
UpdateIntroSet();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Endpoint::HandleDataMessage(const PathID_t& src, ProtocolMessage* msg)
|
||||
{
|
||||
msg->sender.UpdateAddr();
|
||||
PutIntroFor(msg->tag, msg->introReply);
|
||||
EnsureReplyPath(msg->sender);
|
||||
return ProcessDataMessage(msg);
|
||||
}
|
||||
|
||||
bool
|
||||
Endpoint::HandleHiddenServiceFrame(path::Path* p,
|
||||
const ProtocolFrame* frame)
|
||||
{
|
||||
return frame->AsyncDecryptAndVerify(EndpointLogic(), Crypto(), p->RXID(),
|
||||
Worker(), m_Identity, m_DataHandler);
|
||||
}
|
||||
|
||||
Endpoint::SendContext::SendContext(const ServiceInfo& ident,
|
||||
const Introduction& intro, PathSet* send,
|
||||
Endpoint* ep)
|
||||
: remoteIdent(ident)
|
||||
, remoteIntro(intro)
|
||||
, m_PathSet(send)
|
||||
, m_DataHandler(ep)
|
||||
, m_Endpoint(ep)
|
||||
{
|
||||
return frame->AsyncDecryptAndVerify(EndpointLogic(), Crypto(), Worker(),
|
||||
m_Identity, m_DataHandler);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -653,21 +752,54 @@ namespace llarp
|
|||
{
|
||||
p->SetDataHandler(
|
||||
std::bind(&Endpoint::OutboundContext::HandleHiddenServiceFrame, this,
|
||||
std::placeholders::_1));
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
p->SetDropHandler(std::bind(
|
||||
&Endpoint::OutboundContext::HandleDataDrop, this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||
p->SetDeadChecker(std::bind(&Endpoint::CheckPathIsDead, m_Endpoint,
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
void
|
||||
Endpoint::HandlePathDead(void* user)
|
||||
{
|
||||
Endpoint* self = static_cast< Endpoint* >(user);
|
||||
self->RegenAndPublishIntroSet(llarp_time_now_ms());
|
||||
}
|
||||
|
||||
bool
|
||||
Endpoint::CheckPathIsDead(path::Path*, llarp_time_t latency)
|
||||
{
|
||||
if(latency >= m_MinPathLatency)
|
||||
{
|
||||
// rebuild path next tick
|
||||
llarp_logic_queue_job(EndpointLogic(), {this, &HandlePathDead});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Endpoint::OutboundContext::HandleHiddenServiceFrame(
|
||||
const ProtocolFrame* frame)
|
||||
path::Path* p, const ProtocolFrame* frame)
|
||||
{
|
||||
return m_Parent->HandleHiddenServiceFrame(frame);
|
||||
return m_Endpoint->HandleHiddenServiceFrame(p, frame);
|
||||
}
|
||||
|
||||
bool
|
||||
Endpoint::OnOutboundLookup(const IntroSet* introset)
|
||||
Endpoint::OnOutboundLookup(const Address& addr, const IntroSet* introset)
|
||||
{
|
||||
if(!introset)
|
||||
{
|
||||
auto itr = m_PendingServiceLookups.find(addr);
|
||||
if(itr != m_PendingServiceLookups.end())
|
||||
{
|
||||
m_PendingServiceLookups.erase(itr);
|
||||
itr->second(addr, nullptr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
PutNewOutboundContext(*introset);
|
||||
return true;
|
||||
}
|
||||
|
@ -704,7 +836,8 @@ namespace llarp
|
|||
|
||||
HiddenServiceAddressLookup* job = new HiddenServiceAddressLookup(
|
||||
this,
|
||||
std::bind(&Endpoint::OnOutboundLookup, this, std::placeholders::_1),
|
||||
std::bind(&Endpoint::OnOutboundLookup, this, std::placeholders::_1,
|
||||
std::placeholders::_2),
|
||||
remote, GenTXID());
|
||||
|
||||
if(job->SendRequestViaPath(path, Router()))
|
||||
|
@ -716,11 +849,11 @@ namespace llarp
|
|||
Endpoint::OutboundContext::OutboundContext(const IntroSet& intro,
|
||||
Endpoint* parent)
|
||||
: path::Builder(parent->m_Router, parent->m_Router->dht, 2, 4)
|
||||
, SendContext(intro.A, {}, this, parent)
|
||||
, currentIntroSet(intro)
|
||||
, m_Parent(parent)
|
||||
|
||||
{
|
||||
selectedIntro.Clear();
|
||||
updatingIntroSet = false;
|
||||
ShiftIntroduction();
|
||||
}
|
||||
|
||||
|
@ -729,12 +862,15 @@ namespace llarp
|
|||
}
|
||||
|
||||
bool
|
||||
Endpoint::OutboundContext::OnIntroSetUpdate(const IntroSet* i)
|
||||
Endpoint::OutboundContext::OnIntroSetUpdate(const Address& addr,
|
||||
const IntroSet* i)
|
||||
{
|
||||
if(i && i->IsNewerThan(currentIntroSet))
|
||||
if(i)
|
||||
{
|
||||
currentIntroSet = *i;
|
||||
ShiftIntroduction();
|
||||
}
|
||||
updatingIntroSet = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -742,8 +878,64 @@ namespace llarp
|
|||
Endpoint::SendToOrQueue(const Address& remote, llarp_buffer_t data,
|
||||
ProtocolType t)
|
||||
{
|
||||
{
|
||||
auto itr = m_AddressToService.find(remote);
|
||||
if(itr != m_AddressToService.end())
|
||||
{
|
||||
routing::PathTransferMessage transfer;
|
||||
ProtocolFrame& f = transfer.T;
|
||||
path::Path* p = nullptr;
|
||||
std::set< ConvoTag > tags;
|
||||
if(!GetConvoTagsForService(itr->second, tags))
|
||||
{
|
||||
llarp::LogError("no convo tag");
|
||||
return false;
|
||||
}
|
||||
Introduction remoteIntro;
|
||||
const byte_t* K = nullptr;
|
||||
for(const auto& tag : tags)
|
||||
{
|
||||
if(p == nullptr && GetIntroFor(tag, remoteIntro))
|
||||
{
|
||||
p = GetPathByRouter(remoteIntro.router);
|
||||
if(p)
|
||||
{
|
||||
f.T = tag;
|
||||
if(!GetCachedSessionKeyFor(tag, K))
|
||||
{
|
||||
llarp::LogError("no cached session key");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(p)
|
||||
{
|
||||
// TODO: check expiration of our end
|
||||
ProtocolMessage m(f.T);
|
||||
m.proto = t;
|
||||
m.introReply = p->intro;
|
||||
m.sender = m_Identity.pub;
|
||||
m.PutBuffer(data);
|
||||
f.N.Randomize();
|
||||
f.S = GetSeqNoForConvo(f.T);
|
||||
f.C.Zero();
|
||||
transfer.Y.Randomize();
|
||||
transfer.P = remoteIntro.pathID;
|
||||
if(!f.EncryptAndSign(&Router()->crypto, m, K, m_Identity))
|
||||
{
|
||||
llarp::LogError("failed to encrypt and sign");
|
||||
return false;
|
||||
}
|
||||
llarp::LogInfo(Name(), " send ", data.sz, " via ", remoteIntro);
|
||||
return p->SendRoutingMessage(&transfer, Router());
|
||||
}
|
||||
}
|
||||
}
|
||||
if(HasPathToService(remote))
|
||||
{
|
||||
llarp::LogDebug(Name(), " has session to ", remote, " sending ",
|
||||
data.sz, " bytes");
|
||||
m_RemoteSessions[remote]->AsyncEncryptAndSendTo(data, t);
|
||||
return true;
|
||||
}
|
||||
|
@ -752,89 +944,104 @@ namespace llarp
|
|||
if(itr == m_PendingTraffic.end())
|
||||
{
|
||||
m_PendingTraffic.insert(std::make_pair(remote, PendingBufferQueue()));
|
||||
EnsurePathToService(remote,
|
||||
[&](Address addr, OutboundContext* ctx) {
|
||||
if(ctx)
|
||||
{
|
||||
auto itr = m_PendingTraffic.find(addr);
|
||||
if(itr != m_PendingTraffic.end())
|
||||
{
|
||||
while(itr->second.size())
|
||||
{
|
||||
auto& front = itr->second.front();
|
||||
ctx->AsyncEncryptAndSendTo(front.Buffer(),
|
||||
front.protocol);
|
||||
itr->second.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
m_PendingTraffic.erase(addr);
|
||||
},
|
||||
10000);
|
||||
EnsurePathToService(
|
||||
remote,
|
||||
[&](Address addr, OutboundContext* ctx) {
|
||||
if(ctx)
|
||||
{
|
||||
auto itr = m_PendingTraffic.find(addr);
|
||||
if(itr != m_PendingTraffic.end())
|
||||
{
|
||||
while(itr->second.size())
|
||||
{
|
||||
auto& front = itr->second.front();
|
||||
ctx->AsyncEncryptAndSendTo(front.Buffer(), front.protocol);
|
||||
itr->second.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LogWarn("failed to obtain outbound context to ", addr,
|
||||
" within timeout");
|
||||
}
|
||||
m_PendingTraffic.erase(addr);
|
||||
},
|
||||
10000);
|
||||
}
|
||||
m_PendingTraffic[remote].emplace(data, t);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Endpoint::OutboundContext::ShiftIntroduction()
|
||||
Endpoint::OutboundContext::MarkCurrentIntroBad()
|
||||
{
|
||||
for(const auto& intro : currentIntroSet.I)
|
||||
{
|
||||
m_Parent->EnsureRouterIsKnown(selectedIntro.router);
|
||||
if(intro.expiresAt > selectedIntro.expiresAt)
|
||||
{
|
||||
selectedIntro = intro;
|
||||
}
|
||||
}
|
||||
ManualRebuild(2);
|
||||
m_BadIntros.insert(remoteIntro);
|
||||
}
|
||||
|
||||
void
|
||||
Endpoint::OutboundContext::AsyncEncryptAndSendTo(llarp_buffer_t data,
|
||||
ProtocolType protocol)
|
||||
Endpoint::OutboundContext::ShiftIntroduction()
|
||||
{
|
||||
auto path = GetPathByRouter(selectedIntro.router);
|
||||
if(!path)
|
||||
{
|
||||
llarp::LogError("No Path to ", selectedIntro.router, " yet");
|
||||
auto now = llarp_time_now_ms();
|
||||
if(now - lastShift < MIN_SHIFT_INTERVAL)
|
||||
return;
|
||||
}
|
||||
if(sequenceNo)
|
||||
bool shifted = false;
|
||||
for(const auto& intro : currentIntroSet.I)
|
||||
{
|
||||
EncryptAndSendTo(path, data, protocol);
|
||||
m_Endpoint->EnsureRouterIsKnown(intro.router);
|
||||
if(m_BadIntros.count(intro) == 0 && remoteIntro != intro)
|
||||
{
|
||||
shifted = intro.router != remoteIntro.router;
|
||||
remoteIntro = intro;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
if(shifted)
|
||||
{
|
||||
AsyncGenIntro(path, data, protocol);
|
||||
lastShift = now;
|
||||
ManualRebuild(1);
|
||||
}
|
||||
}
|
||||
|
||||
struct AsyncIntroGen
|
||||
void
|
||||
Endpoint::SendContext::AsyncEncryptAndSendTo(llarp_buffer_t data,
|
||||
ProtocolType protocol)
|
||||
{
|
||||
if(sequenceNo)
|
||||
{
|
||||
EncryptAndSendTo(data, protocol);
|
||||
}
|
||||
else
|
||||
{
|
||||
AsyncGenIntro(data, protocol);
|
||||
}
|
||||
}
|
||||
|
||||
struct AsyncKeyExchange
|
||||
{
|
||||
llarp_logic* logic;
|
||||
llarp_crypto* crypto;
|
||||
byte_t* sharedKey;
|
||||
SharedSecret sharedKey;
|
||||
ServiceInfo remote;
|
||||
const Identity& m_LocalIdentity;
|
||||
ProtocolMessage msg;
|
||||
ProtocolFrame frame;
|
||||
Introduction intro;
|
||||
const PQPubKey introPubKey;
|
||||
Introduction remoteIntro;
|
||||
std::function< void(ProtocolFrame&) > hook;
|
||||
IDataHandler* handler;
|
||||
|
||||
AsyncIntroGen(llarp_logic* l, llarp_crypto* c, byte_t* key,
|
||||
const ServiceInfo& r, const Identity& localident,
|
||||
const PQPubKey& introsetPubKey, const Introduction& us,
|
||||
IDataHandler* h)
|
||||
AsyncKeyExchange(llarp_logic* l, llarp_crypto* c, const ServiceInfo& r,
|
||||
const Identity& localident,
|
||||
const PQPubKey& introsetPubKey,
|
||||
const Introduction& remote, IDataHandler* h)
|
||||
: logic(l)
|
||||
, crypto(c)
|
||||
, sharedKey(key)
|
||||
, remote(r)
|
||||
, m_LocalIdentity(localident)
|
||||
, intro(us)
|
||||
, introPubKey(introsetPubKey)
|
||||
, remoteIntro(remote)
|
||||
, handler(h)
|
||||
{
|
||||
}
|
||||
|
@ -842,19 +1049,20 @@ namespace llarp
|
|||
static void
|
||||
Result(void* user)
|
||||
{
|
||||
AsyncIntroGen* self = static_cast< AsyncIntroGen* >(user);
|
||||
AsyncKeyExchange* self = static_cast< AsyncKeyExchange* >(user);
|
||||
// put values
|
||||
self->handler->PutCachedSessionKeyFor(self->msg.tag, self->sharedKey);
|
||||
self->handler->PutIntroFor(self->msg.tag, self->msg.introReply);
|
||||
self->handler->PutIntroFor(self->msg.tag, self->remoteIntro);
|
||||
self->handler->PutSenderFor(self->msg.tag, self->remote);
|
||||
self->hook(self->frame);
|
||||
delete self;
|
||||
}
|
||||
|
||||
/// given protocol message make protocol frame
|
||||
static void
|
||||
Work(void* user)
|
||||
Encrypt(void* user)
|
||||
{
|
||||
AsyncIntroGen* self = static_cast< AsyncIntroGen* >(user);
|
||||
AsyncKeyExchange* self = static_cast< AsyncKeyExchange* >(user);
|
||||
// derive ntru session key component
|
||||
SharedSecret K;
|
||||
self->crypto->pqe_encrypt(self->frame.C, K, self->introPubKey);
|
||||
|
@ -875,86 +1083,94 @@ namespace llarp
|
|||
self->msg.tag.Randomize();
|
||||
// set sender
|
||||
self->msg.sender = self->m_LocalIdentity.pub;
|
||||
// set our introduction
|
||||
self->msg.introReply = self->intro;
|
||||
// set version
|
||||
self->msg.version = LLARP_PROTO_VERSION;
|
||||
// set protocol
|
||||
self->msg.proto = eProtocolTraffic;
|
||||
// encrypt and sign
|
||||
if(self->frame.EncryptAndSign(self->crypto, self->msg, K,
|
||||
self->m_LocalIdentity))
|
||||
llarp_logic_queue_job(self->logic, {self, &Result});
|
||||
else
|
||||
{
|
||||
llarp::LogError("failed to encrypt and sign");
|
||||
delete self;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
Endpoint::OutboundContext::AsyncGenIntro(path::Path* p,
|
||||
llarp_buffer_t payload,
|
||||
ProtocolType t)
|
||||
Endpoint::EnsureReplyPath(const ServiceInfo& ident)
|
||||
{
|
||||
AsyncIntroGen* ex = new AsyncIntroGen(
|
||||
m_Parent->RouterLogic(), m_Parent->Crypto(), sharedKey,
|
||||
currentIntroSet.A, m_Parent->GetIdentity(), currentIntroSet.K,
|
||||
selectedIntro, m_Parent->m_DataHandler);
|
||||
ex->hook = std::bind(&Endpoint::OutboundContext::Send, this,
|
||||
std::placeholders::_1);
|
||||
ex->msg.PutBuffer(payload);
|
||||
ex->msg.introReply = p->intro;
|
||||
llarp_threadpool_queue_job(m_Parent->Worker(),
|
||||
{ex, &AsyncIntroGen::Work});
|
||||
auto itr = m_AddressToService.find(ident.Addr());
|
||||
if(itr == m_AddressToService.end())
|
||||
m_AddressToService.insert(std::make_pair(ident.Addr(), ident));
|
||||
}
|
||||
|
||||
void
|
||||
Endpoint::OutboundContext::Send(ProtocolFrame& msg)
|
||||
Endpoint::OutboundContext::AsyncGenIntro(llarp_buffer_t payload,
|
||||
ProtocolType t)
|
||||
{
|
||||
// in this context we assume the message contents are encrypted
|
||||
auto now = llarp_time_now_ms();
|
||||
if(currentIntroSet.HasExpiredIntros(now))
|
||||
{
|
||||
UpdateIntroSet();
|
||||
}
|
||||
if(selectedIntro.expiresAt <= now || now - selectedIntro.expiresAt > 1000)
|
||||
{
|
||||
ShiftIntroduction();
|
||||
}
|
||||
// XXX: this may be a different path that that was put into the protocol
|
||||
// message inside the protocol frame
|
||||
auto path = GetPathByRouter(selectedIntro.router);
|
||||
auto path = m_PathSet->GetPathByRouter(remoteIntro.router);
|
||||
if(path == nullptr)
|
||||
return;
|
||||
|
||||
AsyncKeyExchange* ex =
|
||||
new AsyncKeyExchange(m_Endpoint->RouterLogic(), m_Endpoint->Crypto(),
|
||||
remoteIdent, m_Endpoint->GetIdentity(),
|
||||
currentIntroSet.K, remoteIntro, m_DataHandler);
|
||||
ex->hook = std::bind(&Endpoint::OutboundContext::Send, this,
|
||||
std::placeholders::_1);
|
||||
ex->msg.PutBuffer(payload);
|
||||
ex->msg.introReply = path->intro;
|
||||
llarp_threadpool_queue_job(m_Endpoint->Worker(),
|
||||
{ex, &AsyncKeyExchange::Encrypt});
|
||||
}
|
||||
|
||||
void
|
||||
Endpoint::SendContext::Send(ProtocolFrame& msg)
|
||||
{
|
||||
auto path = m_PathSet->GetPathByRouter(remoteIntro.router);
|
||||
if(path)
|
||||
{
|
||||
routing::PathTransferMessage transfer(msg, selectedIntro.pathID);
|
||||
llarp::LogDebug("sending frame via ", path->Upstream(), " to ",
|
||||
path->Endpoint(), " for ", Name());
|
||||
if(!path->SendRoutingMessage(&transfer, m_Parent->Router()))
|
||||
auto now = llarp_time_now_ms();
|
||||
if(remoteIntro.ExpiresSoon(now))
|
||||
{
|
||||
MarkCurrentIntroBad();
|
||||
ShiftIntroduction();
|
||||
}
|
||||
routing::PathTransferMessage transfer(msg, remoteIntro.pathID);
|
||||
if(!path->SendRoutingMessage(&transfer, m_Endpoint->Router()))
|
||||
llarp::LogError("Failed to send frame on path");
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LogWarn("No path to ", selectedIntro.router);
|
||||
}
|
||||
llarp::LogError("cannot send becuase we have no path to ",
|
||||
remoteIntro.router);
|
||||
}
|
||||
|
||||
std::string
|
||||
Endpoint::OutboundContext::Name() const
|
||||
{
|
||||
return "OBContext:" + m_Parent->Name() + "-"
|
||||
return "OBContext:" + m_Endpoint->Name() + "-"
|
||||
+ currentIntroSet.A.Addr().ToString();
|
||||
}
|
||||
|
||||
void
|
||||
Endpoint::OutboundContext::UpdateIntroSet()
|
||||
{
|
||||
if(updatingIntroSet)
|
||||
return;
|
||||
auto addr = currentIntroSet.A.Addr();
|
||||
auto path = m_Parent->GetEstablishedPathClosestTo(addr.ToRouter());
|
||||
auto path = m_Endpoint->PickRandomEstablishedPath();
|
||||
if(path)
|
||||
{
|
||||
HiddenServiceAddressLookup* job = new HiddenServiceAddressLookup(
|
||||
m_Parent,
|
||||
m_Endpoint,
|
||||
std::bind(&Endpoint::OutboundContext::OnIntroSetUpdate, this,
|
||||
std::placeholders::_1),
|
||||
addr, m_Parent->GenTXID());
|
||||
std::placeholders::_1, std::placeholders::_2),
|
||||
addr, m_Endpoint->GenTXID());
|
||||
|
||||
if(!job->SendRequestViaPath(path, m_Parent->Router()))
|
||||
llarp::LogError("send via path failed");
|
||||
updatingIntroSet = job->SendRequestViaPath(path, m_Endpoint->Router());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -967,12 +1183,16 @@ namespace llarp
|
|||
bool
|
||||
Endpoint::OutboundContext::Tick(llarp_time_t now)
|
||||
{
|
||||
if(selectedIntro.expiresAt >= now
|
||||
|| selectedIntro.expiresAt - now < 30000)
|
||||
if(remoteIntro.ExpiresSoon(now))
|
||||
{
|
||||
UpdateIntroSet();
|
||||
MarkCurrentIntroBad();
|
||||
ShiftIntroduction();
|
||||
}
|
||||
m_Parent->EnsureRouterIsKnown(selectedIntro.router);
|
||||
m_Endpoint->EnsureRouterIsKnown(remoteIntro.router);
|
||||
std::remove_if(m_BadIntros.cbegin(), m_BadIntros.cend(),
|
||||
[now](const Introduction& intro) -> bool {
|
||||
return intro.IsExpired(now);
|
||||
});
|
||||
// TODO: check for expiration of outbound context
|
||||
return false;
|
||||
}
|
||||
|
@ -984,7 +1204,7 @@ namespace llarp
|
|||
{
|
||||
if(hop == numHops - 1)
|
||||
{
|
||||
if(llarp_nodedb_get_rc(db, selectedIntro.router, cur))
|
||||
if(llarp_nodedb_get_rc(db, remoteIntro.router, cur))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -994,13 +1214,12 @@ namespace llarp
|
|||
llarp::LogError(
|
||||
"cannot build aligned path, don't have router for "
|
||||
"introduction ",
|
||||
selectedIntro);
|
||||
m_Parent->EnsureRouterIsKnown(selectedIntro.router);
|
||||
remoteIntro);
|
||||
m_Endpoint->EnsureRouterIsKnown(remoteIntro.router);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
return path::Builder::SelectHop(db, prev, cur, hop);
|
||||
return path::Builder::SelectHop(db, prev, cur, hop);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
|
@ -1013,58 +1232,57 @@ namespace llarp
|
|||
}
|
||||
|
||||
void
|
||||
Endpoint::OutboundContext::EncryptAndSendTo(path::Path* p,
|
||||
llarp_buffer_t payload,
|
||||
ProtocolType t)
|
||||
Endpoint::SendContext::EncryptAndSendTo(llarp_buffer_t payload,
|
||||
ProtocolType t)
|
||||
{
|
||||
auto path = GetPathByRouter(selectedIntro.router);
|
||||
if(path)
|
||||
std::set< ConvoTag > tags;
|
||||
if(!m_DataHandler->GetConvoTagsForService(remoteIdent, tags))
|
||||
{
|
||||
std::set< ConvoTag > tags;
|
||||
if(!m_Parent->m_DataHandler->GetConvoTagsForService(currentIntroSet.A,
|
||||
tags))
|
||||
llarp::LogError("no open converstations with remote endpoint?");
|
||||
return;
|
||||
}
|
||||
auto crypto = m_Endpoint->Router()->crypto;
|
||||
const byte_t* shared = nullptr;
|
||||
routing::PathTransferMessage msg;
|
||||
ProtocolFrame& f = msg.T;
|
||||
f.N.Randomize();
|
||||
f.T = *tags.begin();
|
||||
f.S = m_Endpoint->GetSeqNoForConvo(f.T);
|
||||
|
||||
auto path = m_PathSet->GetNewestPathByRouter(remoteIntro.router);
|
||||
if(!path)
|
||||
{
|
||||
llarp::LogError("cannot encrypt and send: no path for intro ",
|
||||
remoteIntro);
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_DataHandler->GetCachedSessionKeyFor(f.T, shared))
|
||||
{
|
||||
ProtocolMessage m;
|
||||
m.proto = t;
|
||||
m_DataHandler->PutIntroFor(f.T, remoteIntro);
|
||||
m.introReply = path->intro;
|
||||
m.sender = m_Endpoint->m_Identity.pub;
|
||||
m.PutBuffer(payload);
|
||||
|
||||
if(!f.EncryptAndSign(&crypto, m, shared, m_Endpoint->m_Identity))
|
||||
{
|
||||
llarp::LogError("no open converstations with remote endpoint?");
|
||||
llarp::LogError("failed to sign");
|
||||
return;
|
||||
}
|
||||
auto crypto = m_Parent->Crypto();
|
||||
const byte_t* shared = nullptr;
|
||||
routing::PathTransferMessage msg;
|
||||
ProtocolFrame& f = msg.T;
|
||||
f.N.Randomize();
|
||||
f.T = *tags.begin();
|
||||
f.S = m_Parent->GetSeqNoForConvo(f.T);
|
||||
|
||||
if(m_Parent->m_DataHandler->GetCachedSessionKeyFor(f.T, shared))
|
||||
{
|
||||
ProtocolMessage m;
|
||||
m.proto = t;
|
||||
m.introReply = path->intro;
|
||||
m.sender = m_Parent->m_Identity.pub;
|
||||
m.PutBuffer(payload);
|
||||
|
||||
if(!f.EncryptAndSign(crypto, m, shared, m_Parent->m_Identity))
|
||||
{
|
||||
llarp::LogError("failed to sign");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LogError("No cached session key");
|
||||
return;
|
||||
}
|
||||
|
||||
msg.P = selectedIntro.pathID;
|
||||
msg.Y.Randomize();
|
||||
if(!path->SendRoutingMessage(&msg, m_Parent->Router()))
|
||||
{
|
||||
llarp::LogWarn("Failed to send routing message for data");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LogError("no outbound path for sending message");
|
||||
llarp::LogError("No cached session key");
|
||||
return;
|
||||
}
|
||||
|
||||
msg.P = remoteIntro.pathID;
|
||||
msg.Y.Randomize();
|
||||
if(!path->SendRoutingMessage(&msg, m_Endpoint->Router()))
|
||||
{
|
||||
llarp::LogWarn("Failed to send routing message for data");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,14 +25,14 @@ namespace llarp
|
|||
{
|
||||
payload.resize(buf.sz);
|
||||
memcpy(payload.data(), buf.base, buf.sz);
|
||||
payload.shrink_to_fit();
|
||||
}
|
||||
|
||||
void
|
||||
ProtocolMessage::ProcessAsync(void* user)
|
||||
{
|
||||
ProtocolMessage* self = static_cast< ProtocolMessage* >(user);
|
||||
self->handler->HandleDataMessage(self);
|
||||
if(!self->handler->HandleDataMessage(self->srcPath, self))
|
||||
llarp::LogWarn("failed to handle data message from ", self->srcPath);
|
||||
delete self;
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ namespace llarp
|
|||
if(!BEncodeWriteDictEntry("t", tag, buf))
|
||||
return false;
|
||||
}
|
||||
if(!bencode_write_version_entry(buf))
|
||||
if(!BEncodeWriteDictInt("v", version, buf))
|
||||
return false;
|
||||
return bencode_end(buf);
|
||||
}
|
||||
|
@ -156,9 +156,10 @@ namespace llarp
|
|||
const byte_t* sharedkey,
|
||||
ProtocolMessage& msg) const
|
||||
{
|
||||
msg.PutBuffer(D.Buffer());
|
||||
auto buf = llarp::Buffer(msg.payload);
|
||||
return crypto->xchacha20(buf, sharedkey, N);
|
||||
Encrypted tmp = D;
|
||||
auto buf = tmp.Buffer();
|
||||
crypto->xchacha20(*buf, sharedkey, N);
|
||||
return msg.BDecode(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -200,11 +201,11 @@ namespace llarp
|
|||
ProtocolMessage* msg;
|
||||
const Identity& m_LocalIdentity;
|
||||
IDataHandler* handler;
|
||||
const ProtocolFrame* frame;
|
||||
const ProtocolFrame frame;
|
||||
|
||||
AsyncFrameDecrypt(llarp_logic* l, llarp_crypto* c,
|
||||
const Identity& localIdent, IDataHandler* h,
|
||||
ProtocolMessage* m, const ProtocolFrame* f)
|
||||
ProtocolMessage* m, const ProtocolFrame& f)
|
||||
: crypto(c)
|
||||
, logic(l)
|
||||
, msg(m)
|
||||
|
@ -222,20 +223,18 @@ namespace llarp
|
|||
SharedSecret K;
|
||||
SharedSecret sharedKey;
|
||||
// copy
|
||||
ProtocolFrame frame;
|
||||
frame = *self->frame;
|
||||
if(!crypto->pqe_decrypt(self->frame->C, K,
|
||||
ProtocolFrame frame(self->frame);
|
||||
if(!crypto->pqe_decrypt(self->frame.C, K,
|
||||
pq_keypair_to_secret(self->m_LocalIdentity.pq)))
|
||||
{
|
||||
llarp::LogError("pqke failed C=", self->frame->C);
|
||||
frame.Dump< MAX_PROTOCOL_MESSAGE_SIZE >();
|
||||
llarp::LogError("pqke failed C=", self->frame.C);
|
||||
delete self->msg;
|
||||
delete self;
|
||||
return;
|
||||
}
|
||||
// decrypt
|
||||
auto buf = frame.D.Buffer();
|
||||
crypto->xchacha20(*buf, K, self->frame->N);
|
||||
crypto->xchacha20(*buf, K, self->frame.N);
|
||||
if(!self->msg->BDecode(buf))
|
||||
{
|
||||
llarp::LogError("failed to decode inner protocol message");
|
||||
|
@ -245,11 +244,12 @@ namespace llarp
|
|||
return;
|
||||
}
|
||||
// verify signature of outer message after we parsed the inner message
|
||||
if(!self->frame->Verify(crypto, self->msg->sender))
|
||||
if(!self->frame.Verify(crypto, self->msg->sender))
|
||||
{
|
||||
llarp::LogError("intro frame has invalid signature Z=",
|
||||
self->frame->Z, " from ", self->msg->sender);
|
||||
self->frame->Dump< MAX_PROTOCOL_MESSAGE_SIZE >();
|
||||
llarp::LogError("intro frame has invalid signature Z=", self->frame.Z,
|
||||
" from ", self->msg->sender.Addr());
|
||||
self->frame.Dump< MAX_PROTOCOL_MESSAGE_SIZE >();
|
||||
self->msg->Dump< MAX_PROTOCOL_MESSAGE_SIZE >();
|
||||
delete self->msg;
|
||||
delete self;
|
||||
return;
|
||||
|
@ -258,11 +258,11 @@ namespace llarp
|
|||
// K
|
||||
memcpy(tmp, K, 32);
|
||||
// PKE (A, B, N)
|
||||
if(!self->m_LocalIdentity.KeyExchange(
|
||||
crypto->dh_server, tmp + 32, self->msg->sender, self->frame->N))
|
||||
if(!self->m_LocalIdentity.KeyExchange(crypto->dh_server, tmp + 32,
|
||||
self->msg->sender, self->frame.N))
|
||||
{
|
||||
llarp::LogError("x25519 key exchange failed");
|
||||
self->frame->Dump< MAX_PROTOCOL_MESSAGE_SIZE >();
|
||||
self->frame.Dump< MAX_PROTOCOL_MESSAGE_SIZE >();
|
||||
delete self->msg;
|
||||
delete self;
|
||||
return;
|
||||
|
@ -284,16 +284,19 @@ namespace llarp
|
|||
ProtocolFrame&
|
||||
ProtocolFrame::operator=(const ProtocolFrame& other)
|
||||
{
|
||||
C = other.C;
|
||||
D = other.D;
|
||||
N = other.N;
|
||||
Z = other.Z;
|
||||
T = other.T;
|
||||
C = other.C;
|
||||
D = other.D;
|
||||
N = other.N;
|
||||
Z = other.Z;
|
||||
T = other.T;
|
||||
S = other.S;
|
||||
version = other.version;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
ProtocolFrame::AsyncDecryptAndVerify(llarp_logic* logic, llarp_crypto* c,
|
||||
const PathID_t& srcPath,
|
||||
llarp_threadpool* worker,
|
||||
const Identity& localIdent,
|
||||
IDataHandler* handler) const
|
||||
|
@ -301,9 +304,10 @@ namespace llarp
|
|||
if(T.IsZero())
|
||||
{
|
||||
ProtocolMessage* msg = new ProtocolMessage();
|
||||
msg->srcPath = srcPath;
|
||||
// we need to dh
|
||||
auto dh =
|
||||
new AsyncFrameDecrypt(logic, c, localIdent, handler, msg, this);
|
||||
new AsyncFrameDecrypt(logic, c, localIdent, handler, msg, *this);
|
||||
llarp_threadpool_queue_job(worker, {dh, &AsyncFrameDecrypt::Work});
|
||||
return true;
|
||||
}
|
||||
|
@ -321,7 +325,7 @@ namespace llarp
|
|||
}
|
||||
if(!Verify(c, si))
|
||||
{
|
||||
llarp::LogError("Signature failure");
|
||||
llarp::LogError("Signature failure from ", si.Addr());
|
||||
return false;
|
||||
}
|
||||
ProtocolMessage* msg = new ProtocolMessage();
|
||||
|
@ -331,47 +335,48 @@ namespace llarp
|
|||
delete msg;
|
||||
return false;
|
||||
}
|
||||
msg->srcPath = srcPath;
|
||||
msg->handler = handler;
|
||||
llarp_logic_queue_job(logic, {msg, &ProtocolMessage::ProcessAsync});
|
||||
return true;
|
||||
}
|
||||
|
||||
ProtocolFrame::ProtocolFrame()
|
||||
bool
|
||||
ProtocolFrame::operator==(const ProtocolFrame& other) const
|
||||
{
|
||||
T.Zero();
|
||||
return C == other.C && D == other.D && N == other.N && Z == other.Z
|
||||
&& T == other.T && S == other.S && version == other.version;
|
||||
}
|
||||
|
||||
bool
|
||||
ProtocolFrame::Verify(llarp_crypto* crypto, const ServiceInfo& from) const
|
||||
{
|
||||
ProtocolFrame copy;
|
||||
copy = *this;
|
||||
ProtocolFrame copy(*this);
|
||||
// save signature
|
||||
// zero out signature for verify
|
||||
copy.Z.Zero();
|
||||
bool result = false;
|
||||
// serialize
|
||||
byte_t tmp[MAX_PROTOCOL_MESSAGE_SIZE];
|
||||
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
|
||||
if(copy.BEncode(&buf))
|
||||
if(!copy.BEncode(&buf))
|
||||
{
|
||||
// rewind buffer
|
||||
buf.sz = buf.cur - buf.base;
|
||||
buf.cur = buf.base;
|
||||
// verify
|
||||
result = from.Verify(crypto, buf, Z);
|
||||
llarp::LogError("bencode fail");
|
||||
return false;
|
||||
}
|
||||
// restore signature
|
||||
return result;
|
||||
|
||||
// rewind buffer
|
||||
buf.sz = buf.cur - buf.base;
|
||||
buf.cur = buf.base;
|
||||
// verify
|
||||
return from.Verify(crypto, buf, Z);
|
||||
}
|
||||
|
||||
bool
|
||||
ProtocolFrame::HandleMessage(llarp::routing::IMessageHandler* h,
|
||||
llarp_router* r) const
|
||||
{
|
||||
llarp::LogInfo("Got hidden service frame");
|
||||
return h->HandleHiddenServiceFrame(this);
|
||||
}
|
||||
|
||||
} // namespace service
|
||||
} // namespace llarp
|
||||
} // namespace llarp
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <llarp/path.hpp>
|
||||
#include <llarp/routing/handler.hpp>
|
||||
#include <llarp/messages/discard.hpp>
|
||||
#include "buffer.hpp"
|
||||
#include "router.hpp"
|
||||
|
||||
|
@ -53,7 +54,6 @@ namespace llarp
|
|||
TransitHop::SendRoutingMessage(llarp::routing::IMessage* msg,
|
||||
llarp_router* r)
|
||||
{
|
||||
msg->S = m_SequenceNum++;
|
||||
byte_t tmp[MAX_LINK_MSG_SIZE - 1024];
|
||||
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
|
||||
if(!msg->BEncode(&buf))
|
||||
|
@ -135,6 +135,14 @@ namespace llarp
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
TransitHop::HandleDataDiscardMessage(
|
||||
const llarp::routing::DataDiscardMessage* msg, llarp_router* r)
|
||||
{
|
||||
llarp::LogWarn("unwarranted path data discard message on ", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
TransitHop::HandlePathTransferMessage(
|
||||
const llarp::routing::PathTransferMessage* msg, llarp_router* r)
|
||||
|
@ -142,8 +150,9 @@ namespace llarp
|
|||
auto path = r->paths.GetByUpstream(r->pubkey(), msg->P);
|
||||
if(!path)
|
||||
{
|
||||
llarp::LogWarn("No such path for path transfer pathid=", msg->P);
|
||||
return false;
|
||||
llarp::routing::DataDiscardMessage discarded(msg->P, msg->S);
|
||||
path = r->paths.GetByUpstream(r->pubkey(), msg->from);
|
||||
return path && path->SendRoutingMessage(&discarded, r);
|
||||
}
|
||||
|
||||
byte_t tmp[service::MAX_PROTOCOL_MESSAGE_SIZE];
|
||||
|
|
52
readme.md
52
readme.md
|
@ -1,6 +1,6 @@
|
|||
# LokiNet
|
||||
|
||||
Lokinet is a private, decentralized and Sybil resistant overlay network for the internet, it uses a new routing protocol called LLARP (Low latency anonymous routing protocol)
|
||||
LokiNet is the reference implementation of LLARP (low latency anonymous routing protocol), a layer 3 onion routing protocol.
|
||||
|
||||
You can learn more about the high level design of LLARP [here](doc/high-level.txt)
|
||||
<<<<<<< Updated upstream
|
||||
|
@ -42,4 +42,52 @@ Build requirements:
|
|||
Building a debug build:
|
||||
>>>>>>> Stashed changes
|
||||
|
||||
To build lokinet see the [lokinet-builder](https://github.com/loki-project/lokinet-builder) repository.
|
||||
|
||||
## Building
|
||||
|
||||
![build status](https://gitlab.com/lokiproject/loki-network/badges/master/pipeline.svg "build status")
|
||||
|
||||
|
||||
If you don't have libsodium 1.0.16 or higher use the [lokinet builder](https://github.com/loki-project/lokinet-builder) repo.
|
||||
|
||||
Otherwise:
|
||||
|
||||
$ sudo apt install git libcap-dev build-essential ninja-build cmake libsodium-dev
|
||||
$ git clone https://github.com/loki-project/loki-network
|
||||
$ cd loki-network
|
||||
$ make
|
||||
|
||||
## Usage
|
||||
|
||||
### Windows
|
||||
|
||||
Windows only supports client mode so you run `lokinet.exe` and that's it.
|
||||
|
||||
### Linux
|
||||
|
||||
Client mode:
|
||||
|
||||
For simple testing do:
|
||||
|
||||
$ lokinet
|
||||
|
||||
On systemd based distros you can persist it in the background:
|
||||
|
||||
# systemctl enable --now lokinet-client
|
||||
|
||||
|
||||
Relay mode:
|
||||
|
||||
you can participate as a relay node trivially (for now).
|
||||
|
||||
On systemd based linux distros do:
|
||||
|
||||
# systemctl enable --now lokinet-relay
|
||||
|
||||
Alternatively:
|
||||
|
||||
# mkdir /usr/local/lokinet
|
||||
# cd /usr/local/lokinet
|
||||
# lokinet --genconf daemon.ini
|
||||
# lokinet --check daemon.ini
|
||||
# lokinet /usr/local/lokinet/daemon.ini
|
||||
|
|
|
@ -35,187 +35,215 @@
|
|||
#include "tuntap.h"
|
||||
|
||||
int
|
||||
tuntap_sys_start(struct device *dev, int mode, int tun) {
|
||||
int fd;
|
||||
int persist;
|
||||
char *ifname;
|
||||
struct ifreq ifr;
|
||||
tuntap_sys_start(struct device *dev, int mode, int tun)
|
||||
{
|
||||
int fd;
|
||||
int persist;
|
||||
char *ifname;
|
||||
struct ifreq ifr;
|
||||
|
||||
/* Get the persistence bit */
|
||||
if (mode & TUNTAP_MODE_PERSIST) {
|
||||
mode &= ~TUNTAP_MODE_PERSIST;
|
||||
persist = 1;
|
||||
} else {
|
||||
persist = 0;
|
||||
}
|
||||
/* Get the persistence bit */
|
||||
if(mode & TUNTAP_MODE_PERSIST)
|
||||
{
|
||||
mode &= ~TUNTAP_MODE_PERSIST;
|
||||
persist = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
persist = 0;
|
||||
}
|
||||
|
||||
/* Set the mode: tun or tap */
|
||||
(void)memset(&ifr, '\0', sizeof ifr);
|
||||
if (mode == TUNTAP_MODE_ETHERNET) {
|
||||
ifr.ifr_flags = IFF_TAP;
|
||||
ifname = "tap%i";
|
||||
} else if (mode == TUNTAP_MODE_TUNNEL) {
|
||||
ifr.ifr_flags = IFF_TUN;
|
||||
ifname = "tun%i";
|
||||
} else {
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Invalid parameter 'mode'");
|
||||
return -1;
|
||||
}
|
||||
ifr.ifr_flags |= IFF_NO_PI;
|
||||
/* Set the mode: tun or tap */
|
||||
(void)memset(&ifr, '\0', sizeof ifr);
|
||||
if(mode == TUNTAP_MODE_ETHERNET)
|
||||
{
|
||||
ifr.ifr_flags = IFF_TAP;
|
||||
ifname = "tap%i";
|
||||
}
|
||||
else if(mode == TUNTAP_MODE_TUNNEL)
|
||||
{
|
||||
ifr.ifr_flags = IFF_TUN;
|
||||
if(dev->if_name[0])
|
||||
strncpy(ifr.ifr_name, dev->if_name, sizeof(ifr.ifr_name));
|
||||
else
|
||||
ifname = "tun%i";
|
||||
}
|
||||
else
|
||||
{
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Invalid parameter 'mode'");
|
||||
return -1;
|
||||
}
|
||||
ifr.ifr_flags |= IFF_NO_PI;
|
||||
|
||||
if (tun < 0) {
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Invalid parameter 'tun'");
|
||||
return -1;
|
||||
if(tun < 0)
|
||||
{
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Invalid parameter 'tun'");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Open the clonable interface */
|
||||
fd = -1;
|
||||
if((fd = open("/dev/net/tun", O_RDWR)) == -1)
|
||||
{
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Can't open /dev/net/tun");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set the interface name, if any */
|
||||
|
||||
if(fd > TUNTAP_ID_MAX)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if(ifr.ifr_name[0] == 0 && tun)
|
||||
(void)snprintf(ifr.ifr_name, sizeof ifr.ifr_name, ifname, tun);
|
||||
/* Save interface name *after* SIOCGIFFLAGS */
|
||||
|
||||
/* Configure the interface */
|
||||
if(ioctl(fd, TUNSETIFF, &ifr) == -1)
|
||||
{
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Can't set interface name");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set it persistent if needed */
|
||||
if(persist == 1)
|
||||
{
|
||||
if(ioctl(fd, TUNSETPERSIST, 1) == -1)
|
||||
{
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Can't set persistent");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Open the clonable interface */
|
||||
fd = -1;
|
||||
if ((fd = open("/dev/net/tun", O_RDWR)) == -1) {
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Can't open /dev/net/tun");
|
||||
return -1;
|
||||
}
|
||||
/* Get the interface default values */
|
||||
if(ioctl(dev->ctrl_sock, SIOCGIFFLAGS, &ifr) == -1)
|
||||
{
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Can't get interface values");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set the interface name, if any */
|
||||
if (tun != TUNTAP_ID_ANY) {
|
||||
if (fd > TUNTAP_ID_MAX) {
|
||||
return -1;
|
||||
}
|
||||
(void)snprintf(ifr.ifr_name, sizeof ifr.ifr_name,
|
||||
ifname, tun);
|
||||
/* Save interface name *after* SIOCGIFFLAGS */
|
||||
}
|
||||
/* Save flags for tuntap_{up, down} */
|
||||
dev->flags = ifr.ifr_flags;
|
||||
|
||||
/* Configure the interface */
|
||||
if (ioctl(fd, TUNSETIFF, &ifr) == -1) {
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Can't set interface name");
|
||||
return -1;
|
||||
}
|
||||
/* Save interface name */
|
||||
(void)memcpy(dev->if_name, ifr.ifr_name, sizeof ifr.ifr_name);
|
||||
|
||||
/* Set it persistent if needed */
|
||||
if (persist == 1) {
|
||||
if (ioctl(fd, TUNSETPERSIST, 1) == -1) {
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Can't set persistent");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* Save pre-existing MAC address */
|
||||
if(mode == TUNTAP_MODE_ETHERNET)
|
||||
{
|
||||
struct ifreq ifr_hw;
|
||||
|
||||
/* Get the interface default values */
|
||||
if (ioctl(dev->ctrl_sock, SIOCGIFFLAGS, &ifr) == -1) {
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Can't get interface values");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Save flags for tuntap_{up, down} */
|
||||
dev->flags = ifr.ifr_flags;
|
||||
|
||||
/* Save interface name */
|
||||
(void)memcpy(dev->if_name, ifr.ifr_name, sizeof ifr.ifr_name);
|
||||
|
||||
/* Save pre-existing MAC address */
|
||||
if (mode == TUNTAP_MODE_ETHERNET) {
|
||||
struct ifreq ifr_hw;
|
||||
|
||||
(void)memcpy(ifr_hw.ifr_name, dev->if_name,
|
||||
sizeof(dev->if_name));
|
||||
if (ioctl(fd, SIOCGIFHWADDR, &ifr_hw) == -1) {
|
||||
tuntap_log(TUNTAP_LOG_WARN,
|
||||
"Can't get link-layer address");
|
||||
return fd;
|
||||
}
|
||||
(void)memcpy(dev->hwaddr, ifr_hw.ifr_hwaddr.sa_data, ETH_ALEN);
|
||||
}
|
||||
return fd;
|
||||
(void)memcpy(ifr_hw.ifr_name, dev->if_name, sizeof(dev->if_name));
|
||||
if(ioctl(fd, SIOCGIFHWADDR, &ifr_hw) == -1)
|
||||
{
|
||||
tuntap_log(TUNTAP_LOG_WARN, "Can't get link-layer address");
|
||||
return fd;
|
||||
}
|
||||
(void)memcpy(dev->hwaddr, ifr_hw.ifr_hwaddr.sa_data, ETH_ALEN);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
void
|
||||
tuntap_sys_destroy(struct device *dev) {
|
||||
if (ioctl(dev->tun_fd, TUNSETPERSIST, 0) == -1) {
|
||||
tuntap_log(TUNTAP_LOG_WARN, "Can't destroy the interface");
|
||||
}
|
||||
tuntap_sys_destroy(struct device *dev)
|
||||
{
|
||||
if(ioctl(dev->tun_fd, TUNSETPERSIST, 0) == -1)
|
||||
{
|
||||
tuntap_log(TUNTAP_LOG_WARN, "Can't destroy the interface");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
tuntap_sys_set_hwaddr(struct device *dev, struct ether_addr *eth_addr) {
|
||||
struct ifreq ifr;
|
||||
tuntap_sys_set_hwaddr(struct device *dev, struct ether_addr *eth_addr)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
(void)memset(&ifr, '\0', sizeof ifr);
|
||||
(void)memcpy(ifr.ifr_name, dev->if_name, sizeof dev->if_name);
|
||||
(void)memset(&ifr, '\0', sizeof ifr);
|
||||
(void)memcpy(ifr.ifr_name, dev->if_name, sizeof dev->if_name);
|
||||
|
||||
ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
|
||||
(void)memcpy(ifr.ifr_hwaddr.sa_data, eth_addr->ether_addr_octet, 6);
|
||||
ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
|
||||
(void)memcpy(ifr.ifr_hwaddr.sa_data, eth_addr->ether_addr_octet, 6);
|
||||
|
||||
/* Linux has a special flag for setting the MAC address */
|
||||
if (ioctl(dev->ctrl_sock, SIOCSIFHWADDR, &ifr) == -1) {
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Can't set link-layer address");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
/* Linux has a special flag for setting the MAC address */
|
||||
if(ioctl(dev->ctrl_sock, SIOCSIFHWADDR, &ifr) == -1)
|
||||
{
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Can't set link-layer address");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tuntap_sys_set_ipv4(struct device *dev, t_tun_in_addr *s4, uint32_t bits) {
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_in mask;
|
||||
tuntap_sys_set_ipv4(struct device *dev, t_tun_in_addr *s4, uint32_t bits)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_in mask;
|
||||
|
||||
(void)memset(&ifr, '\0', sizeof ifr);
|
||||
(void)memcpy(ifr.ifr_name, dev->if_name, sizeof dev->if_name);
|
||||
(void)memset(&ifr, '\0', sizeof ifr);
|
||||
(void)memcpy(ifr.ifr_name, dev->if_name, sizeof dev->if_name);
|
||||
|
||||
/* Set the IP address first */
|
||||
(void)memcpy(&(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr),
|
||||
s4, sizeof(struct in_addr));
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
if (ioctl(dev->ctrl_sock, SIOCSIFADDR, &ifr) == -1) {
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Can't set IP address");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Reinit the struct ifr */
|
||||
(void)memset(&ifr.ifr_addr, '\0', sizeof ifr.ifr_addr);
|
||||
/* Set the IP address first */
|
||||
(void)memcpy(&(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr), s4,
|
||||
sizeof(struct in_addr));
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
if(ioctl(dev->ctrl_sock, SIOCSIFADDR, &ifr) == -1)
|
||||
{
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Can't set IP address");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Then set the netmask */
|
||||
(void)memset(&mask, '\0', sizeof mask);
|
||||
mask.sin_family = AF_INET;
|
||||
mask.sin_addr.s_addr = bits;
|
||||
(void)memcpy(&ifr.ifr_netmask, &mask, sizeof ifr.ifr_netmask);
|
||||
if (ioctl(dev->ctrl_sock, SIOCSIFNETMASK, &ifr) == -1) {
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Can't set netmask");
|
||||
return -1;
|
||||
}
|
||||
/* Reinit the struct ifr */
|
||||
(void)memset(&ifr.ifr_addr, '\0', sizeof ifr.ifr_addr);
|
||||
|
||||
return 0;
|
||||
/* Then set the netmask */
|
||||
(void)memset(&mask, '\0', sizeof mask);
|
||||
mask.sin_family = AF_INET;
|
||||
mask.sin_addr.s_addr = bits;
|
||||
(void)memcpy(&ifr.ifr_netmask, &mask, sizeof ifr.ifr_netmask);
|
||||
if(ioctl(dev->ctrl_sock, SIOCSIFNETMASK, &ifr) == -1)
|
||||
{
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Can't set netmask");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tuntap_sys_set_ipv6(struct device *dev, t_tun_in6_addr *s6, uint32_t bits) {
|
||||
(void)dev;
|
||||
(void)s6;
|
||||
(void)bits;
|
||||
tuntap_log(TUNTAP_LOG_NOTICE, "IPv6 is not implemented on your system");
|
||||
return -1;
|
||||
tuntap_sys_set_ipv6(struct device *dev, t_tun_in6_addr *s6, uint32_t bits)
|
||||
{
|
||||
(void)dev;
|
||||
(void)s6;
|
||||
(void)bits;
|
||||
tuntap_log(TUNTAP_LOG_NOTICE, "IPv6 is not implemented on your system");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
tuntap_sys_set_ifname(struct device *dev, const char *ifname, size_t len) {
|
||||
struct ifreq ifr;
|
||||
tuntap_sys_set_ifname(struct device *dev, const char *ifname, size_t len)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
(void)strncpy(ifr.ifr_name, dev->if_name, IF_NAMESIZE);
|
||||
(void)strncpy(ifr.ifr_newname, ifname, len);
|
||||
(void)strncpy(ifr.ifr_name, dev->if_name, IF_NAMESIZE);
|
||||
(void)strncpy(ifr.ifr_newname, ifname, len);
|
||||
|
||||
if (ioctl(dev->ctrl_sock, SIOCSIFNAME, &ifr) == -1) {
|
||||
perror(NULL);
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Can't set interface name");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
if(ioctl(dev->ctrl_sock, SIOCSIFNAME, &ifr) == -1)
|
||||
{
|
||||
perror(NULL);
|
||||
tuntap_log(TUNTAP_LOG_ERR, "Can't set interface name");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tuntap_sys_set_descr(struct device *dev, const char *descr, size_t len) {
|
||||
(void)dev;
|
||||
(void)descr;
|
||||
(void)len;
|
||||
tuntap_log(TUNTAP_LOG_NOTICE,
|
||||
"Your system does not support tuntap_set_descr()");
|
||||
return -1;
|
||||
tuntap_sys_set_descr(struct device *dev, const char *descr, size_t len)
|
||||
{
|
||||
(void)dev;
|
||||
(void)descr;
|
||||
(void)len;
|
||||
tuntap_log(TUNTAP_LOG_NOTICE,
|
||||
"Your system does not support tuntap_set_descr()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue