remove old out of date documentation

pull/1815/head
Jeff Becker 3 years ago committed by Jeff
parent 5890c99a81
commit 29df7bec74
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -1,263 +0,0 @@
LLARP Traffic Routing Protocol (LTRP)
LRTP is a protocol that instructs how to route hidden service traffic on LLARP
based networks.
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].
Overview:
LRTP is a message oriented data delivery and receival protocol for hidden
service traffic. All structures are BitTorrent Encoded dictionaries sent
over TCP.
all structures are bencoded when sent over the networks.
In this document they are provided in JSON for ease of display.
message format:
<2 bytes length (N)>
<N bytes of data>
Nouns (data structures):
Path: information about a path that we have built
{
H: [router_id_32_bytes, router_id_32_bytes, router_id_32_bytes, router_id_32_bytes],
R: "<16 bytes local rxid>",
T: "<16 bytes local txid>"
}
Introduction: a hidden service introduction
{
E: expiration_ms_since_epoch_uint64,
L: advertised_latency_ms_uint64,
P: "<16 bytes pathid>",
R: "<32 bytes RouterID>"
}
ServiceInfo: public key info for hidden service address
{
A: "<32 bytes .loki address>",
E: "<32 bytes public encryption key>",
S: "<32 bytes public signing key>"
}
IntroSet: information about an introduction set from the network
{
E: expires_at_timestamp_ms_since_epoch_uint64,
I: [Intro0, Intro1, ... IntroN],
S: ServiceInfo
}
Converstation: information about a loki network converstation
{
L: "<32 bytes loki address provided if a loki address>",
S: "<32 bytes snode address provided if a snode address>",
T: "<16 bytes convo tag>"
}
SessionInfo: information about our current session
{
I: [inbound,convos,here],
O: [outbound,covos,here],
P: [Path0, Path1, .... PathN],
S: Current IntroSet,
}
Verbs (methods):
session requset (C->S)
the first message sent by the client
{
A: "session",
B: "<8 bytes random>",
T: milliseconds_since_epoch_client_now_uint64,
Y: 0,
Z: "<32 bytes keyed hash>"
}
session accept (S->C)
sent in reply to a session message to indicate session accept and give
a session cookie to the client.
{
A: "session-reply",
B: "<8 bytes random from session request>",
C: "<16 bytes session cookie>",
T: milliseconds_since_epoch_server_now_uint64,
Y: 0,
Z: "<32 bytes keyed hash>"
}
session reject (S->C)
sent in reply to a session message to indicate session rejection
{
A: "session-reject",
B: "<8 bytes random from session request>",
R: "<variable length utf-8 encoded bytes human readable reason here>",
T: milliseconds_since_epoch_server_now_uint64,
Y: 0,
Z: "<32 bytes keyed hash>"
}
spawn a hidden service (C->S)
only one hidden service can be made per session
{
A: "spawn",
C: "<16 bytes session cookie>",
O: config_options_dict,
Y: 1,
Z: "<32 bytes keyed hash>"
}
inform that we have spawned a new hidden service endpoint (S->C)
{
A: "spawn-reply",
C: "<16 bytes session cookie>",
S: ServiceInfo,
Y: 1,
Z: "<32 bytes keyed hash>"
}
inform that we have not spaned a new hidden service endpint (S->C)
after sending this message the server closes the connection
{
A: "spawn-reject",
C: "<16 bytes session cookie>",
E: "<error message goes here>",
Y: 1,
Z: "<32 bytes keyed hash>"
}
create a new convseration on a loki/snode address (C->S)
{
A: "start-convo",
B: "<8 bytes random>",
C: "<16 bytes session cookie>",
R: "human readable remote address .snode/.loki",
Y: sequence_num_uint64,
Z: "<32 bytes keyed hash>"
}
sent in reply to a make-convo message to indicate rejection (S->C)
{
A: "start-convo-reject",
B: "<8 bytes random from start-convo message>",
C: "<16 bytes session cookie>",
S: status_bitmask_uint,
Y: sequence_num_uint64,
Z: "<32 bytes keyed hash>"
}
sent in reply to a make-convo message to indicate that we have accepted this
new conversation and gives the convo tag it uses.
{
A: "start-convo-accept",
B: "<8 bytes random from start-convo message>",
C: "<16 bytes session cookie>",
Y: sequence_num_uint64,
Z: "<32 bytes keyed hash>
}
infrom the status of a converstation on a loki address (S->C)
for an outbund conversation it is sent every time the status bitmask changes.
for inbound convos it is sent immediately when a new inbound conversation is made.
S bit 0 (LSB): we found the introset/endpoint for (set by outbound)
S bit 1: we found the router to align on (set by outbound)
S bit 2: we have a path right now (set by outbound)
S bit 3: we have made the converstation (set by both)
S bit 4: we are an inbound converstation (set by inbound)
{
A: "convo-status",
C: "<16 bytes session cookie>",
R: "human readable address .snode/.loki",
S: bitmask_status_uint64,
T: "<16 bytes convotag>",
Y: sequence_num_uint64,
Z: "<32 bytes keyed hash>"
}
send or recieve authenticated data to or from the network (bidi)
protocol numbers are
1 for ipv4
2 for ipv6
{
A: "data",
C: "<16 bytes session cookie>",
T: "<16 bytes convotag>",
W: protocol_number_uint,
X: "<N bytes payload>",
Y: sequence_num_uint64,
Z: "<32 bytes keyed hash>"
}
get session information (C->S)
{
A: "info",
C: "<16 bytes session cookie>",
Y: sequence_num_uint64,
Z: "<32 bytes keyed hash>"
}
session information update (S->C)
sent in reply to a get session information message
{
A: "info-reply",
C: "<16 bytes session cookie>",
I: hiddenserviceinfo,
Y: sequence_num_uint64,
Z: "<32 bytes keyed hash>"
}
Protocol Flow:
all messages have an A, C, Y and Z value
A is the function name being called
C is the session cookie indicating the current session
Y is the 64 bit message sequence number as an integer
Z is the keyed hash computed by MDS(BE(msg), K) where K is HS(api_password)
with the msg.Z being set to 32 bytes of \x00
both client and server MUST know a variable length string api_password used to
authenticate access to the api subsystem.
the Y value is incremented by 1 for each direction every time the sender sends
a message in that direction.

@ -1,117 +0,0 @@
* lokinet components
** basic data structures
*** AlignedBuffer
*** RouterContact
**** self signed router descriptor
*** Crypto key types
** network / threading / sync utilities
*** threadpool
*** logic (single thread threadpool)
** configuration
*** ini parser
*** llarp::Configuration
** cryptography
*** llarp::Crypto interface
**** libsodium / sntrup implementation
*** llarp::CryptoManager
**** crypto implementation signleton manager
** nodedb
*** llarp_nodedb
**** holds many RouterContacts loaded from disk in memory
**** uses a filesystem skiplist for on disk storage
**** stores in a std::unordered_map addressable via public identity key
** event loop
*** llarp_event_loop
**** udp socket read/write
**** network interface packet read/write
**** stream connection (outbound stream)
**** stream acceptor (inbound stream)
** link layer message transport:
*** ILinkSession
**** the interface for an entity that is single session with relay
**** responsible for delivery recieval of link layer messages in full
*** ILinkLayer
**** bound to an address / interface
**** has a direction, inbound / outbound
**** distinctly identified by the union of interface and direction
**** Holds many ILinkSessions bound on the distinctly idenitfied direction/interface
** link layer messages
*** link layer message parser
**** parses buffers as bencoded dicts
*** link layer message handler
**** handles each type of link layer message
** IHopHandler
*** llarp::PathHopConfig
**** txid, rxid, shared secret at hop
*** llarp::path::Path
**** a built path or a path being built
**** owns a std::vector<PathHopConfig> for each hop's info
*** TransitHop
**** a single hop on a built path
**** has txid, rxid, shared secret, hash of shared secret
** pathset
*** path::Builder
**** builds and maintains a set of paths for a common use
** routing layer message router
*** routing::IMessageHandler
**** interface for routing layer message processing
**** transit hops implement this if they are an endpoint
**** path::Path implement this always
** dht "layer" / rc gossiper
*** TODO rewrite/refactor
** hidden service data structures
*** IntroSet
**** decrypted plaintext hidden service descriptor
*** EncryptedIntroSet
**** public encrpyted / signed version of IntroSet
** service endpoint / outbound context connectivitybackend
*** service::Endpoint
**** backend for sending/recieving packets over the hidden service protocol layer
**** kitchen sink
*** service::SendContext
**** interface type for sending to a resource on the network
*** service::OutboundContext
**** implements SendContext extends path::Builder and path::PathSet
**** for maintaining a pathset that aligns on an introset's intros
~
** snode / exit connectivity backend
*** exit::BaseSession
**** extends path::Builder
**** obtains an exit/snode session from the router they are aligning to
*** exit::Endpoint
**** snode/exit side of an exit::Session
** snapp / exit / mobile / null frontend handlers
*** handlers::TunEndpoint
**** extends service::Endpoint
**** provides tun interface frontend for hidden service backend
*** handlers::ExitEndpoint
**** provides tun interface frontend for exit/snode backend
** outbound message dispatcher
*** TODO tom please document these

@ -1,39 +0,0 @@
cryptography:
H(x) is 512 bit blake2b digest of x
HS(x) is 256 bit blake2b digest of x
MD(x, k) is 512 bit blake2b hmac of x with secret value k
MDS(x, k) is 256 bit blake2b hmac of x with secret value k
SE(k, n, x) is chacha20 encrypt data x using symettric key k and nounce n
SD(k, n, x) is chacha20 dectypt data x using symettric key k and nounce n
S(k, x) is sign x with ed25519 using secret key k
EDKG() is generate ec keypair (p, s) public key p (32 bytes), secret key s (64 bytes)
V(k, x, sig) is verify x data using signature sig using public key k
EDDH(a, b) is curve25519 scalar multiplication of a and b
HKE(a, b, x) is hashed key exchange between a and b using a secret key x HS(a + b + EDDH(x, b))
TKE(a, b, x, n) is a transport shared secret kdf using MDS(n, HKE(a, b, x))
when A is client and B is server where n is a 32 bytes shared random
client computes TKE(A.pk, B.pk, A.sk, n)
server computes TKE(A.pk, B.pk, B.sk, n)
PDH(a, b, x) is path shared secret generation HS(a + b + EDDH(x, b))
PKE(a, b, x, n) is a path shared secret kdf using MDS(n, PDH(a, b, x))
given A is the path creator and B is a hop in the path and n is 32 bytes shared random
A computes PKE(A.pk, B.pk, A.sk, n) as S_a
B computes PKE(A.pk, B.pk, B.sk, n) as S_b
S_a is equal to S_b
RAND(n) is n random bytes
PQKG() is generate a sntrup4591761 key pair (sk, pk)
PQKE_A(pk) is alice generating (x, k) where x is sntrup4591761 ciphertext block and k is the session key
PQKE_B(x, sk) is bob calculating k where x is sntrup4591761 ciphertext block, sk is bob's sntrup4591761 secretkey and k is the session key

@ -1,153 +0,0 @@
DHT messages
DHT messages can be either wrapped in a LIDM message or sent anonymously over a path inside a DHT routing message
The distance function is A xor B (traditional kademlia)
The dht implements both iterative and recursive lookups.
Recursive lookups forward the request to a node closer if not found.
Iterative lookups return the key and of the DHT node who is closer.
In the case of iterative FRCM the RC of the closer router is provided.
In the case of iterative FIM the pubkey of a dht node who is closer is provided in the GIM.
find introduction message (FIM)
variant 1: find an IS by SA
{
A: "F",
R: 0 for iterative and 1 for recurisve,
S: "<32 bytes SA>",
T: transaction_id_uint64,
V: 0
}
variant 2: recursively find many IS in a tag
{
A: "F",
E: [list, of, excluded, SA],
R: 0 for iterative and 1 for recurisve,
N: "<16 bytes topic tag>",
T: transaction_id_uint64,
V: 0
}
exclude adding service addresses in E if present
got introduction message (GIM)
sent in reply to FIM containing the result of the search
sent in reply to PIM to acknoledge the publishing of an IS
{
A: "G",
I: [IS, IS, IS, ...],
K: "<32 bytes public key of router who is closer, provided ONLY if FIM.R is 0>",
T: transaction_id_uint64,
V: 0,
}
The I value MUST NOT contain more than 4 IS.
The I value MUST contain either 1 or 0 IS for PIM and FIM variant 1.
publish introduction message (PIM)
publish one IS to the DHT.
version 0 uses the SA of the IS as the keyspace location.
in the future the location will be determined by the dht kdf
which uses a shared random source to obfuscate keyspace location.
R is currently set to 0 by the sender.
{
A: "I",
I: IS,
R: random_walk_counter,
S: optional member 0 for immediate store otherwise non zero,
T: transaction_id_uint64,
V: 0
}
if R is greater than 0, decrement R and forward the request to a random DHT
node without storing the IS.
As of protocol version 0, R is always 0.
If S is provided store the IS for later lookup unconditionally, then
decrement S by 1 and forward to dht peer who is next closest to
the SA of the IS. If S is greater than 3, don't store the IS and
discard this message.
acknoledge introduction message (AIM)
acknoledge the publishing of an introduction
{
A: "A",
P: published_to_counter,
T: transaction_id_uint64,
V: 0
}
increment P by 1 and forward to requester
find router contact message (FRCM)
find a router by long term RC.k public key
{
A: "R",
E: 0 or 1 if exploritory lookup,
I: 0 or 1 if iterative lookup,
K: "<32 byte public key of router>",
T: transaction_id_uint64,
V: 0
}
if E is provided and non zero then return E dht nodes that are closest to K
if I is provided and non zero then this request is considered an iterative lookup
during an iterative lookup the response's GRCM.K is set to the pubkey of the router closer in key space.
during a recursive lookup the request is forwarded to a router who is closer in
keyspace to K.
If we have no peers that are closer to K and we don't have the RC known locally
we reply with a GRCM whose R value is emtpy.
In any case if we have a locally known RC with pubkey equal to K reply with
a GRCM with 1 RC in the R value corrisponding to that locally known RC.
got router contact message (GRCM)
R is a list containing a single RC if found or is an empty list if not found
sent in reply to FRCM only
{
A: "S",
K: "<32 bytes public identity key of router closer, provided ONLY if FRCM.I is 1>",
R: [RC],
T: transaction_id_uint64,
V: 0
}
in response to an exploritory router lookup, where FRCM.E is provided and non zero.
{
A: "S",
N: [list, of, router, publickeys, near, K],
T: transaction_id_uint64,
V: 0
}
sent in reply to a dht request to indicate transaction timeout
{
A: "T",
T: transaction_id_uint64,
V: 0
}

@ -1,94 +0,0 @@
llarp's dht is a recusrive kademlia dht with optional request proxying via paths for requester anonymization.
dht is separated into 2 different networks, one for router contacts, one for introsets.
format for consesus propagation messages:
keys: A, H, K, N, O, T, U, V
concensus request messages
requester requests current table hash, H,N,O is set to zeros if not known
C -> S
{
A: "C",
H: "<32 byte last hash of consensus table>",
N: uint64_number_of_entries_to_request,
O: uint64_offset_in_table,
T: uint64_txid,
V: []
}
when H or N is set to zero from the requester, they are requesting the current consensus table's hash
consensus response message is as follows for a zero H or N value
S -> C
{
A: "C",
H: "<32 byte hash of current consensus table>",
N: uint64_number_of_entries_in_table,
T: uint64_txid,
U: uint64_ms_next_update_required,
V: [proto, major, minor, patch]
}
requester requests a part of the current table for hash H
N must be less than or equal to 512
C -> S
{
A: "C",
H: "<32 bytes current consensus table hash>",
N: 256,
O: 512,
T: uint64_txid,
V: []
}
consensus response message for routers 512 to 512 + 256
S -> C
{
A: "C",
H: "<32 bytes current concensus table hash>",
K: [list, of, N, pubkeys, from, request, starting, at, position, O],
T: uint64_txid,
V: [proto, major, minor, patch]
}
consensus table is a concatination of all public keys in lexigraphical order.
the hash function in use is 256 bit blake2
gossip RC message
broadcast style RC publish message. sent to all peers infrequently.
it is really an unwarrented GRCM, propagate to all peers.
{
A: "S",
R: [RC],
T: 0,
V: proto
}
replays are dropped using a decaying hashset or decaying bloom filter.
the introset dht has 3 message: GetIntroSet Message (GIM), PutIntroSet Message (PIM), FoundIntroSet Message (FIM)

@ -1,147 +0,0 @@
THIS DOCUMENT IS 3 YEARS OUT OF DATE AND NEEDS TO BE REWRITTEN
LLARP - Low Latency Anon Routing Protocol
TL;DR edition: an onion router with a tun interface for transporting ip packets
anonymously between you and the internet and internally inside itself to other users.
This document describes the high level outline of LLARP, specific all the
project's goals, non-goals and network architecture from a bird's eye view.
Preface:
Working on I2P has been a really big learning experience for everyone involved.
After much deliberation I have decided to start making a "next generation" onion
routing protocol. Specifically LLARP is (currently) a research project
to explore the question:
"What if I2P was made in the current year (2018)? What would be different?"
Project Non Goals:
This project does not attempt to solve traffic shape correlation or active nation
state sponsored network attacks. The former is an inherit property of low latency
computer networks that I personally do not think is possible to properly fully
"solve". The latter is a threat that lies outside the scope of what the current
toolset that is available to me at the moment provides.
This project does not attempt to be a magical application level cure-all for
application or end user security. At the end of the day that is a problem that
exists between chair and keyboard.
The Single Project Goal:
LLARP is a protocol suite meant to anonymize IP by providing an anonymous
network level (IPv4/IPv6) tunnel broker for both "hidden services" and
communication back to "the clearnet" (the normal internet). Both hidden service
and clearnet communication MUST permit both outbound and inbound traffic on the
network level without any NAT (except for IPv4 in which NAT is permitted due to
lack of address availability).
In short We want to permit both anonymous exit and entry network level traffic
between LLARP enabled networks and the internet.
Rationale for starting over:
Despite Tor Project's best efforts to popularize Tor use, Tor2Web seems to be
widely popular for people who do not wish to opt into the ecosystem. My proposed
solution would be to permit inbound traffic from "exit nodes" in addition to
allowing outbound exit traffic. I have no ideas on how this could be done with
the existing protocols in Tor or if it is possible or advisable to attempt such
as I am not familiar with their ecosystem.
I2P could have been used as a medium for encrypted anonymous IP transit but the
current network has issues with latency and throughput. Rebasing I2P atop more
modern cryptography has been going on internally inside I2P for at least 5 years
with less progress than desired. Like some before me, I have concluded that it
would be faster to redo the whole stack "the right way" than to wait for I2P to
finish rebasing. That being said, nothing is preventing I2P from be used for
encrypted anonymous IP transit traffic in a future where I2P finishes their
protocol migrations, I just don't want to wait.
In short, I want to take the "best parts" from Tor and I2P and make a new
protocol suite.
For both Tor and I2P I have 2 categories for the attributes they have.
the good
the bad and the ugly
The good (I2P):
I2P aims to provide an anonymous unspoofable load balanced network layer.
I want this feature.
I2P is trust agile, it does not have any hard coded trusts in its network
architecture. Even network boostrap can be done from a single router if the user
desires to (albeit this is currently ill advised).
I want this feature.
The good (Tor):
Tor embraces the reality of the current internet infrastructure by having a
client/server architecture. This allows very low barriers of entry in using the
Tor network and a higher barrier of entry for contributing routing
infrastructure. This promotes a healthy network shape of high capacity servers
serving low capacity clients that "dangle off of the side" of the network.
I want this feature.
The bad and the ugly (I2P):
Bad: I2P uses old cryptography, specially 2048 bit ElGamal using non standard primes.
The use of ElGamal is so pervasive throughout the I2P protocol stack that it
exists at every level of it. Removing it is a massive task that is taking a long
LONG time.
I don't want this feature.
Ugly: I2P cannot currently mitigate most sybil attacks with their current network
architecture. Recently I2P has added some blocklist solutions signed by release
signers but this probably won't scale in the event of a "big" attack. In
addition I2P isn't staffed for such attacks either.
This is a hard problem to solve that the Loki network may be able to help
with by creating a financial barrier to running multiple a relays.
The bad and the ugly (Tor):
Bad: Tor is strictly TCP oriented.
I don't want this feature.

@ -1,16 +0,0 @@
Lokinet needs certain capabilities to run to set up a virtual network interface and provide a DNS server. The preferred approach to using this is through the linux capabilities mechanism, which allows assigning limited capabilities without needing to run the entire process as root.
There are two main ways to do this:
1. If you are running lokinet via an init system such as systemd, you can specify the capabilities in the service file by adding:
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
into the [Service] section of the systemd service file. This will assign the necessary permissions when running the process and allow lokinet to work while running as a non-root user.
2. You can set the capabilities on the binary by using the setcap program (if not available you may need to install libcap2-bin on Debian/Ubuntu-based systems) and running:
setcap cap_net_admin,cap_net_bind_service=+eip lokinet
This grants the permissions whenever the lokinet binary is executed.

@ -1,102 +0,0 @@
digraph {
constants -> util;
crypto -> constants;
crypto -> llarp;
crypto -> util;
dht -> crypto;
dht -> messages;
dht -> llarp;
dht -> path;
dht -> routing;
dht -> service;
dht -> util;
dns -> crypto;
dns -> ev;
dns -> handlers;
dns -> llarp;
dns -> net;
dns -> service;
dns -> util;
ev -> net;
ev -> util;
exit -> crypto;
exit -> handlers;
exit -> messages;
exit -> net;
exit -> path;
exit -> routing;
exit -> util;
handlers -> dns;
handlers -> ev;
handlers -> exit;
handlers -> net;
handlers -> service;
handlers -> util;
link -> constants;
link -> crypto;
link -> ev;
link -> messages;
link -> net;
link -> util;
messages -> crypto;
messages -> dht;
messages -> exit;
messages -> link;
messages -> llarp;
messages -> path;
messages -> routing;
messages -> service;
messages -> util;
net -> crypto;
net -> util;
path -> crypto;
path -> dht;
path -> llarp;
path -> messages;
path -> routing;
path -> service;
path -> util;
routing -> llarp;
routing -> messages;
routing -> path;
routing -> util;
service -> crypto;
service -> dht;
service -> ev;
service -> exit;
service -> handlers;
service -> messages;
service -> net;
service -> path;
service -> routing;
service -> util;
util -> constants;
llarp -> constants;
llarp -> crypto;
llarp -> dht;
llarp -> dns;
llarp -> ev;
llarp -> exit;
llarp -> handlers;
llarp -> link;
llarp -> messages;
llarp -> net;
llarp -> path;
llarp -> routing;
llarp -> service;
llarp -> util;
}

@ -1,66 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1000 368" style="enable-background:new 0 0 1000 368;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{fill:url(#SVGID_1_);}
.st2{fill:#333333;}
.st3{fill:url(#SVGID_2_);}
.st4{fill:url(#SVGID_3_);}
.st5{fill:#00263A;}
.st6{fill:url(#SVGID_4_);}
.st7{fill:url(#SVGID_5_);}
.st8{fill:url(#SVGID_6_);}
.st9{fill:url(#SVGID_7_);}
.st10{fill:url(#SVGID_8_);}
.st11{fill:url(#SVGID_9_);}
.st12{fill:url(#SVGID_10_);}
.st13{fill:url(#SVGID_11_);}
.st14{fill:url(#SVGID_12_);}
.st15{fill:url(#SVGID_13_);}
.st16{fill:url(#SVGID_14_);}
.st17{fill:url(#SVGID_15_);}
.st18{fill:url(#SVGID_16_);}
.st19{fill:url(#SVGID_17_);}
.st20{opacity:6.000000e-02;}
.st21{opacity:4.000000e-02;fill:#FFFFFF;}
.st22{opacity:7.000000e-02;fill:#FFFFFF;}
.st23{fill:#008522;}
.st24{fill:#78BE20;}
.st25{fill:#005F61;}
.st26{fill:url(#SVGID_18_);}
</style>
<g>
<path class="st0" d="M366.6,78h37.1v178.9H497v32.7H366.6V78z"/>
<path class="st0" d="M619.8,74.5C683.3,74.5,728,120.8,728,184c0,63.1-44.7,109.5-108.2,109.5c-63.5,0-108.2-46.3-108.2-109.5
C511.6,120.8,556.3,74.5,619.8,74.5z M619.8,107.5c-42.8,0-70.1,32.7-70.1,76.5c0,43.5,27.3,76.5,70.1,76.5
c42.5,0,70.1-33,70.1-76.5C689.9,140.2,662.3,107.5,619.8,107.5z"/>
<path class="st0" d="M819.4,200.5L801,222v67.6h-37.1V78H801v100.9L883.8,78h46l-86,99.9l92.3,111.7h-45.7L819.4,200.5z"/>
<path class="st0" d="M960.9,78H998v211.6h-37.1V78z"/>
</g>
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="86.8402" y1="268.7968" x2="86.8402" y2="0.426">
<stop offset="0" style="stop-color:#78BE20"/>
<stop offset="0.1197" style="stop-color:#58AF21"/>
<stop offset="0.3682" style="stop-color:#199122"/>
<stop offset="0.486" style="stop-color:#008522"/>
<stop offset="0.6925" style="stop-color:#007242"/>
<stop offset="0.8806" style="stop-color:#006459"/>
<stop offset="1" style="stop-color:#005F61"/>
</linearGradient>
<polygon class="st1" points="132.1,268.8 0.3,137 136.9,0.4 173.3,36.8 73.1,137 168.5,232.4 "/>
</g>
<g>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="212.9564" y1="367.5197" x2="212.9564" y2="99.1484">
<stop offset="0" style="stop-color:#78BE20"/>
<stop offset="0.1197" style="stop-color:#58AF21"/>
<stop offset="0.3682" style="stop-color:#199122"/>
<stop offset="0.486" style="stop-color:#008522"/>
<stop offset="0.6925" style="stop-color:#007242"/>
<stop offset="0.8806" style="stop-color:#006459"/>
<stop offset="1" style="stop-color:#005F61"/>
</linearGradient>
<polygon class="st3" points="162.9,367.5 126.5,331.1 226.7,230.9 131.3,135.6 167.7,99.1 299.5,230.9 "/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

@ -1,70 +0,0 @@
LokiNET admin api
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].
------
the admin api currently uses jsonrpc 2.0 over http
the methods currently provided are:
llarp.nodedb.rc.getbykey
get rc by public identity key
required parameters:
key: 32 bytes public identity key
returns:
a list of RCs (see protocol v0 spec) that have this public identity key
usually 0 or 1 RCs
llarp.nodedb.rc.getbycidr
get a list of RCs in an address range
required parameters:
cidr: ipv6 network cidr string, i.e. "::ffff.21.0.0.0/8" or "fc00::/7"
limit: integer max number of items to fetch, zero or positive integer,
if zero no limit.
returns:
a list of 0 to limit RCs that advertise themselves as being reachble via an
address in the given CIDR.
llarp.admin.sys.uptime (authentication required)
required paramters:
(none)
returns:
an integer milliseconds since unix epoch we've been online
llarp.admin.link.neighboors
get a list of connected service nodes on all links
required parameters:
(none)
returns:
list of 0 to N dicts in the following format:
{
"connected" : uint64_milliseconds_timestamp_connected_at
"ident" : "<64 hex encoded public identity key>",
"laddr" : "local address",
"raddr" : "remote address"
}

@ -1,90 +0,0 @@
Wire Protocol (version ½)
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in RFC 2119 [RFC2119].
LLARP supports by default an authenticated and framed transport over UTP [1]
Handshake:
Alice establishes a UTP "connection" with Bob.
Alice sends a LIM a_L encrpyted with the initial b_K key
if Bob accepts Alice's router, Bob replies with a LIM b_L encrpyted with the
b_K key.
next the session keys are generated via:
a_h = HS(a_K + a_L.n)
b_h = HS(b_K + b_L.n)
a_K = TKE(A.p, B_a.e, sk, a_h)
b_K = TKE(A.p, B_a.e, sk, b_h)
A.tx_K = b_K
A.rx_K = a_K
B.tx_K = a_K
B.rx_K = B_K
the initial value of a_K is HS(A.k) and b_K is HS(B.k)
608 byte fragments are sent over UTP in an ordered fashion.
The each fragment F has the following structure:
[ 32 bytes blake2 keyed hash of the following 576 bytes (h)]
[ 32 bytes random nonce (n)]
[ 544 bytes encrypted payload (p)]
the recipiant verifies F.h == MDS(F.n + F.p, rx_K) and the UTP session
is reset if verification fails.
the decrypted payload P has the following structure:
[ 24 bytes random (A) ]
[ big endian unsigned 32 bit message id (I) ]
[ big endian unsigned 16 bit fragment length (N) ]
[ big endian unsigned 16 bit fragment remaining bytes (R) ]
[ N bytes of plaintext payload (X) ]
[ trailing bytes discarded ]
link layer messages fragmented and delievered in any order the sender chooses.
recipaint ensures a buffer for message number P.I exists, allocating one if it
does not exist.
recipiant appends P.X to the end of the buffer for message P.I
if P.R is zero then message number P.I is completed and processed as a link
layer messages. otherwise the recipiant expects P.R additional bytes.
P.R's value MUST decrease by P.N in the next fragment sent.
message size MUST NOT exceed 8192 bytes.
if a message is not received in 2 seconds it is discarded and any further
fragments for the message are also discarded.
P.I MUST have the initial value 0
P.I MUST be incremeneted by 1 for each new messsage transmitted
P.I MAY wrap around back to 0
after every fragment F the session key K is mutated via:
K = HS(K + P.A)
Periodically the connection initiator MUST renegotiate the session key by
sending a LIM after L.p milliseconds have elapsed.
If the local RC changes while a connection is established they MUST
renegotioate the session keys by sending a LIM to ensure the new RC is sent.
references:
[1] http://www.bittorrent.org/beps/bep_0029.html

@ -1,903 +0,0 @@
LLARP v0
LLARP (Low Latency Anon Routing Protocol) is a protocol for anonymizing senders and
recipiants of encrypted messages sent over the internet without a centralised
trusted party.
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].
basic structures:
all structures are key, value dictionaries encoded with bittorrent encoding
notation:
a + b is a concatanated with b
a ^ b is a bitwise XOR b
x[a:b] is a memory slice of x from index a to b
BE(x) is bittorrent encode x
BD(x) is bittorrent decode x
{ a: b, y: z } is a dictionary with two keys a and y
whose values are b and z respectively
[ a, b, c ... ] is a list containing a b c and more items in that order
"<description>" is a bytestring whose contents and length is described by the
quoted value <description>
"<value>" * N is a bytestring containing the <value> concatenated N times.
cryptography:
see crypto_v0.txt
---
wire protocol
see wire-protocol.txt
---
datastructures:
all datastructures are assumed version 0 if they lack a v value
otherwise version is provided by the v value
all ip addresses can be ipv4 via hybrid dual stack ipv4 mapped ipv6 addresses,
i.e ::ffff.8.8.8.8. The underlying implementation MAY implement ipv4 as native
ipv4 instead of using a hybrid dual stack.
net address:
net addresses are a variable length byte string, if between 7 and 15 bytes it's
treated as a dot notation ipv4 address (xxx.xxx.xxx.xxx)
if it's exactly 16 bytes it's treated as a big endian encoding ipv6 address.
address info (AI)
An address info (AI) defines a publically reachable endpoint
{
c: transport_rank_uint16,
d: "<transport dialect name>",
e: "<32 bytes public encryption key>",
i: "<net address>",
p: port_uint16,
v: 0
}
example wank address info:
{
c: 1,
d: "wank",
e: "<32 bytes of 0x61>",
i: "123.123.123.123",
p: 1234,
v: 0
}
bencoded form:
d1:ci1e1:d4:wank1:e32:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1:d3:iwp1:i15:123.123.123.1231:pi1234e1:vi0ee
Traffic Policy (TP)
Traffic policy (TP) defines port, protocol and QoS/drop policy.
{
a: protocol_integer,
b: port_integeger,
d: drop_optional_integer,
v: 0
}
drop d is set to 1 to indicate that packets of protocol a with source port b will be dropped.
if d is 0 or not provided this traffic policy does nothing.
Exit Info (XI)
An exit info (XI) defines a exit address that can relay exit traffic to the
internet.
{
a: "<net address exit address>",
b: "<net address exit netmask>",
k: "<32 bytes public encryption/signing key>",
p: [ list, of, traffic, policies],
v: 0
}
Exit Route (XR)
An exit route (XR) define an allocated exit address and any additional
information required to access the internet via that exit address.
{
a: "<16 bytes big endian ipv6 gateway address>",
b: "<16 bytes big endian ipv6 netmask>",
c: "<16 bytes big endian ipv6 source address>",
l: lifetime_in_milliseconds_uint64,
v: 0
}
router contact (RC)
router's full identity
{
a: [ one, or, many, AI, here ... ],
e: extensions_supported,
i: "<max 8 bytes network identifier>",
k: "<32 bytes public long term identity signing key>",
n: "<optional max 32 bytes router nickname>",
p: "<32 bytes public path encryption key>",
s: [services, supported],
u: time_signed_at_milliseconds_since_epoch_uint64,
v: 0,
x: [ Exit, Infos ],
z: "<64 bytes signature using identity key>"
}
e is a dict containing key/value of supported protocol extensions on this service node, keys are strings, values MUST be 0 or 1.
s is a list of services on this service node:
each service is a 6 item long, list of the following:
["_service", "_proto", ttl_uint, priority_uint, weight_uint, port_uint]
with the corrisponding SRV record:
<_service>.<_proto>.router_pubkey_goes_here.snode. <ttl_uint> IN SRV <priority_uint> <weight_uint> <port_uint> router_pubkey_goes_here.snode
RC.t is the timestamp of when this RC was signed.
RC is valid for a maximum of 1 hour after which it MUST be resigned with the new
timestamp.
RC.i is set to the network identifier.
only routers with the same network identifier may connect to each other.
"testnet" for testnet.
"lokinet" for the "official" lokinet mainline network.
other values of RC.i indicate the router belongs to a network fork.
service info (SI)
public information blob for a hidden service
e is the long term public encryption key
s is the long term public signing key
v is the protocol version
x is a nounce value for generating vanity addresses that can be omitted
if x is included it MUST be equal to 16 bytes
{
e: "<32 bytes public encryption key>",
s: "<32 bytes public signing key>",
v: 0,
x: "<optional 16 bytes nonce for vanity>"
}
service address (SA)
the "network address" of a hidden service, which is computed as the blake2b
256 bit hash of the public infomration blob.
HS(BE(SI))
when in string form it's encoded with z-base32 and uses the .loki tld
introduction (I)
a descriptor annoucing a path to a hidden service
k is the rc.k value of the router to contact
p is the path id on the router that is owned by the service
v is the protocol version
x is the timestamp milliseconds since epoch that this introduction expires at
{
k: "<32 bytes public identity key of router>",
l: advertised_path_latency_ms_uint64, (optional)
p: "<16 bytes path id>",
v: 0,
x: time_expires_milliseconds_since_epoch_uint64
}
introduction set (IS)
and introset is a signed set of introductions for a hidden service
a is the service info of the publisher
h is a list of srv records in same format as in RCs
i is the list of introductions that this service is advertising with
k is the public key to use when doing encryption to this hidden service
n is a 16 byte null padded utf-8 encoded string tagging the hidden service in
a topic searchable via a lookup (optional)
v is the protocol version
w is an optinal proof of work for DoS protection (slot for future)
z is the signature of the entire IS where z is set to zero signed by the hidden
service's signing key.
{
a: SI,
h: [list, of, advertised, services],
i: [ I, I, I, ... ],
k: "<1218 bytes sntrup4591761 public key block>",
n: "<16 bytes service topic (optional)>",
t: timestamp_uint64_milliseconds_since_epoch_published_at,
v: 0,
w: optional proof of work,
z: "<64 bytes signature using service info signing key>"
}
h is a list of services on this endpoint
each service is a 7 item long, list of the following:
["_service", "_proto", ttl_uint, priority_uint, weight_uint, port_uint, "<32 bytes SA of the service>"]
with the corrisponding SRV record:
<_service>.<_proto>.<service_address>.loki. <ttl_uint> IN SRV <priority_uint> <weight_uint> <port_uint> <SA of sub service>.loki.
recursion on SRV records is NOT permitted.
---
Encrypted frames:
Encrypted frames are encrypted containers for link message records like LRCR.
32 bytes hmac, h
32 bytes nounce, n
32 bytes ephmeral sender's public encryption key, k
remaining bytes ciphertext, x
decryption:
0) verify hmac
S = PKE(n, k, our_RC.K)
verify h == MDS(n + k + x, S)
If the hmac verification fails the entire parent message is discarded
1) decrypt and decode
new_x = SD(S, n[0:24], x)
msg = BD(new_x)
If the decoding fails the entire parent message is discarded
encryption:
to encrypt a frame to a router with public key B.k
0) prepare nounce n, ephemeral keypair (A.k, s) and derive shared secret S
A.k, s = ECKG()
n = RAND(32)
S = PKE(p, A.k, B.k, n)
1) encode and encrypt
x = BE(msg)
new_x = SE(S, n[0:24], x)
2) generate message authentication
h = MDS(n + A.k + new_x, S)
resulting frame is h + n + A.k + new_x
---
link layer messages:
the link layer is responsible for anonymising the source and destination of
routing layer messages.
any link layer message without a key v is assumed to be version 0 otherwise
indicates the protocol version in use.
link introduce message (LIM)
This message MUST be the first link message sent before any others. This message
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.
{
a: "i",
e: "<32 bytes ephemeral public encryption key>",
n: "<32 bytes nonce for key exhcange>",
p: uint64_milliseconds_session_period,
r: RC,
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.
{
a: "c",
c: [ list, of, encrypted, LRCR frames ],
v: 0
}
c MUST contain dummy records if the hop length is less than the maximum
hop length.
link relay commit record (LRCR)
record requesting relaying messages for 600 seconds to router
on network whose i is equal to RC.k and decrypt data any messages using
PKE(n, rc.p, c) as symmetric key for encryption and decryption.
if l is provided and is less than 600 and greater than 10 then that lifespan
is used (in seconds) instead of 600 seconds.
if w is provided and fits the required proof of work then the lifetime of
the path is extended by w.y seconds
{
c: "<32 byte public encryption key used for upstream>",
d: uint_optional_ms_delay, // TODO
i: "<32 byte RC.k of next hop>",
l: uint_optional_lifespan,
n: "<32 bytes nounce for key exchange>",
r: "<16 bytes rx path id>",
t: "<16 bytes tx path id>",
u: "<optional RC of the next hop>",
v: 0,
w: proof of work
}
w if provided is a dict with the following struct
{
t: time_created_seconds_since_epoch,
v: 0,
y: uint32_seconds_extended_lifetime,
z: "<32 bytes nonce>"
}
the validity of the proof of work is that given
h = HS(BE(w))
h has log_e(y) prefixed bytes being 0x00
this proof of work requirement is subject to change
if i is equal to RC.k then any LRDM.x values are decrypted and interpreted as
routing layer messages. This indicates that we are the farthest hop in the path.
link relay status message (LRSM)
response to path creator about build status
{
a: "s",
c: [ list, of, encrypted, LRSR frames],
p: "<16 bytes rx path id>",
s: uint_status_flags, // for now, only set (or don't) success bit
v: 0
}
the creator of the LRSM MUST include dummy LRSR records
to pad out to the maximum path length
link relay status record (LRSR)
record indicating status of path build
{
s: uint_status_flags,
v: 0
}
uint_status_flags (bitwise booleans):
[0] = success
[1] = fail, hop timeout
[2] = fail, congestion
[3] = fail, refusal, next hop is not known to be a snode
[4] = fail, used by hop creator when decrypting frames if decryption fails
[5] = fail, used by hop creator when record decode fails
[4-63] reserved
link relay upstream message (LRUM)
sent to relay data via upstream direction of a previously created path.
{
a: "u",
p: "<16 bytes path id>",
v: 0,
x: "<N bytes encrypted x1 value>",
y: "<32 bytes nonce>"
}
x1 = SD(k, y, x)
if we are the farthest hop, process x1 as a routing message
otherwise transmit a LRUM to the next hop
{
a: "u",
p: p,
v: 0,
x: x1,
y: y ^ HS(k)
}
link relay downstream message (LRDM)
sent to relay data via downstream direction of a previously created path.
{
a: "d",
p: "<16 bytes path id>",
v: 0,
x: "<N bytes encrypted x1 value>",
y: "<32 bytes nonce>"
}
if we are the creator of the path decrypt x for each hop key k
x = SD(k, y, x)
otherwise transmit LRDM to next hop
x1 = SE(k, y, x)
{
a: "d",
p: p,
v: 0,
x: x1,
y: y ^ HS(k)
}
link immediate dht message (LIDM):
transfer one or more dht messages directly without a previously made path.
{
a: "m",
m: [many, dht, messages],
v: 0
}
link immediate state message (LISM)
transfer a state message between nodes
{
a: "s",
s: state_message,
v: 0
}
---
state message:
NOTE: this message type is currently a documentation stub and remains unimplemented.
state messages propagate changes to the service nodes concensous to thin clients.
service node joined network
{
A: "J",
R: "<32 bytes public key>",
V: 0
}
service node parted network
{
A: "P",
R: "<32 bytes public key>",
V: 0
}
service node list request
request the service node list starting at index I containing R entries
{
A: "R",
I: starting_offset_int,
R: number_of_entires_to_request_int,
V: 0
}
service node list response
response to service node list request
{
A: "L",
S: {
"<32 bytes pubkey>" : 1,
"<32 bytes pubkey>" : 1,
....
},
V: 0
}
---
routing layer:
the routing layer provides inter network communication between the LLARP link
layer and ip (internet protocol) for exit traffic or ap (anonymous protocol) for
hidden services. replies to messages are sent back via the path they
originated from inside a LRDM. all routing messages have an S value which
provides the sequence number of the message so the messages can be ordered.
ipv4 addresses are allowed via ipv4 mapped ipv6 addresses, i.e. ::ffff.10.0.0.1
path confirm message (PCM)
sent as the first message down a path after it's built to confirm it was built
always the first message sent
{
A: "P",
L: uint64_milliseconds_path_lifetime,
S: 0,
T: uint64_milliseconds_sent_timestamp,
V: 0
}
path latency message (PLM)
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:
{
A: "L",
S: uint64_sequence_number,
V: 0
}
variant 2, response, generated by the endpoint that recieved the request.
{
A: "L",
S: uint64_sequence_number,
T: uint64_timestamp_recieved,
V: 0
}
obtain exit message (OXM)
sent to an exit router to obtain ip exit traffic context.
replies are sent down the path that messages originate from.
{
A: "X",
B: [list, of, permitted, blacklisted, traffic, policies],
E: 0 for snode communication or 1 for internet access,
I: "<32 bytes signing public key for future communication>",
S: uint64_sequence_number,
T: uint64_transaction_id,
V: 0,
W: [list, of, required, whitelisted, traffic, policies],
X: lifetime_of_address_mapping_in_seconds_uint64,
Z: "<64 bytes signature using I>"
}
grant exit messsage (GXM)
sent in response to an OXM to grant an ip for exit traffic from an external
ip address used for exit traffic.
{
A: "G",
S: uint64_sequence_number,
T: transaction_id_uint64,
Y: "<16 byte nonce>",
V: 0,
Z: "<64 bytes signature>"
}
any TITM recieved on the same path will be forwarded out to the internet if
OXAM.E is not 0, otherwise it is interpreted as service node traffic.
reject exit message (RXM)
sent in response to an OXAM to indicate that exit traffic is not allowed or
was denied.
{
A: "J",
B: backoff_milliseconds_uint64,
R: [list, of, rejected, traffic, policies],
S: uint64_sequence_number,
T: transaction_id_uint64,
V: 0,
Y: "<16 byte nonce>",
Z: "<64 bytes signature>"
}
discarded data fragment message (DDFM)
sent in reply to TDFM when we don't have a path locally or are doing network
congestion control from a TITM.
{
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.
{
A: "T",
P: "<16 bytes path id>",
S: uint64_sequence_number,
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. if this path does not exist on the router
it is replied to with a DDFM.
hidden service data (HSD)
data sent anonymously over the network to a recipiant from a sender.
sent inside a HSFM encrypted with a shared secret.
{
a: protocol_number_uint,
d: "<N bytes payload>",
i: Introduction for reply,
n: uint_message_sequence_number,
o: N seconds until this converstation plans terminate,
s: SI of sender,
t: "<16 bytes converstation_tag>,
v: 0
}
hidden service frame (HSF)
TODO: document this better
establish converstation tag message (variant 1)
generate a new convotag that is contained inside an encrypted HSD
{
A: "H",
C: "<1048 bytes ciphertext block>",
D: "<N bytes encrypted HSD>",
F: "<16 bytes source path_id>",
N: "<32 bytes nonce for key exchange>",
V: 0,
Z: "<64 bytes signature of entire message using sender's signing key>"
}
alice (A) wants to talk to bob (B) over the network, both have hidden services
set up and are online on the network.
A and B are both referring to alice and bob's SI respectively.
A_sk is alice's private signing key.
for alice (A) to send the string "beep" to bob (B), alice picks an introduction
to use on one of her paths (I_A) such that I_A is aligning with one of bobs's
paths (I_B)
alice generates:
T = RAND(16)
m = {
a: 0,
d: "beep",
i: I_A,
n: 0,
s: A,
t: T,
v: 0
}
X = BE(m)
C, K = PQKE_A(I_B.k)
N = RAND(32)
D = SE(X, K, N)
path = PickSendPath()
M = {
A: "T",
P: I_B.P,
S: uint64_sequence_number,
T: {
A: "H",
C: C,
D: D,
F: path.lastHop.txID,
N: N,
V: 0,
Z: "\x00" * 64
},
V: 0
}
Z = S(A_sk, BE(M))
alice transmits a TDFM to router with public key I_B.K via her path that ends
with router with public key I_B.k
path = PickSendPath()
{
A: "T",
P: I_B.P,
S: uint64_sequence_number,
T: {
A: "H",
C: C,
D: D,
F: path.lastHop.txID,
N: N,
V: 0,
Z: Z
},
V: 0
}
the shared secret (S) for further message encryption is:
S = HS(K + PKE(A, B, sk, N))
given sk is the local secret encryption key used by the current hidden service
please note:
signature verification of the outer message can only be done after decryption
because the signing keys are inside the encrypted HSD.
data from a previously made session (variant 2)
transfer data on a converstation previously made
{
A: "H",
D: "<N bytes encrypted HSD>",
F: "<16 bytes path id of soruce>",
N: "<32 bytes nonce for symettric cipher>",
T: "<16 bytes converstation tag>",
V: 0,
Z: "<64 bytes signature using sender's signing key>"
}
reject a message sent on a convo tag, when a remote endpoint
sends this message a new converstation SHOULD be established.
{
A: "H",
F: "<16 bytes path id of soruce>",
R: 1,
T: "<16 bytes converstation tag>",
V: 0,
Z: "<64 bytes signature using sender's signing key>"
}
transfer ip traffic message (TITM)
transfer ip traffic
{
A: "I",
S: uint64_sequence_number,
V: 0,
X: [list, of, ip, packet, buffers],
}
an ip packet buffer is prefixed with a 64 bit big endian unsigned integer
denoting the sequence number for re-ordering followed by the ip packet itself.
X is parsed as a list of IP packet buffers.
for each ip packet the source addresss is extracted and sent on the
appropriate network interface.
When we receive an ip packet from the internet to an exit address, we put it
into a TITM, and send it downstream the corresponding path in an LRDM.
update exit path message (UXPM)
sent from a new path by client to indicate that a previously established exit
should use the new path that this message came from.
{
A: "U",
P: "<16 bytes previous tx path id>",
S: uint64_sequence_number,
T: uint64_txid,
V: 0,
Y: "<16 bytes nonce>",
Z: "<64 bytes signature using previously provided signing key>"
}
close exit path message (CXPM)
client sends a CXPM when the exit is no longer needed or by the exit if the
exit wants to close prematurely.
also sent by exit in reply to a CXPM to confirm close.
{
A: "C",
S: uint64_sequence_number,
V: 0,
Y: "<16 bytes nonce>",
Z: "<64 bytes signature>"
}
update exit verify message (EXVM)
sent in reply to a UXPM to verify that the path handover was accepted
{
A: "V",
S: uint64_sequence_number,
T: uint64_txid,
V: 0,
Y: "<16 bytes nonce>",
Z: "<64 bytes signature>"
}
DHT message holder message:
wrapper message for sending many dht messages down a path.
{
A: "M",
M: [many, dht, messages, here],
S: uint64_sequence_number,
V: 0
}

@ -1,38 +0,0 @@
What is a RouterEvent?
A RouterEvent is a way of representing a conceptual event that took place in a "router" (relay or client).
RouterEvents are used in order to collect information about a network all in one place and preserve causality.
How do I make a new RouterEvent?
Add your event following the structure in llarp/tooling/router_event.{hpp,cpp}
Add your event to pybind in pybind/llarp/tooling/router_event.cpp
What if a class my event uses is missing members in pybind?
Find the relevant file pybind/whatever/class.cpp and remedy that!
What if I need to refer to classes which aren't available already in pybind?
Add pybind/namespace/namespace/etc/class.cpp and pybind it!
You will need to edit the following files accordingly:
pybind/common.hpp
pybind/module.cpp
pybind/CMakeLists.txt
How do I use a RouterEvent?
From the cpp side, find the place in the code where it makes the most logical sense
that the conceptual event has taken place (and you have the relevant information to
create the "event" instance) and create it there as follows:
#include <llarp/tooling/relevant_event_header.hpp>
where the event takes place, do the following:
auto event = std::make_unique<event_type_here>(constructor_args...);
somehow_get_a_router->NotifyRouterEvent(std::move(event));
From the Python side...it's a python object!

@ -1,309 +0,0 @@
Wire Protocol (version 1)
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in RFC 2119 [RFC2119].
LLARP's wire protocol is Internet Wire Protocol (IWP)
The main goal of iwp is to provide an authenticated encrypted
reliable semi-ordered durable datagram transfer protocol supporting
datagrams of larger size than link mtu.
in iwp there is an initiator who initiates a session to a recipiant.
iwp has 3 phases. the first phase is the proof of flow phase.
the second is a session handshake phase, the third is data transmission.
proof of flow:
the purpose of the proof of flow phase is to verify the existence
of the initiator's endpoint.
At any time before the data transfer phase a reject message
is sent the session is reset.
Alice (A) is the sender and Bob (B) is the recipiant.
A asks for a flow id from B.
B MAY send a flow id to A or MAY reject the message from A.
session handshake:
an encrypted session is established using establish wire session messages
using a newly created flow id.
message format:
there are 2 layers in this protocol, outer messages and inner messages.
outer messages are sent in plaintext and / or obfsucated with symettric
encryption using a preshared key.
inner messages are inside an encrypted and authenticated envelope
wrapped by an outer messages, which is always a data tranmssion message.
outer message format:
every outer message MAY be obfsucated via symettric encryption for dpi
resistance reasons, this is not authenticated encryption.
the message is first assumed to be sent in clear first.
if parsing of clear variant fails then the recipiant MUST fall back to assuming
the protocol is in obfuscated mode.
<16 bytes nounce, n>
<remaining bytes obsfucated, m>
obfuscated via:
K = HS(B_k)
N = HS(n + K)
X = SD(K, m, N[0:24])
where
B_k is the long term identity public key of the recipient.
HS is blake2 256 bit non keyed hash
SD is xchacha20 symettric stream cipher (decryption)
outer-header:
<1 byte command>
<1 byte reserved set to 0x3d>
command 'O' - obtain flow id
obtain a flow id
<outer-header>
<6 magic bytes "netid?">
<8 bytes netid, I>
<8 bytes timestamp milliseconds since epoch, T>
<32 bytes public identity key of sender, A_k>
<0-N bytes discarded>
<last 64 bytes signature of unobfuscated packet, Z>
the if the network id differs from the current network's id a reject message
MUST be sent
MUST be replied to with a message rejected or a give handshake cookie
command 'G' - give flow id
<outer-header>
<6 magic bytes "netid!">
<16 bytes new flow id>
<32 bytes public identiy key of sender, A_k>
<0-N bytes ignored but included in signature>
<last 64 bytes signature of unobfsucated packet, Z>
after recieving a give flow id message a session negotiation can happen with that flow id.
command 'R' - flow rejected
reject new flow
<outer-header>
<14 ascii bytes reason for rejection null padded>
<8 bytes timestamp>
<32 bytes public identity key of sender, A_k>
<0-N bytes ignored but included in signature>
<last 64 bytes signature of unobsfucated packet, Z>
command 'E' - establish wire session
establish an encrypted session using a flow id
<outer-header>
<2 bytes 0x0a 0x0d>
<4 bytes flags, F>
<16 bytes flow id, B>
<32 bytes ephemeral public encryption key, E>
<8 bytes packet counter starting at 0>
<optional 32 bytes authenticated credentials, A>
<last 64 bytes signature of unobfuscated packet using identity key, Z>
F is currently set to all zeros
every time we try establishing a wire session we increment the counter
by 1 for the next message we send.
when we get an establish wire session message
we reply with an establish wire session message with counter being counter + 1
if A is provided that is interpreted as being generated via:
h0 = HS('<insert some password here>')
h1 = EDDH(us, them)
A = HS(B + h0 + h1)
each side establishes their own rx key using this message.
when each side has both established thier rx key data can be transmitted.
command 'D' - encrypted data transmission
transmit encrypted data on a wire session
<outer-header>
<16 bytes flow-id, F>
<24 bytes nonce, N>
<N encrypted data, X>
<last 32 bytes keyed hash of entire payload, Z>
B is the flow id from the recipiant (from outer header)
N is a random nounce
X is encrypted data
Z is keyed hash of entire message
Z is generated via:
msg.Z = MDS(outer-header + F + N + X, tx_K)
data tranmission:
inner message format of X (after decryption):
inner header:
<1 byte protocol version>
<1 byte command>
command: 'k' (keep alive)
tell other side to acknoledge they are alive
<inner header>
<2 bytes resevered, set to 0>
<2 bytes attempt counter, set to 0 and incremented every retransmit, reset when we get a keepalive ack>
<2 bytes milliseconds ping timeout>
<8 bytes current session TX limit in bytes per second>
<8 bytes current session RX use in bytes per second>
<8 bytes milliseconds since epoch our current time>
<remaining bytes discarded>
command: 'l' (keep alive ack)
acknolege keep alive message
<inner header>
<6 bytes reserved, set to 0>
<8 bytes current session RX limit in bytes per second>
<8 bytes current session TX use in bytes per second>
<8 bytes milliseconds since epoch our current time>
<remaining bytes discarded>
command: 'n' (advertise neighboors)
tell peer about neighboors, only sent by non service nodes to other non service
nodes.
<inner header>
<route between us and them>
<0 or more intermediate routes>
<route from a service node>
route:
<1 byte route version (currently 0)>
<1 byte flags, lsb set indicates src is a service node>
<2 bytes latency in ms>
<2 bytes backpressure>
<2 bytes number of connected peers>
<8 bytes publish timestamp ms since epoch>
<32 bytes pubkey neighboor>
<32 bytes pubkey src>
<64 bytes signature of entire route signed by src>
command: 'c' (congestion)
tell other side to slow down
<inner header>
<2 bytes reduce TX rate by this many 1024 bytes per second>
<4 bytes milliseconds slowdown lifetime>
<remaining bytes discarded>
command: 'd' (anti-congestion)
tell other side to speed up
<inner header>
<2 bytes increase TX rate by this many 1024 bytes per second>
<4 bytes milliseconds speedup lifetime>
<remaining bytes discarded>
command: 's' (start transmission)
initate the transmission of a message to the remote peer
<inner header>
<1 byte flags F>
<1 byte reserved R set to zero>
<2 bytes total size of full message>
<4 bytes sequence number S>
<32 bytes blake2 hash of full message>
<N remaining bytes first fragment of message>
if F lsb is set then there is no further fragments
command: 't' (continued transmission)
continue transmission of a bigger message
<inner header>
<1 byte flags F>
<1 bytes reserved R set to zero>
<2 bytes 16 byte block offset in message>
<4 bytes sequence number S>
<N remaining bytes fragment of message aligned to 16 bytes>
<remaining bytes not aligned to 16 bytes discarded>
command: 'q' (acknoledge transmission)
acknoledges a transmitted message
command: 'r' (rotate keys)
inform remote that their RX key should be rotated
given alice(A) sends this message to bob(B) the new keys are computed as such:
n_K = TKE(K, B_e, K_seed, N)
A.tx_K = n_K
B.rx_K = n_K
<inner header>
<2 bytes milliseconds lifetime of old keys, retain them for this long and then discard>
<4 bytes reserved, set to 0>
<32 bytes key exchange nounce, N>
<32 bytes next public encryption key, K>
<remaining bytes discarded>
command: 'u' (upgrade)
request protocol upgrade
<inner header>
<1 byte protocol min version to upgrade to>
<1 byte protocol max version to upgrade to>
<remaining bytes discarded>
command: 'v' (version upgrade)
sent in response to upgrade message
<inner header>
<1 byte protocol version selected>
<1 byte protocol version highest we support>
<remaining bytes discarded>
Loading…
Cancel
Save