static int wait_for_sources(isc_entropy_t *ent) { isc_entropysource_t *source; int maxfd, fd; int cc; fd_set reads; fd_set writes; maxfd = -1; FD_ZERO(&reads); FD_ZERO(&writes); source = ISC_LIST_HEAD(ent->sources); while (source != NULL) { if (source->type == ENTROPY_SOURCETYPE_FILE) { fd = source->sources.file.handle; if (fd >= 0) { maxfd = ISC_MAX(maxfd, fd); FD_SET(fd, &reads); } } if (source->type == ENTROPY_SOURCETYPE_USOCKET) { fd = source->sources.usocket.handle; if (fd >= 0) { switch (source->sources.usocket.status) { case isc_usocketsource_disconnected: break; case isc_usocketsource_connecting: case isc_usocketsource_connected: case isc_usocketsource_ndesired: maxfd = ISC_MAX(maxfd, fd); FD_SET(fd, &writes); break; case isc_usocketsource_wrote: case isc_usocketsource_reading: maxfd = ISC_MAX(maxfd, fd); FD_SET(fd, &reads); break; } } } source = ISC_LIST_NEXT(source, link); } if (maxfd < 0) return (-1); cc = select(maxfd + 1, &reads, &writes, NULL, NULL); if (cc < 0) return (-1); return (cc); }
void dns_dampening_score_size(dns_dampening_t * damp, const isc_sockaddr_t * addr, isc_stdtime_t now, int length) { isc_netaddr_t netaddr, prefix; dns_dampening_entry_t * entry; uint16_t points; dns_dampening_implementation_t *impl; RUNTIME_CHECK( damp != NULL ); RUNTIME_CHECK( addr != NULL ); isc_netaddr_fromsockaddr(&netaddr, addr); extract_prefix(&prefix, &netaddr, &(damp->prefixlen)); for(impl = damp->workers; impl - damp->workers < damp->workers_count; impl++) { if(damp->exempt != NULL) { int match; if (ISC_R_SUCCESS == dns_acl_match(&netaddr, NULL, damp->exempt, NULL, &match, NULL) && match > 0) { DAMPENING_STATISTICS_INC(impl,skipped); continue; } } DAMPENING_STATISTICS_DO(impl, lock, LOCK(&impl->lock)); DAMPENING_STATISTICS_DO(impl, search, entry = impl->search(impl->data, &prefix)); if(entry != NULL) { length = ISC_MAX(length, damp->score.minimum_size); length = ISC_MIN(length, damp->score.maximum_size); points = damp->score.size_penalty * (length - damp->score.minimum_size) / (damp->score.maximum_size - damp->score.minimum_size); DAMPENING_STATISTICS_DO(impl, update, impl->update(impl->data, &entry, points, now)); } UNLOCK(&impl->lock); } }
/* * Make sure we have enough space for at least len + 1 bytes. * This function is private. */ static isc_result_t str_alloc(ld_string_t *str, size_t len) { size_t new_size; char *new_buffer; REQUIRE(str != NULL); REQUIRE(str->mctx != NULL); IGNORE_R(str->allocated > len); len++; /* Account for the last '\0'. */ new_size = ISC_MAX(str->allocated, ALLOC_BASE_SIZE); while (new_size <= len) new_size *= 2; new_size *= sizeof (char); #if ISC_MEM_TRACKLINES new_buffer = isc__mem_get(str->mctx, new_size, str->file, str->line); #else new_buffer = isc_mem_get(str->mctx, new_size); #endif if (new_buffer == NULL) return ISC_R_NOMEMORY; if (str->data != NULL) { memcpy(new_buffer, str->data, len); new_buffer[len] = '\0'; isc_mem_put(str->mctx, str->data, str->allocated); } else { new_buffer[0] = '\0'; } str->data = new_buffer; str->allocated = new_size; return ISC_R_SUCCESS; }
/* * Poll each source, trying to get data from it to stuff into the entropy * pool. */ static void fillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) { unsigned int added; unsigned int remaining; unsigned int needed; unsigned int nsource; isc_entropysource_t *source; isc_entropysource_t *firstsource; REQUIRE(VALID_ENTROPY(ent)); needed = desired; /* * This logic is a little strange, so an explanation is in order. * * If needed is 0, it means we are being asked to "fill to whatever * we think is best." This means that if we have at least a * partially full pool (say, > 1/4th of the pool) we probably don't * need to add anything. * * Also, we will check to see if the "pseudo" count is too high. * If it is, try to mix in better data. Too high is currently * defined as 1/4th of the pool. * * Next, if we are asked to add a specific bit of entropy, make * certain that we will do so. Clamp how much we try to add to * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy). * * Note that if we are in a blocking mode, we will only try to * get as much data as we need, not as much as we might want * to build up. */ if (needed == 0) { REQUIRE(!blocking); if ((ent->pool.entropy >= RND_POOLBITS / 4) && (ent->pool.pseudo <= RND_POOLBITS / 4)) return; needed = THRESHOLD_BITS * 4; } else { needed = ISC_MAX(needed, THRESHOLD_BITS); needed = ISC_MIN(needed, RND_POOLBITS); } /* * In any case, clamp how much we need to how much we can add. */ needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy); /* * But wait! If we're not yet initialized, we need at least * THRESHOLD_BITS * of randomness. */ if (ent->initialized < THRESHOLD_BITS) needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized); /* * Poll each file source to see if we can read anything useful from * it. XXXMLG When where are multiple sources, we should keep a * record of which one we last used so we can start from it (or the * next one) to avoid letting some sources build up entropy while * others are always drained. */ added = 0; remaining = needed; if (ent->nextsource == NULL) { ent->nextsource = ISC_LIST_HEAD(ent->sources); if (ent->nextsource == NULL) return; } source = ent->nextsource; /* * Remember the first source so we can break if we have looped back to * the beginning and still have nothing */ firstsource = source; again_file: for (nsource = 0; nsource < ent->nsources; nsource++) { unsigned int got; if (remaining == 0) break; got = 0; if (source->type == ENTROPY_SOURCETYPE_FILE) got = get_from_filesource(source, remaining); added += got; remaining -= ISC_MIN(remaining, got); source = ISC_LIST_NEXT(source, link); if (source == NULL) source = ISC_LIST_HEAD(ent->sources); } ent->nextsource = source; /* * Go again only if there's been progress and we've not * gone back to the beginning */ if (!(ent->nextsource == firstsource && added == 0)) { if (blocking && remaining != 0) { goto again_file; } } /* * Here, if there are bits remaining to be had and we can block, * check to see if we have a callback source. If so, call them. */ source = ISC_LIST_HEAD(ent->sources); while ((remaining != 0) && (source != NULL)) { unsigned int got; got = 0; if (source->type == ENTROPY_SOURCETYPE_CALLBACK) got = get_from_callback(source, remaining, blocking); added += got; remaining -= ISC_MIN(remaining, got); if (added >= needed) break; source = ISC_LIST_NEXT(source, link); } /* * Mark as initialized if we've added enough data. */ if (ent->initialized < THRESHOLD_BITS) ent->initialized += added; }
ATF_TC_BODY(benchmark, tc) { isc_result_t result; char namestr[sizeof("name18446744073709551616.example.org.")]; unsigned int r; dns_rbt_t *mytree; dns_rbtnode_t *node; unsigned int i; unsigned int maxvalue = 1000000; isc_time_t ts1, ts2; double t; unsigned int nthreads; isc_thread_t threads[32]; UNUSED(tc); srandom(time(NULL)); debug_mem_record = ISC_FALSE; result = dns_test_begin(NULL, ISC_TRUE); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); fnames = (dns_fixedname_t *) malloc(4000000 * sizeof(dns_fixedname_t)); names = (dns_name_t **) malloc(4000000 * sizeof(dns_name_t *)); values = (int *) malloc(4000000 * sizeof(int)); for (i = 0; i < 4000000; i++) { r = ((unsigned long) random()) % maxvalue; snprintf(namestr, sizeof(namestr), "name%u.example.org.", r); build_name_from_str(namestr, &fnames[i]); names[i] = dns_fixedname_name(&fnames[i]); values[i] = r; } /* Create a tree. */ mytree = NULL; result = dns_rbt_create(mctx, NULL, NULL, &mytree); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); /* Insert test data into the tree. */ for (i = 0; i < maxvalue; i++) { snprintf(namestr, sizeof(namestr), "name%u.example.org.", i); node = NULL; result = insert_helper(mytree, namestr, &node); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); node->data = (void *) (intptr_t) i; } result = isc_time_now(&ts1); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); nthreads = ISC_MIN(isc_os_ncpus(), 32); nthreads = ISC_MAX(nthreads, 1); for (i = 0; i < nthreads; i++) { result = isc_thread_create(find_thread, mytree, &threads[i]); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); } for (i = 0; i < nthreads; i++) { result = isc_thread_join(threads[i], NULL); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); } result = isc_time_now(&ts2); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); t = isc_time_microdiff(&ts2, &ts1); printf("%u findnode calls, %f seconds, %f calls/second\n", nthreads * 8 * 4000000, t / 1000000.0, (nthreads * 8 * 4000000) / (t / 1000000.0)); free(values); free(names); free(fnames); dns_rbt_destroy(&mytree); dns_test_end(); }
dns_dampening_state_t dns_dampening_query(dns_dampening_t * damp, const isc_sockaddr_t * addr, isc_stdtime_t now, int * penalty) { isc_netaddr_t netaddr, prefix; dns_dampening_state_t final_state = DNS_DAMPENING_STATE_NORMAL, state = DNS_DAMPENING_STATE_NORMAL; dns_dampening_entry_t * entry; dns_dampening_implementation_t *impl; int max_penalty = -2; RUNTIME_CHECK( damp != NULL ); RUNTIME_CHECK( addr != NULL ); isc_netaddr_fromsockaddr(&netaddr, addr); extract_prefix(&prefix, &netaddr, &(damp->prefixlen)); for(impl = damp->workers; impl - damp->workers < damp->workers_count; impl++) { if(damp->exempt != NULL) { int match; if (ISC_R_SUCCESS == dns_acl_match(&netaddr, NULL, damp->exempt, NULL, &match, NULL) && match > 0) { max_penalty = ISC_MAX(max_penalty, -1); DAMPENING_STATISTICS_INC(impl,skipped); continue; } } DAMPENING_STATISTICS_DO(impl, lock, LOCK(&impl->lock)); if(damp->statistics.report_interval > 0 && damp->statistics.report_interval + impl->statistics.last_report <= now) { if(isc_log_wouldlog(dns_lctx, ISC_LOG_INFO)) isc_log_write(dns_lctx, DNS_LOGCATEGORY_DAMPENING, DNS_LOGMODULE_REQUEST, ISC_LOG_INFO, "Stats for #%d: queries %u/%u/%u: lock=%ld.%06ld, search=%ld.%06ld, update=%ld.%06ld, add=%ld.%06ld", impl - damp->workers, impl->statistics.allowed, impl->statistics.denied, impl->statistics.skipped, impl->statistics.lock.tv_sec, impl->statistics.lock.tv_usec, impl->statistics.search.tv_sec, impl->statistics.search.tv_usec, impl->statistics.update.tv_sec, impl->statistics.update.tv_usec, impl->statistics.add.tv_sec, impl->statistics.add.tv_usec); memset(&impl->statistics, 0, sizeof(impl->statistics)); impl->statistics.last_report = now; } DAMPENING_STATISTICS_DO(impl, search, entry = impl->search(impl->data, &prefix)); if(entry == NULL) { state = DNS_DAMPENING_STATE_NORMAL; DAMPENING_STATISTICS_DO(impl, add, impl->add(impl->data, &prefix, damp->score.first_query, now)); max_penalty = ISC_MAX(max_penalty, 0); } else { state = entry->dampening == 1 ? DNS_DAMPENING_STATE_SUPPRESS : DNS_DAMPENING_STATE_NORMAL; max_penalty = ISC_MAX(max_penalty, entry->penalty); DAMPENING_STATISTICS_DO(impl, update, impl->update(impl->data, &entry, damp->score.per_query, now)); } if(state == DNS_DAMPENING_STATE_NORMAL) { DAMPENING_STATISTICS_INC(impl, allowed); } else { DAMPENING_STATISTICS_INC(impl, denied); final_state = state; /* any dampening suffice */ } UNLOCK(&impl->lock); } if(penalty != NULL) *penalty = max_penalty; return final_state; }