Also seed it using /dev/random or whatever equivalent is available.
tincd.c \
utils.c utils.h \
xalloc.h \
+ xoshiro.c \
version.c version.h \
ed25519/ecdh.c \
ed25519/ecdsa.c \
ed25519/ecdh.c \
ed25519/ecdsa.c \
ed25519/ecdsagen.c \
+ xoshiro.c \
$(ed25519_SOURCES) \
$(chacha_poly1305_SOURCES)
sptps.c sptps.h \
sptps_test.c \
utils.c utils.h \
+ xoshiro.c \
ed25519/ecdh.c \
ed25519/ecdsa.c \
$(ed25519_SOURCES) \
#include "system.h"
#include "connection.h"
+#include "crypto.h"
#include "logger.h"
#include "node.h"
#include "xalloc.h"
static void make_new_connection() {
/* Select a random node we haven't connected to yet. */
- int count = 0;
+ uint32_t count = 0;
for splay_each(node_t, n, &node_tree) {
if(n == myself || n->connection || !(n->status.has_address || n->status.reachable)) {
return;
}
- int r = rand() % count;
+ uint32_t r = prng(count);
for splay_each(node_t, n, &node_tree) {
if(n == myself || n->connection || !(n->status.has_address || n->status.reachable)) {
* are only a few reachable nodes, and many unreachable ones, we're
* going to try harder to connect to them. */
- unsigned int r = rand() % node_tree.count;
+ uint32_t r = prng(node_tree.count);
for splay_each(node_t, n, &node_tree) {
if(r--) {
static void drop_superfluous_outgoing_connection() {
/* Choose a random outgoing connection to a node that has at least one other connection. */
- int count = 0;
+ uint32_t count = 0;
for list_each(connection_t, c, &connection_list) {
if(!c->edge || !c->outgoing || !c->node || c->node->edge_tree.count < 2) {
return;
}
- int r = rand() % count;
+ uint32_t r = prng(count);
for list_each(connection_t, c, &connection_list) {
if(!c->edge || !c->outgoing || !c->node || c->node->edge_tree.count < 2) {
void do_autoconnect() {
/* Count number of active connections. */
- int nc = 0;
+ uint32_t nc = 0;
for list_each(connection_t, c, &connection_list) {
if(c->edge) {
extern void crypto_init(void);
extern void crypto_exit(void);
+extern uint64_t xoshiro(void);
+extern void prng_init(void);
+extern void prng_randomize(void *buf, size_t buflen);
extern void randomize(void *buf, size_t buflen);
+static inline uint32_t prng(uint32_t limit) {
+ uint64_t bins = UINT64_MAX / limit;
+ uint64_t reject_after = bins * limit;
+ uint64_t value;
+
+ do {
+ value = xoshiro();
+ } while(value >= reject_after);
+
+ return value / bins;
+}
+
#endif
uint8_t *encrypted = xzalloc(len);
uint8_t *decrypted = xzalloc(len);
- randomize(plaintext, len);
+ prng_randomize(plaintext, len);
plaintext[0] &= 0x7f;
if(rsa_public_encrypt(rsa_pub, plaintext, len, encrypted)) {
// Generate a random netname, ask for a better one later.
ask_netname = true;
- snprintf(temp_netname, sizeof(temp_netname), "join_%x", rand());
+ snprintf(temp_netname, sizeof(temp_netname), "join_%x", prng(UINT32_MAX));
netname = temp_netname;
goto make_names;
}
#include "conf_net.h"
#include "conf.h"
#include "connection.h"
+#include "crypto.h"
#include "graph.h"
#include "logger.h"
#include "meta.h"
}
timeout_set(data, &(struct timeval) {
- 1, rand() % 100000
+ 1, jitter()
});
}
}
timeout_set(data, &(struct timeval) {
- 5, rand() % 100000
+ 5, jitter()
});
}
int main_loop(void) {
last_periodic_run_time = now;
timeout_add(&pingtimer, timeout_handler, &pingtimer, &(struct timeval) {
- pingtimeout, rand() % 100000
+ pingtimeout, jitter()
});
timeout_add(&periodictimer, periodic_handler, &periodictimer, &(struct timeval) {
0, 0
So we pick a random edge and a random socket. */
unsigned int i = 0;
- unsigned int j = rand() % n->edge_tree.count;
+ unsigned int j = prng(n->edge_tree.count);
edge_t *candidate = NULL;
for splay_each(edge_t, e, &n->edge_tree) {
if(candidate) {
*sa = &candidate->address;
- *sock = rand() % listen_sockets;
+ *sock = prng(listen_sockets);
}
adapt_socket(*sa, sock);
/* Pick one of the edges from this node at random, then use its local address. */
unsigned int i = 0;
- unsigned int j = rand() % n->edge_tree.count;
+ unsigned int j = prng(n->edge_tree.count);
edge_t *candidate = NULL;
for splay_each(edge_t, e, &n->edge_tree) {
if(candidate && candidate->local_address.sa.sa_family) {
*sa = &candidate->local_address;
- *sock = rand() % listen_sockets;
+ *sock = prng(listen_sockets);
adapt_socket(*sa, sock);
}
}
#include "connection.h"
#include "compression.h"
#include "control.h"
+#include "crypto.h"
#include "device.h"
#include "digest.h"
#include "ecdsa.h"
static void keyexpire_handler(void *data) {
regenerate_key();
timeout_set(data, &(struct timeval) {
- keylifetime, rand() % 100000
+ keylifetime, jitter()
});
}
#endif
free(cipher);
timeout_add(&keyexpire_timeout, keyexpire_handler, &keyexpire_timeout, &(struct timeval) {
- keylifetime, rand() % 100000
+ keylifetime, jitter()
});
/* Check if we want to use message authentication codes... */
#include "address_cache.h"
#include "conf.h"
#include "connection.h"
+#include "crypto.h"
#include "list.h"
#include "logger.h"
#include "names.h"
}
timeout_add(&outgoing->ev, retry_outgoing_handler, outgoing, &(struct timeval) {
- outgoing->timeout, rand() % 100000
+ outgoing->timeout, jitter()
});
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Trying to re-establish outgoing connection in %d seconds", outgoing->timeout);
#include "conf.h"
#include "connection.h"
+#include "crypto.h"
#include "logger.h"
#include "meta.h"
#include "protocol.h"
+#include "utils.h"
#include "xalloc.h"
bool tunnelserver = false;
if(left)
timeout_set(&past_request_timeout, &(struct timeval) {
- 10, rand() % 100000
+ 10, jitter()
});
}
new->firstseen = now.tv_sec;
splay_insert(&past_request_tree, new);
timeout_add(&past_request_timeout, age_past_requests, NULL, &(struct timeval) {
- 10, rand() % 100000
+ 10, jitter()
});
return false;
}
#include "system.h"
#include "conf.h"
+#include "crypto.h"
#include "connection.h"
#include "edge.h"
#include "graph.h"
char *local_address, *local_port;
sockaddr2str(&e->local_address, &local_address, &local_port);
- x = send_request(c, "%d %x %s %s %s %s %x %d %s %s", ADD_EDGE, rand(),
+ x = send_request(c, "%d %x %s %s %s %s %x %d %s %s", ADD_EDGE, prng(UINT32_MAX),
e->from->name, e->to->name, address, port,
e->options, e->weight, local_address, local_port);
free(local_address);
free(local_port);
} else {
- x = send_request(c, "%d %x %s %s %s %s %x %d", ADD_EDGE, rand(),
+ x = send_request(c, "%d %x %s %s %s %s %x %d", ADD_EDGE, prng(UINT32_MAX),
e->from->name, e->to->name, address, port,
e->options, e->weight);
}
}
bool send_del_edge(connection_t *c, const edge_t *e) {
- return send_request(c, "%d %x %s %s", DEL_EDGE, rand(),
+ return send_request(c, "%d %x %s %s", DEL_EDGE, prng(UINT32_MAX),
e->from->name, e->to->name);
}
void send_key_changed(void) {
#ifndef DISABLE_LEGACY
- send_request(everyone, "%d %x %s", KEY_CHANGED, rand(), myself->name);
+ send_request(everyone, "%d %x %s", KEY_CHANGED, prng(UINT32_MAX), myself->name);
/* Immediately send new keys to directly connected nodes to keep UDP mappings alive */
#include "address_cache.h"
#include "connection.h"
+#include "crypto.h"
#include "logger.h"
#include "meta.h"
#include "net.h"
return true;
}
+static bool random_early_drop(connection_t *c) {
+ if(c->outbuf.len > maxoutbufsize / 2) {
+ if((c->outbuf.len - maxoutbufsize / 2) > prng((maxoutbufsize) / 2)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* Sending and receiving packets via TCP */
bool send_tcppacket(connection_t *c, const vpn_packet_t *packet) {
/* If there already is a lot of data in the outbuf buffer, discard this packet.
We use a very simple Random Early Drop algorithm. */
- if(2.0 * c->outbuf.len / (float)maxoutbufsize - 1 > (float)rand() / (float)RAND_MAX) {
+ if(random_early_drop(c)) {
return true;
}
/* If there already is a lot of data in the outbuf buffer, discard this packet.
We use a very simple Random Early Drop algorithm. */
- if(2.0 * c->outbuf.len / (float)maxoutbufsize - 1 > (float)rand() / (float)RAND_MAX) {
+ if(random_early_drop(c)) {
return true;
}
#include "conf.h"
#include "connection.h"
+#include "crypto.h"
#include "logger.h"
#include "node.h"
#include "protocol.h"
return false;
}
- return send_request(c, "%d %x %s %s", ADD_SUBNET, rand(), subnet->owner->name, netstr);
+ return send_request(c, "%d %x %s %s", ADD_SUBNET, prng(UINT32_MAX), subnet->owner->name, netstr);
}
bool add_subnet_h(connection_t *c, const char *request) {
return false;
}
- return send_request(c, "%d %x %s %s", DEL_SUBNET, rand(), s->owner->name, netstr);
+ return send_request(c, "%d %x %s %s", DEL_SUBNET, prng(UINT32_MAX), s->owner->name, netstr);
}
bool del_subnet_h(connection_t *c, const char *request) {
#include "connection.h"
#include "control_common.h"
+#include "crypto.h"
#include "ethernet.h"
#include "ipv4.h"
#include "ipv6.h"
#include "protocol.h"
#include "route.h"
#include "subnet.h"
+#include "utils.h"
rmode_t routing_mode = RMODE_ROUTER;
fmode_t forwarding_mode = FMODE_INTERNAL;
if(left)
timeout_set(&age_subnets_timeout, &(struct timeval) {
- 10, rand() % 100000
+ 10, jitter()
});
}
}
timeout_add(&age_subnets_timeout, age_subnets, NULL, &(struct timeval) {
- 10, rand() % 100000
+ 10, jitter()
});
} else {
if(subnet->expires) {
initiator = true;
}
- srand(getpid());
-
#ifdef HAVE_LINUX
if(tun) {
}
crypto_init();
+ prng_init();
FILE *fp = fopen(argv[1], "r");
fprintf(stderr, "Received %zd bytes of data:\n%s\n", len, hex);
}
- if(packetloss && (rand() % 100) < packetloss) {
+ if(packetloss && prng(100) < packetloss) {
if(verbose) {
fprintf(stderr, "Dropped.\n");
}
#include "splay_tree.h"
#include "control_common.h"
+#include "crypto.h"
#include "hash.h"
#include "logger.h"
#include "net.h"
/* Initialising trees */
void init_subnets(void) {
- hash_seed = (uint32_t)rand();
+ hash_seed = prng(UINT32_MAX);
// tables need to be cleared on startup
subnet_cache_flush_tables();
fprintf(stderr, "Warning: could not bind to port 655. ");
for(int i = 0; i < 100; i++) {
- int port = 0x1000 + (rand() & 0x7fff);
+ uint16_t port = 0x1000 + prng(0x8000);
if(try_bind(port)) {
char filename[PATH_MAX];
#endif
gettimeofday(&now, NULL);
- srand(now.tv_sec + now.tv_usec);
crypto_init();
+ prng_init();
if(optind >= argc) {
return cmd_shell(argc, argv);
unsetenv("LISTEN_PID");
#endif
- /* Slllluuuuuuurrrrp! */
-
+ gettimeofday(&now, NULL);
crypto_init();
+ prng_init();
if(!read_server_config(&config_tree)) {
return 1;
#endif
char *priority = NULL;
- gettimeofday(&now, NULL);
- srand(now.tv_sec + now.tv_usec);
-
if(!detach()) {
return 1;
}
#include "system.h"
+#include "crypto.h"
+
#define B64_SIZE(len) ((len) * 4 / 3 + 5)
extern size_t hex2bin(const char *src, void *dst, size_t length);
#define sockinuse(x) ((x) == WSAEADDRINUSE)
#define socknotconn(x) ((x) == WSAENOTCONN)
#define sockshutdown(x) ((x) == WSAESHUTDOWN)
+
+static inline long jitter(void) {
+ return (long)prng(131072);
+}
#else
#define sockerrno errno
#define sockstrerror(x) strerror(x)
#define sockinprogress(x) ((x) == EINPROGRESS)
#define sockinuse(x) ((x) == EADDRINUSE)
#define socknotconn(x) ((x) == ENOTCONN)
+
+static inline suseconds_t jitter(void) {
+ return (suseconds_t)prng(131072);
+}
#endif
extern unsigned int bitfield_to_int(const void *bitfield, size_t size);
--- /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 "crypto.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));
+}
+
+static uint64_t s[4];
+
+uint64_t xoshiro(void) {
+ 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;
+}
+
+void prng_init(void) {
+ do {
+ randomize(s, sizeof(s));
+ } while(!s[0] && !s[1] && !s[2] && !s[3]);
+}
+
+void prng_randomize(void *buf, size_t buflen) {
+ uint8_t *p = buf;
+ uint64_t value;
+
+ while(buflen > sizeof(value)) {
+ value = xoshiro();
+ memcpy(p, &value, sizeof(value));
+ p += sizeof(value);
+ buflen -= sizeof(value);
+ }
+
+ if(!buflen) {
+ return;
+ }
+
+ value = xoshiro();
+ memcpy(p, &value, buflen);
+}