]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
buffer randomness from gnutls
authorVladimír Čunát <vladimir.cunat@nic.cz>
Mon, 17 Sep 2018 15:37:16 +0000 (17:37 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Tue, 11 Dec 2018 11:19:43 +0000 (12:19 +0100)
gnutls_rnd() is more heavy-weight than I originally anticipated,
and in simple profiling it would take roughly 1% of CPU.
With this simple buffering the usage dropped well under 0.1%.

lib/utils.c
lib/utils.h

index 2dd3a85447d27582ff3826ac0ff17a0cce9c5c3d..af43f2277ccd758c846a10d11a6e2e271d05a851 100644 (file)
@@ -989,6 +989,40 @@ finish:
        return d - dst;
 }
 
+static void rnd_noerror(void *data, uint size)
+{
+       int ret = gnutls_rnd(GNUTLS_RND_NONCE, data, size);
+       if (ret) {
+               kr_log_error("gnutls_rnd(): %s\n", gnutls_strerror(ret));
+               abort();
+       }
+}
+void kr_rnd_buffered(void *data, uint size)
+{
+       /* static circular buffer, from index _begin (inclusive) to _end (exclusive) */
+       static uint8_t buf[512/8]; /* gnutls_rnd() works on blocks of 512 bits (chacha) */
+       static uint buf_begin = sizeof(buf);
+
+       if (unlikely(size > sizeof(buf))) {
+               rnd_noerror(data, size);
+               return;
+       }
+       /* Start with contiguous chunk, possibly until the end of buffer. */
+       const uint size1 = MIN(size, sizeof(buf) - buf_begin);
+       uint8_t *d = data;
+       memcpy(d, buf + buf_begin, size1);
+       if (size1 == size) {
+               buf_begin += size1;
+               return;
+       }
+       d += size1;
+       size -= size1;
+       /* Refill the whole buffer, and finish by another contiguous chunk. */
+       rnd_noerror(buf, sizeof(buf));
+       memcpy(d, buf, size);
+       buf_begin = size;
+}
+
 void kr_rrset_init(knot_rrset_t *rrset, knot_dname_t *owner,
                        uint16_t type, uint16_t rclass, uint32_t ttl)
 {
index fc435bb7842365a0c035c4fee6b5557fedd21ebb..67a552d6d3529e165ebf14354f4a852a67a6acb3 100644 (file)
@@ -183,23 +183,21 @@ typedef array_t(ranked_rr_array_entry_t *) ranked_rr_array_t;
 KR_EXPORT
 char* kr_strcatdup(unsigned n, ...);
 
+/** You probably want kr_rand_* convenience functions instead.
+ * This is a buffered version of gnutls_rnd(GNUTLS_RND_NONCE, ..) */
+KR_EXPORT
+void kr_rnd_buffered(void *data, unsigned int size);
+
 /** Return a few random bytes. */
 static inline uint64_t kr_rand_bytes(int size)
 {
-       /* LATER(optim.): we use this to get one or two bytes typically,
-        * so it will probably be suitable to wrap the gnutls function
-        * by a buffer (size to be determined by profiling, perhaps). */
        uint64_t result;
        if (size <= 0 || size > sizeof(result)) {
                kr_log_error("kr_rand_bytes(): EINVAL\n");
                abort();
        }
        uint8_t data[sizeof(result)];
-       int ret = gnutls_rnd(GNUTLS_RND_NONCE, data, size);
-       if (ret) {
-               kr_log_error("gnutls_rnd(): %s\n", gnutls_strerror(ret));
-               abort();
-       }
+       kr_rnd_buffered(data, size);
        /* I would have liked to dump the random data into a size_t directly,
         * but that would work well only on little-endian machines,
         * so intsead I hope that the compiler will optimize this out.