Beispiel #1
0
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);
}
Beispiel #2
0
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);
   }
}
Beispiel #3
0
/*
 * 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;
}
Beispiel #4
0
/*
 * 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;
}
Beispiel #5
0
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();
}
Beispiel #6
0
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;
}