Esempio 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);
}
Esempio 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, 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];

    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);

    count = 0;
    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->type == 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 anwer?
     */
    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[j].key = (*order)(&shuffled[i],
                                             order_arg);
                else
                    sorted[j].key = 0; /* Unused */
                sorted[j].rdata = &shuffled[i];
                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;

    do {
        /*
         * Copy out the name, type, class, ttl.
         */

        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) {
            isc_buffer_putuint32(target, rdataset->ttl);

            /*
             * 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 == 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 += 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);
}
Esempio n. 3
0
void
test(unsigned int allowed, dns_name_t *name1, dns_name_t *name2,
     dns_name_t *name3, unsigned char *result, unsigned int length)
{
	isc_mem_t *mctx = NULL;
	dns_compress_t cctx;
	dns_decompress_t dctx;
	isc_buffer_t source;
	isc_buffer_t target;
	dns_name_t name;
	unsigned char buf1[1024];
	unsigned char buf2[1024];

	if (verbose) {
		const char *s;
		switch (allowed) {
		case DNS_COMPRESS_NONE: s = "DNS_COMPRESS_NONE"; break;
		case DNS_COMPRESS_GLOBAL14: s = "DNS_COMPRESS_GLOBAL14"; break;
		/* case DNS_COMPRESS_ALL: s = "DNS_COMPRESS_ALL"; break; */
		default: s = "UNKNOWN"; break;
		}
		fprintf(stdout, "Allowed = %s\n", s);
	}
	RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
	isc_buffer_init(&source, buf1, sizeof(buf1));
	RUNTIME_CHECK(dns_compress_init(&cctx, -1, mctx) == ISC_R_SUCCESS);

	RUNTIME_CHECK(dns_name_towire(name1, &cctx, &source) == ISC_R_SUCCESS);

	/*
	RUNTIME_CHECK(dns_compress_localinit(&cctx, name1, &source) ==
		      ISC_R_SUCCESS);
	*/
	dns_compress_setmethods(&cctx, allowed);
	RUNTIME_CHECK(dns_name_towire(name2, &cctx, &source) == ISC_R_SUCCESS);
	RUNTIME_CHECK(dns_name_towire(name2, &cctx, &source) == ISC_R_SUCCESS);
	RUNTIME_CHECK(dns_name_towire(name3, &cctx, &source) == ISC_R_SUCCESS);

	/*
	dns_compress_localinvalidate(&cctx);
	*/
	dns_compress_rollback(&cctx, 0);	/* testing only */
	dns_compress_invalidate(&cctx);

	if (raw) {
		unsigned int i;
		for (i = 0; i < source.used; /* */ ) {
			fprintf(stdout, "%02x",
				((unsigned char *)source.base)[i]);
			if ((++i % 20) == 0)
				fputs("\n", stdout);
			else
				if (i == source.used)
					fputs("\n", stdout);
				else
					fputs(" ", stdout);
		}
	}

	isc_buffer_setactive(&source, source.used);
	isc_buffer_init(&target, buf2, sizeof(buf2));
	dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_STRICT);

	dns_name_init(&name, NULL);
	RUNTIME_CHECK(dns_name_fromwire(&name, &source, &dctx, ISC_FALSE,
					&target) == ISC_R_SUCCESS);
	dns_decompress_setmethods(&dctx, allowed);
	/*
	dns_decompress_localinit(&dctx, &name, &source);
	*/
	RUNTIME_CHECK(dns_name_fromwire(&name, &source, &dctx, ISC_FALSE,
					&target) == ISC_R_SUCCESS);
	RUNTIME_CHECK(dns_name_fromwire(&name, &source, &dctx, ISC_FALSE,
					&target) == ISC_R_SUCCESS);
	RUNTIME_CHECK(dns_name_fromwire(&name, &source, &dctx, ISC_FALSE,
					&target) == ISC_R_SUCCESS);
	/*
	dns_decompress_localinvalidate(&dctx);
	*/
	dns_decompress_invalidate(&dctx);

	if (raw) {
		unsigned int i;
		for (i = 0; i < target.used; /* */ ) {
			fprintf(stdout, "%02x",
				((unsigned char *)target.base)[i]);
			if ((++i % 20) == 0)
				fputs("\n", stdout);
			else
				if (i == target.used)
					fputs("\n", stdout);
				else
					fputs(" ", stdout);
		}
		fputs("\n", stdout);
		fflush(stdout);
	}

	RUNTIME_CHECK(target.used == length);
	RUNTIME_CHECK(memcmp(target.base, result, target.used) == 0);
	isc_mem_destroy(&mctx);
}