diff options
Diffstat (limited to 'sysdep')
-rw-r--r-- | sysdep/unix/main.c | 1 | ||||
-rw-r--r-- | sysdep/unix/random.c | 88 |
2 files changed, 89 insertions, 0 deletions
diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 76f92c5e..392aff9d 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -867,6 +867,7 @@ main(int argc, char **argv) parse_args(argc, argv); log_switch(1, NULL, NULL); + random_init(); net_init(); resource_init(); timer_init(); diff --git a/sysdep/unix/random.c b/sysdep/unix/random.c index b1f5086f..de81f3ca 100644 --- a/sysdep/unix/random.c +++ b/sysdep/unix/random.c @@ -7,6 +7,21 @@ */ #include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +#include "sysdep/config.h" + +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef HAVE_LINUX_RANDOM_H +# include <linux/random.h> +#endif +#if defined(HAVE_SYS_RANDOM_H) && (defined(HAVE_GETRANDOM) || defined(HAVE_GETENTROPY)) +# include <sys/random.h> +#endif #include "nest/bird.h" @@ -19,3 +34,76 @@ random_u32(void) rand_high = random(); return (rand_low & 0xffff) | ((rand_high & 0xffff) << 16); } + +void +random_init() +{ + char buf; + /* get a single random byte to trip any errors early */ + random_bytes(&buf, sizeof(buf)); +} + +#if defined(HAVE_GETRANDOM) || defined(HAVE_GENTROPY) +int +random_bytes(char *buf, size_t size) +{ + int n; + int flags = 0; + while (0 < size) { +#if defined(HAVE_GETRANDOM) + n = getrandom(buf, size, flags); +#else + n = getentropy(buf, size); +#endif + if (n < 0) { + if (errno == EINTR) + continue; + die("Couldn't get random bytes: %m"); + } + buf += n; + size -= n; + } + + return 0; +} + +void random_close(void) {} + +#else + +static int urandom_fd = -1; +int random_bytes(char *buf, size_t size) +{ + int n; + + if (urandom_fd < 0) + { + urandom_fd = open("/dev/urandom", O_RDONLY); + if (urandom_fd < 0) + die("Couldn't open /dev/urandom: %m"); + } + + do + { + n = read(urandom_fd, buf, size); + if (n <= 0) { + if (errno == EINTR) + continue; + die("Couldn't read from /dev/urandom: %m"); + } + buf += n; + size -= n; + } while (size > 0); + + return 0; +} + +void +random_close(void) +{ + if (urandom_fd >= 0) { + close(urandom_fd); + urandom_fd = -1; + } +} +#endif |