1999-01-15 03:31:17 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 1999 Internet Software Consortium.
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
|
|
|
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
|
|
|
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
|
|
|
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
|
|
|
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|
|
|
* SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
1999-01-22 01:21:44 +00:00
|
|
|
#include <config.h>
|
|
|
|
|
1999-01-15 03:31:17 +00:00
|
|
|
#include <stddef.h>
|
1999-01-15 19:36:07 +00:00
|
|
|
#include <string.h>
|
1999-01-15 03:31:17 +00:00
|
|
|
|
|
|
|
#include <isc/assertions.h>
|
|
|
|
|
1999-09-22 00:26:40 +00:00
|
|
|
#include <dns/ncache.h>
|
1999-01-15 19:36:07 +00:00
|
|
|
#include <dns/rdata.h>
|
1999-01-20 07:49:30 +00:00
|
|
|
#include <dns/rdataclass.h>
|
|
|
|
#include <dns/rdatatype.h>
|
1999-01-15 03:31:17 +00:00
|
|
|
#include <dns/rdataset.h>
|
1999-02-22 07:24:05 +00:00
|
|
|
#include <dns/compress.h>
|
1999-01-15 03:31:17 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
dns_rdataset_init(dns_rdataset_t *rdataset) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make 'rdataset' a valid, disassociated rdataset.
|
|
|
|
*/
|
|
|
|
|
|
|
|
REQUIRE(rdataset != NULL);
|
|
|
|
|
1999-01-15 08:07:09 +00:00
|
|
|
rdataset->magic = DNS_RDATASET_MAGIC;
|
1999-01-15 03:31:17 +00:00
|
|
|
rdataset->methods = NULL;
|
|
|
|
ISC_LINK_INIT(rdataset, link);
|
1999-03-04 02:48:47 +00:00
|
|
|
rdataset->rdclass = 0;
|
1999-01-15 03:31:17 +00:00
|
|
|
rdataset->type = 0;
|
|
|
|
rdataset->ttl = 0;
|
1999-06-16 23:47:09 +00:00
|
|
|
rdataset->trust = 0;
|
1999-08-31 22:14:06 +00:00
|
|
|
rdataset->covers = 0;
|
1999-05-21 00:48:45 +00:00
|
|
|
rdataset->attributes = 0;
|
1999-01-15 03:31:17 +00:00
|
|
|
rdataset->private1 = NULL;
|
|
|
|
rdataset->private2 = NULL;
|
|
|
|
rdataset->private3 = NULL;
|
1999-01-29 22:19:38 +00:00
|
|
|
rdataset->private4 = NULL;
|
|
|
|
rdataset->private5 = NULL;
|
1999-01-15 03:31:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_rdataset_invalidate(dns_rdataset_t *rdataset) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Invalidate 'rdataset'.
|
|
|
|
*/
|
|
|
|
|
1999-01-15 08:07:09 +00:00
|
|
|
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
1999-01-15 03:31:17 +00:00
|
|
|
REQUIRE(rdataset->methods == NULL);
|
|
|
|
|
|
|
|
rdataset->magic = 0;
|
|
|
|
ISC_LINK_INIT(rdataset, link);
|
1999-03-04 02:48:47 +00:00
|
|
|
rdataset->rdclass = 0;
|
1999-01-15 03:31:17 +00:00
|
|
|
rdataset->type = 0;
|
|
|
|
rdataset->ttl = 0;
|
1999-06-16 23:47:09 +00:00
|
|
|
rdataset->trust = 0;
|
1999-08-31 22:14:06 +00:00
|
|
|
rdataset->covers = 0;
|
1999-05-21 00:48:45 +00:00
|
|
|
rdataset->attributes = 0;
|
1999-01-15 03:31:17 +00:00
|
|
|
rdataset->private1 = NULL;
|
|
|
|
rdataset->private2 = NULL;
|
|
|
|
rdataset->private3 = NULL;
|
1999-01-29 22:19:38 +00:00
|
|
|
rdataset->private4 = NULL;
|
|
|
|
rdataset->private5 = NULL;
|
1999-01-15 03:31:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_rdataset_disassociate(dns_rdataset_t *rdataset) {
|
|
|
|
|
|
|
|
/*
|
1999-01-28 23:52:24 +00:00
|
|
|
* Disassociate 'rdataset' from its rdata, allowing it to be reused.
|
1999-01-15 03:31:17 +00:00
|
|
|
*/
|
|
|
|
|
1999-01-15 08:07:09 +00:00
|
|
|
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
1999-04-01 04:01:30 +00:00
|
|
|
REQUIRE(rdataset->methods != NULL);
|
1999-01-15 03:31:17 +00:00
|
|
|
|
|
|
|
(rdataset->methods->disassociate)(rdataset);
|
|
|
|
rdataset->methods = NULL;
|
|
|
|
ISC_LINK_INIT(rdataset, link);
|
1999-03-04 02:48:47 +00:00
|
|
|
rdataset->rdclass = 0;
|
1999-01-15 03:31:17 +00:00
|
|
|
rdataset->type = 0;
|
|
|
|
rdataset->ttl = 0;
|
1999-06-16 23:47:09 +00:00
|
|
|
rdataset->trust = 0;
|
1999-08-31 22:14:06 +00:00
|
|
|
rdataset->covers = 0;
|
1999-05-21 00:48:45 +00:00
|
|
|
rdataset->attributes = 0;
|
1999-01-15 03:31:17 +00:00
|
|
|
rdataset->private1 = NULL;
|
|
|
|
rdataset->private2 = NULL;
|
|
|
|
rdataset->private3 = NULL;
|
1999-01-29 22:19:38 +00:00
|
|
|
rdataset->private4 = NULL;
|
|
|
|
rdataset->private5 = NULL;
|
1999-01-15 03:31:17 +00:00
|
|
|
}
|
|
|
|
|
1999-08-19 20:44:56 +00:00
|
|
|
isc_boolean_t
|
|
|
|
dns_rdataset_isassociated(dns_rdataset_t *rdataset) {
|
|
|
|
/*
|
|
|
|
* Is 'rdataset' associated?
|
|
|
|
*/
|
|
|
|
|
|
|
|
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
|
|
|
|
|
|
|
if (rdataset->methods != NULL)
|
|
|
|
return (ISC_TRUE);
|
|
|
|
|
|
|
|
return (ISC_FALSE);
|
|
|
|
}
|
|
|
|
|
1999-07-03 20:52:50 +00:00
|
|
|
static void
|
|
|
|
question_disassociate(dns_rdataset_t *rdataset) {
|
|
|
|
(void)rdataset;
|
|
|
|
}
|
|
|
|
|
|
|
|
static dns_result_t
|
|
|
|
question_cursor(dns_rdataset_t *rdataset) {
|
|
|
|
(void)rdataset;
|
|
|
|
return (DNS_R_NOMORE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
question_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
|
|
|
|
/*
|
|
|
|
* This routine should never be called.
|
|
|
|
*/
|
|
|
|
(void)rdataset;
|
|
|
|
(void)rdata;
|
|
|
|
REQUIRE(0);
|
|
|
|
}
|
|
|
|
|
1999-07-13 01:50:22 +00:00
|
|
|
static void
|
|
|
|
question_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
|
|
|
|
*target = *source;
|
|
|
|
}
|
|
|
|
|
1999-09-21 20:40:42 +00:00
|
|
|
static unsigned int
|
|
|
|
question_count(dns_rdataset_t *rdataset) {
|
|
|
|
/*
|
|
|
|
* This routine should never be called.
|
|
|
|
*/
|
|
|
|
(void)rdataset;
|
|
|
|
REQUIRE(0);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1999-07-03 20:52:50 +00:00
|
|
|
static dns_rdatasetmethods_t question_methods = {
|
|
|
|
question_disassociate,
|
|
|
|
question_cursor,
|
|
|
|
question_cursor,
|
1999-07-13 01:50:22 +00:00
|
|
|
question_current,
|
1999-08-31 22:14:06 +00:00
|
|
|
question_clone,
|
1999-09-21 20:40:42 +00:00
|
|
|
question_count
|
1999-07-03 20:52:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_rdataset_makequestion(dns_rdataset_t *rdataset, dns_rdataclass_t rdclass,
|
|
|
|
dns_rdatatype_t type)
|
|
|
|
{
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make 'rdataset' a valid, associated, question rdataset, with a
|
|
|
|
* question class of 'rdclass' and type 'type'.
|
|
|
|
*/
|
|
|
|
|
|
|
|
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
|
|
|
REQUIRE(rdataset->methods == NULL);
|
|
|
|
|
|
|
|
rdataset->methods = &question_methods;
|
|
|
|
rdataset->rdclass = rdclass;
|
|
|
|
rdataset->type = type;
|
|
|
|
rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
|
|
|
|
}
|
|
|
|
|
1999-09-21 20:40:42 +00:00
|
|
|
unsigned int
|
|
|
|
dns_rdataset_count(dns_rdataset_t *rdataset) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return the number of records in 'rdataset'.
|
|
|
|
*/
|
|
|
|
|
|
|
|
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
|
|
|
REQUIRE(rdataset->methods != NULL);
|
|
|
|
|
|
|
|
return ((rdataset->methods->count)(rdataset));
|
|
|
|
}
|
|
|
|
|
1999-07-13 01:50:22 +00:00
|
|
|
void
|
|
|
|
dns_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make 'target' refer to the same rdataset as 'source'.
|
|
|
|
*/
|
|
|
|
|
|
|
|
REQUIRE(DNS_RDATASET_VALID(source));
|
|
|
|
REQUIRE(source->methods != NULL);
|
|
|
|
REQUIRE(DNS_RDATASET_VALID(target));
|
|
|
|
REQUIRE(target->methods == NULL);
|
|
|
|
|
|
|
|
(source->methods->clone)(source, target);
|
|
|
|
}
|
|
|
|
|
1999-01-15 03:31:17 +00:00
|
|
|
dns_result_t
|
|
|
|
dns_rdataset_first(dns_rdataset_t *rdataset) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Move the rdata cursor to the first rdata in the rdataset (if any).
|
|
|
|
*/
|
|
|
|
|
1999-01-15 08:07:09 +00:00
|
|
|
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
1999-04-01 04:01:30 +00:00
|
|
|
REQUIRE(rdataset->methods != NULL);
|
1999-01-15 03:31:17 +00:00
|
|
|
|
|
|
|
return ((rdataset->methods->first)(rdataset));
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_result_t
|
|
|
|
dns_rdataset_next(dns_rdataset_t *rdataset) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Move the rdata cursor to the next rdata in the rdataset (if any).
|
|
|
|
*/
|
|
|
|
|
1999-01-15 08:07:09 +00:00
|
|
|
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
1999-04-01 04:01:30 +00:00
|
|
|
REQUIRE(rdataset->methods != NULL);
|
1999-01-15 03:31:17 +00:00
|
|
|
|
|
|
|
return ((rdataset->methods->next)(rdataset));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make 'rdata' refer to the current rdata.
|
|
|
|
*/
|
|
|
|
|
1999-01-15 08:07:09 +00:00
|
|
|
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
1999-04-01 04:01:30 +00:00
|
|
|
REQUIRE(rdataset->methods != NULL);
|
1999-01-15 03:31:17 +00:00
|
|
|
|
|
|
|
(rdataset->methods->current)(rdataset, rdata);
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_result_t
|
|
|
|
dns_rdataset_towire(dns_rdataset_t *rdataset,
|
|
|
|
dns_name_t *owner_name,
|
|
|
|
dns_compress_t *cctx,
|
1999-01-30 05:01:01 +00:00
|
|
|
isc_buffer_t *target,
|
1999-04-30 21:15:02 +00:00
|
|
|
unsigned int *countp)
|
1999-01-15 03:31:17 +00:00
|
|
|
{
|
1999-01-27 05:54:39 +00:00
|
|
|
dns_rdata_t rdata;
|
|
|
|
isc_region_t r;
|
|
|
|
dns_result_t result;
|
1999-01-30 05:01:01 +00:00
|
|
|
unsigned int count;
|
1999-09-22 00:26:40 +00:00
|
|
|
isc_buffer_t savedbuffer, rdlen;
|
1999-04-30 07:08:55 +00:00
|
|
|
unsigned int headlen;
|
1999-07-03 20:52:50 +00:00
|
|
|
isc_boolean_t question = ISC_FALSE;
|
1999-01-15 03:31:17 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert 'rdataset' to wire format, compressing names as specified
|
|
|
|
* in cctx, and storing the result in 'target'.
|
|
|
|
*/
|
|
|
|
|
1999-01-15 19:36:07 +00:00
|
|
|
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
1999-01-30 05:01:01 +00:00
|
|
|
REQUIRE(countp != NULL);
|
1999-01-15 19:36:07 +00:00
|
|
|
|
1999-08-03 20:54:56 +00:00
|
|
|
if ((rdataset->attributes & DNS_RDATASETATTR_QUESTION) != 0) {
|
1999-07-03 20:52:50 +00:00
|
|
|
question = ISC_TRUE;
|
1999-08-03 20:54:56 +00:00
|
|
|
result = dns_rdataset_first(rdataset);
|
|
|
|
INSIST(result == DNS_R_NOMORE);
|
1999-09-22 00:26:40 +00:00
|
|
|
} else if (rdataset->type == 0) {
|
|
|
|
/*
|
|
|
|
* This is a negative caching rdataset.
|
|
|
|
*/
|
|
|
|
return (dns_ncache_towire(rdataset, cctx, target, countp));
|
1999-08-03 20:54:56 +00:00
|
|
|
} else {
|
1999-07-03 20:52:50 +00:00
|
|
|
result = dns_rdataset_first(rdataset);
|
1999-08-03 13:30:54 +00:00
|
|
|
if (result == DNS_R_NOMORE)
|
|
|
|
return (DNS_R_SUCCESS);
|
1999-07-03 20:52:50 +00:00
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
1999-09-22 00:26:40 +00:00
|
|
|
savedbuffer = *target;
|
|
|
|
|
1999-01-30 05:01:01 +00:00
|
|
|
count = 0;
|
1999-01-27 05:54:39 +00:00
|
|
|
do {
|
|
|
|
/*
|
|
|
|
* copy out the name, type, class, ttl.
|
|
|
|
*/
|
1999-02-22 07:24:05 +00:00
|
|
|
if (dns_compress_getedns(cctx) >= 1)
|
|
|
|
dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL);
|
|
|
|
else
|
|
|
|
dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
|
1999-01-27 05:54:39 +00:00
|
|
|
result = dns_name_towire(owner_name, cctx, target);
|
1999-09-22 00:26:40 +00:00
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
goto rollback;
|
1999-04-30 07:08:55 +00:00
|
|
|
headlen = sizeof(dns_rdataclass_t) + sizeof(dns_rdatatype_t);
|
1999-07-03 20:52:50 +00:00
|
|
|
if (!question)
|
1999-04-30 07:08:55 +00:00
|
|
|
headlen += sizeof(dns_ttl_t)
|
|
|
|
+ 2; /* XXX 2 for rdata len */
|
1999-01-27 05:54:39 +00:00
|
|
|
isc_buffer_available(target, &r);
|
1999-04-30 07:08:55 +00:00
|
|
|
if (r.length < headlen) {
|
1999-09-22 00:26:40 +00:00
|
|
|
result = ISC_R_NOSPACE;
|
|
|
|
goto rollback;
|
1999-02-22 07:24:05 +00:00
|
|
|
}
|
1999-01-27 06:18:45 +00:00
|
|
|
isc_buffer_putuint16(target, rdataset->type);
|
1999-03-04 02:48:47 +00:00
|
|
|
isc_buffer_putuint16(target, rdataset->rdclass);
|
1999-07-03 20:52:50 +00:00
|
|
|
if (!question) {
|
1999-04-30 07:08:55 +00:00
|
|
|
isc_buffer_putuint32(target, rdataset->ttl);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Save space for rdlen.
|
|
|
|
*/
|
|
|
|
rdlen = *target;
|
|
|
|
isc_buffer_add(target, 2);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* copy out the rdata
|
|
|
|
*/
|
|
|
|
dns_rdataset_current(rdataset, &rdata);
|
|
|
|
result = dns_compress_localinit(cctx, owner_name,
|
|
|
|
target);
|
1999-09-22 00:26:40 +00:00
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
goto rollback;
|
1999-04-30 07:08:55 +00:00
|
|
|
result = dns_rdata_towire(&rdata, cctx, target);
|
|
|
|
dns_compress_localinvalidate(cctx);
|
1999-09-22 00:26:40 +00:00
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
goto rollback;
|
1999-10-17 22:40:05 +00:00
|
|
|
INSIST((target->used >= rdlen.used + 2) &&
|
|
|
|
(target->used - rdlen.used - 2 < 65536));
|
1999-04-30 07:08:55 +00:00
|
|
|
isc_buffer_putuint16(&rdlen,
|
1999-10-17 22:40:05 +00:00
|
|
|
(isc_uint16_t)(target->used -
|
|
|
|
rdlen.used - 2));
|
1999-02-22 07:24:05 +00:00
|
|
|
}
|
1999-01-27 05:54:39 +00:00
|
|
|
|
1999-01-30 05:01:01 +00:00
|
|
|
count++;
|
|
|
|
|
1999-01-27 05:54:39 +00:00
|
|
|
result = dns_rdataset_next(rdataset);
|
|
|
|
} while (result == DNS_R_SUCCESS);
|
|
|
|
|
|
|
|
if (result != DNS_R_NOMORE)
|
|
|
|
return (result);
|
|
|
|
|
1999-01-30 05:01:01 +00:00
|
|
|
*countp += count;
|
|
|
|
|
1999-01-27 05:54:39 +00:00
|
|
|
return (DNS_R_SUCCESS);
|
1999-09-22 00:26:40 +00:00
|
|
|
|
|
|
|
rollback:
|
1999-10-17 22:40:05 +00:00
|
|
|
INSIST(savedbuffer.used < 65536);
|
|
|
|
dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
|
1999-09-22 00:26:40 +00:00
|
|
|
*countp = 0;
|
|
|
|
*target = savedbuffer;
|
|
|
|
|
|
|
|
return (result);
|
1999-01-15 03:31:17 +00:00
|
|
|
}
|
1999-08-02 22:18:31 +00:00
|
|
|
|
|
|
|
dns_result_t
|
|
|
|
dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
|
|
|
|
dns_additionaldatafunc_t add, void *arg)
|
|
|
|
{
|
|
|
|
dns_rdata_t rdata;
|
|
|
|
dns_result_t result;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For each rdata in rdataset, call 'add' for each name and type in the
|
|
|
|
* rdata which is subject to additional section processing.
|
|
|
|
*/
|
|
|
|
|
|
|
|
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
|
|
|
REQUIRE((rdataset->attributes & DNS_RDATASETATTR_QUESTION) == 0);
|
|
|
|
|
|
|
|
result = dns_rdataset_first(rdataset);
|
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
|
|
|
|
do {
|
|
|
|
dns_rdataset_current(rdataset, &rdata);
|
|
|
|
result = dns_rdata_additionaldata(&rdata, add, arg);
|
|
|
|
if (result == DNS_R_SUCCESS)
|
|
|
|
result = dns_rdataset_next(rdataset);
|
|
|
|
} while (result == DNS_R_SUCCESS);
|
|
|
|
|
|
|
|
if (result != DNS_R_NOMORE)
|
|
|
|
return (result);
|
|
|
|
|
|
|
|
return (DNS_R_SUCCESS);
|
|
|
|
}
|