message.c revision e223094b2248afa2697c531f75e6f84855638bec
/*
* 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>
#include <dns/rdataset.h>
#include <dns/rdataclass.h>
#include <dns/rdatatype.h>
#include <dns/rdatalist.h>
#include <dns/compress.h>
#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.
*/
#define SCRATCHPAD_SIZE 512
#define NAME_COUNT 16
#define RDATA_COUNT 32
#define RDATASET_COUNT 32
/*
* internal state stuff.
*/
#define TO_FROM_UNKNOWN 0
#define TO_FROM_FROMWIRE 1
#define TO_FROM_TOWIRE 2
/*
* "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;
}; /* dynamically sized */
static inline void
static inline void *
msgblock_internalget(dns_msgblock_t *, unsigned int);
static inline void
msgblock_reset(dns_msgblock_t *, unsigned int);
static inline dns_msgblock_t *
msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
/*
* Allocate a new dns_msgblock_t, and return a pointer to it. If no memory
* is free, return NULL.
*/
static inline dns_msgblock_t *
unsigned int count)
{
unsigned int length;
return NULL;
return (block);
}
/*
* Return an element from the msgblock. If no more are available, return
* NULL.
*/
static inline void *
{
void *ptr;
return (NULL);
+ sizeof(dns_msgblock_t)
return (ptr);
}
static inline void
{
}
/*
* Release memory associated with a message block.
*/
static inline void
{
}
/*
* 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
{
if (result != ISC_R_SUCCESS)
return (DNS_R_NOMEMORY);
return (DNS_R_SUCCESS);
}
static inline isc_buffer_t *
{
}
static inline void
{
}
static inline dns_name_t *
{
return (name);
}
return (NULL);
}
return (name);
}
static inline void
{
}
static inline dns_rdata_t *
{
return (rdata);
}
return (NULL);
}
return (rdata);
}
static inline void
{
}
static inline dns_rdatalist_t *
{
return (rdatalist);
}
sizeof(dns_rdatalist_t),
return (NULL);
}
return (rdatalist);
}
static inline void
{
}
static inline dns_rdataset_t *
{
return (rdataset);
}
return (NULL);
}
return (rdataset);
}
/*
* Init elements to default state. Used both when allocating a new element
* and when resetting one.
*/
static inline void
msginit(dns_message_t *m)
{
unsigned int i;
m->id = 0;
m->flags = 0;
m->rcode = 0;
m->opcode = 0;
m->rdclass = 0;
for (i = 0 ; i < DNS_SECTION_MAX ; i++) {
}
m->nextrdataset = NULL;
m->nextrdatalist = NULL;
}
/*
* Free all but one (or everything) for this message. This is used by
* both dns_message_reset() and dns_message_parse().
*/
static void
{
unsigned int i;
/*
* Clean up name lists by calling the rdataset disassociate function.
*/
for (i = 0 ; i < DNS_SECTION_MAX ; i++) {
}
}
}
/*
* Clean up linked lists.
*/
if (everything == ISC_FALSE) {
}
}
if (everything == ISC_FALSE) {
}
}
if (everything == ISC_FALSE) {
}
}
if (everything == ISC_FALSE) {
}
}
if (everything == ISC_FALSE) {
}
}
}
/*
* Set other bits to normal default values.
*/
}
{
dns_message_t *m;
unsigned int i;
|| intent == DNS_MESSAGE_INTENT_RENDER);
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]);
ISC_LIST_INIT(m->scratchpad);
ISC_LIST_INIT(m->names);
ISC_LIST_INIT(m->rdatas);
ISC_LIST_INIT(m->rdatalists);
if (iresult != ISC_R_SUCCESS)
goto cleanup1;
goto cleanup2;
goto cleanup3;
goto cleanup4;
if (intent == DNS_MESSAGE_INTENT_PARSE) {
goto cleanup5;
}
return (DNS_R_SUCCESS);
/*
* Cleanup for error returns.
*/
m->magic = 0;
return (DNS_R_NOMEMORY);
}
void
{
}
void
{
}
static dns_result_t
{
return (DNS_R_SUCCESS);
}
}
return (DNS_R_NOTFOUND);
}
static dns_result_t
{
return (DNS_R_SUCCESS);
}
}
return (DNS_R_NOTFOUND);
}
/*
* Read a name from buffer "source".
*
* Assumes dns_name_init() was already called on this name.
*/
static dns_result_t
{
unsigned int tries;
else
tries = 0;
while (tries < 2) {
scratch);
if (result == DNS_R_NOSPACE) {
tries++;
if (result != DNS_R_SUCCESS)
return (result);
} else {
return (result);
}
}
return (DNS_R_UNEXPECTED); /* should never get here... XXXMLG */
}
static dns_result_t
{
isc_region_t r;
unsigned int count;
return (DNS_R_NOMEMORY);
/*
* Parse the name out of this packet.
*/
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.
*/
/*
* If it is a new name, append to the section. Note that
* 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.
*/
if (result != DNS_R_SUCCESS)
return (DNS_R_FORMERR);
/*
* Get type and class.
*/
isc_buffer_remaining(source, &r);
if (r.length < 4)
return (DNS_R_UNEXPECTEDEND);
/*
* If this class is different than the one we alrady read,
* this is an error.
*/
return (DNS_R_FORMERR);
/*
* Search name for the particular type and class.
* If it was found, this is an error, return FORMERR.
*/
if (result == DNS_R_SUCCESS)
return (DNS_R_FORMERR);
/*
* Allocate a new rdatalist.
*/
/*
* Convert rdatalist to rdataset, and attach the latter to
* the name.
*/
if (result != DNS_R_SUCCESS)
return (result);
}
return (DNS_R_SUCCESS);
}
static dns_result_t
{
isc_region_t r;
unsigned int count;
return (DNS_R_NOMEMORY);
/*
* Parse the name out of this packet.
*/
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.
*/
/*
* If it is a new name, append to the section.
*/
if (result == DNS_R_SUCCESS) {
}
/*
* 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);
/*
* If this class is different than the one we already read,
* this is an error.
*/
return (DNS_R_FORMERR);
/*
* ... now get ttl and rdatalen, and check buffer.
*/
r.length -= 10;
return (DNS_R_UNEXPECTEDEND);
/*
* Search name for the particular type and class.
* If it was found, this is an error, return FORMERR.
*/
/*
* Oh hurt me... I need to add this name to the rdatalist,
* but I have to cheat to get at that given the rdataset...
*
* This sucks. XXXMLG stop point, code below probably wrong.
*/
if (result != DNS_R_SUCCESS) {
return (DNS_R_NOMEMORY);
return (DNS_R_FORMERR);
/*
* Allocate a new rdatalist, rdata.
*/
/*
* Convert rdatalist to rdataset, and attach the latter to
* the name.
*/
if (result != DNS_R_SUCCESS)
return (result);
}
return (DNS_R_SUCCESS);
}
{
isc_region_t r;
isc_buffer_remaining(source, &r);
if (r.length >= DNS_MESSAGE_HEADER_LEN)
return (DNS_R_UNEXPECTEDEND);
if (ret != DNS_R_SUCCESS)
return (ret);
if (ret != DNS_R_SUCCESS)
return (ret);
if (ret != DNS_R_SUCCESS)
return (ret);
if (ret != DNS_R_SUCCESS)
return (ret);
/*
* XXXMLG Need to check the tsig(s) here...
*/
return (DNS_R_SUCCESS);
}
{
/* XXX implement */
return (ISC_R_NOTIMPLEMENTED);
}
{
return (DNS_R_NOSPACE);
return (DNS_R_SUCCESS);
}
unsigned int space)
{
isc_region_t r;
/*
* "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.
*/
isc_buffer_available(buffer, &r);
return (DNS_R_NOSPACE);
return (DNS_R_SUCCESS);
}
unsigned int flags)
{
/* XXX implement */
return (ISC_R_NOTIMPLEMENTED);
}
{
/* XXX implement */
return (ISC_R_NOTIMPLEMENTED);
}
{
return (DNS_R_NOMORE);
return (ISC_R_SUCCESS);
}
{
return (DNS_R_NOMORE);
return (ISC_R_SUCCESS);
}
void
dns_name_t **name)
{
}
{
/*
* 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.
*/
if (type == dns_rdatatype_any) {
} else {
}
return (ISC_R_NOTIMPLEMENTED);
/* XXX implement */
}
void
{
/*
* Unlink the name from the old section
*/
}
void
{
}