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-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>
|
|
|
|
|
|
|
|
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);
|
|
|
|
rdataset->class = 0;
|
|
|
|
rdataset->type = 0;
|
|
|
|
rdataset->ttl = 0;
|
|
|
|
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);
|
|
|
|
rdataset->class = 0;
|
|
|
|
rdataset->type = 0;
|
|
|
|
rdataset->ttl = 0;
|
|
|
|
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-01-15 03:31:17 +00:00
|
|
|
|
|
|
|
(rdataset->methods->disassociate)(rdataset);
|
|
|
|
rdataset->methods = NULL;
|
|
|
|
ISC_LINK_INIT(rdataset, link);
|
|
|
|
rdataset->class = 0;
|
|
|
|
rdataset->type = 0;
|
|
|
|
rdataset->ttl = 0;
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
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-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-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-01-15 03:31:17 +00:00
|
|
|
|
|
|
|
(rdataset->methods->current)(rdataset, rdata);
|
|
|
|
}
|
|
|
|
|
1999-01-16 01:25:06 +00:00
|
|
|
static char *tabs = "\t\t\t\t\t\t\t\t\t\t";
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
tabs_needed(unsigned int current_offset, unsigned int desired_offset) {
|
|
|
|
unsigned int needed;
|
|
|
|
unsigned int spaces;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Assumes tabs are 8 characters.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (current_offset >= desired_offset)
|
|
|
|
return (1);
|
|
|
|
spaces = desired_offset - current_offset;
|
|
|
|
needed = spaces / 8;
|
|
|
|
if (spaces % 8 != 0)
|
|
|
|
needed++;
|
|
|
|
if (needed > 10)
|
|
|
|
needed = 10;
|
|
|
|
return (needed);
|
|
|
|
}
|
|
|
|
|
1999-01-15 03:31:17 +00:00
|
|
|
dns_result_t
|
|
|
|
dns_rdataset_totext(dns_rdataset_t *rdataset,
|
|
|
|
dns_name_t *owner_name,
|
|
|
|
isc_boolean_t omit_final_dot,
|
|
|
|
isc_buffer_t *target)
|
|
|
|
{
|
1999-01-15 19:36:07 +00:00
|
|
|
dns_result_t result;
|
1999-01-20 07:49:30 +00:00
|
|
|
unsigned int common_start, common_length, length, ntabs, ttabs;
|
1999-01-16 01:25:06 +00:00
|
|
|
char *common;
|
1999-01-15 19:36:07 +00:00
|
|
|
dns_rdata_t rdata;
|
|
|
|
isc_boolean_t first = ISC_TRUE;
|
|
|
|
isc_region_t r;
|
1999-01-20 07:49:30 +00:00
|
|
|
char ttl[64];
|
1999-01-15 03:31:17 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert 'rdataset' to text format, storing the result in 'target'.
|
|
|
|
*/
|
|
|
|
|
1999-01-15 08:07:09 +00:00
|
|
|
REQUIRE(DNS_RDATASET_VALID(rdataset));
|
1999-01-15 19:36:07 +00:00
|
|
|
result = dns_rdataset_first(rdataset);
|
|
|
|
REQUIRE(result == DNS_R_SUCCESS);
|
1999-01-15 03:31:17 +00:00
|
|
|
|
1999-01-15 19:36:07 +00:00
|
|
|
/*
|
|
|
|
* XXX Explicit buffer structure references here. Improve buffer
|
|
|
|
* API.
|
|
|
|
*/
|
1999-01-20 07:49:30 +00:00
|
|
|
common_start = target->used;
|
|
|
|
/*
|
|
|
|
* The caller might want to give us an empty owner
|
|
|
|
* name (e.g. if they are outputting into a master
|
|
|
|
* file and this rdataset has the same name as the
|
|
|
|
* previous one.)
|
|
|
|
*/
|
|
|
|
if (dns_name_countlabels(owner_name) != 0) {
|
|
|
|
result = dns_name_totext(owner_name,
|
|
|
|
omit_final_dot,
|
|
|
|
target);
|
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
common = (char *)target->base + common_start;
|
|
|
|
common_length = target->used - common_start;
|
|
|
|
ntabs = tabs_needed(common_length, 24);
|
|
|
|
ttabs = ntabs;
|
|
|
|
isc_buffer_available(target, &r);
|
|
|
|
if (r.length < ntabs)
|
|
|
|
return (DNS_R_NOSPACE);
|
|
|
|
memcpy(r.base, tabs, ntabs);
|
|
|
|
isc_buffer_add(target, ntabs);
|
|
|
|
/*
|
|
|
|
* XXX The following sprintf() is safe, but it
|
|
|
|
* would still be good to use snprintf if we had it.
|
|
|
|
*/
|
|
|
|
length = sprintf(ttl, "%u ", rdataset->ttl);
|
|
|
|
INSIST(length <= sizeof ttl);
|
|
|
|
isc_buffer_available(target, &r);
|
|
|
|
if (r.length < length)
|
|
|
|
return (DNS_R_NOSPACE);
|
|
|
|
memcpy(r.base, ttl, length);
|
|
|
|
isc_buffer_add(target, length);
|
|
|
|
result = dns_rdataclass_totext(rdataset->class, target);
|
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
isc_buffer_available(target, &r);
|
|
|
|
if (r.length == 0)
|
|
|
|
return (DNS_R_NOSPACE);
|
|
|
|
*r.base = ' ';
|
|
|
|
isc_buffer_add(target, 1);
|
|
|
|
result = dns_rdatatype_totext(rdataset->type, target);
|
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
common_length = target->used - common_start;
|
|
|
|
ntabs = tabs_needed(common_length + ttabs * 7, 40);
|
|
|
|
ttabs += ntabs;
|
|
|
|
isc_buffer_available(target, &r);
|
|
|
|
if (r.length < ntabs)
|
|
|
|
return (DNS_R_NOSPACE);
|
|
|
|
memcpy(r.base, tabs, ntabs);
|
|
|
|
isc_buffer_add(target, ntabs);
|
|
|
|
common_length = target->used - common_start;
|
|
|
|
|
1999-01-15 19:36:07 +00:00
|
|
|
do {
|
1999-01-20 07:49:30 +00:00
|
|
|
if (!first) {
|
1999-01-15 19:36:07 +00:00
|
|
|
isc_buffer_available(target, &r);
|
|
|
|
if (r.length < common_length)
|
|
|
|
return (DNS_R_NOSPACE);
|
|
|
|
memcpy(r.base, common, common_length);
|
|
|
|
isc_buffer_add(target, common_length);
|
1999-01-20 07:49:30 +00:00
|
|
|
} else
|
|
|
|
first = ISC_FALSE;
|
1999-01-15 19:36:07 +00:00
|
|
|
|
|
|
|
dns_rdataset_current(rdataset, &rdata);
|
1999-02-16 02:54:18 +00:00
|
|
|
result = dns_rdata_totext(&rdata, NULL, target);
|
1999-01-16 01:25:06 +00:00
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
return (result);
|
1999-01-15 19:36:07 +00:00
|
|
|
isc_buffer_available(target, &r);
|
|
|
|
if (r.length < 1)
|
|
|
|
return (DNS_R_NOSPACE);
|
|
|
|
memcpy(r.base, "\n", 1);
|
|
|
|
isc_buffer_add(target, 1);
|
|
|
|
|
|
|
|
result = dns_rdataset_next(rdataset);
|
|
|
|
} while (result == DNS_R_SUCCESS);
|
|
|
|
|
|
|
|
if (result != DNS_R_NOMORE)
|
|
|
|
return (result);
|
|
|
|
|
|
|
|
return (DNS_R_SUCCESS);
|
1999-01-15 03:31:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
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-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-27 05:54:39 +00:00
|
|
|
result = dns_rdataset_first(rdataset);
|
|
|
|
REQUIRE(result == DNS_R_SUCCESS);
|
1999-01-30 05:01:01 +00:00
|
|
|
REQUIRE(countp != NULL);
|
1999-01-15 19:36:07 +00:00
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
result = dns_name_towire(owner_name, cctx, target);
|
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
isc_buffer_available(target, &r);
|
|
|
|
if (r.length < (sizeof(dns_rdataclass_t)
|
|
|
|
+ sizeof(dns_rdatatype_t)
|
|
|
|
+ sizeof(dns_ttl_t)
|
|
|
|
+ 2)) /* XXX 2? it's for the rdata length */
|
|
|
|
return (DNS_R_NOSPACE);
|
1999-01-27 06:18:45 +00:00
|
|
|
isc_buffer_putuint16(target, rdataset->type);
|
|
|
|
isc_buffer_putuint16(target, rdataset->class);
|
|
|
|
isc_buffer_putuint32(target, rdataset->ttl);
|
|
|
|
|
1999-01-27 05:54:39 +00:00
|
|
|
/*
|
|
|
|
* copy out the rdata length
|
|
|
|
*/
|
|
|
|
dns_rdataset_current(rdataset, &rdata);
|
1999-01-27 06:18:45 +00:00
|
|
|
isc_buffer_putuint16(target, rdata.length);
|
1999-01-15 03:31:17 +00:00
|
|
|
|
1999-01-27 05:54:39 +00:00
|
|
|
/*
|
|
|
|
* copy out the rdata
|
|
|
|
*/
|
|
|
|
result = dns_rdata_towire(&rdata, cctx, target);
|
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
|
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-01-15 03:31:17 +00:00
|
|
|
}
|