1From 823df3b989e59465d17b0a2eb1239a5fc048b4e5 Mon Sep 17 00:00:00 2001 2From: Brad House <brad@brad-house.com> 3Date: Mon, 22 May 2023 06:51:06 -0400 4Subject: [PATCH] Merge pull request from GHSA-8r8p-23f3-64c2 5 6* segment random number generation into own file 7 8* abstract random code to make it more modular so we can have multiple backends 9 10* rand: add support for arc4random_buf() and also direct CARES_RANDOM_FILE reading 11 12* autotools: fix detection of arc4random_buf 13 14* rework initial rc4 seed for PRNG as last fallback 15 16* rc4: more proper implementation, simplified for clarity 17 18* clarifications 19 20Conflict:NA 21Reference:https://github.com/c-ares/c-ares/commit/823df3b989e59465d17b0a2eb1239a5fc048b4e5 22--- 23 CMakeLists.txt | 2 + 24 configure.ac | 1 + 25 m4/cares-functions.m4 | 85 +++++++++++ 26 src/lib/Makefile.inc | 1 + 27 src/lib/ares_config.h.cmake | 3 + 28 src/lib/ares_destroy.c | 3 + 29 src/lib/ares_init.c | 89 ++---------- 30 src/lib/ares_private.h | 19 ++- 31 src/lib/ares_query.c | 36 +---- 32 src/lib/ares_rand.c | 274 ++++++++++++++++++++++++++++++++++++ 33 10 files changed, 387 insertions(+), 126 deletions(-) 34 create mode 100644 src/lib/ares_rand.c 35 36diff --git a/CMakeLists.txt b/CMakeLists.txt 37index 3987d0ab7..e2290af10 100644 38--- a/CMakeLists.txt 39+++ b/CMakeLists.txt 40@@ -393,6 +393,8 @@ CHECK_SYMBOL_EXISTS (strncasecmp "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_STRNCAS 41 CHECK_SYMBOL_EXISTS (strncmpi "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_STRNCMPI) 42 CHECK_SYMBOL_EXISTS (strnicmp "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_STRNICMP) 43 CHECK_SYMBOL_EXISTS (writev "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_WRITEV) 44+CHECK_SYMBOL_EXISTS (arc4random_buf "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_ARC4RANDOM_BUF) 45+ 46 47 # On Android, the system headers may define __system_property_get(), but excluded 48 # from libc. We need to perform a link test instead of a header/symbol test. 49diff --git a/configure.ac b/configure.ac 50index 7884cbb26..54e79d6e2 100644 51--- a/configure.ac 52+++ b/configure.ac 53@@ -683,6 +683,7 @@ CARES_CHECK_FUNC_STRNCASECMP 54 CARES_CHECK_FUNC_STRNCMPI 55 CARES_CHECK_FUNC_STRNICMP 56 CARES_CHECK_FUNC_WRITEV 57+CARES_CHECK_FUNC_ARC4RANDOM_BUF 58 59 60 dnl check for AF_INET6 61diff --git a/m4/cares-functions.m4 b/m4/cares-functions.m4 62index 0f3992c7f..d4f4f994c 100644 63--- a/m4/cares-functions.m4 64+++ b/m4/cares-functions.m4 65@@ -3753,3 +3753,88 @@ AC_DEFUN([CARES_CHECK_FUNC_WRITEV], [ 66 ac_cv_func_writev="no" 67 fi 68 ]) 69+ 70+dnl CARES_CHECK_FUNC_ARC4RANDOM_BUF 71+dnl ------------------------------------------------- 72+dnl Verify if arc4random_buf is available, prototyped, and 73+dnl can be compiled. If all of these are true, and 74+dnl usage has not been previously disallowed with 75+dnl shell variable cares_disallow_arc4random_buf, then 76+dnl HAVE_ARC4RANDOM_BUF will be defined. 77+ 78+AC_DEFUN([CARES_CHECK_FUNC_ARC4RANDOM_BUF], [ 79+ AC_REQUIRE([CARES_INCLUDES_STDLIB])dnl 80+ # 81+ tst_links_arc4random_buf="unknown" 82+ tst_proto_arc4random_buf="unknown" 83+ tst_compi_arc4random_buf="unknown" 84+ tst_allow_arc4random_buf="unknown" 85+ # 86+ AC_MSG_CHECKING([if arc4random_buf can be linked]) 87+ AC_LINK_IFELSE([ 88+ AC_LANG_FUNC_LINK_TRY([arc4random_buf]) 89+ ],[ 90+ AC_MSG_RESULT([yes]) 91+ tst_links_arc4random_buf="yes" 92+ ],[ 93+ AC_MSG_RESULT([no]) 94+ tst_links_arc4random_buf="no" 95+ ]) 96+ # 97+ if test "$tst_links_arc4random_buf" = "yes"; then 98+ AC_MSG_CHECKING([if arc4random_buf is prototyped]) 99+ AC_EGREP_CPP([arc4random_buf],[ 100+ $cares_includes_stdlib 101+ ],[ 102+ AC_MSG_RESULT([yes]) 103+ tst_proto_arc4random_buf="yes" 104+ ],[ 105+ AC_MSG_RESULT([no]) 106+ tst_proto_arc4random_buf="no" 107+ ]) 108+ fi 109+ # 110+ if test "$tst_proto_arc4random_buf" = "yes"; then 111+ AC_MSG_CHECKING([if arc4random_buf is compilable]) 112+ AC_COMPILE_IFELSE([ 113+ AC_LANG_PROGRAM([[ 114+ $cares_includes_stdlib 115+ ]],[[ 116+ arc4random_buf(NULL, 0); 117+ return 1; 118+ ]]) 119+ ],[ 120+ AC_MSG_RESULT([yes]) 121+ tst_compi_arc4random_buf="yes" 122+ ],[ 123+ AC_MSG_RESULT([no]) 124+ tst_compi_arc4random_buf="no" 125+ ]) 126+ fi 127+ # 128+ if test "$tst_compi_arc4random_buf" = "yes"; then 129+ AC_MSG_CHECKING([if arc4random_buf usage allowed]) 130+ if test "x$cares_disallow_arc4random_buf" != "xyes"; then 131+ AC_MSG_RESULT([yes]) 132+ tst_allow_arc4random_buf="yes" 133+ else 134+ AC_MSG_RESULT([no]) 135+ tst_allow_arc4random_buf="no" 136+ fi 137+ fi 138+ # 139+ AC_MSG_CHECKING([if arc4random_buf might be used]) 140+ if test "$tst_links_arc4random_buf" = "yes" && 141+ test "$tst_proto_arc4random_buf" = "yes" && 142+ test "$tst_compi_arc4random_buf" = "yes" && 143+ test "$tst_allow_arc4random_buf" = "yes"; then 144+ AC_MSG_RESULT([yes]) 145+ AC_DEFINE_UNQUOTED(HAVE_ARC4RANDOM_BUF, 1, 146+ [Define to 1 if you have the arc4random_buf function.]) 147+ ac_cv_func_arc4random_buf="yes" 148+ else 149+ AC_MSG_RESULT([no]) 150+ ac_cv_func_arc4random_buf="no" 151+ fi 152+]) 153+ 154diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc 155index 140378d67..49bbe6016 100644 156--- a/src/lib/Makefile.inc 157+++ b/src/lib/Makefile.inc 158@@ -45,6 +45,7 @@ CSOURCES = ares__addrinfo2hostent.c \ 159 ares_platform.c \ 160 ares_process.c \ 161 ares_query.c \ 162+ ares_rand.c \ 163 ares_search.c \ 164 ares_send.c \ 165 ares_strcasecmp.c \ 166diff --git a/src/lib/ares_config.h.cmake b/src/lib/ares_config.h.cmake 167index fddb78535..798820a3a 100644 168--- a/src/lib/ares_config.h.cmake 169+++ b/src/lib/ares_config.h.cmake 170@@ -346,6 +346,9 @@ 171 /* Define to 1 if you need the memory.h header file even with stdlib.h */ 172 #cmakedefine NEED_MEMORY_H 173 174+/* Define if have arc4random_buf() */ 175+#cmakedefine HAVE_ARC4RANDOM_BUF 176+ 177 /* a suitable file/device to read random data from */ 178 #cmakedefine CARES_RANDOM_FILE "@CARES_RANDOM_FILE@" 179 180diff --git a/src/lib/ares_destroy.c b/src/lib/ares_destroy.c 181index 7ec2bde5a..62c899f82 100644 182--- a/src/lib/ares_destroy.c 183+++ b/src/lib/ares_destroy.c 184@@ -95,6 +95,9 @@ void ares_destroy(ares_channel channel) 185 if (channel->resolvconf_path) 186 ares_free(channel->resolvconf_path); 187 188+ if (channel->rand_state) 189+ ares__destroy_rand_state(channel->rand_state); 190+ 191 ares_free(channel); 192 } 193 194diff --git a/src/lib/ares_init.c b/src/lib/ares_init.c 195index c7ca7af1b..0519f43e5 100644 196--- a/src/lib/ares_init.c 197+++ b/src/lib/ares_init.c 198@@ -87,7 +76,6 @@ static int config_nameserver(struct server_state **servers, int *nservers, 199 static int set_search(ares_channel channel, const char *str); 200 static int set_options(ares_channel channel, const char *str); 201 static const char *try_option(const char *p, const char *q, const char *opt); 202-static int init_id_key(rc4_key* key,int key_data_len); 203 204 static int config_sortlist(struct apattern **sortlist, int *nsort, 205 const char *str); 206@@ -165,6 +153,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, 207 channel->sock_funcs = NULL; 208 channel->sock_func_cb_data = NULL; 209 channel->resolvconf_path = NULL; 210+ channel->rand_state = NULL; 211 212 channel->last_server = 0; 213 channel->last_timeout_processed = (time_t)now.tv_sec; 214@@ -218,9 +207,13 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, 215 /* Generate random key */ 216 217 if (status == ARES_SUCCESS) { 218- status = init_id_key(&channel->id_key, ARES_ID_KEY_LEN); 219+ channel->rand_state = ares__init_rand_state(); 220+ if (channel->rand_state == NULL) { 221+ status = ARES_ENOMEM; 222+ } 223+ 224 if (status == ARES_SUCCESS) 225- channel->next_id = ares__generate_new_id(&channel->id_key); 226+ channel->next_id = ares__generate_new_id(channel->rand_state); 227 else 228 DEBUGF(fprintf(stderr, "Error: init_id_key failed: %s\n", 229 ares_strerror(status))); 230@@ -242,6 +235,8 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, 231 ares_free(channel->lookups); 232 if(channel->resolvconf_path) 233 ares_free(channel->resolvconf_path); 234+ if (channel->rand_state) 235+ ares__destroy_rand_state(channel->rand_state); 236 ares_free(channel); 237 return status; 238 } 239@@ -2182,76 +2177,6 @@ static int sortlist_alloc(struct apattern **sortlist, int *nsort, 240 return 1; 241 } 242 243-/* initialize an rc4 key. If possible a cryptographically secure random key 244- is generated using a suitable function (for example win32's RtlGenRandom as 245- described in 246- http://blogs.msdn.com/michael_howard/archive/2005/01/14/353379.aspx 247- otherwise the code defaults to cross-platform albeit less secure mechanism 248- using rand 249-*/ 250-static void randomize_key(unsigned char* key,int key_data_len) 251-{ 252- int randomized = 0; 253- int counter=0; 254-#ifdef WIN32 255- BOOLEAN res; 256- if (ares_fpSystemFunction036) 257- { 258- res = (*ares_fpSystemFunction036) (key, key_data_len); 259- if (res) 260- randomized = 1; 261- } 262-#else /* !WIN32 */ 263-#ifdef CARES_RANDOM_FILE 264- FILE *f = fopen(CARES_RANDOM_FILE, "rb"); 265- if(f) { 266- setvbuf(f, NULL, _IONBF, 0); 267- counter = aresx_uztosi(fread(key, 1, key_data_len, f)); 268- fclose(f); 269- } 270-#endif 271-#endif /* WIN32 */ 272- 273- if (!randomized) { 274- for (;counter<key_data_len;counter++) 275- key[counter]=(unsigned char)(rand() % 256); /* LCOV_EXCL_LINE */ 276- } 277-} 278- 279-static int init_id_key(rc4_key* key,int key_data_len) 280-{ 281- unsigned char index1; 282- unsigned char index2; 283- unsigned char* state; 284- short counter; 285- unsigned char *key_data_ptr = 0; 286- 287- key_data_ptr = ares_malloc(key_data_len); 288- if (!key_data_ptr) 289- return ARES_ENOMEM; 290- memset(key_data_ptr, 0, key_data_len); 291- 292- state = &key->state[0]; 293- for(counter = 0; counter < 256; counter++) 294- /* unnecessary AND but it keeps some compilers happier */ 295- state[counter] = (unsigned char)(counter & 0xff); 296- randomize_key(key->state,key_data_len); 297- key->x = 0; 298- key->y = 0; 299- index1 = 0; 300- index2 = 0; 301- for(counter = 0; counter < 256; counter++) 302- { 303- index2 = (unsigned char)((key_data_ptr[index1] + state[counter] + 304- index2) % 256); 305- ARES_SWAP_BYTE(&state[counter], &state[index2]); 306- 307- index1 = (unsigned char)((index1 + 1) % key_data_len); 308- } 309- ares_free(key_data_ptr); 310- return ARES_SUCCESS; 311-} 312- 313 void ares_set_local_ip4(ares_channel channel, unsigned int local_ip) 314 { 315 channel->local_ip4 = local_ip; 316diff --git a/src/lib/ares_private.h b/src/lib/ares_private.h 317index 53043a651..b6eab8a7d 100644 318--- a/src/lib/ares_private.h 319+++ b/src/lib/ares_private.h 320@@ -101,8 +101,6 @@ W32_FUNC const char *_w32_GetHostsFile (void); 321 322 #endif 323 324-#define ARES_ID_KEY_LEN 31 325- 326 #include "ares_ipv6.h" 327 #include "ares_llist.h" 328 329@@ -262,12 +260,8 @@ struct apattern { 330 unsigned short type; 331 }; 332 333-typedef struct rc4_key 334-{ 335- unsigned char state[256]; 336- unsigned char x; 337- unsigned char y; 338-} rc4_key; 339+struct ares_rand_state; 340+typedef struct ares_rand_state ares_rand_state; 341 342 struct ares_channeldata { 343 /* Configuration data */ 344@@ -302,8 +296,8 @@ struct ares_channeldata { 345 346 /* ID to use for next query */ 347 unsigned short next_id; 348- /* key to use when generating new ids */ 349- rc4_key id_key; 350+ /* random state to use when generating new ids */ 351+ ares_rand_state *rand_state; 352 353 /* Generation number to use for the next TCP socket open/close */ 354 int tcp_connection_generation; 355@@ -362,7 +356,10 @@ void ares__close_sockets(ares_channel channel, struct server_state *server); 356 int ares__get_hostent(FILE *fp, int family, struct hostent **host); 357 int ares__read_line(FILE *fp, char **buf, size_t *bufsize); 358 void ares__free_query(struct query *query); 359-unsigned short ares__generate_new_id(rc4_key* key); 360+ 361+ares_rand_state *ares__init_rand_state(void); 362+void ares__destroy_rand_state(ares_rand_state *state); 363+unsigned short ares__generate_new_id(ares_rand_state *state); 364 struct timeval ares__tvnow(void); 365 int ares__expand_name_validated(const unsigned char *encoded, 366 const unsigned char *abuf, 367diff --git a/src/lib/ares_query.c b/src/lib/ares_query.c 368index 508274db3..42323bec5 100644 369--- a/src/lib/ares_query.c 370+++ b/src/lib/ares_query.c 371@@ -33,32 +33,6 @@ struct qquery { 372 373 static void qcallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen); 374 375-static void rc4(rc4_key* key, unsigned char *buffer_ptr, int buffer_len) 376-{ 377- unsigned char x; 378- unsigned char y; 379- unsigned char* state; 380- unsigned char xorIndex; 381- int counter; 382- 383- x = key->x; 384- y = key->y; 385- 386- state = &key->state[0]; 387- for(counter = 0; counter < buffer_len; counter ++) 388- { 389- x = (unsigned char)((x + 1) % 256); 390- y = (unsigned char)((state[x] + y) % 256); 391- ARES_SWAP_BYTE(&state[x], &state[y]); 392- 393- xorIndex = (unsigned char)((state[x] + state[y]) % 256); 394- 395- buffer_ptr[counter] = (unsigned char)(buffer_ptr[counter]^state[xorIndex]); 396- } 397- key->x = x; 398- key->y = y; 399-} 400- 401 static struct query* find_query_by_id(ares_channel channel, unsigned short id) 402 { 403 unsigned short qid; 404@@ -78,7 +52,6 @@ static struct query* find_query_by_id(ares_channel channel, unsigned short id) 405 return NULL; 406 } 407 408- 409 /* a unique query id is generated using an rc4 key. Since the id may already 410 be used by a running query (as infrequent as it may be), a lookup is 411 performed per id generation. In practice this search should happen only 412@@ -89,19 +62,12 @@ static unsigned short generate_unique_id(ares_channel channel) 413 unsigned short id; 414 415 do { 416- id = ares__generate_new_id(&channel->id_key); 417+ id = ares__generate_new_id(channel->rand_state); 418 } while (find_query_by_id(channel, id)); 419 420 return (unsigned short)id; 421 } 422 423-unsigned short ares__generate_new_id(rc4_key* key) 424-{ 425- unsigned short r=0; 426- rc4(key, (unsigned char *)&r, sizeof(r)); 427- return r; 428-} 429- 430 void ares_query(ares_channel channel, const char *name, int dnsclass, 431 int type, ares_callback callback, void *arg) 432 { 433diff --git a/src/lib/ares_rand.c b/src/lib/ares_rand.c 434new file mode 100644 435index 000000000..a564bc236 436--- /dev/null 437+++ b/src/lib/ares_rand.c 438@@ -0,0 +1,274 @@ 439+/* Copyright 1998 by the Massachusetts Institute of Technology. 440+ * Copyright (C) 2007-2013 by Daniel Stenberg 441+ * 442+ * Permission to use, copy, modify, and distribute this 443+ * software and its documentation for any purpose and without 444+ * fee is hereby granted, provided that the above copyright 445+ * notice appear in all copies and that both that copyright 446+ * notice and this permission notice appear in supporting 447+ * documentation, and that the name of M.I.T. not be used in 448+ * advertising or publicity pertaining to distribution of the 449+ * software without specific, written prior permission. 450+ * M.I.T. makes no representations about the suitability of 451+ * this software for any purpose. It is provided "as is" 452+ * without express or implied warranty. 453+ */ 454+ 455+#include "ares_setup.h" 456+#include "ares.h" 457+#include "ares_private.h" 458+#include "ares_nowarn.h" 459+#include <stdlib.h> 460+ 461+typedef enum { 462+ ARES_RAND_OS = 1, /* OS-provided such as RtlGenRandom or arc4random */ 463+ ARES_RAND_FILE = 2, /* OS file-backed random number generator */ 464+ ARES_RAND_RC4 = 3 /* Internal RC4 based PRNG */ 465+} ares_rand_backend; 466+ 467+typedef struct ares_rand_rc4 468+{ 469+ unsigned char S[256]; 470+ size_t i; 471+ size_t j; 472+} ares_rand_rc4; 473+ 474+struct ares_rand_state 475+{ 476+ ares_rand_backend type; 477+ union { 478+ FILE *rand_file; 479+ ares_rand_rc4 rc4; 480+ } state; 481+}; 482+ 483+ 484+/* Define RtlGenRandom = SystemFunction036. This is in advapi32.dll. There is 485+ * no need to dynamically load this, other software used widely does not. 486+ * http://blogs.msdn.com/michael_howard/archive/2005/01/14/353379.aspx 487+ * https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom 488+ */ 489+#ifdef _WIN32 490+BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG RandomBufferLength); 491+# ifndef RtlGenRandom 492+# define RtlGenRandom(a,b) SystemFunction036(a,b) 493+# endif 494+#endif 495+ 496+ 497+#define ARES_RC4_KEY_LEN 32 /* 256 bits */ 498+ 499+static unsigned int ares_u32_from_ptr(void *addr) 500+{ 501+ if (sizeof(void *) == 8) { 502+ return (unsigned int)((((size_t)addr >> 32) & 0xFFFFFFFF) | ((size_t)addr & 0xFFFFFFFF)); 503+ } 504+ return (unsigned int)((size_t)addr & 0xFFFFFFFF); 505+} 506+ 507+ 508+/* initialize an rc4 key as the last possible fallback. */ 509+static void ares_rc4_generate_key(ares_rand_rc4 *rc4_state, unsigned char *key, size_t key_len) 510+{ 511+ size_t i; 512+ size_t len = 0; 513+ unsigned int data; 514+ struct timeval tv; 515+ 516+ if (key_len != ARES_RC4_KEY_LEN) 517+ return; 518+ 519+ /* Randomness is hard to come by. Maybe the system randomizes heap and stack addresses. 520+ * Maybe the current timestamp give us some randomness. 521+ * Use rc4_state (heap), &i (stack), and ares__tvnow() 522+ */ 523+ data = ares_u32_from_ptr(rc4_state); 524+ memcpy(key + len, &data, sizeof(data)); 525+ len += sizeof(data); 526+ 527+ data = ares_u32_from_ptr(&i); 528+ memcpy(key + len, &data, sizeof(data)); 529+ len += sizeof(data); 530+ 531+ tv = ares__tvnow(); 532+ data = (unsigned int)((tv.tv_sec | tv.tv_usec) & 0xFFFFFFFF); 533+ memcpy(key + len, &data, sizeof(data)); 534+ len += sizeof(data); 535+ 536+ srand(ares_u32_from_ptr(rc4_state) | ares_u32_from_ptr(&i) | (unsigned int)((tv.tv_sec | tv.tv_usec) & 0xFFFFFFFF)); 537+ 538+ for (i=len; i<key_len; i++) { 539+ key[i]=(unsigned char)(rand() % 256); /* LCOV_EXCL_LINE */ 540+ } 541+} 542+ 543+ 544+static void ares_rc4_init(ares_rand_rc4 *rc4_state) 545+{ 546+ unsigned char key[ARES_RC4_KEY_LEN]; 547+ size_t i; 548+ size_t j; 549+ 550+ ares_rc4_generate_key(rc4_state, key, sizeof(key)); 551+ 552+ for (i = 0; i < sizeof(rc4_state->S); i++) { 553+ rc4_state->S[i] = i & 0xFF; 554+ } 555+ 556+ for(i = 0, j = 0; i < 256; i++) { 557+ j = (j + rc4_state->S[i] + key[i % sizeof(key)]) % 256; 558+ ARES_SWAP_BYTE(&rc4_state->S[i], &rc4_state->S[j]); 559+ } 560+ 561+ rc4_state->i = 0; 562+ rc4_state->j = 0; 563+} 564+ 565+/* Just outputs the key schedule, no need to XOR with any data since we have none */ 566+static void ares_rc4_prng(ares_rand_rc4 *rc4_state, unsigned char *buf, int len) 567+{ 568+ unsigned char *S = rc4_state->S; 569+ size_t i = rc4_state->i; 570+ size_t j = rc4_state->j; 571+ size_t cnt; 572+ 573+ for (cnt=0; cnt<len; cnt++) { 574+ i = (i + 1) % 256; 575+ j = (j + S[i]) % 256; 576+ 577+ ARES_SWAP_BYTE(&S[i], &S[j]); 578+ buf[cnt] = S[(S[i] + S[j]) % 256]; 579+ } 580+ 581+ rc4_state->i = i; 582+ rc4_state->j = j; 583+} 584+ 585+ 586+static int ares__init_rand_engine(ares_rand_state *state) 587+{ 588+ memset(state, 0, sizeof(*state)); 589+ 590+#if defined(HAVE_ARC4RANDOM_BUF) || defined(_WIN32) 591+ state->type = ARES_RAND_OS; 592+ return 1; 593+#elif defined(CARES_RANDOM_FILE) 594+ state->type = ARES_RAND_FILE; 595+ state->state.rand_file = fopen(CARES_RANDOM_FILE, "rb"); 596+ if (state->state.rand_file) { 597+ setvbuf(state->state.rand_file, NULL, _IONBF, 0); 598+ return 1; 599+ } 600+ /* Fall-Thru on failure to RC4 */ 601+#endif 602+ 603+ state->type = ARES_RAND_RC4; 604+ ares_rc4_init(&state->state.rc4); 605+ 606+ /* Currently cannot fail */ 607+ return 1; 608+} 609+ 610+ 611+ares_rand_state *ares__init_rand_state() 612+{ 613+ ares_rand_state *state = NULL; 614+ 615+ state = ares_malloc(sizeof(*state)); 616+ if (!state) 617+ return NULL; 618+ 619+ if (!ares__init_rand_engine(state)) { 620+ ares_free(state); 621+ return NULL; 622+ } 623+ 624+ return state; 625+} 626+ 627+ 628+static void ares__clear_rand_state(ares_rand_state *state) 629+{ 630+ if (!state) 631+ return; 632+ 633+ switch (state->type) { 634+ case ARES_RAND_OS: 635+ break; 636+ case ARES_RAND_FILE: 637+ fclose(state->state.rand_file); 638+ break; 639+ case ARES_RAND_RC4: 640+ break; 641+ } 642+} 643+ 644+ 645+static void ares__reinit_rand(ares_rand_state *state) 646+{ 647+ ares__clear_rand_state(state); 648+ ares__init_rand_engine(state); 649+} 650+ 651+ 652+void ares__destroy_rand_state(ares_rand_state *state) 653+{ 654+ if (!state) 655+ return; 656+ 657+ ares__clear_rand_state(state); 658+ ares_free(state); 659+} 660+ 661+ 662+static void ares__rand_bytes(ares_rand_state *state, unsigned char *buf, size_t len) 663+{ 664+ 665+ while (1) { 666+ size_t rv; 667+ size_t bytes_read = 0; 668+ 669+ switch (state->type) { 670+ case ARES_RAND_OS: 671+#ifdef _WIN32 672+ RtlGenRandom(buf, len); 673+ return; 674+#elif defined(HAVE_ARC4RANDOM_BUF) 675+ arc4random_buf(buf, len); 676+ return; 677+#else 678+ /* Shouldn't be possible to be here */ 679+ break; 680+#endif 681+ 682+ case ARES_RAND_FILE: 683+ while (1) { 684+ size_t rv = fread(buf + bytes_read, 1, len - bytes_read, state->state.rand_file); 685+ if (rv == 0) 686+ break; /* critical error, will reinit rand state */ 687+ 688+ bytes_read += rv; 689+ if (bytes_read == len) 690+ return; 691+ } 692+ break; 693+ 694+ case ARES_RAND_RC4: 695+ ares_rc4_prng(&state->state.rc4, buf, len); 696+ return; 697+ } 698+ 699+ /* If we didn't return before we got here, that means we had a critical rand 700+ * failure and need to reinitialized */ 701+ ares__reinit_rand(state); 702+ } 703+} 704+ 705+unsigned short ares__generate_new_id(ares_rand_state *state) 706+{ 707+ unsigned short r=0; 708+ 709+ ares__rand_bytes(state, (unsigned char *)&r, sizeof(r)); 710+ return r; 711+} 712+ 713