system.h \
utils.c utils.h \
xalloc.h \
+ xoshiro.c xoshiro.h \
devtools.c devtools.h \
$(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES) \
#define MESHLINK_MDNS_NAME_KEY "name"
#define MESHLINK_MDNS_FINGERPRINT_KEY "fingerprint"
-static void generate_rand_string(char *buffer, size_t size) {
+static void generate_rand_string(meshlink_handle_t *mesh, char *buffer, size_t size) {
assert(size);
for(size_t i = 0; i < (size - 1); ++i) {
- buffer[i] = 'a' + (rand() % ('z' - 'a' + 1));
+ buffer[i] = 'a' + prng(mesh, 'z' - 'a' + 1);
}
buffer[size - 1] = '\0';
case CATTA_SERVER_COLLISION: {
/* A host name collision happened. Let's pick a new name for the server */
char hostname[17];
- generate_rand_string(hostname, sizeof(hostname));
+ generate_rand_string(mesh, hostname, sizeof(hostname));
pthread_mutex_lock(&(mesh->mesh_mutex));
// generate some unique host name (we actually do not care about it)
char hostname[17];
- generate_rand_string(hostname, sizeof(hostname));
+ generate_rand_string(mesh, hostname, sizeof(hostname));
// Let's set the host name for this server.
CattaServerConfig config;
static int check_port(meshlink_handle_t *mesh) {
for(int i = 0; i < 1000; i++) {
- int port = 0x1000 + (rand() & 0x7fff);
+ int port = 0x1000 + prng(mesh, 0x8000);
if(try_bind(port)) {
free(mesh->myport);
mesh->log_cb = global_log_cb;
mesh->log_level = global_log_level;
+ randomize(&mesh->prng_state, sizeof(mesh->prng_state));
+
memcpy(mesh->dev_class_traits, default_class_traits, sizeof(default_class_traits));
if(usingname) {
static void __attribute__((constructor)) meshlink_init(void) {
crypto_init();
- unsigned int seed;
- randomize(&seed, sizeof(seed));
- srand(seed);
}
static void __attribute__((destructor)) meshlink_exit(void) {
#include "meshlink_queue.h"
#include "sockaddr.h"
#include "sptps.h"
+#include "xoshiro.h"
#include <pthread.h>
timeout_t periodictimer;
struct connection_t *everyone;
+ uint64_t prng_state[4];
int next_pit;
int pits[10];
extern void handle_duplicate_node(meshlink_handle_t *mesh, struct node_t *n);
extern void handle_network_change(meshlink_handle_t *mesh, bool online);
+/// Per-instance PRNG
+static inline int prng(meshlink_handle_t *mesh, uint64_t max) {
+ return xoshiro(mesh->prng_state) % max;
+}
+
+/// Fudge value of ~0.1 seconds, in microseconds.
+static const unsigned int TIMER_FUDGE = 0x20000;
+
#endif
}
timeout_set(&mesh->loop, data, &(struct timeval) {
- default_timeout, rand() % 100000
+ default_timeout, prng(mesh, TIMER_FUDGE)
});
}
}
timeout_set(&mesh->loop, data, &(struct timeval) {
- timeout, rand() % 100000
+ timeout, prng(mesh, TIMER_FUDGE)
});
}
*/
int main_loop(meshlink_handle_t *mesh) {
timeout_add(&mesh->loop, &mesh->pingtimer, timeout_handler, &mesh->pingtimer, &(struct timeval) {
- default_timeout, rand() % 100000
+ default_timeout, prng(mesh, TIMER_FUDGE)
});
timeout_add(&mesh->loop, &mesh->periodictimer, periodic_handler, &mesh->periodictimer, &(struct timeval) {
0, 0
} else if(n->maxmtu <= n->minmtu) {
len = n->maxmtu;
} else {
- len = n->minmtu + 1 + rand() % (n->maxmtu - n->minmtu);
+ len = n->minmtu + 1 + prng(mesh, n->maxmtu - n->minmtu);
}
if(len < 64) {
end:
timeout_set(&mesh->loop, &n->mtutimeout, &(struct timeval) {
- timeout, rand() % 100000
+ timeout, prng(mesh, TIMER_FUDGE)
});
}
So we pick a random edge and a random socket. */
int i = 0;
- int j = rand() % n->edge_tree->count;
+ int j = prng(mesh, n->edge_tree->count);
edge_t *candidate = NULL;
for splay_each(edge_t, e, n->edge_tree) {
if(candidate) {
*sa = &candidate->address;
- *sock = rand() % mesh->listen_sockets;
+ *sock = prng(mesh, mesh->listen_sockets);
}
/* Make sure we have a suitable socket for the chosen address */
}
};
- *sock = rand() % mesh->listen_sockets;
+ *sock = prng(mesh, mesh->listen_sockets);
if(mesh->listen_socket[*sock].sa.sa.sa_family == AF_INET6) {
broadcast_ipv6.in6.sin6_port = n->prevedge->address.in.sin_port;
if(left) {
timeout_set(&mesh->loop, &mesh->past_request_timeout, &(struct timeval) {
- 10, rand() % 100000
+ 10, prng(mesh, TIMER_FUDGE)
});
}
}
if(!mesh->past_request_tree->head) {
timeout_set(&mesh->loop, &mesh->past_request_timeout, &(struct timeval) {
- 10, rand() % 100000
+ 10, prng(mesh, TIMER_FUDGE)
});
}
s = e->to->submesh;
}
- x = send_request(mesh, c, s, "%d %x %s %d %s %s %s %s %d %s %x %d %d", ADD_EDGE, rand(),
+ x = send_request(mesh, c, s, "%d %x %s %d %s %s %s %s %d %s %x %d %d", ADD_EDGE, prng(mesh, UINT_MAX),
e->from->name, e->from->devclass, from_submesh, e->to->name, address, port,
e->to->devclass, to_submesh, OPTION_PMTU_DISCOVERY, e->weight, contradictions);
free(address);
s = e->to->submesh;
}
- return send_request(mesh, c, s, "%d %x %s %s %d", DEL_EDGE, rand(),
+ return send_request(mesh, c, s, "%d %x %s %s %d", DEL_EDGE, prng(mesh, UINT_MAX),
e->from->name, e->to->name, contradictions);
}
static const int req_key_timeout = 2;
void send_key_changed(meshlink_handle_t *mesh) {
- send_request(mesh, mesh->everyone, NULL, "%d %x %s", KEY_CHANGED, rand(), mesh->self->name);
+ send_request(mesh, mesh->everyone, NULL, "%d %x %s", KEY_CHANGED, prng(mesh, UINT_MAX), mesh->self->name);
/* Force key exchange for connections using SPTPS */
--- /dev/null
+/* Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
+
+To the extent possible under law, the author has dedicated all copyright
+and related and neighboring rights to this software to the public domain
+worldwide. This software is distributed without any warranty.
+
+See <http://creativecommons.org/publicdomain/zero/1.0/>. */
+
+#include <stdint.h>
+#include "xoshiro.h"
+
+/* This is xoshiro256** 1.0, one of our all-purpose, rock-solid
+ generators. It has excellent (sub-ns) speed, a state (256 bits) that is
+ large enough for any parallel application, and it passes all tests we
+ are aware of.
+
+ For generating just floating-point numbers, xoshiro256+ is even faster.
+
+ The state must be seeded so that it is not everywhere zero. If you have
+ a 64-bit seed, we suggest to seed a splitmix64 generator and use its
+ output to fill s. */
+
+static inline uint64_t rotl(const uint64_t x, int k) {
+ return (x << k) | (x >> (64 - k));
+}
+
+uint64_t xoshiro(uint64_t s[4]) {
+ const uint64_t result = rotl(s[1] * 5, 7) * 9;
+
+ const uint64_t t = s[1] << 17;
+
+ s[2] ^= s[0];
+ s[3] ^= s[1];
+ s[1] ^= s[2];
+ s[0] ^= s[3];
+
+ s[2] ^= t;
+
+ s[3] = rotl(s[3], 45);
+
+ return result;
+}
--- /dev/null
+#ifndef MESHLINK_XOSHIRO_H
+#define MESHLINK_XOSHIRO_H
+
+extern uint64_t xoshiro(uint64_t s[4]);
+
+#endif