pull/1/head
Jeff Becker 6 years ago
parent fcadf09f23
commit d6a4425017
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -18,7 +18,7 @@ LIBUV_FLAGS = $(shell pkg-config --cflags libuv)
LIBUV_LIBS = $(shell pkg-config --libs libuv)
REQUIRED_CFLAGS = $(LIBUV_FLAGS) $(SODIUM_FLAGS) -I$(REPO)/include -std=c99 $(CFLAGS)
REQUIRED_CXXFLAGS = $(LIBUV_FLAGS) $(SODIUM_FLAGS) -I$(REPO)/include -std=c++17 $(CXXFLAGS)
REQUIRED_CXXFLAGS = $(LIBUV_FLAGS) $(SODIUM_FLAGS) -I$(REPO)/include -std=c++14 $(CXXFLAGS)
REQUIRED_LDFLAGS = $(LDFLAGS) -ljemalloc $(SODIUM_LIBS) $(LIBUV_LIBS)
all: build

@ -36,7 +36,9 @@ BD(x) is bittorrent decode x
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
NE(k, x) is sntrup4591761 encrypt data x to public key k
ND(k, x) is sntrup4591761 decrypt data x with private key k
SE(k, n, x) is chacha20 encrypt data x using symettric key k and nounce n
@ -45,24 +47,203 @@ S(k, x) is sign x with ed25519 using seed k
V(k, x, sig) is verify x data using signature sig using public key k
DH(x, y) is a ecdh key exchange using ed25519 scalarmult between public keys x
and y
KE(x, y) is a ecdh key exchange using H(DH(x, y) + x)
KE(x, y) is a ecdh key exchange using H(x + y + DH(x, y))
PKE(x, y, n) is a path key exchange using MDS(n, KE(x, y))
TKE(x, y, n) is a transport key exchange using MD(n, KE(x, y))
RAND(n) is n random bytes
---
wire protocol:
as of version 0 plaintext sctp is used, future versions will use an encrypted udp transport (IWP).
as of version 0 plaintext sctp is used, future versions will use an encrypted
udp transport (IWP).
frame decryption:
the first 32 bytes are message authentication bytes, h
the next 32 bytes are nounce for shared secret, n
the remaining bytes are interpreted as ciphertext, x
a shared secret s is generated via TKE(us, them, n)
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, n, x)
frame encryption:
given variadic sized payload p, 32 byte nounce n and public encryption keys A
and B
s = TKE(A, B, n)
x = SE(s, n, p)
h = MDS(n + x, s)
the resulting frame is:
h + n + x
handshake:
0) intro frame:
32 bytes hmac, h
32 bytes nounce, n
64 bytes elligator sqaured encoded alice's transport public encryption key, k
variadic bytes padding, w0
Alice sends ( h + n + k + w0 ) to Bob from the transport address matching her
public transport encryption key.
1) intro ack frame
in reply to an intro frame, bob sends an intro ack frame encrypted to Alice
using
32 bytes hmac, h
32 bytes nounce, n
32 bytes ciphertext, x
variadic bytes padding, w1
token = RAND(32)
k = TKE(a.k, b.k, n)
x = SE(k, token, n[0:24])
h = MDS(n + x, k)
Bob sends ( h + n + x + w1 ) to Alice
2) token frame:
Alice sends the token from the intro ack frame back to Bob
32 bytes hmac, h
32 bytes nounce, n
32 bytes ciphertext, x
variadic byttes padding, w2
k = TKE(a.k, b.k, n)
x = SE(k, token, n[0:24])
h = MDS(n + x, k)
Alice sends ( h + n + x + w2 ) to Bob
4) token ack frame:
Bob acks the token that he got from Alice
32 bytes hmac, h
32 bytes nounce, n
32 bytes ciphertext, x
variadic byttes padding, w3
S = TKE(a.k, b.k, token)
x = SE(S, token, n[0:24])
h = MDS(n + x, S)
Alice sends ( h + n + x + w3 ) to Bob and the session is now established using
shared secret S
IWP frame format:
ciphertext:
32 bytes hmac, h
32 bytes nounce, n
N bytes of ciphertext, x
plaintext frame header, H
8 bits protocol version, v (currently 0)
8 bits message type, t
12 bits payload size, s
4 bits flags, f
plaintext payload: P
s bytes of data
N bytes remaining data is discarded
x = SE(H + P, S, n)
h = MDS(n + x, S)
transmit h + n + x
message types:
XMIT = 0x01
begin link layer message transmission
IWP inbound handshake:
ACKS = 0x02
acknolege link layer message fragment
IWP outbound handshake:
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 msgid computed as HS(msg_bytes)
12 bits unsigned int fragment size bytes, s
4 bits unsigned int number of fragments, n
8 bits size of last fragment in bytes, l
msg_bytes is s * (n - 1) + l bytes long
FRAG payload:
transmit a link layer message fragment
32 bytes msgid
4 bits ignored
4 bits unsigned int fragment number
remaining bytes of payload are fragment data
ACKS payload:
indicates we which chunks we have recieved
32 bytes msgid
16 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.
---
@ -94,9 +275,10 @@ router contact (RC)
{
a: [ one, or, many, AI, here ... ],
k: "<32 bytes public sigining/encryption key>",
k: "<32 bytes public signing/encryption identity key>",
x: [ Exit, Infos ],
z: "<64 bytes signature using signing key>"
v: 0,
z: "<64 bytes signature using identity key>"
}
service info (SI)
@ -104,6 +286,7 @@ service info (SI)
{
n: "<optional claimed name>",
s: "<32 bytes public signing key>",
v: 0,
x: "<optional nounce for vanity>"
}
@ -116,6 +299,7 @@ introducer (I)
{
i: "<32 bytes public key of router>",
p: path_id_uint64,
v: 0,
x: time_expires_seconds_since_epoch_uint64
}
@ -125,6 +309,7 @@ introducer set (IS)
a: "<64 bytes SA>",
e: "<1218 bytes ntru public encryption key>",
i: [ I, I, I, ... ],
v: 0,
z: "<64 bytes signature using service info signing key>"
}
@ -144,20 +329,23 @@ link relay commit message (LRCM)
{
a: "c",
b: [ list, of, encrypted, RCR, as, bytes ],
b: [ list, of, encrypted, frames ],
v: 0,
}
relay commit record (RCR)
record requesting path with tunnel id p relay messages for x seconds to router
record requesting path with id p relay messages for x seconds to router
on network who's i is equal to RC.k and decrypt data any messages using
MD(n, KE(c, RC.k)) as symettric key for encryption and decryption.
PKE(n, rc.K, c) as symettric key for encryption and decryption.
{
c: "<32 byte public signing/encryption key used for further communication>",
i: "<32 byte RC.k of next hop>",
n: "<32 bytes nounce for key exchange>",
p: path_id_uint64,
v: 0,
x: seconds_lifetime_uint64
}
@ -186,6 +374,7 @@ is RECOMMENDED.
c: "r",
p: path_id_uint64,
r: "<optional reason metadata here>",
v: 0,
x: "<N bytes arbirary padding>"
}
@ -197,6 +386,7 @@ for path with id p.
{
c: "a",
p: path_id_uint64,
v: 0,
x: "<N bytes arbitrary padding>"
}
@ -208,7 +398,8 @@ path build and send the result of the build.
{
a: "s",
p: [list, of, encrypted, replies]
p: [list, of, encrypted, replies],
v: 0,
}
@ -224,6 +415,7 @@ new_y = y ^ new_z[0:24]
{
a: "u",
p: path_id_uint64,
v: 0,
y: "<insert 24 bytes nounce here>",
z: "<insert N bytes payload here>"
}
@ -240,6 +432,7 @@ new_z = SE(k, new_y, z)
{
a: "d",
p: path_id_uint64,
v: 0,
y: "<insert 24 bytes nounce here>",
z: "<insert N bytes payload here>"
}
@ -251,7 +444,8 @@ verify signature using cancel key c in relay commit message.
{
a: "x",
b: [ list, of, exit, records, as, bytes ]
b: [ list, of, exit, records, as, bytes ],
v: 0,
}
link relay exit record (LRXR)
@ -259,19 +453,30 @@ link relay exit record (LRXR)
{
c: "x",
p: path_id_uint64,
v: 0,
x: "<N bytes padding>",
z: "<64 bytes signature>"
}
---
direct paths:
a direct path is a "0 hop" path built by Alice to communicate directly to Bob for point to point transmission of routing layer messages.
these are built by sending a LRCM where B has 1 entry
---
routing layer:
the routing layer provides inter network communication between the SARP link
layer and ip (internet protocol) for exit traffic or hp (hidden protocol) for
SARP hidden services. replies to messages are sent back via the path they
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.
for direct communication between routers a direct path MUST be used, these messages MUST NOT be sent on the link leyer.
obtain exit address message (OXAM)
sent to an exit router to obtain a NAT ip address for ip exit traffic.
@ -280,6 +485,7 @@ replies are sent down the path that messages originate from.
{
A: "X",
I: "<32 bytes signing public key for future communication>",
V: 0,
X: lifetime_of_address_mapping_in_seconds_uint64,
}
@ -292,6 +498,7 @@ ip address used for exit traffic.
A: "G",
E: "<16 byte big endian externally reachable ipv6 address>",
I: "<32 bytes signing public key of requester>",
V: 0,
Z: "<64 bytes signature using exit's signing key>"
}
@ -302,6 +509,7 @@ reject exit address message (RXAM)
B: backoff_milliseconds_uint64,
I: "<32 bytes signing public key of requester>",
R: "<optional reject metadata>",
V: 0,
Z: "<64 bytes signature signed by exit>"
}
@ -317,6 +525,7 @@ y and z values in LRDM message respectively.
{
A: "T",
P: path_id_uint64,
V: 0,
X: "<N bytes payload>",
Y: "<24 bytes nounce>",
Z: "<64 bytes signature of entire message where Z is set to NUL>",
@ -328,6 +537,7 @@ transfer ip traffic for exit
{
A: "T",
V: 0,
X: "<N bytes ipv6 packet>",
Z: "<64 bytes signature of previously provided signing key>"
}
@ -337,6 +547,7 @@ find introduction message (FIM)
{
A: "F",
S: "<64 bytes dht key>",
V: 0,
T: transaction_id_uint64
}
@ -345,6 +556,7 @@ got introduction message (GIM)
{
A: "G",
T: transaction_id_uint64,
V: 0,
X: [ IS, IS, IS, ... ]
}
@ -362,19 +574,20 @@ which uses a shared random source to obfuscate keyspace location.
{
A: "P",
T: transaction_id_uint64,
X: [ IS, IS, IS, ... ]
V: 0,
X: [ IS, IS, IS, ... ],
}
acknoleged introduction message (AIM)
acknolege the publishing of a previous PIM, back off publishing for B ms.
nonzero B value indicates failure to publish.
acknolege the publishing of a previous PIM, X contains the backoff values in ms
for the previously provided IS, if backoff is 0 the operation was successfull
{
A: "A",
B: backoff_milliseconds_uint64,
P: number_of_IS_published_uint,
T: transaction_id_uint64,
V: 0,
X: [ 0, 0, backoff, ...],
}
find router contact message (FRCM)
@ -383,21 +596,18 @@ find a router by public key
{
A: "F",
R: "<32 byte public key of router>",
K: "<32 byte public key of router>",
T: transaction_id_uint64
V: 0
}
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: "G",
R: [RC, RC, RC ...],
T: transaction_id_uint64
}
store router contact message (SRCM)
{
A: "S",
R: RC
R: [RC],
T: transaction_id_uint64,
V: 0
}

@ -4,18 +4,14 @@
extern "C" {
#endif
#include <stdlib.h>
#include <stdint.h>
typedef struct sarp_buffer_t {
uint8_t * base;
char * base;
size_t sz;
uint8_t * cur;
char * cur;
} sarp_buffer_t;
static inline size_t sarp_buffer_size_left(sarp_buffer_t * buff)
{
return buff->sz - (buff->cur - buff->base);
}
size_t sarp_buffer_size_left(sarp_buffer_t * buff);
#ifdef __cplusplus
}

@ -1,41 +1,42 @@
#ifndef SARP_CRYPTO_H_
#define SARP_CRYPTO_H_
#include <sarp/buffer.h>
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#define PUBKEYSIZE 32
#define SECKEYSIZE 32
#define SYMKEYSIZE 32
#define NOUNCESIZE 24
#define SHAREDKEYSIZE 64
#define SHAREDKEYSIZE 32
#define HASHSIZE 64
#define HMACSECSIZE 32
#define SIGSIZE 64
#define TUNNOUNCESIZE 32
typedef uint8_t sarp_pubkey_t[PUBKEYSIZE];
typedef uint8_t sarp_seckey_t[SECKEYSIZE];
typedef uint8_t sarp_symkey_t[SYMKEYSIZE];
typedef uint8_t sarp_nounce_t[NOUNCESIZE];
typedef uint8_t sarp_sharedkey_t[SHAREDKEYSIZE];
typedef uint8_t sarp_hash_t[HASHSIZE];
typedef uint8_t sarp_hmacsec_t[HMACSECSIZE];
typedef uint8_t sarp_sig_t[SIGSIZE];
typedef uint8_t sarp_pubkey_t[PUBKEYSIZE];
typedef uint8_t sarp_seckey_t[SECKEYSIZE];
typedef uint8_t sarp_nounce_t[NOUNCESIZE];
typedef uint8_t sarp_sharedkey_t[SHAREDKEYSIZE];
typedef uint8_t sarp_hash_t[HASHSIZE];
typedef uint8_t sarp_hmacsec_t[HMACSECSIZE];
typedef uint8_t sarp_sig_t[SIGSIZE];
typedef uint8_t sarp_tunnel_nounce_t[TUNNOUNCESIZE];
struct sarp_crypto
{
int (*xchacha20)(sarp_buffer_t, sarp_symkey_t, sarp_nounce_t);
int (*dh_client)(sarp_sharedkey_t *, sarp_pubkey_t, sarp_seckey_t);
int (*dh_server)(sarp_sharedkey_t *, sarp_pubkey_t, sarp_seckey_t);
int (*hash)(sarp_hash_t *, sarp_buffer_t);
int (*mhac)(sarp_hash_t *, sarp_buffer_t, sarp_hmacsec_t);
int (*sign)(sarp_sig_t *, sarp_seckey_t, sarp_buffer_t);
int (*verify)(sarp_pubkey_t, sarp_buffer_t, sarp_sig_t);
};
struct sarp_crypto
{
bool (*xchacha20)(sarp_buffer_t, sarp_sharedkey_t, sarp_nounce_t);
bool (*dh_client)(sarp_sharedkey_t *, sarp_pubkey_t, sarp_tunnel_nounce_t, sarp_seckey_t);
bool (*dh_server)(sarp_sharedkey_t *, sarp_pubkey_t, sarp_tunnel_nounce_t, sarp_seckey_t);
bool (*hash)(sarp_hash_t *, sarp_buffer_t);
bool (*hmac)(sarp_hash_t *, sarp_buffer_t, sarp_hmacsec_t);
bool (*sign)(sarp_sig_t *, sarp_seckey_t, sarp_buffer_t);
bool (*verify)(sarp_pubkey_t, sarp_buffer_t, sarp_sig_t);
};
void sarp_crypto_libsodium_init(struct sarp_crypto * c);
void sarp_crypto_libsodium_init(struct sarp_crypto * c);
#ifdef __cplusplus
}

@ -18,15 +18,17 @@ extern "C" {
struct sarp_udp_listener
{
const char * host;
char * host;
uint16_t port;
void * user;
void * impl;
void (*recvfrom)(struct sarp_udp_listener *, struct sockaddr, uint8_t *, size_t);
void (*recvfrom)(struct sarp_udp_listener *, const struct sockaddr *, char *, ssize_t);
void (*closed)(struct sarp_udp_listener *);
};
int sarp_ev_add_udp_listener(struct sarp_ev_loop * ev, struct sarp_udp_listener * listener);
int srap_ev_close_udp_listener(struct sarp_ev_loop * ev, struct sarp_udp_listener * listener);
int sarp_ev_close_udp_listener(struct sarp_udp_listener * listener);
#ifdef __cplusplus
}

@ -0,0 +1,14 @@
#ifndef SARP_TIME_H
#define SARP_TIME_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
uint64_t sarp_time_now_ms();
uint64_t sarp_time_now_sec();
#ifdef __cplusplus
}
#endif
#endif

@ -4,9 +4,9 @@
bool sarp_address_info_bencode(struct sarp_address_info * ai, sarp_buffer_t * buff)
{
uint8_t * ptr = buff->cur;
char * ptr = buff->cur;
size_t sz = sarp_buffer_size_left(buff);
uint8_t * end = ptr + sz;
char * end = ptr + sz;
int r = 0;
r = snprintf(ptr, (end - ptr), "d1:ci%de1:e32:", ai->rank);
if (r == -1) return false;

@ -0,0 +1,16 @@
#include <sarp/buffer.h>
extern "C" {
size_t sarp_buffer_size_left(sarp_buffer_t * buff)
{
std::ptrdiff_t diff = buff->cur - buff->base;
if(diff < 0)
{
return 0;
}
else if(diff > buff->sz) return 0;
else return buff->sz - diff;
}
}

@ -7,10 +7,10 @@ namespace sarp
{
template<typename Config, typename Section>
static Section find_section(Config & c, const std::string & name, const Section & sect)
static Section find_section(Config & c, const std::string & name, const Section & fallback)
{
if(c.sections.find(name) == c.sections.end())
return sect;
return fallback;
return c.sections[name].values;
}
@ -26,6 +26,7 @@ namespace sarp
router = find_section(top, "router", section_t{});
network = find_section(top, "network", section_t{});
netdb = find_section(top, "netdb", section_t{});
links = find_section(top, "links", section_t{});
return true;
}
return false;
@ -64,6 +65,7 @@ extern "C" {
std::map<std::string, sarp::Config::section_t&> sections = {
{"router", conf->impl.router},
{"network", conf->impl.network},
{"links", conf->impl.links},
{"netdb", conf->impl.netdb}
};
for(const auto & section : sections)

@ -14,6 +14,7 @@ namespace sarp
section_t router;
section_t network;
section_t netdb;
section_t links;
bool Load(const char * fname);

@ -2,42 +2,76 @@
#include <sodium/crypto_stream_xchacha20.h>
#include <sodium/crypto_generichash.h>
#include <sodium/crypto_scalarmult.h>
#include <sodium/crypto_sign.h>
namespace sarp
{
namespace sodium
{
int xchacha20(sarp_buffer_t buff, sarp_symkey_t k, sarp_nounce_t n)
bool xchacha20(sarp_buffer_t buff, sarp_sharedkey_t k, sarp_nounce_t n)
{
return crypto_stream_xchacha20_xor(buff.base, buff.base, buff.sz, n, k);
uint8_t * base = (uint8_t*)buff.base;
return crypto_stream_xchacha20_xor(base, base, buff.sz, n, k) == 0;
}
int dh(sarp_sharedkey_t * shared, uint8_t * client_pk, uint8_t * server_pk, uint8_t * remote_key, uint8_t * local_key)
bool dh(sarp_sharedkey_t * shared, uint8_t * client_pk, uint8_t * server_pk, uint8_t * remote_key, uint8_t * local_key)
{
uint8_t * out = *shared;
const size_t outsz = sizeof(sarp_sharedkey_t);
const size_t outsz = SHAREDKEYSIZE;
crypto_generichash_state h;
if(crypto_scalarmult(out, local_key, remote_key) == -1) return -1;
if(crypto_scalarmult(out, local_key, remote_key) == -1) return false;
crypto_generichash_init(&h, NULL, 0U, outsz);
crypto_generichash_update(&h, client_pk, sizeof(sarp_pubkey_t));
crypto_generichash_update(&h, server_pk, sizeof(sarp_pubkey_t));
crypto_generichash_update(&h, out, crypto_scalarmult_BYTES);
crypto_generichash_final(&h, out, outsz);
return 0;
return true;
}
int dh_client(sarp_sharedkey_t * shared, sarp_pubkey_t pk, sarp_seckey_t sk)
bool dh_client(sarp_sharedkey_t * shared, sarp_pubkey_t pk, sarp_tunnel_nounce_t n, sarp_seckey_t sk)
{
sarp_pubkey_t local_pk;
crypto_scalarmult_base(local_pk, sk);
return dh(shared, local_pk, pk, pk, sk);
if(dh(shared, local_pk, pk, pk, sk))
{
return crypto_generichash(*shared, SHAREDKEYSIZE, *shared, SHAREDKEYSIZE, n, TUNNOUNCESIZE) != -1;
}
return false;
}
int dh_server(sarp_sharedkey_t * shared, sarp_pubkey_t pk, sarp_seckey_t sk)
bool dh_server(sarp_sharedkey_t * shared, sarp_pubkey_t pk, sarp_tunnel_nounce_t n, sarp_seckey_t sk)
{
sarp_pubkey_t local_pk;
crypto_scalarmult_base(local_pk, sk);
return dh(shared, pk, local_pk, pk, sk);
if(dh(shared, pk, local_pk, pk, sk))
{
return crypto_generichash(*shared, SHAREDKEYSIZE, *shared, SHAREDKEYSIZE, n, TUNNOUNCESIZE) != -1;
}
return false;
}
bool hash(sarp_hash_t * result, sarp_buffer_t buff)
{
const uint8_t * base = (const uint8_t *) buff.base;
return crypto_generichash(*result, HASHSIZE, base, buff.sz, nullptr, 0) != -1;
}
bool hmac(sarp_hash_t * result, sarp_buffer_t buff, sarp_seckey_t secret)
{
const uint8_t * base = (const uint8_t *) buff.base;
return crypto_generichash(*result, sizeof(sarp_hash_t), base, buff.sz, secret, HMACSECSIZE) != -1;
}
bool sign(sarp_sig_t * result, sarp_seckey_t secret, sarp_buffer_t buff)
{
const uint8_t * base = (const uint8_t *) buff.base;
return crypto_sign_detached(*result, nullptr, base, buff.sz, secret) != -1;
}
bool verify(sarp_pubkey_t pub, sarp_buffer_t buff, sarp_sig_t sig)
{
const uint8_t * base = (const uint8_t *) buff.base;
return crypto_sign_verify_detached(sig, base, buff.sz, pub) != -1;
}
}
}
@ -48,5 +82,9 @@ extern "C" {
c->xchacha20 = sarp::sodium::xchacha20;
c->dh_client = sarp::sodium::dh_client;
c->dh_server = sarp::sodium::dh_server;
c->hash = sarp::sodium::hash;
c->hmac = sarp::sodium::hmac;
c->sign = sarp::sodium::sign;
c->verify = sarp::sodium::verify;
}
}

@ -15,8 +15,22 @@ namespace sarp
{
uv_udp_t _handle;
struct sarp_udp_listener * listener;
void recvfrom(const struct sockaddr * addr, char * buff, ssize_t sz)
{
if(listener->recvfrom)
listener->recvfrom(listener, addr, buff, sz);
}
uv_udp_t * handle() { return &_handle; }
/** called after closed */
void closed()
{
if(listener->closed)
listener->closed(listener);
listener->impl = nullptr;
}
uv_udp_t * udp() { return &_handle; }
};
static void udp_alloc_cb(uv_handle_t * h, size_t sz, uv_buf_t * buf)
@ -28,6 +42,15 @@ namespace sarp
static void udp_recv_cb(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags)
{
udp_listener * l = static_cast<udp_listener *>(handle->data);
l->recvfrom(addr, buf->base, nread);
sarp_g_mem.free(buf->base);
}
static void udp_close_cb(uv_handle_t * handle)
{
udp_listener * l = static_cast<udp_listener *>(handle->data);
l->closed();
sarp_g_mem.free(l);
}
}
@ -64,18 +87,37 @@ extern "C" {
int ret = 0;
sarp::udp_listener * l = static_cast<sarp::udp_listener *>(sarp_g_mem.malloc(sizeof(sarp::udp_listener)));
listener->impl = l;
l->handle()->data = l;
l->udp()->data = l;
l->listener = listener;
ret = uv_udp_init(ev->loop(), l->handle());
ret = uv_udp_init(ev->loop(), l->udp());
if (ret == 0)
{
ret = uv_udp_bind(l->handle(), (const sockaddr *)&addr, 0);
ret = uv_udp_bind(l->udp(), (const sockaddr *)&addr, 0);
if (ret == 0)
{
ret = uv_udp_recv_start(l->handle(), sarp::udp_alloc_cb, sarp::udp_recv_cb);
ret = uv_udp_recv_start(l->udp(), sarp::udp_alloc_cb, sarp::udp_recv_cb);
}
}
return ret;
}
int sarp_ev_close_udp_listener(struct sarp_udp_listener * listener)
{
int ret = -1;
if(listener)
{
sarp::udp_listener * l = static_cast<sarp::udp_listener*>(listener->impl);
if(l)
{
if(!uv_udp_recv_stop(l->udp()))
{
l->closed();
sarp_g_mem.free(l);
ret = 0;
}
}
}
return ret;
}
}

@ -1,5 +1,6 @@
#include "link.hpp"
#include <cstring>
#include <sarp/time.h>
bool operator < (const sockaddr_in6 addr0, const sockaddr_in6 addr1)
{
@ -9,13 +10,13 @@ bool operator < (const sockaddr_in6 addr0, const sockaddr_in6 addr1)
namespace sarp
{
static void link_recv_from(struct sarp_udp_listener * l, struct sockaddr src, uint8_t * buff, size_t sz)
static void link_recv_from(struct sarp_udp_listener * l, const struct sockaddr * src, char * buff, ssize_t sz)
{
if(src.sa_family == AF_INET6)
if(src && src->sa_family == AF_INET6)
{
Link * link = static_cast<Link*>(l->user);
struct sockaddr_in6 remote;
memcpy(&remote, &src, sizeof(sockaddr_in6));
memcpy(&remote, src, sizeof(sockaddr_in6));
auto itr = link->sessions.find(remote);
if(itr == link->sessions.end())
{
@ -31,5 +32,18 @@ namespace sarp
listener.recvfrom = link_recv_from;
}
PeerSession::PeerSession(sarp_crypto * crypto, sockaddr_in6 remote) :
lastRX(0),
remoteAddr(remote),
_crypto(crypto),
state(eHandshakeInboundInit)
{
memset(remotePubkey, 0, sizeof(remotePubkey));
memset(sessionKey, 0, sizeof(sessionKey));
}
void PeerSession::RecvFrom(const char * buff, ssize_t sz)
{
lastRX = sarp_time_now_ms();
}
}

@ -24,10 +24,13 @@ namespace sarp
enum State
{
eHandshake0,
eHandshake1,
eHandshake2,
eHandshake3,
eStateNULL,
eHandshakeInboundInit,
eHandshakeOutboundInit,
eHandshakeInboundRepliedInit,
eHandshakeOutboundGotReply,
eHandshakeInboundGotAck,
eHandshakeOutboundGotAck,
eEstablished,
eTimeout
};
@ -42,9 +45,9 @@ namespace sarp
PeerSession & operator=(const PeerSession & other);
void SendTo(Link * link, const uint8_t * buff, std::size_t sz);
void SendTo(Link * link, const char * buff, std::size_t sz);
void RecvFrom(const uint8_t * buff, std::size_t sz);
void RecvFrom(const char * buff, ssize_t sz);
};
@ -65,6 +68,8 @@ namespace sarp
sarp_udp_listener listener;
};
typedef std::unique_ptr<Link> Link_ptr;
}
#endif

@ -1,46 +1,59 @@
#include <sarp/router.h>
#include <sarp/link.h>
#include "link.hpp"
#include <vector>
#include <list>
#include "str.hpp"
namespace sarp
{
void router_iter_config(sarp_config_iterator * iter, const char * section, const char * key, const char * val);
struct Router
{
std::vector<Link> Links;
static void iter_config(sarp_config_iterator * iter, const char * section, const char * key, const char * val)
std::list<Link_ptr> Links;
sarp_crypto * crypto;
void Close()
{
sarp_router * self = static_cast<sarp_router *>(iter->user);
for(auto & itr : Links)
{
sarp_ev_close_udp_listener(&itr->listener);
}
Links.clear();
}
bool Configured()
{
if(Links.size()) return true;
return false;
}
};
}
extern "C" {
struct sarp_router
{
sarp::Router impl;
sarp_crypto crypto;
};
void sarp_init_router(struct sarp_router ** router)
{
*router = static_cast<sarp_router *>(sarp_g_mem.malloc(sizeof(sarp_router)));
if(*router)
{
sarp_crypto_libsodium_init(&(*router)->crypto);
}
}
int sarp_configure_router(struct sarp_router * router, struct sarp_config * conf)
{
sarp_config_iterator iter;
iter.user = router;
iter.visit = sarp::Router::iter_config;
iter.visit = sarp::router_iter_config;
sarp_config_iter(conf, iter);
return router->impl.Configured() ? 0 : -1;
}
@ -48,13 +61,37 @@ extern "C" {
void sarp_run_router(struct sarp_router * router, struct sarp_ev_loop * loop)
{
for(auto & iter : router->impl.Links)
sarp_ev_add_udp_listener(loop, &iter.listener);
sarp_ev_add_udp_listener(loop, &iter->listener);
}
void sarp_free_router(struct sarp_router ** router)
{
if(*router)
{
sarp_router * r = *router;
r->impl.Close();
sarp_g_mem.free(*router);
}
*router = nullptr;
}
}
namespace sarp
{
void router_iter_config(sarp_config_iterator * iter, const char * section, const char * key, const char * val)
{
sarp_router * self = static_cast<sarp_router *>(iter->user);
if (streq(section, "links"))
{
if(streq(val, "ip"))
{
self->impl.Links.push_back(std::make_unique<Link>(&self->crypto));
}
else if (streq(val, "eth"))
{
/** todo: ethernet link */
}
}
}
}

@ -0,0 +1,20 @@
#ifndef LIBSARP_STR_HPP
#define LIBSARP_STR_HPP
#include <cstring>
namespace sarp
{
static bool streq(const char * s1, const char * s2)
{
size_t sz1 = strlen(s1);
size_t sz2 = strlen(s2);
if (sz1 == sz2)
{
return strncmp(s1, s2, sz1) == 0;
}
else
return false;
}
}
#endif

@ -0,0 +1,25 @@
#include <sarp/time.h>
#include <chrono>
namespace sarp
{
typedef std::chrono::steady_clock clock_t;
template<typename Res>
static uint64_t time_since_epoch()
{
return std::chrono::duration_cast<Res>(sarp::clock_t::now().time_since_epoch()).count();
}
}
extern "C" {
uint64_t sarp_time_now_ms()
{
return sarp::time_since_epoch<std::chrono::milliseconds>();
}
uint64_t sarp_time_now_sec()
{
return sarp::time_since_epoch<std::chrono::seconds>();
}
}
Loading…
Cancel
Save