Exemplo n.º 1
0
isc_result_t
dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
		  isc_buffer_t *target, unsigned int options,
		  unsigned int *countp)
{
	dns_rdata_t rdata = DNS_RDATA_INIT;
	isc_result_t result;
	isc_region_t remaining, tavailable;
	isc_buffer_t source, savedbuffer, rdlen;
	dns_name_t name;
	dns_rdatatype_t type;
	unsigned int i, rcount, count;

	/*
	 * Convert the negative caching rdataset 'rdataset' to wire format,
	 * compressing names as specified in 'cctx', and storing the result in
	 * 'target'.
	 */

	REQUIRE(rdataset != NULL);
	REQUIRE(rdataset->type == 0);
	REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);

	savedbuffer = *target;
	count = 0;

	result = dns_rdataset_first(rdataset);
	while (result == ISC_R_SUCCESS) {
		dns_rdataset_current(rdataset, &rdata);
		isc_buffer_init(&source, rdata.data, rdata.length);
		isc_buffer_add(&source, rdata.length);
		dns_name_init(&name, NULL);
		isc_buffer_remainingregion(&source, &remaining);
		dns_name_fromregion(&name, &remaining);
		INSIST(remaining.length >= name.length);
		isc_buffer_forward(&source, name.length);
		remaining.length -= name.length;

		INSIST(remaining.length >= 5);
		type = isc_buffer_getuint16(&source);
		isc_buffer_forward(&source, 1);
		rcount = isc_buffer_getuint16(&source);

		for (i = 0; i < rcount; i++) {
			/*
			 * Get the length of this rdata and set up an
			 * rdata structure for it.
			 */
			isc_buffer_remainingregion(&source, &remaining);
			INSIST(remaining.length >= 2);
			dns_rdata_reset(&rdata);
			rdata.length = isc_buffer_getuint16(&source);
			isc_buffer_remainingregion(&source, &remaining);
			rdata.data = remaining.base;
			rdata.type = type;
			rdata.rdclass = rdataset->rdclass;
			INSIST(remaining.length >= rdata.length);
			isc_buffer_forward(&source, rdata.length);

			if ((options & DNS_NCACHETOWIRE_OMITDNSSEC) != 0 &&
			    dns_rdatatype_isdnssec(type))
				continue;

			/*
			 * Write the name.
			 */
			dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
			result = dns_name_towire(&name, cctx, target);
			if (result != ISC_R_SUCCESS)
				goto rollback;

			/*
			 * See if we have space for type, class, ttl, and
			 * rdata length.  Write the type, class, and ttl.
			 */
			isc_buffer_availableregion(target, &tavailable);
			if (tavailable.length < 10) {
				result = ISC_R_NOSPACE;
				goto rollback;
			}
			isc_buffer_putuint16(target, type);
			isc_buffer_putuint16(target, rdataset->rdclass);
			isc_buffer_putuint32(target, rdataset->ttl);

			/*
			 * Save space for rdata length.
			 */
			rdlen = *target;
			isc_buffer_add(target, 2);

			/*
			 * Write the rdata.
			 */
			result = dns_rdata_towire(&rdata, cctx, target);
			if (result != ISC_R_SUCCESS)
				goto rollback;

			/*
			 * Set the rdata length field to the compressed
			 * length.
			 */
			INSIST((target->used >= rdlen.used + 2) &&
			       (target->used - rdlen.used - 2 < 65536));
			isc_buffer_putuint16(&rdlen,
					     (isc_uint16_t)(target->used -
							    rdlen.used - 2));

			count++;
		}
		INSIST(isc_buffer_remaininglength(&source) == 0);
		result = dns_rdataset_next(rdataset);
		dns_rdata_reset(&rdata);
	}
	if (result != ISC_R_NOMORE)
		goto rollback;

	*countp = count;

	return (ISC_R_SUCCESS);

 rollback:
	INSIST(savedbuffer.used < 65536);
	dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
	*countp = 0;
	*target = savedbuffer;

	return (result);
}
Exemplo n.º 2
0
static isc_result_t
towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
	     dns_compress_t *cctx, isc_buffer_t *target,
	     dns_rdatasetorderfunc_t order, const void *order_arg,
	     isc_boolean_t partial, unsigned int options,
	     unsigned int *countp, void **state)
{
	dns_rdata_t rdata = DNS_RDATA_INIT;
	isc_region_t r;
	isc_result_t result;
	unsigned int i, count = 0, added, choice;
	isc_buffer_t savedbuffer, rdlen, rrbuffer;
	unsigned int headlen;
	isc_boolean_t question = ISC_FALSE;
	isc_boolean_t shuffle = ISC_FALSE;
	dns_rdata_t *shuffled = NULL, shuffled_fixed[MAX_SHUFFLE];
	struct towire_sort *sorted = NULL, sorted_fixed[MAX_SHUFFLE];

	/* count processed auswer ips */
	int answer_count = 0;
	int is_no_auth_answer    = 0;
	/* tmp count for record */
	int tmp_count = 0;

	UNUSED(state);

	/*
	 * Convert 'rdataset' to wire format, compressing names as specified
	 * in cctx, and storing the result in 'target'.
	 */

	REQUIRE(DNS_RDATASET_VALID(rdataset));
	REQUIRE(countp != NULL);
	REQUIRE((order == NULL) == (order_arg == NULL));
	REQUIRE(cctx != NULL && cctx->mctx != NULL);

	if ((rdataset->attributes & DNS_RDATASETATTR_QUESTION) != 0) {
		question = ISC_TRUE;
		count = 1;
		result = dns_rdataset_first(rdataset);
		INSIST(result == ISC_R_NOMORE);
	} else if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
		/*
		 * This is a negative caching rdataset.
		 */
		unsigned int ncache_opts = 0;
		if ((options & DNS_RDATASETTOWIRE_OMITDNSSEC) != 0)
			ncache_opts |= DNS_NCACHETOWIRE_OMITDNSSEC;
		return (dns_ncache_towire(rdataset, cctx, target, ncache_opts,
					  countp));
	} else {
		count = (rdataset->methods->count)(rdataset);
		result = dns_rdataset_first(rdataset);
		if (result == ISC_R_NOMORE)
			return (ISC_R_SUCCESS);
		if (result != ISC_R_SUCCESS)
			return (result);
	}

	/*
	 * Do we want to shuffle this answer?
	 */
	if (!question && count > 1 &&
	    (!WANT_FIXED(rdataset) || order != NULL) &&
	    rdataset->type != dns_rdatatype_rrsig)
		shuffle = ISC_TRUE;

	if (shuffle && count > MAX_SHUFFLE) {
		shuffled = isc_mem_get(cctx->mctx, count * sizeof(*shuffled));
		sorted = isc_mem_get(cctx->mctx, count * sizeof(*sorted));
		if (shuffled == NULL || sorted == NULL)
			shuffle = ISC_FALSE;
	} else {
		shuffled = shuffled_fixed;
		sorted = sorted_fixed;
	}

	if (shuffle) {
		/*
		 * First we get handles to all of the rdata.
		 */
		i = 0;
		do {
			INSIST(i < count);
			dns_rdata_init(&shuffled[i]);
			dns_rdataset_current(rdataset, &shuffled[i]);
			i++;
			result = dns_rdataset_next(rdataset);
		} while (result == ISC_R_SUCCESS);
		if (result != ISC_R_NOMORE)
			goto cleanup;
		INSIST(i == count);

		/*
		 * Now we shuffle.
		 */
		if (WANT_FIXED(rdataset)) {
			/*
			 * 'Fixed' order.
			 */
			INSIST(order != NULL);
			for (i = 0; i < count; i++) {
				sorted[i].key = (*order)(&shuffled[i],
							 order_arg);
				sorted[i].rdata = &shuffled[i];
			}
		} else if (WANT_RANDOM(rdataset)) {
			/*
			 * 'Random' order.
			 */
			for (i = 0; i < count; i++) {
				dns_rdata_t rdata;
				isc_uint32_t val;

				isc_random_get(&val);
				choice = i + (val % (count - i));
				rdata = shuffled[i];
				shuffled[i] = shuffled[choice];
				shuffled[choice] = rdata;
				if (order != NULL)
					sorted[i].key = (*order)(&shuffled[i],
								 order_arg);
				else
					sorted[i].key = 0; /* Unused */
				sorted[i].rdata = &shuffled[i];
			}
		} else {
			/*
			 * "Cyclic" order.
			 */
			isc_uint32_t val;
			unsigned int j;

			val = rdataset->count;
			if (val == ISC_UINT32_MAX)
				isc_random_get(&val);
			j = val % count;
			for (i = 0; i < count; i++) {
				if (order != NULL)
					sorted[i].key = (*order)(&shuffled[j],
								 order_arg);
				else
					sorted[i].key = 0; /* Unused */
				sorted[i].rdata = &shuffled[j];
				j++;
				if (j == count)
					j = 0; /* Wrap around. */
			}
		}

		/*
		 * Sorted order.
		 */
		if (order != NULL)
			qsort(sorted, count, sizeof(sorted[0]),
			      towire_compare);
	}

	savedbuffer = *target;
	i = 0;
	added = 0;

	// save the count here
	tmp_count = count;

	do {
		/*
		 * Copy out the name, type, class, ttl.
		 */
			/* mark if is answer data. */
			is_no_auth_answer = 0;
			/* Answer from a non-authoritative server,we set the ttl fixed as 500. */
			if(rdataset->attributes == DNS_RDATASETATTR_LOADORDER && 
					rdataset->type == dns_rdatatype_a){
				/* Answer from a non-authoritative server,we set the ttl fixed as 500. */
				if(rdataset->trust == dns_trust_answer ){
					is_no_auth_answer = 1;
				}

				/* for all multi-ip answer,if set DNS_ANSWER_ONLY_ONE_IP flag, return only 1 ip. */
				if(answer_count == 0){
					answer_count ++;
				}else{
					if( DNS_ANSWER_ONLY_ONE_IP ){
						//fprintf(stderr,"DNS_ANSWER_ONLY_ONE_IP set,skip. \n");
						if (shuffle) {
							tmp_count--;
							if (i == tmp_count)
								result = ISC_R_NOMORE;
							else
								result = ISC_R_SUCCESS;
						} else {
							result = dns_rdataset_next(rdataset);
						}
						continue;
					}
				}
			}


			rrbuffer = *target;
		dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
		result = dns_name_towire(owner_name, cctx, target);
		if (result != ISC_R_SUCCESS)
			goto rollback;
		headlen = sizeof(dns_rdataclass_t) + sizeof(dns_rdatatype_t);
		if (!question)
			headlen += sizeof(dns_ttl_t)
				+ 2;  /* XXX 2 for rdata len */
		isc_buffer_availableregion(target, &r);
		if (r.length < headlen) {
			result = ISC_R_NOSPACE;
			goto rollback;
		}

		isc_buffer_putuint16(target, rdataset->type);
		isc_buffer_putuint16(target, rdataset->rdclass);
		if (!question) {
			
			if( is_no_auth_answer ){
					isc_buffer_putuint32(target, DNS_DEFAULT_TTL_FOR_NO_AUTH_NAME);
			}else{
					isc_buffer_putuint32(target, rdataset->ttl);
			}
			//fprintf(stderr,"xxxxxxxxx:trust : %d artr: %d ttl:%d  cover: %d type: %d count: %d class: %d\n", rdataset->trust,rdataset->attributes,rdataset->ttl, rdataset->covers,rdataset->type, rdataset->count, rdataset->rdclass);

			/*
			 * Save space for rdlen.
			 */
			rdlen = *target;
			isc_buffer_add(target, 2);

			/*
			 * Copy out the rdata
			 */
			if (shuffle)
				rdata = *(sorted[i].rdata);
			else {
				dns_rdata_reset(&rdata);
				dns_rdataset_current(rdataset, &rdata);
			}
			result = dns_rdata_towire(&rdata, cctx, target);
			if (result != ISC_R_SUCCESS)
				goto rollback;
			INSIST((target->used >= rdlen.used + 2) &&
			       (target->used - rdlen.used - 2 < 65536));
			isc_buffer_putuint16(&rdlen,
					     (isc_uint16_t)(target->used -
							    rdlen.used - 2));
			added++;
		}

		if (shuffle) {
			i++;
			if (i == tmp_count)
				result = ISC_R_NOMORE;
			else
				result = ISC_R_SUCCESS;
		} else {
			result = dns_rdataset_next(rdataset);
		}
	} while (result == ISC_R_SUCCESS);

	if (result != ISC_R_NOMORE)
		goto rollback;

	*countp += tmp_count;

	result = ISC_R_SUCCESS;
	goto cleanup;

 rollback:
	if (partial && result == ISC_R_NOSPACE) {
		INSIST(rrbuffer.used < 65536);
		dns_compress_rollback(cctx, (isc_uint16_t)rrbuffer.used);
		*countp += added;
		*target = rrbuffer;
		goto cleanup;
	}
	INSIST(savedbuffer.used < 65536);
	dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
	*countp = 0;
	*target = savedbuffer;

 cleanup:
	if (sorted != NULL && sorted != sorted_fixed)
		isc_mem_put(cctx->mctx, sorted, count * sizeof(*sorted));
	if (shuffled != NULL && shuffled != shuffled_fixed)
		isc_mem_put(cctx->mctx, shuffled, count * sizeof(*shuffled));
	return (result);
}