1999-04-26 21:59:36 +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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/***
|
|
|
|
*** Imports
|
|
|
|
***/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <isc/assertions.h>
|
1999-04-27 02:24:11 +00:00
|
|
|
#include <isc/boolean.h>
|
|
|
|
#include <isc/region.h>
|
1999-04-30 00:17:15 +00:00
|
|
|
#include <isc/types.h>
|
1999-04-26 21:59:36 +00:00
|
|
|
|
|
|
|
#include <dns/message.h>
|
|
|
|
#include <dns/rdataset.h>
|
1999-04-27 02:24:11 +00:00
|
|
|
#include <dns/rdata.h>
|
|
|
|
#include <dns/rdataclass.h>
|
|
|
|
#include <dns/rdatatype.h>
|
|
|
|
#include <dns/rdatalist.h>
|
|
|
|
#include <dns/compress.h>
|
1999-04-26 21:59:36 +00:00
|
|
|
|
|
|
|
#define MESSAGE_MAGIC 0x4d534740U /* MSG@ */
|
1999-04-27 02:24:11 +00:00
|
|
|
#define VALID_MESSAGE(msg) (((msg)->magic) == MESSAGE_MAGIC)
|
|
|
|
|
|
|
|
#define VALID_NAMED_SECTION(s) (((s) > DNS_SECTION_ANY) \
|
|
|
|
&& ((s) < DNS_SECTION_MAX))
|
|
|
|
#define VALID_SECTION(s) (((s) >= DNS_SECTION_ANY) \
|
|
|
|
&& ((s) < DNS_SECTION_MAX))
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the size of each individual scratchpad buffer, and the numbers
|
|
|
|
* of various block allocations used within the server.
|
|
|
|
*/
|
1999-04-29 08:18:57 +00:00
|
|
|
#define SCRATCHPAD_SIZE 512
|
1999-05-01 17:18:47 +00:00
|
|
|
#define NAME_COUNT 8
|
|
|
|
#define RDATA_COUNT 8
|
|
|
|
#define RDATALIST_COUNT 8
|
|
|
|
#define RDATASET_COUNT RDATALIST_COUNT
|
1999-04-27 02:24:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* "helper" type, which consists of a block of some type, and is linkable.
|
|
|
|
* For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
|
|
|
|
* size, or the allocated elements will not be alligned correctly.
|
|
|
|
*/
|
|
|
|
struct dns_msgblock {
|
|
|
|
unsigned int length;
|
|
|
|
unsigned int remaining;
|
|
|
|
ISC_LINK(dns_msgblock_t) link;
|
|
|
|
}; /* dynamically sized */
|
1999-04-26 21:59:36 +00:00
|
|
|
|
|
|
|
static inline void
|
1999-04-27 02:24:11 +00:00
|
|
|
msgblock_free(isc_mem_t *, dns_msgblock_t *);
|
1999-04-30 00:17:15 +00:00
|
|
|
|
1999-04-27 02:24:11 +00:00
|
|
|
#define msgblock_get(block, type) \
|
1999-04-28 03:19:58 +00:00
|
|
|
((type *)msgblock_internalget(block, sizeof(type)))
|
1999-04-26 21:59:36 +00:00
|
|
|
|
|
|
|
static inline void *
|
1999-04-27 02:24:11 +00:00
|
|
|
msgblock_internalget(dns_msgblock_t *, unsigned int);
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
msgblock_reset(dns_msgblock_t *, unsigned int);
|
1999-04-26 21:59:36 +00:00
|
|
|
|
|
|
|
static inline dns_msgblock_t *
|
1999-04-27 02:24:11 +00:00
|
|
|
msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
|
1999-04-26 21:59:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate a new dns_msgblock_t, and return a pointer to it. If no memory
|
|
|
|
* is free, return NULL.
|
|
|
|
*/
|
|
|
|
static inline dns_msgblock_t *
|
1999-04-27 02:24:11 +00:00
|
|
|
msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
|
|
|
|
unsigned int count)
|
1999-04-26 21:59:36 +00:00
|
|
|
{
|
|
|
|
dns_msgblock_t *block;
|
|
|
|
unsigned int length;
|
|
|
|
|
|
|
|
length = sizeof(dns_msgblock_t) + (sizeof_type * count);
|
|
|
|
|
|
|
|
block = isc_mem_get(mctx, length);
|
|
|
|
if (block == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
block->length = length;
|
|
|
|
block->remaining = count;
|
|
|
|
|
|
|
|
ISC_LINK_INIT(block, link);
|
|
|
|
|
|
|
|
return (block);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return an element from the msgblock. If no more are available, return
|
|
|
|
* NULL.
|
|
|
|
*/
|
|
|
|
static inline void *
|
1999-04-27 02:24:11 +00:00
|
|
|
msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type)
|
1999-04-26 21:59:36 +00:00
|
|
|
{
|
|
|
|
void *ptr;
|
|
|
|
|
|
|
|
if (block->remaining == 0)
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
block->remaining--;
|
|
|
|
|
|
|
|
ptr = (((unsigned char *)block)
|
|
|
|
+ sizeof(dns_msgblock_t)
|
|
|
|
+ (sizeof_type * block->remaining));
|
|
|
|
|
|
|
|
return (ptr);
|
|
|
|
}
|
|
|
|
|
1999-04-27 02:24:11 +00:00
|
|
|
static inline void
|
|
|
|
msgblock_reset(dns_msgblock_t *block, unsigned int count)
|
|
|
|
{
|
|
|
|
block->remaining = count;
|
|
|
|
}
|
|
|
|
|
1999-04-26 21:59:36 +00:00
|
|
|
/*
|
|
|
|
* Release memory associated with a message block.
|
|
|
|
*/
|
|
|
|
static inline void
|
1999-04-27 02:24:11 +00:00
|
|
|
msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block)
|
1999-04-26 21:59:36 +00:00
|
|
|
{
|
|
|
|
isc_mem_put(mctx, block, block->length);
|
|
|
|
}
|
1999-04-27 02:24:11 +00:00
|
|
|
|
1999-04-28 03:19:58 +00:00
|
|
|
/*
|
|
|
|
* Allocate a new dynamic buffer, and attach it to this message as the
|
|
|
|
* "current" buffer. (which is always the last on the list, for our
|
|
|
|
* uses)
|
|
|
|
*/
|
|
|
|
static inline dns_result_t
|
|
|
|
newbuffer(dns_message_t *msg)
|
|
|
|
{
|
|
|
|
isc_result_t result;
|
|
|
|
isc_dynbuffer_t *dynbuf;
|
|
|
|
|
|
|
|
dynbuf = NULL;
|
|
|
|
result = isc_dynbuffer_allocate(msg->mctx, &dynbuf, SCRATCHPAD_SIZE,
|
|
|
|
ISC_BUFFERTYPE_BINARY);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (DNS_R_NOMEMORY);
|
|
|
|
|
|
|
|
ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
|
|
|
|
return (DNS_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline isc_buffer_t *
|
|
|
|
currentbuffer(dns_message_t *msg)
|
|
|
|
{
|
|
|
|
isc_dynbuffer_t *dynbuf;
|
|
|
|
|
|
|
|
dynbuf = ISC_LIST_TAIL(msg->scratchpad);
|
|
|
|
|
|
|
|
return (&dynbuf->buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
releasename(dns_message_t *msg, dns_name_t *name)
|
|
|
|
{
|
|
|
|
msg->nextname = name;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline dns_name_t *
|
|
|
|
newname(dns_message_t *msg)
|
|
|
|
{
|
|
|
|
dns_msgblock_t *msgblock;
|
|
|
|
dns_name_t *name;
|
|
|
|
|
|
|
|
if (msg->nextname != NULL) {
|
|
|
|
name = msg->nextname;
|
|
|
|
msg->nextname = NULL;
|
|
|
|
return (name);
|
|
|
|
}
|
|
|
|
|
|
|
|
msgblock = ISC_LIST_HEAD(msg->names);
|
|
|
|
name = msgblock_get(msgblock, dns_name_t);
|
|
|
|
if (name == NULL) {
|
|
|
|
msgblock = msgblock_allocate(msg->mctx, sizeof(dns_name_t),
|
|
|
|
NAME_COUNT);
|
|
|
|
if (msgblock == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
ISC_LIST_APPEND(msg->names, msgblock, link);
|
|
|
|
|
|
|
|
name = msgblock_get(msgblock, dns_name_t);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
releaserdata(dns_message_t *msg, dns_rdata_t *rdata)
|
|
|
|
{
|
|
|
|
msg->nextrdata = rdata;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline dns_rdata_t *
|
|
|
|
newrdata(dns_message_t *msg)
|
|
|
|
{
|
|
|
|
dns_msgblock_t *msgblock;
|
|
|
|
dns_rdata_t *rdata;
|
|
|
|
|
|
|
|
if (msg->nextrdata != NULL) {
|
|
|
|
rdata = msg->nextrdata;
|
|
|
|
msg->nextrdata = NULL;
|
|
|
|
return (rdata);
|
|
|
|
}
|
|
|
|
|
|
|
|
msgblock = ISC_LIST_HEAD(msg->rdatas);
|
|
|
|
rdata = msgblock_get(msgblock, dns_rdata_t);
|
|
|
|
if (rdata == NULL) {
|
|
|
|
msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
|
|
|
|
RDATA_COUNT);
|
|
|
|
if (msgblock == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
ISC_LIST_APPEND(msg->rdatas, msgblock, link);
|
|
|
|
|
|
|
|
rdata = msgblock_get(msgblock, dns_rdata_t);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (rdata);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist)
|
|
|
|
{
|
|
|
|
msg->nextrdatalist = rdatalist;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline dns_rdatalist_t *
|
|
|
|
newrdatalist(dns_message_t *msg)
|
|
|
|
{
|
|
|
|
dns_msgblock_t *msgblock;
|
|
|
|
dns_rdatalist_t *rdatalist;
|
|
|
|
|
|
|
|
if (msg->nextrdatalist != NULL) {
|
|
|
|
rdatalist = msg->nextrdatalist;
|
|
|
|
msg->nextrdatalist = NULL;
|
|
|
|
return (rdatalist);
|
|
|
|
}
|
|
|
|
|
|
|
|
msgblock = ISC_LIST_HEAD(msg->rdatalists);
|
|
|
|
rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
|
|
|
|
if (rdatalist == NULL) {
|
|
|
|
msgblock = msgblock_allocate(msg->mctx,
|
|
|
|
sizeof(dns_rdatalist_t),
|
|
|
|
RDATALIST_COUNT);
|
|
|
|
if (msgblock == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
|
|
|
|
|
|
|
|
rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (rdatalist);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
releaserdataset(dns_message_t *msg, dns_rdataset_t *rdataset)
|
|
|
|
{
|
|
|
|
msg->nextrdataset = rdataset;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline dns_rdataset_t *
|
|
|
|
newrdataset(dns_message_t *msg)
|
|
|
|
{
|
|
|
|
dns_msgblock_t *msgblock;
|
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
|
|
|
|
if (msg->nextrdataset != NULL) {
|
|
|
|
rdataset = msg->nextrdataset;
|
|
|
|
msg->nextrdataset = NULL;
|
|
|
|
return (rdataset);
|
|
|
|
}
|
|
|
|
|
|
|
|
msgblock = ISC_LIST_HEAD(msg->rdatasets);
|
|
|
|
rdataset = msgblock_get(msgblock, dns_rdataset_t);
|
|
|
|
if (rdataset == NULL) {
|
|
|
|
msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdataset_t),
|
|
|
|
RDATASET_COUNT);
|
|
|
|
if (msgblock == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
ISC_LIST_APPEND(msg->rdatasets, msgblock, link);
|
|
|
|
|
|
|
|
rdataset = msgblock_get(msgblock, dns_rdataset_t);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (rdataset);
|
|
|
|
}
|
|
|
|
|
1999-04-27 02:24:11 +00:00
|
|
|
/*
|
|
|
|
* Init elements to default state. Used both when allocating a new element
|
|
|
|
* and when resetting one.
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
msginit(dns_message_t *m)
|
|
|
|
{
|
1999-04-28 03:19:58 +00:00
|
|
|
unsigned int i;
|
|
|
|
|
1999-04-27 02:24:11 +00:00
|
|
|
m->id = 0;
|
|
|
|
m->flags = 0;
|
|
|
|
m->rcode = 0;
|
|
|
|
m->opcode = 0;
|
1999-04-29 08:18:57 +00:00
|
|
|
m->rdclass = 0;
|
1999-04-28 03:19:58 +00:00
|
|
|
|
1999-04-29 08:18:57 +00:00
|
|
|
for (i = 0 ; i < DNS_SECTION_MAX ; i++) {
|
1999-04-28 03:19:58 +00:00
|
|
|
m->cursors[i] = NULL;
|
1999-04-30 22:35:49 +00:00
|
|
|
m->counts[i] = 0;
|
1999-04-29 08:18:57 +00:00
|
|
|
}
|
1999-05-12 19:32:13 +00:00
|
|
|
m->opt = NULL;
|
1999-04-28 03:19:58 +00:00
|
|
|
|
1999-04-27 02:24:11 +00:00
|
|
|
m->state = DNS_SECTION_ANY; /* indicate nothing parsed or rendered */
|
1999-04-28 03:19:58 +00:00
|
|
|
|
|
|
|
m->nextname = NULL;
|
|
|
|
m->nextrdata = NULL;
|
|
|
|
m->nextrdataset = NULL;
|
|
|
|
m->nextrdatalist = NULL;
|
1999-04-30 05:42:06 +00:00
|
|
|
|
|
|
|
m->buffer = NULL;
|
1999-04-30 07:53:07 +00:00
|
|
|
m->need_cctx_cleanup = ISC_FALSE;
|
1999-04-27 02:24:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free all but one (or everything) for this message. This is used by
|
|
|
|
* both dns_message_reset() and dns_message_parse().
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
msgreset(dns_message_t *msg, isc_boolean_t everything)
|
|
|
|
{
|
|
|
|
dns_msgblock_t *msgblock, *next_msgblock;
|
|
|
|
isc_dynbuffer_t *dynbuf, *next_dynbuf;
|
|
|
|
dns_rdataset_t *rds, *next_rds;
|
|
|
|
dns_name_t *name, *next_name;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clean up name lists by calling the rdataset disassociate function.
|
|
|
|
*/
|
|
|
|
for (i = 0 ; i < DNS_SECTION_MAX ; i++) {
|
|
|
|
name = ISC_LIST_HEAD(msg->sections[i]);
|
|
|
|
while (name != NULL) {
|
|
|
|
next_name = ISC_LIST_NEXT(name, link);
|
|
|
|
ISC_LIST_UNLINK(msg->sections[i], name, link);
|
|
|
|
|
|
|
|
rds = ISC_LIST_HEAD(name->list);
|
|
|
|
while (rds != NULL) {
|
|
|
|
next_rds = ISC_LIST_NEXT(rds, link);
|
|
|
|
ISC_LIST_UNLINK(name->list, rds, link);
|
|
|
|
|
|
|
|
dns_rdataset_disassociate(rds);
|
|
|
|
rds = next_rds;
|
|
|
|
}
|
1999-04-30 00:17:15 +00:00
|
|
|
name = next_name;
|
1999-04-27 02:24:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clean up linked lists.
|
|
|
|
*/
|
|
|
|
|
|
|
|
dynbuf = ISC_LIST_HEAD(msg->scratchpad);
|
|
|
|
INSIST(dynbuf != NULL);
|
|
|
|
if (everything == ISC_FALSE) {
|
|
|
|
isc_dynbuffer_reset(dynbuf);
|
|
|
|
dynbuf = ISC_LIST_NEXT(dynbuf, link);
|
|
|
|
}
|
|
|
|
while (dynbuf != NULL) {
|
|
|
|
next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
|
|
|
|
ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
|
|
|
|
isc_dynbuffer_free(msg->mctx, &dynbuf);
|
|
|
|
dynbuf = next_dynbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
msgblock = ISC_LIST_HEAD(msg->names);
|
|
|
|
INSIST(msgblock != NULL);
|
|
|
|
if (everything == ISC_FALSE) {
|
|
|
|
msgblock_reset(msgblock, NAME_COUNT);
|
|
|
|
msgblock = ISC_LIST_NEXT(msgblock, link);
|
|
|
|
}
|
|
|
|
while (msgblock != NULL) {
|
|
|
|
next_msgblock = ISC_LIST_NEXT(msgblock, link);
|
|
|
|
ISC_LIST_UNLINK(msg->names, msgblock, link);
|
|
|
|
msgblock_free(msg->mctx, msgblock);
|
|
|
|
msgblock = next_msgblock;
|
|
|
|
}
|
|
|
|
|
|
|
|
msgblock = ISC_LIST_HEAD(msg->rdatas);
|
|
|
|
INSIST(msgblock != NULL);
|
|
|
|
if (everything == ISC_FALSE) {
|
|
|
|
msgblock_reset(msgblock, RDATA_COUNT);
|
|
|
|
msgblock = ISC_LIST_NEXT(msgblock, link);
|
|
|
|
}
|
|
|
|
while (msgblock != NULL) {
|
|
|
|
next_msgblock = ISC_LIST_NEXT(msgblock, link);
|
|
|
|
ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
|
|
|
|
msgblock_free(msg->mctx, msgblock);
|
|
|
|
msgblock = next_msgblock;
|
|
|
|
}
|
|
|
|
|
1999-04-28 03:19:58 +00:00
|
|
|
msgblock = ISC_LIST_HEAD(msg->rdatasets);
|
|
|
|
INSIST(msgblock != NULL);
|
|
|
|
if (everything == ISC_FALSE) {
|
|
|
|
msgblock_reset(msgblock, RDATASET_COUNT);
|
|
|
|
msgblock = ISC_LIST_NEXT(msgblock, link);
|
|
|
|
}
|
|
|
|
while (msgblock != NULL) {
|
|
|
|
next_msgblock = ISC_LIST_NEXT(msgblock, link);
|
|
|
|
ISC_LIST_UNLINK(msg->rdatasets, msgblock, link);
|
|
|
|
msgblock_free(msg->mctx, msgblock);
|
|
|
|
msgblock = next_msgblock;
|
|
|
|
}
|
|
|
|
|
1999-04-30 21:52:40 +00:00
|
|
|
/*
|
|
|
|
* "rdatalists" is special, since it is possible (but not recommended)
|
|
|
|
* that the message could be switched from parse into render mode.
|
|
|
|
*
|
|
|
|
* Note that the reverse is not possible -- switching to parse after
|
|
|
|
* render will not work, and should not.
|
|
|
|
*/
|
|
|
|
|
|
|
|
msgblock = ISC_LIST_HEAD(msg->rdatalists);
|
|
|
|
if (everything == ISC_FALSE) {
|
|
|
|
msgblock_reset(msgblock, RDATALIST_COUNT);
|
|
|
|
msgblock = ISC_LIST_NEXT(msgblock, link);
|
|
|
|
}
|
|
|
|
while (msgblock != NULL) {
|
|
|
|
next_msgblock = ISC_LIST_NEXT(msgblock, link);
|
|
|
|
ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
|
|
|
|
msgblock_free(msg->mctx, msgblock);
|
|
|
|
msgblock = next_msgblock;
|
1999-04-27 02:24:11 +00:00
|
|
|
}
|
|
|
|
|
1999-04-30 07:53:07 +00:00
|
|
|
if (msg->need_cctx_cleanup)
|
|
|
|
dns_compress_invalidate(&msg->cctx);
|
|
|
|
|
1999-04-27 02:24:11 +00:00
|
|
|
/*
|
|
|
|
* Set other bits to normal default values.
|
|
|
|
*/
|
|
|
|
msginit(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_result_t
|
|
|
|
dns_message_create(isc_mem_t *mctx, dns_message_t **msg, unsigned int intent)
|
|
|
|
{
|
|
|
|
dns_message_t *m;
|
|
|
|
isc_result_t iresult;
|
|
|
|
dns_msgblock_t *msgblock;
|
|
|
|
isc_dynbuffer_t *dynbuf;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
REQUIRE(mctx != NULL);
|
|
|
|
REQUIRE(msg != NULL);
|
|
|
|
REQUIRE(*msg == NULL);
|
|
|
|
REQUIRE(intent == DNS_MESSAGE_INTENT_PARSE
|
|
|
|
|| intent == DNS_MESSAGE_INTENT_RENDER);
|
|
|
|
|
|
|
|
m = isc_mem_get(mctx, sizeof(dns_message_t));
|
|
|
|
if (m == NULL)
|
|
|
|
return(DNS_R_NOMEMORY);
|
|
|
|
|
|
|
|
m->magic = MESSAGE_MAGIC;
|
|
|
|
m->from_to_wire = intent;
|
|
|
|
msginit(m);
|
|
|
|
for (i = 0 ; i < DNS_SECTION_MAX ; i++)
|
|
|
|
ISC_LIST_INIT(m->sections[i]);
|
|
|
|
m->mctx = mctx;
|
|
|
|
ISC_LIST_INIT(m->scratchpad);
|
|
|
|
ISC_LIST_INIT(m->names);
|
|
|
|
ISC_LIST_INIT(m->rdatas);
|
|
|
|
ISC_LIST_INIT(m->rdatalists);
|
|
|
|
|
|
|
|
dynbuf = NULL;
|
|
|
|
iresult = isc_dynbuffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE,
|
|
|
|
ISC_BUFFERTYPE_BINARY);
|
|
|
|
if (iresult != ISC_R_SUCCESS)
|
|
|
|
goto cleanup1;
|
|
|
|
ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
|
|
|
|
|
|
|
|
msgblock = msgblock_allocate(mctx, sizeof(dns_name_t),
|
|
|
|
NAME_COUNT);
|
|
|
|
if (msgblock == NULL)
|
|
|
|
goto cleanup2;
|
|
|
|
ISC_LIST_APPEND(m->names, msgblock, link);
|
|
|
|
|
|
|
|
msgblock = msgblock_allocate(mctx, sizeof(dns_rdata_t),
|
|
|
|
RDATA_COUNT);
|
|
|
|
if (msgblock == NULL)
|
|
|
|
goto cleanup3;
|
|
|
|
ISC_LIST_APPEND(m->rdatas, msgblock, link);
|
|
|
|
|
1999-04-28 03:19:58 +00:00
|
|
|
msgblock = msgblock_allocate(mctx, sizeof(dns_rdataset_t),
|
|
|
|
RDATASET_COUNT);
|
|
|
|
if (msgblock == NULL)
|
|
|
|
goto cleanup4;
|
1999-04-30 00:17:15 +00:00
|
|
|
ISC_LIST_APPEND(m->rdatasets, msgblock, link);
|
1999-04-28 03:19:58 +00:00
|
|
|
|
1999-04-27 02:24:11 +00:00
|
|
|
if (intent == DNS_MESSAGE_INTENT_PARSE) {
|
|
|
|
msgblock = msgblock_allocate(mctx, sizeof(dns_rdatalist_t),
|
|
|
|
RDATALIST_COUNT);
|
|
|
|
if (msgblock == NULL)
|
1999-04-28 03:19:58 +00:00
|
|
|
goto cleanup5;
|
1999-04-27 02:24:11 +00:00
|
|
|
ISC_LIST_APPEND(m->rdatalists, msgblock, link);
|
|
|
|
}
|
|
|
|
|
1999-04-30 00:17:15 +00:00
|
|
|
*msg = m;
|
1999-04-27 02:24:11 +00:00
|
|
|
return (DNS_R_SUCCESS);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Cleanup for error returns.
|
|
|
|
*/
|
1999-04-28 03:19:58 +00:00
|
|
|
cleanup5:
|
|
|
|
msgblock = ISC_LIST_HEAD(m->rdatasets);
|
|
|
|
msgblock_free(mctx, msgblock);
|
1999-04-27 02:24:11 +00:00
|
|
|
cleanup4:
|
|
|
|
msgblock = ISC_LIST_HEAD(m->rdatas);
|
|
|
|
msgblock_free(mctx, msgblock);
|
|
|
|
cleanup3:
|
|
|
|
msgblock = ISC_LIST_HEAD(m->names);
|
|
|
|
msgblock_free(mctx, msgblock);
|
|
|
|
cleanup2:
|
|
|
|
dynbuf = ISC_LIST_HEAD(m->scratchpad);
|
|
|
|
isc_dynbuffer_free(mctx, &dynbuf);
|
|
|
|
cleanup1:
|
|
|
|
m->magic = 0;
|
|
|
|
isc_mem_put(mctx, m, sizeof(dns_message_t));
|
|
|
|
|
|
|
|
return (DNS_R_NOMEMORY);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_message_reset(dns_message_t *msg)
|
|
|
|
{
|
|
|
|
msgreset(msg, ISC_FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_message_destroy(dns_message_t **xmsg)
|
|
|
|
{
|
|
|
|
dns_message_t *msg;
|
|
|
|
|
|
|
|
REQUIRE(xmsg != NULL);
|
|
|
|
REQUIRE(VALID_MESSAGE(*xmsg));
|
|
|
|
|
|
|
|
msg = *xmsg;
|
|
|
|
*xmsg = NULL;
|
|
|
|
|
|
|
|
msgreset(msg, ISC_TRUE);
|
|
|
|
msg->magic = 0;
|
|
|
|
isc_mem_put(msg->mctx, msg, sizeof(dns_message_t));
|
|
|
|
}
|
|
|
|
|
1999-04-29 08:18:57 +00:00
|
|
|
static dns_result_t
|
|
|
|
findname(dns_name_t **foundname, dns_name_t *target, dns_namelist_t *section)
|
|
|
|
{
|
|
|
|
dns_name_t *curr;
|
|
|
|
|
|
|
|
for (curr = ISC_LIST_TAIL(*section) ;
|
|
|
|
curr != NULL ;
|
|
|
|
curr = ISC_LIST_PREV(curr, link)) {
|
|
|
|
if (dns_name_compare(curr, target) == 0) {
|
|
|
|
if (foundname != NULL)
|
|
|
|
*foundname = curr;
|
|
|
|
return (DNS_R_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (DNS_R_NOTFOUND);
|
|
|
|
}
|
|
|
|
|
|
|
|
static dns_result_t
|
|
|
|
findtype(dns_rdataset_t **rdataset, dns_name_t *name, dns_rdatatype_t type)
|
|
|
|
{
|
|
|
|
dns_rdataset_t *curr;
|
|
|
|
|
|
|
|
for (curr = ISC_LIST_TAIL(name->list) ;
|
|
|
|
curr != NULL ;
|
|
|
|
curr = ISC_LIST_PREV(curr, link)) {
|
|
|
|
if (curr->type == type) {
|
|
|
|
if (rdataset != NULL)
|
|
|
|
*rdataset = curr;
|
|
|
|
return (DNS_R_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (DNS_R_NOTFOUND);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read a name from buffer "source".
|
|
|
|
*/
|
|
|
|
static dns_result_t
|
|
|
|
getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
|
|
|
|
dns_decompress_t *dctx)
|
|
|
|
{
|
|
|
|
isc_buffer_t *scratch;
|
|
|
|
dns_result_t result;
|
|
|
|
unsigned int tries;
|
|
|
|
|
|
|
|
scratch = currentbuffer(msg);
|
|
|
|
|
|
|
|
if (dns_decompress_edns(dctx) > 1 || !dns_decompress_strict(dctx))
|
|
|
|
dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL);
|
|
|
|
else
|
|
|
|
dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14);
|
|
|
|
|
|
|
|
tries = 0;
|
|
|
|
while (tries < 2) {
|
1999-05-01 17:18:47 +00:00
|
|
|
dns_name_init(name, NULL);
|
1999-04-29 08:18:57 +00:00
|
|
|
result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
|
|
|
|
scratch);
|
|
|
|
|
|
|
|
if (result == DNS_R_NOSPACE) {
|
|
|
|
tries++;
|
|
|
|
|
|
|
|
result = newbuffer(msg);
|
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
|
|
|
|
scratch = currentbuffer(msg);
|
|
|
|
} else {
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (DNS_R_UNEXPECTED); /* should never get here... XXXMLG */
|
|
|
|
}
|
|
|
|
|
1999-04-30 00:17:15 +00:00
|
|
|
static dns_result_t
|
|
|
|
getrdata(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
|
|
|
|
dns_decompress_t *dctx, dns_rdataclass_t rdclass,
|
|
|
|
dns_rdatatype_t rdtype, unsigned int rdatalen, dns_rdata_t *rdata)
|
|
|
|
{
|
|
|
|
isc_buffer_t *scratch;
|
|
|
|
dns_result_t result;
|
|
|
|
unsigned int tries;
|
|
|
|
|
|
|
|
scratch = currentbuffer(msg);
|
|
|
|
|
|
|
|
isc_buffer_setactive(source, rdatalen);
|
|
|
|
dns_decompress_localinit(dctx, name, source);
|
|
|
|
|
|
|
|
tries = 0;
|
|
|
|
while (tries < 2) {
|
|
|
|
result = dns_rdata_fromwire(rdata, rdclass, rdtype,
|
|
|
|
source, dctx, ISC_FALSE,
|
|
|
|
scratch);
|
|
|
|
|
|
|
|
if (result == DNS_R_NOSPACE) {
|
|
|
|
tries++;
|
|
|
|
|
|
|
|
result = newbuffer(msg);
|
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
|
|
|
|
scratch = currentbuffer(msg);
|
|
|
|
} else {
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (DNS_R_UNEXPECTED); /* should never get here... XXXMLG */
|
|
|
|
}
|
1999-04-29 08:18:57 +00:00
|
|
|
|
1999-04-28 03:19:58 +00:00
|
|
|
static dns_result_t
|
|
|
|
getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx)
|
|
|
|
{
|
|
|
|
isc_region_t r;
|
|
|
|
unsigned int count;
|
|
|
|
dns_name_t *name;
|
|
|
|
dns_name_t *name2;
|
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
dns_rdatalist_t *rdatalist;
|
|
|
|
dns_result_t result;
|
1999-04-29 08:18:57 +00:00
|
|
|
dns_rdatatype_t rdtype;
|
|
|
|
dns_rdataclass_t rdclass;
|
|
|
|
dns_namelist_t *section;
|
1999-04-28 03:19:58 +00:00
|
|
|
|
1999-04-29 08:18:57 +00:00
|
|
|
section = &msg->sections[DNS_SECTION_QUESTION];
|
1999-04-28 03:19:58 +00:00
|
|
|
|
1999-04-29 08:18:57 +00:00
|
|
|
for (count = 0 ; count < msg->counts[DNS_SECTION_QUESTION] ; count++) {
|
1999-04-28 03:19:58 +00:00
|
|
|
name = newname(msg);
|
|
|
|
if (name == NULL)
|
|
|
|
return (DNS_R_NOMEMORY);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse the name out of this packet.
|
|
|
|
*/
|
1999-04-30 00:17:15 +00:00
|
|
|
isc_buffer_remaining(source, &r);
|
|
|
|
isc_buffer_setactive(source, r.length);
|
1999-04-28 03:19:58 +00:00
|
|
|
result = getname(name, source, msg, dctx);
|
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run through the section, looking to see if this name
|
|
|
|
* is already there. If it is found, put back the allocated
|
|
|
|
* name since we no longer need it, and set our name pointer
|
|
|
|
* to point to the name we found.
|
|
|
|
*/
|
1999-04-29 08:18:57 +00:00
|
|
|
result = findname(&name2, name, section);
|
1999-04-28 03:19:58 +00:00
|
|
|
|
|
|
|
/*
|
1999-04-30 00:17:15 +00:00
|
|
|
* If it is the first name in the section, accept it.
|
|
|
|
*
|
|
|
|
* If it is not, but is not the same as the name already
|
|
|
|
* in the question section, append to the section. Note that
|
1999-04-29 08:18:57 +00:00
|
|
|
* here in the question section this is illegal, so return
|
|
|
|
* FORMERR. In the future, check the opcode to see if
|
|
|
|
* this should be legal or not. In either case we no longer
|
|
|
|
* need this name pointer.
|
1999-04-28 03:19:58 +00:00
|
|
|
*/
|
1999-04-30 00:17:15 +00:00
|
|
|
if (result != DNS_R_SUCCESS) {
|
|
|
|
if (ISC_LIST_EMPTY(*section)) {
|
|
|
|
ISC_LIST_APPEND(*section, name, link);
|
|
|
|
} else {
|
|
|
|
return (DNS_R_FORMERR);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
name = name2;
|
|
|
|
}
|
1999-04-28 03:19:58 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Get type and class.
|
|
|
|
*/
|
1999-04-29 08:18:57 +00:00
|
|
|
isc_buffer_remaining(source, &r);
|
|
|
|
if (r.length < 4)
|
|
|
|
return (DNS_R_UNEXPECTEDEND);
|
|
|
|
rdtype = isc_buffer_getuint16(source);
|
|
|
|
rdclass = isc_buffer_getuint16(source);
|
1999-04-28 03:19:58 +00:00
|
|
|
|
|
|
|
/*
|
1999-05-12 19:32:13 +00:00
|
|
|
* If this class is different than the one we already read,
|
1999-04-29 08:18:57 +00:00
|
|
|
* this is an error.
|
1999-04-28 03:19:58 +00:00
|
|
|
*/
|
1999-04-29 08:18:57 +00:00
|
|
|
if (msg->state == DNS_SECTION_ANY) {
|
|
|
|
msg->state = DNS_SECTION_QUESTION;
|
|
|
|
msg->rdclass = rdclass;
|
1999-05-12 19:32:13 +00:00
|
|
|
msg->state = DNS_SECTION_QUESTION;
|
1999-04-29 08:18:57 +00:00
|
|
|
} else if (msg->rdclass != rdclass)
|
|
|
|
return (DNS_R_FORMERR);
|
|
|
|
|
1999-04-28 03:19:58 +00:00
|
|
|
/*
|
1999-04-29 08:18:57 +00:00
|
|
|
* Search name for the particular type and class.
|
1999-04-28 03:19:58 +00:00
|
|
|
* If it was found, this is an error, return FORMERR.
|
|
|
|
*/
|
1999-04-29 08:18:57 +00:00
|
|
|
result = findtype(NULL, name, rdtype);
|
|
|
|
if (result == DNS_R_SUCCESS)
|
|
|
|
return (DNS_R_FORMERR);
|
1999-04-28 03:19:58 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate a new rdatalist.
|
|
|
|
*/
|
1999-04-29 08:18:57 +00:00
|
|
|
rdatalist = newrdatalist(msg);
|
|
|
|
rdataset = newrdataset(msg);
|
1999-04-28 03:19:58 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert rdatalist to rdataset, and attach the latter to
|
|
|
|
* the name.
|
|
|
|
*/
|
1999-04-29 08:18:57 +00:00
|
|
|
rdatalist->type = rdtype;
|
|
|
|
rdatalist->rdclass = rdclass;
|
|
|
|
rdatalist->ttl = 0;
|
|
|
|
ISC_LIST_INIT(rdatalist->rdata);
|
|
|
|
|
1999-04-30 00:17:15 +00:00
|
|
|
dns_rdataset_init(rdataset);
|
1999-04-29 08:18:57 +00:00
|
|
|
result = dns_rdatalist_tordataset(rdatalist, rdataset);
|
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
|
|
|
|
ISC_LIST_APPEND(name->list, rdataset, link);
|
1999-04-28 03:19:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (DNS_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static dns_result_t
|
|
|
|
getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
1999-04-29 08:18:57 +00:00
|
|
|
dns_section_t sectionid)
|
1999-04-28 03:19:58 +00:00
|
|
|
{
|
1999-04-29 08:18:57 +00:00
|
|
|
isc_region_t r;
|
|
|
|
unsigned int count;
|
1999-04-29 19:58:51 +00:00
|
|
|
unsigned int rdatalen;
|
1999-04-29 08:18:57 +00:00
|
|
|
dns_name_t *name;
|
|
|
|
dns_name_t *name2;
|
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
dns_rdatalist_t *rdatalist;
|
|
|
|
dns_result_t result;
|
|
|
|
dns_rdatatype_t rdtype;
|
|
|
|
dns_rdataclass_t rdclass;
|
1999-04-30 00:17:15 +00:00
|
|
|
dns_rdata_t *rdata;
|
1999-04-29 08:18:57 +00:00
|
|
|
dns_ttl_t ttl;
|
|
|
|
dns_namelist_t *section;
|
|
|
|
|
|
|
|
for (count = 0 ; count < msg->counts[sectionid] ; count++) {
|
1999-05-12 19:32:13 +00:00
|
|
|
section = &msg->sections[sectionid];
|
|
|
|
|
1999-04-29 08:18:57 +00:00
|
|
|
name = newname(msg);
|
|
|
|
if (name == NULL)
|
|
|
|
return (DNS_R_NOMEMORY);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse the name out of this packet.
|
|
|
|
*/
|
1999-04-30 00:17:15 +00:00
|
|
|
isc_buffer_remaining(source, &r);
|
|
|
|
isc_buffer_setactive(source, r.length);
|
1999-04-29 08:18:57 +00:00
|
|
|
result = getname(name, source, msg, dctx);
|
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get type, class, ttl, and rdatalen. Verify that at least
|
|
|
|
* rdatalen bytes remain. (Some of this is deferred to
|
|
|
|
* later.
|
|
|
|
*/
|
|
|
|
isc_buffer_remaining(source, &r);
|
|
|
|
if (r.length < 10)
|
|
|
|
return (DNS_R_UNEXPECTEDEND);
|
|
|
|
rdtype = isc_buffer_getuint16(source);
|
|
|
|
rdclass = isc_buffer_getuint16(source);
|
|
|
|
|
|
|
|
/*
|
1999-05-12 19:32:13 +00:00
|
|
|
* If this class is different than the one in the question
|
|
|
|
* section, bail.
|
1999-04-29 08:18:57 +00:00
|
|
|
*/
|
1999-05-12 19:32:13 +00:00
|
|
|
if (msg->rdclass != rdclass)
|
1999-04-29 08:18:57 +00:00
|
|
|
return (DNS_R_FORMERR);
|
1999-05-12 19:32:13 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If it is a tsig, verify that it is in the additional data
|
|
|
|
* section, and switch sections for the rest of this rdata.
|
|
|
|
*/
|
|
|
|
if (rdtype == dns_rdatatype_tsig) {
|
|
|
|
if (sectionid != DNS_SECTION_ADDITIONAL)
|
|
|
|
return (DNS_R_FORMERR);
|
|
|
|
section = &msg->sections[DNS_SECTION_TSIG];
|
|
|
|
}
|
1999-04-29 08:18:57 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* ... now get ttl and rdatalen, and check buffer.
|
|
|
|
*/
|
|
|
|
ttl = isc_buffer_getuint32(source);
|
|
|
|
rdatalen = isc_buffer_getuint16(source);
|
|
|
|
r.length -= 10;
|
|
|
|
if (r.length < rdatalen)
|
|
|
|
return (DNS_R_UNEXPECTEDEND);
|
|
|
|
|
1999-05-12 19:32:13 +00:00
|
|
|
/*
|
|
|
|
* If we are doing a dynamic update don't bother searching
|
|
|
|
* for a name, just append this one to the end of the message.
|
|
|
|
*/
|
|
|
|
if (msg->opcode == dns_opcode_update
|
|
|
|
|| rdtype == dns_rdatatype_tsig) {
|
|
|
|
ISC_LIST_APPEND(*section, name, link);
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Run through the section, looking to see if this name
|
|
|
|
* is already there. If it is found, put back the
|
|
|
|
* allocated name since we no longer need it, and set
|
|
|
|
* our name pointer to point to the name we found.
|
|
|
|
*/
|
|
|
|
result = findname(&name2, name, section);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If it is a new name, append to the section.
|
|
|
|
*/
|
|
|
|
if (result == DNS_R_SUCCESS) {
|
|
|
|
releasename(msg, name);
|
|
|
|
name = name2;
|
|
|
|
} else {
|
|
|
|
ISC_LIST_APPEND(*section, name, link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this is an OPT record, There Can Be Only One.
|
|
|
|
*/
|
|
|
|
#if 0 /* until there is a dns_rdatatype_opt XXXMLG */
|
|
|
|
if (rdtype == dns_rdatatype_opt && msg->opt != NULL)
|
|
|
|
return (DNS_R_FORMERR);
|
|
|
|
#endif
|
|
|
|
|
1999-04-29 08:18:57 +00:00
|
|
|
/*
|
|
|
|
* Search name for the particular type and class.
|
1999-05-12 19:32:13 +00:00
|
|
|
* Skip this stage if in update mode, or this is a TSIG.
|
1999-04-29 08:18:57 +00:00
|
|
|
*/
|
1999-05-12 19:32:13 +00:00
|
|
|
if (msg->opcode == dns_opcode_update
|
|
|
|
|| rdtype == dns_rdatatype_tsig)
|
|
|
|
result = DNS_R_NOTFOUND;
|
|
|
|
else
|
|
|
|
result = findtype(&rdataset, name, rdtype);
|
1999-04-29 08:18:57 +00:00
|
|
|
|
|
|
|
/*
|
1999-04-30 00:17:15 +00:00
|
|
|
* If we found an rdataset that matches, we need to
|
|
|
|
* append this rdata to that set. If we did not, we need
|
|
|
|
* to create a new rdatalist, store the important bits there,
|
|
|
|
* convert it to an rdataset, and link the latter to the name.
|
|
|
|
* Yuck.
|
1999-04-29 08:18:57 +00:00
|
|
|
*/
|
|
|
|
if (result != DNS_R_SUCCESS) {
|
|
|
|
rdataset = newrdataset(msg);
|
|
|
|
if (rdataset == NULL)
|
|
|
|
return (DNS_R_NOMEMORY);
|
1999-04-30 00:17:15 +00:00
|
|
|
rdatalist = newrdatalist(msg);
|
|
|
|
if (rdatalist == NULL)
|
|
|
|
return (DNS_R_NOMEMORY);
|
1999-04-29 08:18:57 +00:00
|
|
|
|
1999-04-30 00:17:15 +00:00
|
|
|
rdatalist->type = rdtype;
|
|
|
|
rdatalist->rdclass = rdclass;
|
|
|
|
rdatalist->ttl = ttl;
|
|
|
|
ISC_LIST_INIT(rdatalist->rdata);
|
1999-04-29 08:18:57 +00:00
|
|
|
|
1999-04-30 00:17:15 +00:00
|
|
|
dns_rdataset_init(rdataset);
|
|
|
|
dns_rdatalist_tordataset(rdatalist, rdataset);
|
|
|
|
|
|
|
|
ISC_LIST_APPEND(name->list, rdataset, link);
|
|
|
|
}
|
1999-04-29 08:18:57 +00:00
|
|
|
|
|
|
|
/*
|
1999-04-30 00:17:15 +00:00
|
|
|
* Read the rdata from the wire format.
|
1999-04-29 08:18:57 +00:00
|
|
|
*/
|
1999-04-30 00:17:15 +00:00
|
|
|
rdata = newrdata(msg);
|
|
|
|
if (rdata == NULL)
|
|
|
|
return (DNS_R_NOMEMORY);
|
|
|
|
result = getrdata(name, source, msg, dctx,
|
|
|
|
rdclass, rdtype, rdatalen, rdata);
|
1999-04-29 08:18:57 +00:00
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
|
1999-04-30 00:17:15 +00:00
|
|
|
/*
|
|
|
|
* XXX Perform a totally ugly hack here to pull
|
|
|
|
* the rdatalist out of the private field in the rdataset,
|
|
|
|
* and append this rdata to the rdatalist's linked list
|
|
|
|
* of rdata.
|
|
|
|
*/
|
|
|
|
rdatalist = (dns_rdatalist_t *)(rdataset->private1);
|
|
|
|
|
|
|
|
ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
|
1999-05-12 19:32:13 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If this is an OPT record, remember it.
|
|
|
|
*/
|
|
|
|
#if 0 /* until there is a dns_rdatatype_opt XXXMLG */
|
|
|
|
if (rdtype == dns_rdatatype_opt)
|
|
|
|
msg->opt = rdata;
|
|
|
|
#endif
|
1999-04-29 08:18:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (DNS_R_SUCCESS);
|
1999-04-28 03:19:58 +00:00
|
|
|
}
|
|
|
|
|
1999-04-27 02:24:11 +00:00
|
|
|
dns_result_t
|
1999-04-28 03:19:58 +00:00
|
|
|
dns_message_parse(dns_message_t *msg, isc_buffer_t *source)
|
1999-04-27 02:24:11 +00:00
|
|
|
{
|
1999-04-28 03:19:58 +00:00
|
|
|
isc_region_t r;
|
|
|
|
dns_decompress_t dctx;
|
|
|
|
dns_result_t ret;
|
1999-04-30 00:17:15 +00:00
|
|
|
isc_uint16_t tmpflags;
|
1999-04-27 02:24:11 +00:00
|
|
|
|
|
|
|
REQUIRE(VALID_MESSAGE(msg));
|
1999-04-28 03:19:58 +00:00
|
|
|
REQUIRE(source != NULL);
|
1999-04-30 05:57:39 +00:00
|
|
|
REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENT_PARSE);
|
1999-04-27 02:24:11 +00:00
|
|
|
|
1999-04-28 03:19:58 +00:00
|
|
|
isc_buffer_remaining(source, &r);
|
1999-04-30 00:17:15 +00:00
|
|
|
if (r.length < DNS_MESSAGE_HEADER_LEN)
|
1999-04-28 03:19:58 +00:00
|
|
|
return (DNS_R_UNEXPECTEDEND);
|
|
|
|
|
|
|
|
msg->id = isc_buffer_getuint16(source);
|
1999-04-30 00:17:15 +00:00
|
|
|
tmpflags = isc_buffer_getuint16(source);
|
|
|
|
msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
|
|
|
|
>> DNS_MESSAGE_OPCODE_SHIFT);
|
|
|
|
msg->rcode = (tmpflags & DNS_MESSAGE_RCODE_MASK);
|
1999-05-01 17:18:47 +00:00
|
|
|
msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
|
1999-04-29 08:18:57 +00:00
|
|
|
msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
|
|
|
|
msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
|
|
|
|
msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
|
|
|
|
msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
|
1999-04-28 03:19:58 +00:00
|
|
|
|
|
|
|
dns_decompress_init(&dctx, -1, ISC_FALSE);
|
|
|
|
|
|
|
|
ret = getquestions(source, msg, &dctx);
|
|
|
|
if (ret != DNS_R_SUCCESS)
|
|
|
|
return (ret);
|
|
|
|
|
|
|
|
ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER);
|
|
|
|
if (ret != DNS_R_SUCCESS)
|
|
|
|
return (ret);
|
|
|
|
|
|
|
|
ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY);
|
|
|
|
if (ret != DNS_R_SUCCESS)
|
|
|
|
return (ret);
|
|
|
|
|
|
|
|
ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL);
|
|
|
|
if (ret != DNS_R_SUCCESS)
|
|
|
|
return (ret);
|
|
|
|
|
1999-04-30 00:17:15 +00:00
|
|
|
isc_buffer_remaining(source, &r);
|
|
|
|
if (r.length != 0)
|
|
|
|
return (DNS_R_FORMERR);
|
|
|
|
|
1999-04-28 03:19:58 +00:00
|
|
|
/*
|
|
|
|
* XXXMLG Need to check the tsig(s) here...
|
|
|
|
*/
|
|
|
|
|
|
|
|
return (DNS_R_SUCCESS);
|
1999-04-27 02:24:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dns_result_t
|
|
|
|
dns_message_renderbegin(dns_message_t *msg, isc_buffer_t *buffer)
|
|
|
|
{
|
1999-04-30 05:42:06 +00:00
|
|
|
isc_region_t r;
|
1999-04-30 07:53:07 +00:00
|
|
|
dns_result_t result;
|
1999-04-30 05:42:06 +00:00
|
|
|
|
1999-04-27 02:24:11 +00:00
|
|
|
REQUIRE(VALID_MESSAGE(msg));
|
|
|
|
REQUIRE(buffer != NULL);
|
1999-04-30 05:42:06 +00:00
|
|
|
REQUIRE(msg->buffer == NULL);
|
1999-04-30 05:57:39 +00:00
|
|
|
REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENT_RENDER);
|
1999-04-27 02:24:11 +00:00
|
|
|
|
1999-04-30 05:42:06 +00:00
|
|
|
/*
|
|
|
|
* Erase the contents of this buffer.
|
|
|
|
*/
|
|
|
|
isc_buffer_clear(buffer);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make certain there is enough for at least the header in this
|
|
|
|
* buffer.
|
|
|
|
*/
|
|
|
|
isc_buffer_available(buffer, &r);
|
|
|
|
if (r.length < DNS_MESSAGE_HEADER_LEN)
|
|
|
|
return (DNS_R_NOSPACE);
|
|
|
|
|
1999-04-30 07:53:07 +00:00
|
|
|
result = dns_compress_init(&msg->cctx, -1, msg->mctx);
|
|
|
|
if (result != DNS_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
msg->need_cctx_cleanup = ISC_TRUE;
|
|
|
|
|
1999-04-30 05:42:06 +00:00
|
|
|
/*
|
|
|
|
* Reserve enough space for the header in this buffer.
|
|
|
|
*/
|
|
|
|
isc_buffer_add(buffer, DNS_MESSAGE_HEADER_LEN);
|
|
|
|
|
1999-04-30 21:52:40 +00:00
|
|
|
msg->buffer = buffer;
|
|
|
|
|
1999-04-30 05:42:06 +00:00
|
|
|
return (DNS_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_result_t
|
|
|
|
dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer)
|
|
|
|
{
|
|
|
|
isc_region_t r, rn;
|
|
|
|
|
|
|
|
REQUIRE(VALID_MESSAGE(msg));
|
|
|
|
REQUIRE(buffer != NULL);
|
|
|
|
REQUIRE(msg->buffer != NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ensure that the new buffer is empty, and has enough space to
|
|
|
|
* hold the current contents.
|
|
|
|
*/
|
|
|
|
isc_buffer_clear(buffer);
|
|
|
|
|
|
|
|
isc_buffer_available(buffer, &rn);
|
|
|
|
isc_buffer_used(msg->buffer, &r);
|
|
|
|
if (rn.length < r.length)
|
|
|
|
return (DNS_R_NOSPACE);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy the contents from the old to the new buffer.
|
|
|
|
*/
|
|
|
|
isc_buffer_add(buffer, r.length);
|
|
|
|
memcpy(rn.base, r.base, r.length);
|
|
|
|
|
|
|
|
msg->buffer = buffer;
|
|
|
|
|
|
|
|
return (DNS_R_SUCCESS);
|
1999-04-27 02:24:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dns_result_t
|
|
|
|
dns_message_renderrelease(dns_message_t *msg, unsigned int space)
|
|
|
|
{
|
|
|
|
REQUIRE(VALID_MESSAGE(msg));
|
1999-04-30 05:42:06 +00:00
|
|
|
REQUIRE(msg->buffer != NULL);
|
1999-04-27 02:24:11 +00:00
|
|
|
|
|
|
|
if (msg->reserved < space)
|
|
|
|
return (DNS_R_NOSPACE);
|
|
|
|
|
|
|
|
msg->reserved -= space;
|
|
|
|
|
|
|
|
return (DNS_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_result_t
|
1999-04-30 05:42:06 +00:00
|
|
|
dns_message_renderreserve(dns_message_t *msg, unsigned int space)
|
1999-04-27 02:24:11 +00:00
|
|
|
{
|
|
|
|
isc_region_t r;
|
|
|
|
|
|
|
|
REQUIRE(VALID_MESSAGE(msg));
|
1999-04-30 05:42:06 +00:00
|
|
|
REQUIRE(msg->buffer != NULL);
|
1999-04-27 02:24:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* "space" can be positive or negative. If it is negative we are
|
|
|
|
* removing our reservation of space. If it is positive, we are
|
|
|
|
* requesting more space to be reserved.
|
|
|
|
*/
|
|
|
|
|
1999-04-30 05:42:06 +00:00
|
|
|
isc_buffer_available(msg->buffer, &r);
|
1999-04-27 02:24:11 +00:00
|
|
|
if (r.length < (space + msg->reserved))
|
|
|
|
return (DNS_R_NOSPACE);
|
|
|
|
|
|
|
|
msg->reserved += space;
|
|
|
|
|
|
|
|
return (DNS_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_result_t
|
1999-04-30 06:37:35 +00:00
|
|
|
dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
|
1999-04-30 05:42:06 +00:00
|
|
|
unsigned int priority, unsigned int flags)
|
1999-04-27 02:24:11 +00:00
|
|
|
{
|
1999-04-30 06:37:35 +00:00
|
|
|
unsigned int used;
|
|
|
|
dns_namelist_t *section;
|
1999-04-30 07:53:07 +00:00
|
|
|
dns_name_t *name, *next_name;
|
|
|
|
dns_rdataset_t *rdataset, *next_rdataset;
|
|
|
|
unsigned int count, total;
|
|
|
|
isc_boolean_t no_render_rdata;
|
|
|
|
dns_result_t result;
|
1999-04-30 06:37:35 +00:00
|
|
|
|
1999-04-27 02:24:11 +00:00
|
|
|
REQUIRE(VALID_MESSAGE(msg));
|
1999-04-30 05:42:06 +00:00
|
|
|
REQUIRE(msg->buffer != NULL);
|
1999-04-30 06:37:35 +00:00
|
|
|
REQUIRE(VALID_NAMED_SECTION(sectionid));
|
|
|
|
|
|
|
|
section = &msg->sections[sectionid];
|
1999-04-30 07:53:07 +00:00
|
|
|
if (sectionid == DNS_SECTION_QUESTION)
|
|
|
|
no_render_rdata = ISC_TRUE;
|
|
|
|
else
|
|
|
|
no_render_rdata = ISC_FALSE;
|
|
|
|
|
|
|
|
name = ISC_LIST_HEAD(*section);
|
|
|
|
if (name == NULL)
|
|
|
|
return (ISC_R_SUCCESS);
|
1999-04-30 23:37:23 +00:00
|
|
|
|
1999-04-30 07:53:07 +00:00
|
|
|
/*
|
1999-04-30 23:04:29 +00:00
|
|
|
* Shrink the space in the buffer by the reserved amount.
|
1999-04-30 07:53:07 +00:00
|
|
|
*/
|
1999-04-30 23:04:29 +00:00
|
|
|
msg->buffer->length -= msg->reserved;
|
|
|
|
|
1999-04-30 22:35:49 +00:00
|
|
|
total = 0;
|
|
|
|
while (name != NULL) {
|
1999-04-30 07:53:07 +00:00
|
|
|
next_name = ISC_LIST_NEXT(name, link);
|
|
|
|
|
|
|
|
rdataset = ISC_LIST_HEAD(name->list);
|
|
|
|
while (rdataset != NULL) {
|
|
|
|
next_rdataset = ISC_LIST_NEXT(rdataset, link);
|
1999-04-30 23:04:29 +00:00
|
|
|
used = msg->buffer->used;
|
1999-04-30 22:35:49 +00:00
|
|
|
|
|
|
|
count = 0;
|
1999-04-30 07:53:07 +00:00
|
|
|
result = dns_rdataset_towire(rdataset, name,
|
1999-04-30 21:15:02 +00:00
|
|
|
&msg->cctx,
|
|
|
|
no_render_rdata,
|
1999-04-30 23:04:29 +00:00
|
|
|
msg->buffer, &count);
|
1999-04-30 07:53:07 +00:00
|
|
|
|
1999-04-30 22:35:49 +00:00
|
|
|
total += count;
|
|
|
|
|
1999-04-30 07:53:07 +00:00
|
|
|
/*
|
|
|
|
* If out of space, record stats on what we rendered
|
|
|
|
* so far, and return that status.
|
|
|
|
*/
|
1999-04-30 21:09:19 +00:00
|
|
|
if (result != DNS_R_SUCCESS) {
|
1999-04-30 23:04:29 +00:00
|
|
|
msg->buffer->length += msg->reserved;
|
1999-04-30 07:53:07 +00:00
|
|
|
msg->counts[sectionid] += total;
|
|
|
|
return (result);
|
1999-04-30 21:09:19 +00:00
|
|
|
}
|
1999-04-30 07:53:07 +00:00
|
|
|
|
|
|
|
ISC_LIST_UNLINK(name->list, rdataset, link);
|
1999-04-30 22:35:49 +00:00
|
|
|
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
|
1999-04-30 07:53:07 +00:00
|
|
|
rdataset = next_rdataset;
|
|
|
|
}
|
|
|
|
|
|
|
|
ISC_LIST_UNLINK(*section, name, link);
|
|
|
|
name = next_name;
|
|
|
|
}
|
1999-04-27 02:24:11 +00:00
|
|
|
|
1999-04-30 23:04:29 +00:00
|
|
|
msg->buffer->length += msg->reserved;
|
1999-04-30 21:52:40 +00:00
|
|
|
msg->counts[sectionid] += total;
|
1999-04-30 22:35:49 +00:00
|
|
|
|
1999-04-30 21:09:19 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
1999-04-27 02:24:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dns_result_t
|
1999-04-30 05:42:06 +00:00
|
|
|
dns_message_renderend(dns_message_t *msg)
|
1999-04-27 02:24:11 +00:00
|
|
|
{
|
1999-04-30 21:52:40 +00:00
|
|
|
isc_buffer_t tmpbuf;
|
|
|
|
isc_region_t r;
|
1999-05-12 19:32:13 +00:00
|
|
|
isc_uint16_t tmp;
|
1999-04-30 21:52:40 +00:00
|
|
|
|
1999-04-27 02:24:11 +00:00
|
|
|
REQUIRE(VALID_MESSAGE(msg));
|
1999-04-30 05:42:06 +00:00
|
|
|
REQUIRE(msg->buffer != NULL);
|
|
|
|
|
1999-04-30 21:52:40 +00:00
|
|
|
isc_buffer_used(msg->buffer, &r);
|
|
|
|
isc_buffer_init(&tmpbuf, r.base, r.length, ISC_BUFFERTYPE_BINARY);
|
|
|
|
|
|
|
|
isc_buffer_putuint16(&tmpbuf, msg->id);
|
|
|
|
|
1999-05-12 19:32:13 +00:00
|
|
|
tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
|
|
|
|
& DNS_MESSAGE_OPCODE_MASK);
|
|
|
|
tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK); /* XXX edns? */
|
|
|
|
tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
|
1999-04-30 21:52:40 +00:00
|
|
|
|
1999-05-12 19:32:13 +00:00
|
|
|
isc_buffer_putuint16(&tmpbuf, tmp);
|
1999-04-30 21:52:40 +00:00
|
|
|
isc_buffer_putuint16(&tmpbuf, msg->counts[DNS_SECTION_QUESTION]);
|
|
|
|
isc_buffer_putuint16(&tmpbuf, msg->counts[DNS_SECTION_ANSWER]);
|
|
|
|
isc_buffer_putuint16(&tmpbuf, msg->counts[DNS_SECTION_AUTHORITY]);
|
1999-05-12 19:32:13 +00:00
|
|
|
tmp = msg->counts[DNS_SECTION_ADDITIONAL]
|
|
|
|
+ msg->counts[DNS_SECTION_TSIG];
|
|
|
|
isc_buffer_putuint16(&tmpbuf, tmp);
|
1999-04-30 21:52:40 +00:00
|
|
|
|
1999-04-30 05:42:06 +00:00
|
|
|
msg->buffer = NULL; /* forget about this buffer only on success XXX */
|
1999-04-27 02:24:11 +00:00
|
|
|
|
1999-04-30 07:53:07 +00:00
|
|
|
dns_compress_invalidate(&msg->cctx);
|
|
|
|
msg->need_cctx_cleanup = ISC_FALSE;
|
|
|
|
|
1999-04-27 02:24:11 +00:00
|
|
|
/* XXX implement */
|
|
|
|
return (ISC_R_NOTIMPLEMENTED);
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_result_t
|
|
|
|
dns_message_firstname(dns_message_t *msg, dns_section_t section)
|
|
|
|
{
|
|
|
|
REQUIRE(VALID_MESSAGE(msg));
|
|
|
|
REQUIRE(VALID_NAMED_SECTION(section));
|
|
|
|
|
|
|
|
msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
|
|
|
|
|
|
|
|
if (msg->cursors[section] == NULL)
|
|
|
|
return (DNS_R_NOMORE);
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_result_t
|
|
|
|
dns_message_nextname(dns_message_t *msg, dns_section_t section)
|
|
|
|
{
|
|
|
|
REQUIRE(VALID_MESSAGE(msg));
|
|
|
|
REQUIRE(VALID_NAMED_SECTION(section));
|
|
|
|
REQUIRE(msg->cursors[section] != NULL);
|
|
|
|
|
|
|
|
msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
|
|
|
|
|
|
|
|
if (msg->cursors[section] == NULL)
|
|
|
|
return (DNS_R_NOMORE);
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_message_currentname(dns_message_t *msg, dns_section_t section,
|
|
|
|
dns_name_t **name)
|
|
|
|
{
|
|
|
|
REQUIRE(VALID_MESSAGE(msg));
|
|
|
|
REQUIRE(VALID_NAMED_SECTION(section));
|
1999-04-30 00:17:15 +00:00
|
|
|
REQUIRE(name != NULL && *name == NULL);
|
1999-04-27 02:24:11 +00:00
|
|
|
REQUIRE(msg->cursors[section] != NULL);
|
|
|
|
|
|
|
|
*name = msg->cursors[section];
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_result_t
|
|
|
|
dns_message_findname(dns_message_t *msg, dns_section_t section,
|
|
|
|
dns_name_t *target, dns_rdatatype_t type,
|
|
|
|
dns_name_t **name, dns_rdataset_t **rdataset)
|
|
|
|
{
|
1999-04-30 06:13:07 +00:00
|
|
|
dns_name_t *foundname;
|
|
|
|
dns_result_t result;
|
1999-04-27 02:24:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX These requirements are probably too intensive, especially
|
|
|
|
* where things can be NULL, but as they are they ensure that if
|
|
|
|
* something is NON-NULL, indicating that the caller expects it
|
|
|
|
* to be filled in, that we can in fact fill it in.
|
|
|
|
*/
|
|
|
|
REQUIRE(msg != NULL);
|
|
|
|
REQUIRE(VALID_SECTION(section));
|
|
|
|
REQUIRE(target != NULL);
|
|
|
|
if (name != NULL)
|
|
|
|
REQUIRE(*name == NULL);
|
|
|
|
if (type == dns_rdatatype_any) {
|
|
|
|
REQUIRE(rdataset == NULL);
|
|
|
|
} else {
|
|
|
|
if (rdataset != NULL)
|
|
|
|
REQUIRE(*rdataset == NULL);
|
|
|
|
}
|
|
|
|
|
1999-04-30 06:13:07 +00:00
|
|
|
/*
|
|
|
|
* Search through, looking for the name.
|
|
|
|
*/
|
|
|
|
result = findname(&foundname, target, &msg->sections[section]);
|
1999-04-30 06:37:35 +00:00
|
|
|
if (result == DNS_R_NOTFOUND)
|
|
|
|
return (DNS_R_NXDOMAIN);
|
|
|
|
else if (result != DNS_R_SUCCESS)
|
1999-04-30 06:13:07 +00:00
|
|
|
return (result);
|
|
|
|
|
|
|
|
if (name != NULL)
|
|
|
|
*name = foundname;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* And now look for the type.
|
|
|
|
*/
|
|
|
|
if (rdataset == NULL)
|
|
|
|
return (DNS_R_SUCCESS);
|
|
|
|
|
|
|
|
result = findtype(rdataset, foundname, type);
|
1999-04-30 06:37:35 +00:00
|
|
|
if (result == DNS_R_NOTFOUND)
|
|
|
|
return (DNS_R_NXRDATASET);
|
|
|
|
|
1999-04-30 06:13:07 +00:00
|
|
|
return (result);
|
1999-04-27 02:24:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_message_movename(dns_message_t *msg, dns_name_t *name,
|
|
|
|
dns_section_t fromsection,
|
|
|
|
dns_section_t tosection)
|
|
|
|
{
|
|
|
|
REQUIRE(msg != NULL);
|
1999-04-30 05:57:39 +00:00
|
|
|
REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENT_RENDER);
|
1999-04-27 02:24:11 +00:00
|
|
|
REQUIRE(name != NULL);
|
|
|
|
REQUIRE(VALID_NAMED_SECTION(fromsection));
|
|
|
|
REQUIRE(VALID_NAMED_SECTION(tosection));
|
|
|
|
REQUIRE(fromsection != tosection);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Unlink the name from the old section
|
|
|
|
*/
|
|
|
|
ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
|
|
|
|
ISC_LIST_APPEND(msg->sections[tosection], name, link);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_message_addname(dns_message_t *msg, dns_name_t *name,
|
|
|
|
dns_section_t section)
|
|
|
|
{
|
|
|
|
REQUIRE(msg != NULL);
|
1999-04-30 05:57:39 +00:00
|
|
|
REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENT_RENDER);
|
1999-04-27 02:24:11 +00:00
|
|
|
REQUIRE(name != NULL);
|
|
|
|
REQUIRE(VALID_NAMED_SECTION(section));
|
|
|
|
|
|
|
|
ISC_LIST_APPEND(msg->sections[section], name, link);
|
|
|
|
}
|