Beispiel #1
0
void
dns_compress_add(dns_compress_t *cctx, const dns_name_t *name,
		 const dns_name_t *prefix, isc_uint16_t offset)
{
	dns_name_t tname;
	unsigned int start;
	unsigned int n;
	unsigned int count;
	unsigned int hash;
	dns_compressnode_t *node;
	unsigned int length;
	unsigned int tlength;
	isc_uint16_t toffset;

	REQUIRE(VALID_CCTX(cctx));
	REQUIRE(dns_name_isabsolute(name));

	dns_name_init(&tname, NULL);

	n = dns_name_countlabels(name);
	count = dns_name_countlabels(prefix);
	if (dns_name_isabsolute(prefix))
		count--;
	start = 0;
	length = name_length(name);
	while (count > 0) {
		if (offset >= 0x4000)
			break;
		dns_name_getlabelsequence(name, start, n, &tname);
		hash = dns_name_hash(&tname, ISC_FALSE) %
		       DNS_COMPRESS_TABLESIZE;
		tlength = name_length(&tname);
		toffset = (isc_uint16_t)(offset + (length - tlength));
		/*
		 * Create a new node and add it.
		 */
		if (cctx->count < DNS_COMPRESS_INITIALNODES)
			node = &cctx->initialnodes[cctx->count];
		else {
			node = isc_mem_get(cctx->mctx,
					   sizeof(dns_compressnode_t));
			if (node == NULL)
				return;
		}
		node->count = cctx->count++;
		node->offset = toffset;
		dns_name_toregion(&tname, &node->r);
		node->labels = (isc_uint8_t)dns_name_countlabels(&tname);
		node->next = cctx->table[hash];
		cctx->table[hash] = node;
		start++;
		n--;
		count--;
	}
}
Beispiel #2
0
/*
 * Find the longest match of name in the table.
 * If match is found return ISC_TRUE. prefix, suffix and offset are updated.
 * If no match is found return ISC_FALSE.
 */
isc_boolean_t
dns_compress_findglobal(dns_compress_t *cctx, const dns_name_t *name,
			dns_name_t *prefix, isc_uint16_t *offset)
{
	dns_name_t tname, nname;
	dns_compressnode_t *node = NULL;
	unsigned int labels, hash, n;

	REQUIRE(VALID_CCTX(cctx));
	REQUIRE(dns_name_isabsolute(name) == ISC_TRUE);
	REQUIRE(offset != NULL);

	if (cctx->count == 0)
		return (ISC_FALSE);

	labels = dns_name_countlabels(name);
	INSIST(labels > 0);

	dns_name_init(&tname, NULL);
	dns_name_init(&nname, NULL);

	for (n = 0; n < labels - 1; n++) {
		dns_name_getlabelsequence(name, n, labels - n, &tname);
		hash = dns_name_hash(&tname, ISC_FALSE) %
		       DNS_COMPRESS_TABLESIZE;
		for (node = cctx->table[hash]; node != NULL; node = node->next)
		{
			NODENAME(node, &nname);
			if ((cctx->allowed & DNS_COMPRESS_CASESENSITIVE) != 0) {
				if (dns_name_caseequal(&nname, &tname))
					break;
			} else {
				if (dns_name_equal(&nname, &tname))
					break;
			}
		}
		if (node != NULL)
			break;
	}

	/*
	 * If node == NULL, we found no match at all.
	 */
	if (node == NULL)
		return (ISC_FALSE);

	if (n == 0)
		dns_name_reset(prefix);
	else
		dns_name_getlabelsequence(name, 0, n, prefix);

	*offset = node->offset;
	return (ISC_TRUE);
}
Beispiel #3
0
void
dns_badcache_flushname(dns_badcache_t *bc, dns_name_t *name) {
	dns_bcentry_t *bad, *prev, *next;
	isc_result_t result;
	isc_time_t now;
	unsigned int i;

	REQUIRE(VALID_BADCACHE(bc));
	REQUIRE(name != NULL);

	LOCK(&bc->lock);

	result = isc_time_now(&now);
	if (result != ISC_R_SUCCESS)
		isc_time_settoepoch(&now);
	i = dns_name_hash(name, ISC_FALSE) % bc->size;
	prev = NULL;
	for (bad = bc->table[i]; bad != NULL; bad = next) {
		int n;
		next = bad->next;
		n = isc_time_compare(&bad->expire, &now);
		if (n < 0 || dns_name_equal(name, &bad->name)) {
			if (prev == NULL)
				bc->table[i] = bad->next;
			else
				prev->next = bad->next;

			isc_mem_put(bc->mctx, bad, sizeof(*bad) +
				    bad->name.length);
			bc->count--;
		} else
			prev = bad;
	}

	UNLOCK(&bc->lock);
}
Beispiel #4
0
isc_boolean_t
dns_badcache_find(dns_badcache_t *bc, dns_name_t *name,
		  dns_rdatatype_t type, isc_uint32_t *flagp,
		  isc_time_t *now)
{
	dns_bcentry_t *bad, *prev, *next;
	isc_boolean_t answer = ISC_FALSE;
	unsigned int i;

	REQUIRE(VALID_BADCACHE(bc));
	REQUIRE(name != NULL);
	REQUIRE(now != NULL);

	LOCK(&bc->lock);

	/*
	 * XXXMUKS: dns_name_equal() is expensive as it does a
	 * octet-by-octet comparison, and it can be made better in two
	 * ways here. First, lowercase the names (use
	 * dns_name_downcase() instead of dns_name_copy() in
	 * dns_badcache_add()) so that dns_name_caseequal() can be used
	 * which the compiler will emit as SIMD instructions. Second,
	 * don't put multiple copies of the same name in the chain (or
	 * multiple names will have to be matched for equality), but use
	 * name->link to store the type specific part.
	 */

	if (bc->count == 0)
		goto skip;

	i = dns_name_hash(name, ISC_FALSE) % bc->size;
	prev = NULL;
	for (bad = bc->table[i]; bad != NULL; bad = next) {
		next = bad->next;
		/*
		 * Search the hash list. Clean out expired records as we go.
		 */
		if (isc_time_compare(&bad->expire, now) < 0) {
			if (prev != NULL)
				prev->next = bad->next;
			else
				bc->table[i] = bad->next;

			isc_mem_put(bc->mctx, bad, sizeof(*bad) +
				    bad->name.length);
			bc->count--;
			continue;
		}
		if (bad->type == type && dns_name_equal(name, &bad->name)) {
			if (flagp != NULL)
				*flagp = bad->flags;
			answer = ISC_TRUE;
			break;
		}
		prev = bad;
	}
 skip:

	/*
	 * Slow sweep to clean out stale records.
	 */
	i = bc->sweep++ % bc->size;
	bad = bc->table[i];
	if (bad != NULL && isc_time_compare(&bad->expire, now) < 0) {
		bc->table[i] = bad->next;
		isc_mem_put(bc->mctx, bad, sizeof(*bad) + bad->name.length);
		bc->count--;
	}

	UNLOCK(&bc->lock);
	return (answer);
}
Beispiel #5
0
void
dns_badcache_add(dns_badcache_t *bc, dns_name_t *name,
		 dns_rdatatype_t type, isc_boolean_t update,
		 isc_uint32_t flags, isc_time_t *expire)
{
	isc_result_t result;
	unsigned int i, hashval;
	dns_bcentry_t *bad, *prev, *next;
	isc_time_t now;

	REQUIRE(VALID_BADCACHE(bc));
	REQUIRE(name != NULL);
	REQUIRE(expire != NULL);

	LOCK(&bc->lock);

	result = isc_time_now(&now);
	if (result != ISC_R_SUCCESS)
		isc_time_settoepoch(&now);

	hashval = dns_name_hash(name, ISC_FALSE);
	i = hashval % bc->size;
	prev = NULL;
	for (bad = bc->table[i]; bad != NULL; bad = next) {
		next = bad->next;
		if (bad->type == type && dns_name_equal(name, &bad->name)) {
			if (update) {
				bad->expire = *expire;
				bad->flags = flags;
			}
			break;
		}
		if (isc_time_compare(&bad->expire, &now) < 0) {
			if (prev == NULL)
				bc->table[i] = bad->next;
			else
				prev->next = bad->next;
			isc_mem_put(bc->mctx, bad,
				    sizeof(*bad) + bad->name.length);
			bc->count--;
		} else
			prev = bad;
	}

	if (bad == NULL) {
		isc_buffer_t buffer;
		bad = isc_mem_get(bc->mctx, sizeof(*bad) + name->length);
		if (bad == NULL)
			goto cleanup;
		bad->type = type;
		bad->hashval = hashval;
		bad->expire = *expire;
		bad->flags = flags;
		isc_buffer_init(&buffer, bad + 1, name->length);
		dns_name_init(&bad->name, NULL);
		dns_name_copy(name, &bad->name, &buffer);
		bad->next = bc->table[i];
		bc->table[i] = bad;
		bc->count++;
		if (bc->count > bc->size * 8)
			badcache_resize(bc, &now, ISC_TRUE);
		if (bc->count < bc->size * 2 && bc->size > bc->minsize)
			badcache_resize(bc, &now, ISC_FALSE);
	} else
		bad->expire = *expire;

 cleanup:
	UNLOCK(&bc->lock);
}