diff --git a/conf/conf.c b/conf/conf.c index 58abcde1..0c355be4 100644 --- a/conf/conf.c +++ b/conf/conf.c @@ -524,6 +524,7 @@ order_shutdown(int gr) c->gr_down = gr; config_commit(c, RECONFIG_HARD, 0); + random_close(); shutting_down = 1; } diff --git a/configure.ac b/configure.ac index 7d92a5d4..ded258d3 100644 --- a/configure.ac +++ b/configure.ac @@ -374,6 +374,10 @@ elif test "$bird_cv_lib_log" != yes ; then LIBS="$LIBS $bird_cv_lib_log" fi +AC_CHECK_FUNCS(getrandom) +AC_CHECK_FUNCS(getentropy) +AC_CHECK_HEADERS(sys/random.h) + if test "$enable_debug" = yes ; then AC_DEFINE([DEBUGGING], [1], [Define to 1 if debugging is enabled]) LDFLAGS="$LDFLAGS -rdynamic" diff --git a/lib/birdlib.h b/lib/birdlib.h index 23036c1b..61098f92 100644 --- a/lib/birdlib.h +++ b/lib/birdlib.h @@ -192,5 +192,8 @@ asm( /* Pseudorandom numbers */ u32 random_u32(void); +int random_bytes(char *buf, size_t size); +void random_close(void); +void random_init(void); #endif 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 +#include +#include +#include + +#include "sysdep/config.h" + +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef HAVE_LINUX_RANDOM_H +# include +#endif +#if defined(HAVE_SYS_RANDOM_H) && (defined(HAVE_GETRANDOM) || defined(HAVE_GETENTROPY)) +# include +#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